feat(blog): refactor blog components and improve category/tag handling

- Add new CategoryCard and TagCard components to centralize UI logic
- Convert BlogList from React to Astro component
- Improve category and tag matching by using IDs from frontmatter
- Update all blog pages to use new components
- Add line-height to global styles for better readability
This commit is contained in:
joyzhao
2025-06-19 14:45:29 +08:00
parent deb80c0df7
commit 429b13985f
11 changed files with 545 additions and 363 deletions

View File

@@ -0,0 +1,95 @@
---
// 导入必要的依赖
import { type Lang } from '@/i18n/utils';
import { defaultLang } from '@/i18n/ui';
// 定义组件属性
interface Props {
lang?: Lang;
currentCategory?: string;
}
// 获取组件属性
const { lang = defaultLang, currentCategory = '' } = Astro.props;
// 确定基础URL路径
const baseUrl = lang === defaultLang ? '/blog' : `/${lang}/blog`;
// 读取所有博客文章 - 根据语言选择不同的静态路径
let allPosts = [];
if (lang === 'zh') {
allPosts = await Astro.glob('/src/pages/zh/blog/posts/*.md');
} else {
allPosts = await Astro.glob('/src/pages/blog/posts/*.md');
}
// 收集所有分类
const allCategories = new Set<string>();
// 处理所有文章的分类
const categoryMap = new Map<string, string>(); // 存储 categoryId 到 category 名称的映射
allPosts.forEach(post => {
// 处理分类
if (post.frontmatter?.category) {
const categories = Array.isArray(post.frontmatter.category)
? post.frontmatter.category
: [post.frontmatter.category];
const categoryIds = Array.isArray(post.frontmatter.categoryId)
? post.frontmatter.categoryId
: post.frontmatter.categoryId ? [post.frontmatter.categoryId] : [];
// 如果有 categoryId则使用 categoryId 和 category 的映射
if (categoryIds.length > 0 && categoryIds.length === categories.length) {
categories.forEach((cat, index) => {
if (cat && categoryIds[index]) {
allCategories.add(cat);
categoryMap.set(cat, categoryIds[index]);
}
});
} else {
// 如果没有 categoryId 或长度不匹配,则使用 category 名称作为 ID
categories.forEach(cat => {
if (cat) {
allCategories.add(cat);
categoryMap.set(cat, cat.toLowerCase());
}
});
}
}
});
// 转换为数组并排序
const categories = Array.from(allCategories).sort();
// 多语言标题
const titles = {
en: 'Categories',
zh: '分类'
};
// 获取当前语言的标题
const title = titles[lang] || titles[defaultLang];
---
<div class="bg-card/50 backdrop-blur-sm rounded-2xl p-6 border border-border">
<h3 class="text-xl font-semibold text-card-foreground mb-4 flex items-center">
<svg class="w-5 h-5 mr-2 text-purple-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14-7l2 2-2 2m2-2H9m10 0V9M5 19l2-2-2-2m2 2H3m2 0v2"></path>
</svg>
{title}
</h3>
<div class="space-y-2">
{categories.map((cat) => {
const categoryId = categoryMap.get(cat) || cat.toLowerCase();
return (
<a href={`${baseUrl}/categories/${encodeURIComponent(categoryId)}`}
class={`block transition-colors duration-200 ${categoryId === currentCategory.toLowerCase() ? 'text-purple-500 font-medium' : 'text-muted-foreground hover:text-purple-500'}`}>
{cat}
</a>
);
})}
</div>
</div>