This commit is contained in:
2026-02-04 16:25:30 +04:00
parent fa6b4fbff9
commit 74cc476f90
19 changed files with 72 additions and 79 deletions

View File

@@ -97,6 +97,7 @@ collections:
- { label: "Type", name: "type", widget: "select", options: ["certificate","project","other"] } - { label: "Type", name: "type", widget: "select", options: ["certificate","project","other"] }
- { label: "Icon", name: "icon", widget: "string", required: false } - { label: "Icon", name: "icon", widget: "string", required: false }
- { label: "Color", name: "color", widget: "string", required: false } - { label: "Color", name: "color", widget: "string", required: false }
- { label: "Not Pin", name: "not_pin", widget: "boolean", required: false, default: false, hint: "If enabled, this item will not be shown in the 'Current Status' section" }
- name: "diary" - name: "diary"
label: "Diary" label: "Diary"
@@ -155,11 +156,19 @@ collections:
- { label: "Site URL", name: "siteurl", widget: "string" } - { label: "Site URL", name: "siteurl", widget: "string" }
- { label: "Tags", name: "tags", widget: "list", required: false, default: [] } - { label: "Tags", name: "tags", widget: "list", required: false, default: [] }
- name: "worth-mentioning" - name: "Static Pages"
label: "Worth Mentioning" label: "Static Pages"
file: "src/content/worth-mentioning.md" files:
fields: - label: "Worth Mentioning"
- { label: "Body", name: "body", widget: "markdown" } name: "worth-mentioning"
file: "src/content/worth-mentioning.md"
fields:
- { label: "Body", name: "body", widget: "markdown" }
- label: "About"
name: "about"
file: "src/content/about.md"
fields:
- { label: "Body", name: "body", widget: "markdown" }
editor: editor:

View File

@@ -69,7 +69,11 @@ let groups = $derived.by(() => {
if (categories.length > 0) { if (categories.length > 0) {
filteredPosts = filteredPosts.filter( filteredPosts = filteredPosts.filter(
(post) => post.data.category && categories.includes(post.data.category), (post) => {
if (!post.data.category) return false;
const postCategory = post.data.category.trim();
return categories.some(cat => cat.trim() === postCategory);
},
); );
} }

View File

@@ -2,6 +2,7 @@
import { i18n } from "@i18n/translation"; import { i18n } from "@i18n/translation";
import I18nKey from "@i18n/i18nKey"; import I18nKey from "@i18n/i18nKey";
import Icon from "@components/common/icon.astro"; import Icon from "@components/common/icon.astro";
import { getResolvedSiteLang } from "@utils/language";
export interface Props { export interface Props {
@@ -100,10 +101,23 @@ const getLinkIcon = (type: string) => {
} }
}; };
// 获取 локаль для форматирования дат
const getDateLocale = () => {
const lang = getResolvedSiteLang();
const localeMap: Record<string, string> = {
ru: "ru-RU",
en: "en-US",
zh: "zh-CN",
ja: "ja-JP",
};
return localeMap[lang] || "en-US";
};
// 格式化日期 // 格式化日期
const formatDate = (dateString: string) => { const formatDate = (dateString: string) => {
const date = new Date(dateString); const date = new Date(dateString);
return date.toLocaleDateString("zh-CN", { year: "numeric", month: "long" }); const locale = getDateLocale();
return date.toLocaleDateString(locale, { year: "numeric", month: "long" });
}; };
// 计算持续时间 // 计算持续时间
@@ -330,7 +344,7 @@ const itemColor = item.color || "#3B82F6";
))} ))}
{item.achievements.length > 3 && ( {item.achievements.length > 3 && (
<li class={`text-black/60 dark:text-white/60 ${sizeClasses.description}`}> <li class={`text-black/60 dark:text-white/60 ${sizeClasses.description}`}>
... 还有 {item.achievements.length - 3} 项成就 {i18n(I18nKey.timelineMoreAchievements).replace("{0}", String(item.achievements.length - 3))}
</li> </li>
)} )}
</ul> </ul>

View File

@@ -40,8 +40,9 @@ let links: NavbarLink[] = navbarConfig.links.map(
"overflow-visible! max-w-(--page-width) h-18 mx-auto flex items-center justify-between md:px-4"]}> "overflow-visible! max-w-(--page-width) h-18 mx-auto flex items-center justify-between md:px-4"]}>
<a href={url('/')} class="btn-plain scale-animation rounded-lg h-13 px-5 font-bold active:scale-95"> <a href={url('/')} class="btn-plain scale-animation rounded-lg h-13 px-5 font-bold active:scale-95">
<div class="flex flex-row text-(--primary) items-center text-md"> <div class="flex flex-row text-(--primary) items-center text-md">
<Icon name="material-symbols:home-pin-outline" class="text-[1.75rem] mb-1 mr-2" /> <Icon name="material-symbols:home-rounded" class="text-[1.75rem] mb-1 mr-2" />
{siteConfig.title} {/*siteConfig.title*/}
Главная
</div> </div>
</a> </a>
<div class="hidden md:flex items-center navbar-nav-links"> <div class="hidden md:flex items-center navbar-nav-links">

