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

@@ -1,6 +1,8 @@
---
import BlogLayout from '../../../layouts/BlogLayout.astro';
import BlogList from '../../../components/BlogList.tsx';
import BlogList from '../../../components/blog/BlogList.astro';
import CategoryCard from '../../../components/blog/CategoryCard.astro';
import TagCard from '../../../components/blog/TagCard.astro';
import { type Lang } from '@/i18n/utils';
import { defaultLang } from '@/i18n/ui';
import { type BlogPost } from '@/types';
@@ -137,12 +139,33 @@ allPosts.forEach(post => {
const categories = Array.from(allCategories).sort();
const tags = Array.from(allTags).map(tag => `# ${tag}`).sort();
// 获取当前分类的格式化名称(首字母大写)
const formattedCategory = decodedCategory.charAt(0).toUpperCase() + decodedCategory.slice(1);
// 查找与当前分类ID匹配的分类名称
let displayCategoryName = "";
// 从博客文章中查找匹配的分类名称
for (const post of allPosts) {
if (post.frontmatter?.categoryId && Array.isArray(post.frontmatter.categoryId) &&
post.frontmatter?.category && Array.isArray(post.frontmatter.category)) {
// 查找分类ID和分类名称的索引匹配
const categoryIndex = post.frontmatter.categoryId.findIndex(id =>
id.toLowerCase() === decodedCategory.toLowerCase()
);
if (categoryIndex !== -1 && categoryIndex < post.frontmatter.category.length) {
displayCategoryName = post.frontmatter.category[categoryIndex];
break;
}
}
}
// 如果没有找到匹配的分类名称则使用分类ID并格式化首字母大写
if (!displayCategoryName) {
displayCategoryName = decodedCategory.charAt(0).toUpperCase() + decodedCategory.slice(1);
}
// 动态生成页面标题和描述
const pageTitle = `${formattedCategory} - Blog | Joy Zhao`;
const pageDescription = `Explore articles about ${formattedCategory}. Dive into my thoughts on ${formattedCategory} and related topics.`;
const pageTitle = `${displayCategoryName} - Blog | Joy Zhao`;
const pageDescription = `Explore articles about ${displayCategoryName}. Dive into my thoughts on ${displayCategoryName} and related topics.`;
---
<BlogLayout title={pageTitle} description={pageDescription}>
@@ -151,10 +174,10 @@ const pageDescription = `Explore articles about ${formattedCategory}. Dive into
<div class="container mx-auto px-4 pt-24 pb-12">
<div class="text-center mb-16">
<h1 class="text-5xl md:text-6xl font-bold bg-gradient-to-r from-foreground via-purple-600 to-purple-800 dark:from-foreground dark:via-purple-200 dark:to-purple-300 bg-clip-text text-transparent mb-6">
Category: <span class="text-purple-500">{formattedCategory}</span>
Category: <span class="text-purple-500">{displayCategoryName}</span>
</h1>
<p class="text-xl text-muted-foreground max-w-3xl mx-auto">
Explore articles about {formattedCategory}. Found {sortedBlogPosts.length} article{sortedBlogPosts.length !== 1 ? 's' : ''}.
Explore articles about {displayCategoryName}. Found {sortedBlogPosts.length} article{sortedBlogPosts.length !== 1 ? 's' : ''}.
</p>
</div>
</div>
@@ -164,47 +187,18 @@ const pageDescription = `Explore articles about ${formattedCategory}. Dive into
<div class="grid grid-cols-1 lg:grid-cols-4 gap-8">
<!-- Sidebar -->
<div class="lg:col-span-1 space-y-8">
<!-- Categories -->
<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>
Categories
</h3>
<div class="space-y-2">
{categories.map((cat) => (
<a href={`/blog/categories/${encodeURIComponent(cat.toLowerCase())}`}
class={`block transition-colors duration-200 ${cat.toLowerCase() === decodedCategory.toLowerCase() ? 'text-purple-500 font-medium' : 'text-muted-foreground hover:text-purple-500'}`}>
{cat}
</a>
))}
</div>
</div>
<!-- 分类卡片 -->
<CategoryCard lang="en" currentCategory={decodedCategory} />
<!-- 标签卡片 -->
<TagCard lang="en" />
<!-- Tags -->
<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="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"></path>
</svg>
# Tags
</h3>
<div class="flex flex-wrap gap-2">
{tags.map((tag) => (
<a href={`/blog/tags/${encodeURIComponent(tag.slice(2).toLowerCase())}`}
class="inline-block px-3 py-1 text-sm bg-muted text-muted-foreground rounded-full hover:bg-purple-500/20 hover:text-purple-500 transition-all duration-200">
{tag}
</a>
))}
</div>
</div>
</div>
<!-- Blog Posts -->
<div class="lg:col-span-3">
{sortedBlogPosts.length > 0 ? (
<BlogList posts={sortedBlogPosts} lang="en" client:load />
<BlogList posts={sortedBlogPosts} lang="en" category={decodedCategory} />
) : (
<div class="bg-card/50 backdrop-blur-sm rounded-2xl p-8 border border-border text-center">
<h2 class="text-2xl font-semibold mb-4">No articles found</h2>

View File

@@ -1,9 +1,11 @@
---
import BlogLayout from '../../layouts/BlogLayout.astro';
import BlogList from '../../components/BlogList.tsx';
import BlogList from '../../components/blog/BlogList.astro';
import CategoryCard from '../../components/blog/CategoryCard.astro';
import TagCard from '../../components/blog/TagCard.astro';
import { type BlogPost } from '@/types';
import { type Lang } from '@/i18n/utils';
import { defaultLang } from '@/i18n/ui';
import { type BlogPost } from '@/types';
// 使用Astro.currentLocale获取当前语言环境
const lang = Astro.currentLocale as Lang || defaultLang;
@@ -89,48 +91,18 @@ const tags = Array.from(allTags).map(tag => `# ${tag}`).sort();
<!-- Main Content -->
<div class="container mx-auto px-4 pb-20">
<div class="grid grid-cols-1 lg:grid-cols-4 gap-8">
<!-- Sidebar -->
<!-- 侧边栏 -->
<div class="lg:col-span-1 space-y-8">
<!-- Categories -->
<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>
Categories
</h3>
<div class="space-y-2">
{categories.map((category) => (
<a href={`/blog/categories/${encodeURIComponent(category.toLowerCase())}`}
class="block text-muted-foreground hover:text-purple-500 transition-colors duration-200">
{category}
</a>
))}
</div>
</div>
<!-- 分类卡片 -->
<CategoryCard lang="en" />
<!-- Tags -->
<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="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"></path>
</svg>
# Tags
</h3>
<div class="flex flex-wrap gap-2">
{tags.map((tag) => (
<a href={`/blog/tags/${encodeURIComponent(tag.slice(2).toLowerCase())}`}
class="inline-block px-3 py-1 text-sm bg-muted text-muted-foreground rounded-full hover:bg-purple-500/20 hover:text-purple-500 transition-all duration-200">
{tag}
</a>
))}
</div>
</div>
<!-- 标签卡片 -->
<TagCard lang="en" />
</div>
<!-- Blog Posts -->
<div class="lg:col-span-3">
<BlogList posts={sortedBlogPosts} lang="en" client:load />
<BlogList posts={sortedBlogPosts} lang="en" />
</div>
</div>
</div>

View File

@@ -1,6 +1,8 @@
---
import BlogLayout from '../../../layouts/BlogLayout.astro';
import BlogList from '../../../components/BlogList.tsx';
import BlogList from '../../../components/blog/BlogList.astro';
import CategoryCard from '../../../components/blog/CategoryCard.astro';
import TagCard from '../../../components/blog/TagCard.astro';
import { type Lang } from '@/i18n/utils';
import { defaultLang } from '@/i18n/ui';
import { type BlogPost } from '@/types';
@@ -125,12 +127,33 @@ allPosts.forEach(post => {
const categories = Array.from(allCategories).sort();
const tags = Array.from(allTags).map(postTag => `# ${postTag}`).sort();
// 获取当前标签的格式化名称(首字母大写)
const formattedTag = decodedTag.charAt(0).toUpperCase() + decodedTag.slice(1);
// 查找与当前标签ID匹配的标签名称
let displayTagName = "";
// 从博客文章中查找匹配的标签名称
for (const post of allPosts) {
if (post.frontmatter?.tagId && Array.isArray(post.frontmatter.tagId) &&
post.frontmatter?.tags && Array.isArray(post.frontmatter.tags)) {
// 查找标签ID和标签名称的索引匹配
const tagIndex = post.frontmatter.tagId.findIndex(id =>
id.toLowerCase() === decodedTag.toLowerCase()
);
if (tagIndex !== -1 && tagIndex < post.frontmatter.tags.length) {
displayTagName = post.frontmatter.tags[tagIndex];
break;
}
}
}
// 如果没有找到匹配的标签名称则使用标签ID并格式化首字母大写
if (!displayTagName) {
displayTagName = decodedTag.charAt(0).toUpperCase() + decodedTag.slice(1);
}
// 动态生成页面标题和描述
const pageTitle = `# ${formattedTag} - Blog | Joy Zhao`;
const pageDescription = `Explore articles tagged with # ${formattedTag}. Dive into my thoughts on ${formattedTag} and related topics.`;
const pageTitle = `# ${displayTagName} - Blog | Joy Zhao`;
const pageDescription = `Explore articles tagged with # ${displayTagName}. Dive into my thoughts on ${displayTagName} and related topics.`;
---
<BlogLayout title={pageTitle} description={pageDescription}>
@@ -139,10 +162,10 @@ const pageDescription = `Explore articles tagged with # ${formattedTag}. Dive in
<div class="container mx-auto px-4 pt-24 pb-12">
<div class="text-center mb-16">
<h1 class="text-5xl md:text-6xl font-bold bg-gradient-to-r from-foreground via-purple-600 to-purple-800 dark:from-foreground dark:via-purple-200 dark:to-purple-300 bg-clip-text text-transparent mb-6">
Tag: <span class="text-purple-500"># {formattedTag}</span>
Tag: <span class="text-purple-500"># {displayTagName}</span>
</h1>
<p class="text-xl text-muted-foreground max-w-3xl mx-auto">
Explore articles tagged with # {formattedTag}. Found {sortedBlogPosts.length} article{sortedBlogPosts.length !== 1 ? 's' : ''}.
Explore articles tagged with # {displayTagName}. Found {sortedBlogPosts.length} article{sortedBlogPosts.length !== 1 ? 's' : ''}.
</p>
</div>
</div>
@@ -152,51 +175,18 @@ const pageDescription = `Explore articles tagged with # ${formattedTag}. Dive in
<div class="grid grid-cols-1 lg:grid-cols-4 gap-8">
<!-- Sidebar -->
<div class="lg:col-span-1 space-y-8">
<!-- Categories -->
<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>
Categories
</h3>
<div class="space-y-2">
{categories.map((cat) => (
<a href={`/blog/categories/${cat.toLowerCase()}`}
class="block text-muted-foreground hover:text-purple-500 transition-colors duration-200">
{cat}
</a>
))}
</div>
</div>
<!-- 分类卡片 -->
<CategoryCard lang="en" />
<!-- 标签卡片 -->
<TagCard lang="en" currentTag={decodedTag} />
<!-- Tags -->
<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="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"></path>
</svg>
# Tags
</h3>
<div class="flex flex-wrap gap-2">
{tags.map((tagItem) => {
const tagName = tagItem.slice(2).toLowerCase();
const isCurrentTag = tagName === decodedTag.toLowerCase();
return (
<a href={`/blog/tags/${encodeURIComponent(tagName)}`}
class={`inline-block px-3 py-1 text-sm rounded-full transition-all duration-200 ${isCurrentTag ? 'bg-purple-500/20 text-purple-500 font-medium' : 'bg-muted text-muted-foreground hover:bg-purple-500/20 hover:text-purple-500'}`}>
{tagItem}
</a>
);
})}
</div>
</div>
</div>
<!-- Blog Posts -->
<div class="lg:col-span-3">
{sortedBlogPosts.length > 0 ? (
<BlogList posts={sortedBlogPosts} lang="en" client:load />
<BlogList posts={sortedBlogPosts} lang="en" tag={decodedTag} />
) : (
<div class="bg-card/50 backdrop-blur-sm rounded-2xl p-8 border border-border text-center">
<h2 class="text-2xl font-semibold mb-4">No articles found</h2>

View File

@@ -1,6 +1,8 @@
---
import BlogLayout from '../../../../layouts/BlogLayout.astro';
import BlogList from '../../../../components/BlogList.tsx';
import BlogList from '../../../../components/blog/BlogList.astro';
import CategoryCard from '../../../../components/blog/CategoryCard.astro';
import TagCard from '../../../../components/blog/TagCard.astro';
import { type Lang } from '@/i18n/utils';
import { defaultLang } from '@/i18n/ui';
import { type BlogPost } from '@/types';
@@ -137,12 +139,33 @@ allPosts.forEach(post => {
const categories = Array.from(allCategories).sort();
const tags = Array.from(allTags).map(tag => `# ${tag}`).sort();
// 获取当前分类的格式化名称(首字母大写)
const formattedCategory = decodedCategory.charAt(0).toUpperCase() + decodedCategory.slice(1);
// 查找与当前分类ID匹配的分类名称
let displayCategoryName = "";
// 从博客文章中查找匹配的分类名称
for (const post of allPosts) {
if (post.frontmatter?.categoryId && Array.isArray(post.frontmatter.categoryId) &&
post.frontmatter?.category && Array.isArray(post.frontmatter.category)) {
// 查找分类ID和分类名称的索引匹配
const categoryIndex = post.frontmatter.categoryId.findIndex(id =>
id.toLowerCase() === decodedCategory.toLowerCase()
);
if (categoryIndex !== -1 && categoryIndex < post.frontmatter.category.length) {
displayCategoryName = post.frontmatter.category[categoryIndex];
break;
}
}
}
// 如果没有找到匹配的分类名称则使用分类ID并格式化首字母大写
if (!displayCategoryName) {
displayCategoryName = decodedCategory.charAt(0).toUpperCase() + decodedCategory.slice(1);
}
// 动态生成页面标题和描述
const pageTitle = `${formattedCategory} - 博客 | 赵桂阳`;
const pageDescription = `探索关于${formattedCategory}的文章。深入了解我对${formattedCategory}和相关主题的思考。`;
const pageTitle = `${displayCategoryName} - 博客 | 赵桂阳`;
const pageDescription = `探索关于${displayCategoryName}的文章。深入了解我对${displayCategoryName}和相关主题的思考。`;
---
<BlogLayout title={pageTitle} description={pageDescription}>
@@ -151,10 +174,10 @@ const pageDescription = `探索关于${formattedCategory}的文章。深入了
<div class="container mx-auto px-4 pt-24 pb-12">
<div class="text-center mb-16">
<h1 class="text-5xl md:text-6xl font-bold bg-gradient-to-r from-foreground via-purple-600 to-purple-800 dark:from-foreground dark:via-purple-200 dark:to-purple-300 bg-clip-text text-transparent mb-6">
分类: <span class="text-purple-500">{formattedCategory}</span>
分类: <span class="text-purple-500">{displayCategoryName}</span>
</h1>
<p class="text-xl text-muted-foreground max-w-3xl mx-auto">
探索关于{formattedCategory}的文章。找到 {sortedBlogPosts.length} 篇文章。
探索关于{displayCategoryName}的文章。找到 {sortedBlogPosts.length} 篇文章。
</p>
</div>
</div>
@@ -164,47 +187,18 @@ const pageDescription = `探索关于${formattedCategory}的文章。深入了
<div class="grid grid-cols-1 lg:grid-cols-4 gap-8">
<!-- 侧边栏 -->
<div class="lg:col-span-1 space-y-8">
<!-- 分类 -->
<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>
分类
</h3>
<div class="space-y-2">
{categories.map((cat) => (
<a href={`/zh/blog/categories/${encodeURIComponent(cat.toLowerCase())}`}
class={`block transition-colors duration-200 ${cat.toLowerCase() === decodedCategory.toLowerCase() ? 'text-purple-500 font-medium' : 'text-muted-foreground hover:text-purple-500'}`}>
{cat}
</a>
))}
</div>
</div>
<!-- 分类卡片 -->
<CategoryCard lang="zh" currentCategory={decodedCategory} />
<!-- 标签卡片 -->
<TagCard lang="zh" />
<!-- 标签 -->
<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="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"></path>
</svg>
# 标签
</h3>
<div class="flex flex-wrap gap-2">
{tags.map((tag) => (
<a href={`/zh/blog/tags/${encodeURIComponent(tag.slice(2).toLowerCase())}`}
class="inline-block px-3 py-1 text-sm bg-muted text-muted-foreground rounded-full hover:bg-purple-500/20 hover:text-purple-500 transition-all duration-200">
{tag}
</a>
))}
</div>
</div>
</div>
<!-- 博客文章 -->
<div class="lg:col-span-3">
{sortedBlogPosts.length > 0 ? (
<BlogList posts={sortedBlogPosts} lang="zh" client:load />
<BlogList posts={sortedBlogPosts} lang="zh" category={decodedCategory} />
) : (
<div class="bg-card/50 backdrop-blur-sm rounded-2xl p-8 border border-border text-center">
<h2 class="text-2xl font-semibold mb-4">未找到文章</h2>

View File

@@ -1,9 +1,11 @@
---
import BlogLayout from '../../../layouts/BlogLayout.astro';
import BlogList from '../../../components/BlogList.tsx';
import BlogList from '../../../components/blog/BlogList.astro';
import CategoryCard from '../../../components/blog/CategoryCard.astro';
import TagCard from '../../../components/blog/TagCard.astro';
import { type BlogPost } from '@/types';
import { type Lang } from '@/i18n/utils';
import { defaultLang } from '@/i18n/ui';
import { type BlogPost } from '@/types';
// 使用Astro.currentLocale获取当前语言环境
const lang = Astro.currentLocale as Lang || defaultLang;
@@ -91,46 +93,17 @@ const tags = Array.from(allTags).map(tag => `# ${tag}`).sort();
<div class="grid grid-cols-1 lg:grid-cols-4 gap-8">
<!-- 侧边栏 -->
<div class="lg:col-span-1 space-y-8">
<!-- 分类 -->
<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>
分类
</h3>
<div class="space-y-2">
{categories.map((category) => (
<a href={`/zh/blog/categories/${encodeURIComponent(category.toLowerCase())}`}
class="block text-muted-foreground hover:text-purple-500 transition-colors duration-200">
{category}
</a>
))}
</div>
</div>
<!-- 分类卡片 -->
<CategoryCard lang="zh" />
<!-- 标签卡片 -->
<TagCard lang="zh" />
<!-- 标签 -->
<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="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"></path>
</svg>
# 标签
</h3>
<div class="flex flex-wrap gap-2">
{tags.map((tag) => (
<a href={`/zh/blog/tags/${encodeURIComponent(tag.slice(2).toLowerCase())}`}
class="inline-block px-3 py-1 text-sm bg-muted text-muted-foreground rounded-full hover:bg-purple-500/20 hover:text-purple-500 transition-all duration-200">
{tag}
</a>
))}
</div>
</div>
</div>
<!-- 博客文章 -->
<div class="lg:col-span-3">
<BlogList posts={sortedBlogPosts} lang="zh" client:load />
<BlogList posts={sortedBlogPosts} lang="zh" />
</div>
</div>
</div>

View File

@@ -1,6 +1,8 @@
---
import BlogLayout from '../../../../layouts/BlogLayout.astro';
import BlogList from '../../../../components/BlogList.tsx';
import BlogList from '../../../../components/blog/BlogList.astro';
import CategoryCard from '../../../../components/blog/CategoryCard.astro';
import TagCard from '../../../../components/blog/TagCard.astro';
import { type Lang } from '@/i18n/utils';
import { defaultLang } from '@/i18n/ui';
import { type BlogPost } from '@/types';
@@ -125,12 +127,33 @@ allPosts.forEach(post => {
const categories = Array.from(allCategories).sort();
const tags = Array.from(allTags).map(postTag => `# ${postTag}`).sort();
// 获取当前标签的格式化名称(首字母大写)
const formattedTag = decodedTag.charAt(0).toUpperCase() + decodedTag.slice(1);
// 查找与当前标签ID匹配的标签名称
let displayTagName = "";
// 从博客文章中查找匹配的标签名称
for (const post of allPosts) {
if (post.frontmatter?.tagId && Array.isArray(post.frontmatter.tagId) &&
post.frontmatter?.tags && Array.isArray(post.frontmatter.tags)) {
// 查找标签ID和标签名称的索引匹配
const tagIndex = post.frontmatter.tagId.findIndex(id =>
id.toLowerCase() === decodedTag.toLowerCase()
);
if (tagIndex !== -1 && tagIndex < post.frontmatter.tags.length) {
displayTagName = post.frontmatter.tags[tagIndex];
break;
}
}
}
// 如果没有找到匹配的标签名称则使用标签ID并格式化首字母大写
if (!displayTagName) {
displayTagName = decodedTag.charAt(0).toUpperCase() + decodedTag.slice(1);
}
// 动态生成页面标题和描述
const pageTitle = `# ${formattedTag} - 博客 | Joy Zhao`;
const pageDescription = `浏览带有 # ${formattedTag} 标签的文章。深入了解我关于 ${formattedTag} 及相关主题的想法。`;
const pageTitle = `# ${displayTagName} - 博客 | Joy Zhao`;
const pageDescription = `浏览带有 # ${displayTagName} 标签的文章。深入了解我关于 ${displayTagName} 及相关主题的想法。`;
---
<BlogLayout title={pageTitle} description={pageDescription}>
@@ -139,10 +162,10 @@ const pageDescription = `浏览带有 # ${formattedTag} 标签的文章。深入
<div class="container mx-auto px-4 pt-24 pb-12">
<div class="text-center mb-16">
<h1 class="text-5xl md:text-6xl font-bold bg-gradient-to-r from-foreground via-purple-600 to-purple-800 dark:from-foreground dark:via-purple-200 dark:to-purple-300 bg-clip-text text-transparent mb-6">
标签: <span class="text-purple-500"># {formattedTag}</span>
标签: <span class="text-purple-500"># {displayTagName}</span>
</h1>
<p class="text-xl text-muted-foreground max-w-3xl mx-auto">
浏览带有 # {formattedTag} 标签的文章。找到 {sortedBlogPosts.length} 篇文章。
浏览带有 # {displayTagName} 标签的文章。找到 {sortedBlogPosts.length} 篇文章。
</p>
</div>
</div>
@@ -150,53 +173,20 @@ const pageDescription = `浏览带有 # ${formattedTag} 标签的文章。深入
<!-- Main Content -->
<div class="container mx-auto px-4 pb-20">
<div class="grid grid-cols-1 lg:grid-cols-4 gap-8">
<!-- Sidebar -->
<!-- 侧边栏 -->
<div class="lg:col-span-1 space-y-8">
<!-- Categories -->
<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>
分类
</h3>
<div class="space-y-2">
{categories.map((cat) => (
<a href={`/zh/blog/categories/${cat.toLowerCase()}`}
class="block text-muted-foreground hover:text-purple-500 transition-colors duration-200">
{cat}
</a>
))}
</div>
</div>
<!-- 分类卡片 -->
<CategoryCard lang="zh" />
<!-- 标签卡片 -->
<TagCard lang="zh" currentTag={decodedTag} />
<!-- Tags -->
<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="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"></path>
</svg>
# 标签
</h3>
<div class="flex flex-wrap gap-2">
{tags.map((tagItem) => {
const tagName = tagItem.slice(2).toLowerCase();
const isCurrentTag = tagName === decodedTag.toLowerCase();
return (
<a href={`/zh/blog/tags/${encodeURIComponent(tagName)}`}
class={`inline-block px-3 py-1 text-sm rounded-full transition-all duration-200 ${isCurrentTag ? 'bg-purple-500/20 text-purple-500 font-medium' : 'bg-muted text-muted-foreground hover:bg-purple-500/20 hover:text-purple-500'}`}>
{tagItem}
</a>
);
})}
</div>
</div>
</div>
<!-- Blog Posts -->
<div class="lg:col-span-3">
{sortedBlogPosts.length > 0 ? (
<BlogList posts={sortedBlogPosts} lang="zh" client:load />
<BlogList posts={sortedBlogPosts} lang="zh" tag={decodedTag} />
) : (
<div class="bg-card/50 backdrop-blur-sm rounded-2xl p-8 border border-border text-center">
<h2 class="text-2xl font-semibold mb-4">未找到文章</h2>