mirror of
https://github.com/StepanovPlaton/AboutMe.git
synced 2026-04-03 20:30:49 +04:00
Fixes
This commit is contained in:
@@ -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"
|
||||||
|
files:
|
||||||
|
- label: "Worth Mentioning"
|
||||||
|
name: "worth-mentioning"
|
||||||
file: "src/content/worth-mentioning.md"
|
file: "src/content/worth-mentioning.md"
|
||||||
fields:
|
fields:
|
||||||
- { label: "Body", name: "body", widget: "markdown" }
|
- { label: "Body", name: "body", widget: "markdown" }
|
||||||
|
- label: "About"
|
||||||
|
name: "about"
|
||||||
|
file: "src/content/about.md"
|
||||||
|
fields:
|
||||||
|
- { label: "Body", name: "body", widget: "markdown" }
|
||||||
|
|
||||||
|
|
||||||
editor:
|
editor:
|
||||||
|
|||||||
@@ -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);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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 |
@@ -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
|
|
||||||
```
|
|
||||||
@@ -13,6 +13,6 @@ draft: false
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Если вам интересно как всё устроено, то обязательно заходите на страницу [О сайте](../about/)
|
Если вам интересно как всё устроено, то обязательно заходите на страницу [О сайте](/about/)
|
||||||
|
|
||||||
Так же можете посмотреть другие классные проекты на странице [Посмотрите так же](../worth-mentioning/)
|
Так же можете посмотреть другие классные проекты на странице [Посмотрите так же](/worth-mentioning/)
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ enum I18nKey {
|
|||||||
timelineCurrentRole = "timelineCurrentRole",
|
timelineCurrentRole = "timelineCurrentRole",
|
||||||
timelineEmployed = "timelineEmployed",
|
timelineEmployed = "timelineEmployed",
|
||||||
timelineAvailable = "timelineAvailable",
|
timelineAvailable = "timelineAvailable",
|
||||||
|
timelineMoreAchievements = "timelineMoreAchievements",
|
||||||
|
|
||||||
// 短文页面
|
// 短文页面
|
||||||
diary = "diary",
|
diary = "diary",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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]: "日記",
|
||||||
|
|||||||
@@ -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]: "Дневник",
|
||||||
|
|||||||
@@ -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]: "日记",
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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>,
|
||||||
|
|||||||
@@ -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" />
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user