View File

@@ -14,7 +14,7 @@ export const LinkPresets: { [key in LinkPreset]: NavbarLink } = {
name: i18n(I18nKey.archive), name: i18n(I18nKey.archive),
url: "/archive/", url: "/archive/",
icon: "material-symbols:archive", icon: "material-symbols:archive",
description: "A chronological list of all published posts.", description: "Список постов в хронологическом порядке",
}, },
[LinkPreset.Projects]: { [LinkPreset.Projects]: {
name: i18n(I18nKey.projects), name: i18n(I18nKey.projects),

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

View File

@@ -1,56 +0,0 @@
---
title: Guide for Blog Template
published: 2001-10-02
description: "How to use this blog template."
cover: "./cover.jpg"
pinned: true
tags: []
category: Guides
draft: false
---
Tip: For the things that are not mentioned in this guide, you may find the answers in the [Astro Docs](https://docs.astro.build/).
## Front-matter of Posts
```yaml
---
title: My First Blog Post
published: 2020-02-02
description: This is the first post of my new Astro blog.
cover: ./cover.jpg
tags: [Foo, Bar]
category: Front-end
draft: false
---
```
| Attribute | Description |
|---------------|---------------|
| `title` | The title of the post. |
| `published` | The date the post was published. |
| `pinned` | Whether this post is pinned to the top of the post list. |
| `description` | A short description of the post. Displayed on index page. |
| `cover` | The cover image path of the post. <br/>1. Start with `http://` or `https://`: For web image <br/>2. Start with `/`: For image in `public` dir <br/>3. With none of the prefixes: Relative to the markdown file |
| `tags` | The tags of the post. |
| `category` | The category of the post. |
| `licenseName` | The license name for the post content. |
| `author` | The author of the post. |
| `sourceLink` | The source link or reference for the post content. |
| `draft` | If this post is still a draft, which won't be displayed. |
## Where to Place the Post Files
Your post files should be placed in `src/content/posts/` directory. You can also create sub-directories to better organize your posts and assets.
```
src/content/posts/
├── post-1.md
└── post-2/
├── cover.jpg
└── index.md
```

View File

@@ -13,6 +13,6 @@ draft: false
Если вам интересно как всё устроено, то обязательно заходите на страницу [О сайте](../about/) Если вам интересно как всё устроено, то обязательно заходите на страницу [О сайте](/about/)
Так же можете посмотреть другие классные проекты на странице [Посмотрите так же](../worth-mentioning/) Так же можете посмотреть другие классные проекты на странице [Посмотрите так же](/worth-mentioning/)

View File

@@ -147,6 +147,7 @@ enum I18nKey {
timelineCurrentRole = "timelineCurrentRole", timelineCurrentRole = "timelineCurrentRole",
timelineEmployed = "timelineEmployed", timelineEmployed = "timelineEmployed",
timelineAvailable = "timelineAvailable", timelineAvailable = "timelineAvailable",
timelineMoreAchievements = "timelineMoreAchievements",
// 短文页面 // 短文页面
diary = "diary", diary = "diary",

View File

@@ -150,6 +150,7 @@ export const en: Translation = {
[Key.timelineCurrentRole]: "Current Status", [Key.timelineCurrentRole]: "Current Status",
[Key.timelineEmployed]: "Employed", [Key.timelineEmployed]: "Employed",
[Key.timelineAvailable]: "Available", [Key.timelineAvailable]: "Available",
[Key.timelineMoreAchievements]: "... {0} more achievements",
// Diary Page // Diary Page
[Key.diary]: "Diary", [Key.diary]: "Diary",

View File

@@ -150,6 +150,7 @@ export const ja: Translation = {
[Key.timelineCurrentRole]: "現在の状態", [Key.timelineCurrentRole]: "現在の状態",
[Key.timelineEmployed]: "在職中", [Key.timelineEmployed]: "在職中",
[Key.timelineAvailable]: "入社可能", [Key.timelineAvailable]: "入社可能",
[Key.timelineMoreAchievements]: "... あと {0} 件の実績",
// 日記ページ // 日記ページ
[Key.diary]: "日記", [Key.diary]: "日記",

View File

@@ -8,7 +8,7 @@ export const ru: Translation = {
// Навигация // Навигация
[Key.home]: "Главная", [Key.home]: "Главная",
[Key.archive]: "Архив", [Key.archive]: "Все посты",
[Key.about]: "О сайте", [Key.about]: "О сайте",
[Key.search]: "Поиск", [Key.search]: "Поиск",
@@ -148,8 +148,9 @@ export const ru: Translation = {
[Key.timelineTotalExperience]: "Общий опыт работы", [Key.timelineTotalExperience]: "Общий опыт работы",
[Key.timelineWorkPositions]: "Рабочих позиций", [Key.timelineWorkPositions]: "Рабочих позиций",
[Key.timelineCurrentRole]: "Текущий статус", [Key.timelineCurrentRole]: "Текущий статус",
[Key.timelineEmployed]: "Трудоустроен", [Key.timelineEmployed]: "Рассматриваю предложения",
[Key.timelineAvailable]: "Доступен", [Key.timelineAvailable]: "Доступен",
[Key.timelineMoreAchievements]: "... еще {0} достижений",
// Страница дневника // Страница дневника
[Key.diary]: "Дневник", [Key.diary]: "Дневник",

View File

@@ -150,6 +150,7 @@ export const zh: Translation = {
[Key.timelineCurrentRole]: "当前状态", [Key.timelineCurrentRole]: "当前状态",
[Key.timelineEmployed]: "在职", [Key.timelineEmployed]: "在职",
[Key.timelineAvailable]: "可入职", [Key.timelineAvailable]: "可入职",
[Key.timelineMoreAchievements]: "... 还有 {0} 项成就",
// 短文页面 // 短文页面
[Key.diary]: "日记", [Key.diary]: "日记",

View File

@@ -60,7 +60,8 @@ const len = page.data.length;
<!-- Заголовок --> <!-- Заголовок -->
<header class="mb-8"> <header class="mb-8">
<h1 class="text-3xl font-bold text-neutral-900 dark:text-neutral-100 mb-3"> <h1 class="text-3xl font-bold text-neutral-900 dark:text-neutral-100 mb-3">
{pageTitle} {/*pageTitle*/}
Добро пожаловать!
</h1> </h1>
{pageDescription && ( {pageDescription && (
<p class="text-neutral-600 dark:text-neutral-400"> <p class="text-neutral-600 dark:text-neutral-400">

View File

@@ -36,7 +36,13 @@ const categories = categoryOrder.filter(cat => allCategories.includes(cat));
// 按分类获取技能 // 按分类获取技能
const skillsByCategory = categories.reduce( const skillsByCategory = categories.reduce(
(acc, category) => { (acc, category) => {
acc[category] = getSkillsByCategory(category); const categorySkills = getSkillsByCategory(category);
// 按 опыту сортировка: больше опыта - выше, меньше опыта - ниже
acc[category] = categorySkills.sort((a, b) => {
const aMonths = a.experience.years * 12 + a.experience.months;
const bMonths = b.experience.years * 12 + b.experience.months;
return bMonths - aMonths; // Сортировка по убыванию (больше опыта первым)
});
return acc; return acc;
}, },
{} as Record<string, typeof skillsData>, {} as Record<string, typeof skillsData>,

View File

@@ -94,7 +94,7 @@ const getTypeIcon = (type: string) => {
<h2 class="text-2xl font-bold text-black/90 dark:text-white/90 mb-4"> <h2 class="text-2xl font-bold text-black/90 dark:text-white/90 mb-4">
{i18n(I18nKey.timelineCurrent)} {i18n(I18nKey.timelineCurrent)}
</h2> </h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <div class="grid grid-cols-1 gap-6">
{currentItems.map((item) => ( {currentItems.map((item) => (
<TimelineItem item={item} layout="card" size="medium" /> <TimelineItem item={item} layout="card" size="medium" />
))} ))}

View File

@@ -50,10 +50,18 @@ export const getProjectStats = () => {
// Get projects by category // Get projects by category
export const getProjectsByCategory = (category?: string) => { export const getProjectsByCategory = (category?: string) => {
let filteredProjects: Project[];
if (!category || category === "all") { if (!category || category === "all") {
return projectsData; filteredProjects = projectsData;
} else {
filteredProjects = projectsData.filter((p) => p.category === category);
} }
return projectsData.filter((p) => p.category === category); // Sort by startDate in descending order (newest first)
return filteredProjects.sort((a, b) => {
const dateA = new Date(a.startDate).getTime();
const dateB = new Date(b.startDate).getTime();
return dateB - dateA;
});
}; };
// Get featured projects // Get featured projects

View File

@@ -22,6 +22,7 @@ export interface TimelineItem {
icon?: string; // Iconify icon name icon?: string; // Iconify icon name
color?: string; color?: string;
featured?: boolean; featured?: boolean;
not_pin?: boolean; // If true, exclude from "Current Status" section
} }
export const timelineData: TimelineItem[] = Object.entries(timelineModules).map(([path, mod]: [string, any]) => { export const timelineData: TimelineItem[] = Object.entries(timelineModules).map(([path, mod]: [string, any]) => {
@@ -74,7 +75,7 @@ export const getFeaturedTimeline = () => {
// Get current ongoing items // Get current ongoing items
export const getCurrentItems = () => { export const getCurrentItems = () => {
return timelineData.filter((item) => !item.endDate); return timelineData.filter((item) => !item.endDate && !item.not_pin);
}; };

View File

@@ -35,8 +35,8 @@ site:
- "/assets/images/banner1.png" - "/assets/images/banner1.png"
position: "center" position: "center"
carousel: carousel:
enable: true enable: false
interval: 3.6 interval: 12
kenBurns: true kenBurns: true
banner: banner:
homeText: homeText: