diff --git a/src/layouts/BlogLayout.astro b/src/layouts/BlogLayout.astro index 4f887d3..03811d8 100644 --- a/src/layouts/BlogLayout.astro +++ b/src/layouts/BlogLayout.astro @@ -39,7 +39,7 @@ const lang = Astro.currentLocale as Lang || defaultLang;
- +
diff --git a/src/layouts/TaxonomyPageLayout.astro b/src/layouts/TaxonomyPageLayout.astro new file mode 100644 index 0000000..84bfa30 --- /dev/null +++ b/src/layouts/TaxonomyPageLayout.astro @@ -0,0 +1,95 @@ +--- +/** + * TaxonomyPageLayout component + * A unified layout for category and tag pages + */ +import BlogLayout from './BlogLayout.astro'; +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'; + +interface Props { + lang: Lang; + title: string; + description?: string; + taxonomyType: 'category' | 'tag'; + currentTaxonomy: string; + displayName?: string; + posts: BlogPost[]; + categories: Map; + tags: Map; +} + +const { + lang, + title, + taxonomyType, + currentTaxonomy, + displayName, + posts, + categories, + tags +} = Astro.props; + +// Get localized text based on language and taxonomy type +const getLocalizedText = () => { + if (taxonomyType === 'category') { + return { + heading: lang === 'zh' ? '分类' : 'Category', + noResults: lang === 'zh' ? '该分类下没有文章' : 'No posts in this category', + }; + } else { + return { + heading: lang === 'zh' ? '标签' : 'Tag', + noResults: lang === 'zh' ? '该标签下没有文章' : 'No posts with this tag', + }; + } +}; + +const localizedText = getLocalizedText(); +--- + + +
+ +
+

+ {displayName || currentTaxonomy} +

+ +

+ {localizedText.heading}: {posts.length} {lang === 'zh' ? '篇文章' : 'posts'} +

+
+ + +
+ +
+ + + +
+ + +
+ {posts.length > 0 ? ( + + ) : ( +
+

{localizedText.noResults}

+
+ )} +
+
+
+
\ No newline at end of file diff --git a/src/pages/blog/categories/[category].astro b/src/pages/blog/categories/[category].astro index 4a8edc0..2ecbb01 100644 --- a/src/pages/blog/categories/[category].astro +++ b/src/pages/blog/categories/[category].astro @@ -1,12 +1,8 @@ --- -import BlogLayout from '../../../layouts/BlogLayout.astro'; -import BlogList from '../../../components/blog/BlogList.astro'; -import CategoryCard from '../../../components/blog/CategoryCard.astro'; -import TagCard from '../../../components/blog/TagCard.astro'; +import TaxonomyPageLayout from '../../../layouts/TaxonomyPageLayout.astro'; import { type Lang } from '@/i18n/utils'; import { defaultLang } from '@/i18n/ui'; -import { type BlogPost } from '@/types'; -import { filterPostsByCategory, sortPostsByDate, extractCategories, extractTags } from '@/utils/blog-utils'; +import { getTaxonomyPageData } from '@/utils/blog-utils'; // Generate static paths for dynamic routing export async function getStaticPaths() { @@ -56,35 +52,9 @@ export interface Props { const { category } = Astro.params; const decodedCategory = category ? decodeURIComponent(category) : ''; -// Read all blog posts using import.meta.glob -const allPosts = await import.meta.glob('../posts/*.md', { eager: true }); - -// Process blog post data -const blogPosts: BlogPost[] = Object.values(allPosts).map((post: any) => { - const slug = post.url?.split('/').filter(Boolean).pop() || ''; - - // Default image if not specified in frontmatter - const defaultImage = "https://images.unsplash.com/photo-1516321318423-f06f85e504b3?w=400&h=250&fit=crop&crop=center"; - - return { - title: post.frontmatter.title, - description: post.frontmatter.description || '', - 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', - }; -}); - -// Filter posts by category -const filteredPosts = filterPostsByCategory(blogPosts, decodedCategory); - -// Sort posts by date -const sortedBlogPosts = sortPostsByDate(filteredPosts); +// Get taxonomy page data using the utility function +const { posts: sortedBlogPosts, categories, tags, allPosts } = + await getTaxonomyPageData(lang, { category: decodedCategory }); // Find category name matching the current category ID let categoryName = decodedCategory; @@ -118,70 +88,19 @@ Object.values(allPosts).forEach((post: any) => { // Page title and description const title = `${categoryName} - Blog | Joy Zhao`; const description = `Explore articles about ${categoryName}. Dive into my thoughts on ${categoryName} and related topics.`; - -// Extract categories and tags from all posts for sidebar -const allPostsArray = Object.values(allPosts).map((post: any) => ({ - category: post.frontmatter.category || [], - categoryId: post.frontmatter.categoryId || [], - tags: post.frontmatter.tags || [], - tagId: post.frontmatter.tagId || [] -})); - -// Get categories and tags for sidebar - -// Get categories and tags for sidebar -const categories = extractCategories(allPostsArray); -const tags = extractTags(allPostsArray); --- - -
- -
-
-

- Category: {categoryName} -

-

- Explore articles about {categoryName}. Found {sortedBlogPosts.length} article{sortedBlogPosts.length !== 1 ? 's' : ''}. -

-
-
- - -
-
- -
- - - - - - -
- - -
- {sortedBlogPosts.length > 0 ? ( - - ) : ( -
-

No articles found

-

There are no articles in this category yet. Check back later or explore other categories.

- - - - - Back to all posts - -
- )} -
-
-
-
-
+