diff --git a/src/components/BlogList.tsx b/src/components/BlogList.tsx index d50624c..6189844 100644 --- a/src/components/BlogList.tsx +++ b/src/components/BlogList.tsx @@ -48,14 +48,22 @@ export default function BlogList({ posts, lang, baseUrl = '/blog/posts/' }: Blog {/* Tags */}
- {post.tags.map((tag, tagIndex) => ( - - {tag} - - ))} + {post.tags.map((tag, tagIndex) => { + // 使用 tagId 如果存在,否则使用 tag 本身 + const tagRoute = post.tagId && Array.isArray(post.tagId) && tagIndex < post.tagId.length + ? post.tagId[tagIndex] + : tag.toLowerCase(); + + return ( + + # {tag} + + ); + })}
diff --git a/src/components/blog/PostMeta.astro b/src/components/blog/PostMeta.astro index 61c18cb..0209c43 100644 --- a/src/components/blog/PostMeta.astro +++ b/src/components/blog/PostMeta.astro @@ -7,7 +7,9 @@ export interface Props { publishDate?: string; readingTime?: number; tags?: string[]; + tagId?: string[]; category?: string | string[]; + categoryId?: string[] | string; className?: string; } @@ -16,7 +18,9 @@ const { publishDate, readingTime, tags, + tagId, category, + categoryId, className = '' } = Astro.props; @@ -84,19 +88,26 @@ const getReadingTimeText = (minutes: number) => { {category && (
- 分类 + {lang === 'zh' ? '分类' : 'Categories'}
{Array.isArray(category) ? ( - category.map((cat) => ( - - {cat} - - )) + category.map((cat, index) => { + // 获取对应的 categoryId,如果存在 + const catId = categoryId && Array.isArray(categoryId) && index < categoryId.length + ? categoryId[index] + : cat.toLowerCase(); + + return ( + + {cat} + + ); + }) ) : ( - + {category} - + )}
@@ -106,14 +117,21 @@ const getReadingTimeText = (minutes: number) => { {tags && tags.length > 0 && (
- 标签 + {lang === 'zh' ? '标签' : 'Tags'}
- {tags.map((tag) => ( - - # {tag} - - ))} + {tags.map((tag, index) => { + // 获取对应的 tagId,如果存在 + const tagRoute = tagId && Array.isArray(tagId) && index < tagId.length + ? tagId[index] + : tag.toLowerCase(); + + return ( + + # {tag} + + ); + })}
)} diff --git a/src/layouts/BlogPostLayout.astro b/src/layouts/BlogPostLayout.astro index 8d64b14..8439d37 100644 --- a/src/layouts/BlogPostLayout.astro +++ b/src/layouts/BlogPostLayout.astro @@ -23,7 +23,9 @@ const { publishDate, date, tags, + tagId, category, + categoryId, readTime, } = frontmatter; @@ -85,7 +87,9 @@ const finalReadingTime = readTime ? parseInt(readTime.replace(/\D/g, '')) : unde publishDate={finalPublishDate} readingTime={finalReadingTime} tags={tags} + tagId={tagId} category={category} + categoryId={categoryId} className="justify-start" /> diff --git a/src/pages/blog/categories/[category].astro b/src/pages/blog/categories/[category].astro index ada5190..c489da4 100644 --- a/src/pages/blog/categories/[category].astro +++ b/src/pages/blog/categories/[category].astro @@ -9,11 +9,22 @@ import { type BlogPost } from '@/types'; export async function getStaticPaths() { const allPosts = await Astro.glob('../posts/*.md'); - // 收集所有分类 + // 收集所有分类ID或分类 const uniqueCategories = new Set(); allPosts.forEach(post => { - if (post.frontmatter?.category) { + // 优先使用 categoryId 作为路由标识符 + if (post.frontmatter?.categoryId) { + const categoryIds = Array.isArray(post.frontmatter.categoryId) + ? post.frontmatter.categoryId + : [post.frontmatter.categoryId]; + + categoryIds.forEach(categoryId => { + if (categoryId) uniqueCategories.add(categoryId.toLowerCase()); + }); + } + // 如果没有 categoryId,则使用 category 作为后备 + else if (post.frontmatter?.category) { const categories = Array.isArray(post.frontmatter.category) ? post.frontmatter.category : [post.frontmatter.category]; @@ -49,8 +60,18 @@ const allPosts = await Astro.glob('../posts/*.md'); // 处理博客文章数据 const blogPosts: BlogPost[] = allPosts .filter(post => { - // 检查文章是否属于当前分类 - if (post.frontmatter?.category) { + // 优先检查文章是否包含当前分类ID + if (post.frontmatter?.categoryId) { + const postCategoryIds = Array.isArray(post.frontmatter.categoryId) + ? post.frontmatter.categoryId + : [post.frontmatter.categoryId]; + + return postCategoryIds.some(catId => + catId.toLowerCase() === decodedCategory.toLowerCase() + ); + } + // 如果没有 categoryId,则检查 category + else if (post.frontmatter?.category) { const postCategories = Array.isArray(post.frontmatter.category) ? post.frontmatter.category : [post.frontmatter.category]; @@ -114,7 +135,7 @@ allPosts.forEach(post => { // 转换为数组并排序 const categories = Array.from(allCategories).sort(); -const tags = Array.from(allTags).map(tag => `#${tag}`).sort(); +const tags = Array.from(allTags).map(tag => `# ${tag}`).sort(); // 获取当前分类的格式化名称(首字母大写) const formattedCategory = decodedCategory.charAt(0).toUpperCase() + decodedCategory.slice(1); @@ -171,7 +192,7 @@ const pageDescription = `Explore articles about ${formattedCategory}. Dive into
{tags.map((tag) => ( - {tag} diff --git a/src/pages/blog/index.astro b/src/pages/blog/index.astro index 0de5895..a36bfc1 100644 --- a/src/pages/blog/index.astro +++ b/src/pages/blog/index.astro @@ -24,6 +24,9 @@ const blogPosts: BlogPost[] = allPosts.map((post) => { image: post.frontmatter.image || defaultImage, slug: slug, tags: post.frontmatter.tags || [], + tagId: post.frontmatter.tagId || [], + category: Array.isArray(post.frontmatter.category) ? post.frontmatter.category : post.frontmatter.category ? [post.frontmatter.category] : [], + categoryId: Array.isArray(post.frontmatter.categoryId) ? post.frontmatter.categoryId : post.frontmatter.categoryId ? [post.frontmatter.categoryId] : [], date: post.frontmatter.date || post.frontmatter.pubDate || '', readTime: post.frontmatter.readTime || post.frontmatter.readingTime || '5 min read', }; @@ -65,7 +68,7 @@ allPosts.forEach(post => { // 转换为数组并排序 const categories = Array.from(allCategories).sort(); -const tags = Array.from(allTags).map(tag => `#${tag}`).sort(); +const tags = Array.from(allTags).map(tag => `# ${tag}`).sort(); --- @@ -98,7 +101,7 @@ const tags = Array.from(allTags).map(tag => `#${tag}`).sort();
{categories.map((category) => ( - {category} @@ -116,7 +119,7 @@ const tags = Array.from(allTags).map(tag => `#${tag}`).sort();
{tags.map((tag) => ( - {tag} diff --git a/src/pages/blog/posts/mastering-react-hooks.md b/src/pages/blog/posts/mastering-react-hooks.md index 0e95ce0..81dd58e 100644 --- a/src/pages/blog/posts/mastering-react-hooks.md +++ b/src/pages/blog/posts/mastering-react-hooks.md @@ -5,7 +5,9 @@ image: "https://images.unsplash.com/photo-1633356122544-f134324a6cee?w=400&h=250 date: "May 10, 2025" readTime: "5 min read" tags: ["React", "JavaScript", "Frontend"] +tagId: ["react", "javascript", "frontend"] category: ["React", "Frontend"] +categoryId: ["react", "frontend"] slug: "mastering-react-hooks" layout: "../../../layouts/BlogPostLayout.astro" --- diff --git a/src/pages/blog/tags/[tag].astro b/src/pages/blog/tags/[tag].astro index a044c36..a296a56 100644 --- a/src/pages/blog/tags/[tag].astro +++ b/src/pages/blog/tags/[tag].astro @@ -9,11 +9,18 @@ import { type BlogPost } from '@/types'; export async function getStaticPaths() { const allPosts = await Astro.glob('../posts/*.md'); - // 收集所有标签 + // 收集所有标签ID或标签 const uniqueTags = new Set(); allPosts.forEach(post => { - if (post.frontmatter?.tags && Array.isArray(post.frontmatter.tags)) { + // 优先使用 tagId 作为路由标识符 + if (post.frontmatter?.tagId && Array.isArray(post.frontmatter.tagId)) { + post.frontmatter.tagId.forEach(tagId => { + if (tagId) uniqueTags.add(tagId.toLowerCase()); + }); + } + // 如果没有 tagId,则使用 tags 作为后备 + else if (post.frontmatter?.tags && Array.isArray(post.frontmatter.tags)) { post.frontmatter.tags.forEach(tag => { if (tag) uniqueTags.add(tag.toLowerCase()); }); @@ -45,8 +52,14 @@ const allPosts = await Astro.glob('../posts/*.md'); // 处理博客文章数据 const blogPosts: BlogPost[] = allPosts .filter(post => { - // 检查文章是否包含当前标签 - if (post.frontmatter?.tags && Array.isArray(post.frontmatter.tags)) { + // 优先检查文章是否包含当前标签ID + if (post.frontmatter?.tagId && Array.isArray(post.frontmatter.tagId)) { + return post.frontmatter.tagId.some(postTagId => + postTagId.toLowerCase() === decodedTag.toLowerCase() + ); + } + // 如果没有 tagId,则检查 tags + else if (post.frontmatter?.tags && Array.isArray(post.frontmatter.tags)) { return post.frontmatter.tags.some(postTag => postTag.toLowerCase() === decodedTag.toLowerCase() ); @@ -102,18 +115,22 @@ allPosts.forEach(post => { if (postTag) allTags.add(postTag); }); } + // 同时收集标签ID(用于内部路由) + if (post.frontmatter?.tagId && Array.isArray(post.frontmatter.tagId)) { + // 这里我们不添加到 allTags 中,因为 tagId 只用于路由,不用于显示 + } }); // 转换为数组并排序 const categories = Array.from(allCategories).sort(); -const tags = Array.from(allTags).map(postTag => `#${postTag}`).sort(); +const tags = Array.from(allTags).map(postTag => `# ${postTag}`).sort(); // 获取当前标签的格式化名称(首字母大写) const formattedTag = 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 = `# ${formattedTag} - Blog | Joy Zhao`; +const pageDescription = `Explore articles tagged with # ${formattedTag}. Dive into my thoughts on ${formattedTag} and related topics.`; --- @@ -122,10 +139,10 @@ const pageDescription = `Explore articles tagged with #${formattedTag}. Dive int

- Tag: #{formattedTag} + Tag: # {formattedTag}

- Explore articles tagged with #{formattedTag}. Found {sortedBlogPosts.length} article{sortedBlogPosts.length !== 1 ? 's' : ''}. + Explore articles tagged with # {formattedTag}. Found {sortedBlogPosts.length} article{sortedBlogPosts.length !== 1 ? 's' : ''}.

@@ -163,7 +180,7 @@ const pageDescription = `Explore articles tagged with #${formattedTag}. Dive int
{tags.map((tagItem) => { - const tagName = tagItem.slice(1).toLowerCase(); + const tagName = tagItem.slice(2).toLowerCase(); const isCurrentTag = tagName === decodedTag.toLowerCase(); return ( (); allPosts.forEach(post => { - if (post.frontmatter?.category) { + // 优先使用 categoryId 作为路由标识符 + if (post.frontmatter?.categoryId) { + const categoryIds = Array.isArray(post.frontmatter.categoryId) + ? post.frontmatter.categoryId + : [post.frontmatter.categoryId]; + + categoryIds.forEach(categoryId => { + if (categoryId) uniqueCategories.add(categoryId.toLowerCase()); + }); + } + // 如果没有 categoryId,则使用 category 作为后备 + else if (post.frontmatter?.category) { const categories = Array.isArray(post.frontmatter.category) ? post.frontmatter.category : [post.frontmatter.category]; @@ -49,8 +60,18 @@ const allPosts = await Astro.glob('../posts/*.md'); // 处理博客文章数据 const blogPosts: BlogPost[] = allPosts .filter(post => { - // 检查文章是否属于当前分类 - if (post.frontmatter?.category) { + // 优先检查文章是否包含当前分类ID + if (post.frontmatter?.categoryId) { + const postCategoryIds = Array.isArray(post.frontmatter.categoryId) + ? post.frontmatter.categoryId + : [post.frontmatter.categoryId]; + + return postCategoryIds.some(catId => + catId.toLowerCase() === decodedCategory.toLowerCase() + ); + } + // 如果没有 categoryId,则检查 category + else if (post.frontmatter?.category) { const postCategories = Array.isArray(post.frontmatter.category) ? post.frontmatter.category : [post.frontmatter.category]; @@ -114,7 +135,7 @@ allPosts.forEach(post => { // 转换为数组并排序 const categories = Array.from(allCategories).sort(); -const tags = Array.from(allTags).map(tag => `#${tag}`).sort(); +const tags = Array.from(allTags).map(tag => `# ${tag}`).sort(); // 获取当前分类的格式化名称(首字母大写) const formattedCategory = decodedCategory.charAt(0).toUpperCase() + decodedCategory.slice(1); @@ -171,7 +192,7 @@ const pageDescription = `探索关于${formattedCategory}的文章。深入了
{tags.map((tag) => ( - {tag} diff --git a/src/pages/zh/blog/index.astro b/src/pages/zh/blog/index.astro index 4729ed0..f4a33a8 100644 --- a/src/pages/zh/blog/index.astro +++ b/src/pages/zh/blog/index.astro @@ -24,6 +24,9 @@ const blogPosts: BlogPost[] = allPosts.map((post) => { image: post.frontmatter.image || defaultImage, slug: slug, tags: post.frontmatter.tags || [], + tagId: post.frontmatter.tagId || [], + category: Array.isArray(post.frontmatter.category) ? post.frontmatter.category : post.frontmatter.category ? [post.frontmatter.category] : [], + categoryId: Array.isArray(post.frontmatter.categoryId) ? post.frontmatter.categoryId : post.frontmatter.categoryId ? [post.frontmatter.categoryId] : [], date: post.frontmatter.date || post.frontmatter.pubDate || '', readTime: post.frontmatter.readTime || post.frontmatter.readingTime || '5分钟阅读', }; @@ -65,7 +68,7 @@ allPosts.forEach(post => { // 转换为数组并排序 const categories = Array.from(allCategories).sort(); -const tags = Array.from(allTags).map(tag => `#${tag}`).sort(); +const tags = Array.from(allTags).map(tag => `# ${tag}`).sort(); --- @@ -98,7 +101,7 @@ const tags = Array.from(allTags).map(tag => `#${tag}`).sort();
{categories.map((category) => ( - {category} @@ -116,7 +119,7 @@ const tags = Array.from(allTags).map(tag => `#${tag}`).sort();
{tags.map((tag) => ( - {tag} diff --git a/src/pages/zh/blog/posts/mastering-react-hooks.md b/src/pages/zh/blog/posts/mastering-react-hooks.md index 7178220..d02e940 100644 --- a/src/pages/zh/blog/posts/mastering-react-hooks.md +++ b/src/pages/zh/blog/posts/mastering-react-hooks.md @@ -4,7 +4,10 @@ description: "探索 React Hooks 在函数组件中管理状态和副作用的 image: "https://images.unsplash.com/photo-1633356122544-f134324a6cee?w=400&h=250&fit=crop&crop=center" date: "2025年5月10日" readTime: "5分钟阅读" -tags: ["React", "JavaScript", "前端"] +tags: ["React", "JavaScript", "前端开发"] +tagId: ["react", "javascript", "frontend"] +category: ["React", "前端"] +categoryId: ["react", "frontend"] slug: "mastering-react-hooks" layout: "../../../../layouts/BlogPostLayout.astro" --- diff --git a/src/pages/zh/blog/posts/typescript-best-practices.md b/src/pages/zh/blog/posts/typescript-best-practices.md index 8f2c713..5746768 100644 --- a/src/pages/zh/blog/posts/typescript-best-practices.md +++ b/src/pages/zh/blog/posts/typescript-best-practices.md @@ -4,7 +4,7 @@ description: "掌握 TypeScript 在企业级应用中的高级技巧,提升代 image: "https://images.unsplash.com/photo-1516116216624-53e697fedbea?w=400&h=250&fit=crop&crop=center" date: "2025年4月15日" readTime: "8分钟阅读" -tags: ["TypeScript", "架构", "最佳实践"] +tags: ["TypeScript", "JavaScript", "Architecture"] slug: "typescript-best-practices" layout: "../../../../layouts/BlogPostLayout.astro" --- diff --git a/src/pages/zh/blog/tags/[tag].astro b/src/pages/zh/blog/tags/[tag].astro index 21c0820..2d4f985 100644 --- a/src/pages/zh/blog/tags/[tag].astro +++ b/src/pages/zh/blog/tags/[tag].astro @@ -9,11 +9,18 @@ import { type BlogPost } from '@/types'; export async function getStaticPaths() { const allPosts = await Astro.glob('../posts/*.md'); - // 收集所有标签 + // 收集所有标签ID或标签 const uniqueTags = new Set(); allPosts.forEach(post => { - if (post.frontmatter?.tags && Array.isArray(post.frontmatter.tags)) { + // 优先使用 tagId 作为路由标识符 + if (post.frontmatter?.tagId && Array.isArray(post.frontmatter.tagId)) { + post.frontmatter.tagId.forEach(tagId => { + if (tagId) uniqueTags.add(tagId.toLowerCase()); + }); + } + // 如果没有 tagId,则使用 tags 作为后备 + else if (post.frontmatter?.tags && Array.isArray(post.frontmatter.tags)) { post.frontmatter.tags.forEach(tag => { if (tag) uniqueTags.add(tag.toLowerCase()); }); @@ -45,8 +52,14 @@ const allPosts = await Astro.glob('../posts/*.md'); // 处理博客文章数据 const blogPosts: BlogPost[] = allPosts .filter(post => { - // 检查文章是否包含当前标签 - if (post.frontmatter?.tags && Array.isArray(post.frontmatter.tags)) { + // 优先检查文章是否包含当前标签ID + if (post.frontmatter?.tagId && Array.isArray(post.frontmatter.tagId)) { + return post.frontmatter.tagId.some(postTagId => + postTagId.toLowerCase() === decodedTag.toLowerCase() + ); + } + // 如果没有 tagId,则检查 tags + else if (post.frontmatter?.tags && Array.isArray(post.frontmatter.tags)) { return post.frontmatter.tags.some(postTag => postTag.toLowerCase() === decodedTag.toLowerCase() ); @@ -102,18 +115,22 @@ allPosts.forEach(post => { if (postTag) allTags.add(postTag); }); } + // 同时收集标签ID(用于内部路由) + if (post.frontmatter?.tagId && Array.isArray(post.frontmatter.tagId)) { + // 这里我们不添加到 allTags 中,因为 tagId 只用于路由,不用于显示 + } }); // 转换为数组并排序 const categories = Array.from(allCategories).sort(); -const tags = Array.from(allTags).map(postTag => `#${postTag}`).sort(); +const tags = Array.from(allTags).map(postTag => `# ${postTag}`).sort(); // 获取当前标签的格式化名称(首字母大写) const formattedTag = decodedTag.charAt(0).toUpperCase() + decodedTag.slice(1); // 动态生成页面标题和描述 -const pageTitle = `#${formattedTag} - 博客 | Joy Zhao`; -const pageDescription = `浏览带有 #${formattedTag} 标签的文章。深入了解我关于 ${formattedTag} 及相关主题的想法。`; +const pageTitle = `# ${formattedTag} - 博客 | Joy Zhao`; +const pageDescription = `浏览带有 # ${formattedTag} 标签的文章。深入了解我关于 ${formattedTag} 及相关主题的想法。`; --- @@ -122,10 +139,10 @@ const pageDescription = `浏览带有 #${formattedTag} 标签的文章。深入

- 标签: #{formattedTag} + 标签: # {formattedTag}

- 浏览带有 #{formattedTag} 标签的文章。找到 {sortedBlogPosts.length} 篇文章。 + 浏览带有 # {formattedTag} 标签的文章。找到 {sortedBlogPosts.length} 篇文章。

@@ -163,7 +180,7 @@ const pageDescription = `浏览带有 #${formattedTag} 标签的文章。深入
{tags.map((tagItem) => { - const tagName = tagItem.slice(1).toLowerCase(); + const tagName = tagItem.slice(2).toLowerCase(); const isCurrentTag = tagName === decodedTag.toLowerCase(); return (