refactor(blog) blog category pages

This commit is contained in:
javayhu 2025-06-17 18:02:29 +08:00
parent 3645cf5773
commit 2cb041beb1
3 changed files with 82 additions and 65 deletions

View File

@ -1,9 +1,9 @@
import BlogGridWithPagination from '@/components/blog/blog-grid-with-pagination';
import { websiteConfig } from '@/config/website';
import { LOCALES } from '@/i18n/routing';
import { getPaginatedBlogPosts } from '@/lib/blog/data';
import { blogSource, categorySource } from '@/lib/docs/source';
import { constructMetadata } from '@/lib/metadata';
import { getUrlWithLocale } from '@/lib/urls/urls';
import { allCategories } from 'content-collections';
import type { Locale } from 'next-intl';
import { getTranslations } from 'next-intl/server';
import { notFound } from 'next/navigation';
@ -12,11 +12,11 @@ import { notFound } from 'next/navigation';
export function generateStaticParams() {
const params: { locale: string; slug: string }[] = [];
for (const locale of LOCALES) {
const localeCategories = allCategories.filter(
(category) => category.locale === locale
);
const localeCategories = categorySource
.getPages(locale)
.filter((category) => category.locale === locale);
for (const category of localeCategories) {
params.push({ locale, slug: category.slug });
params.push({ locale, slug: category.slugs[0] });
}
}
return params;
@ -25,17 +25,16 @@ export function generateStaticParams() {
// Generate metadata for each static category page (locale + category)
export async function generateMetadata({ params }: BlogCategoryPageProps) {
const { locale, slug } = await params;
const category = allCategories.find(
(category) => category.locale === locale && category.slug === slug
);
const category = categorySource.getPage([slug], locale);
if (!category) {
notFound();
}
const t = await getTranslations({ locale, namespace: 'Metadata' });
const canonicalPath = `/blog/category/${slug}`;
return constructMetadata({
title: `${category.name} | ${t('title')}`,
description: category.description,
title: `${category.data.name} | ${t('title')}`,
description: category.data.description,
canonicalUrl: getUrlWithLocale(canonicalPath, locale),
});
}
@ -51,21 +50,31 @@ export default async function BlogCategoryPage({
params,
}: BlogCategoryPageProps) {
const { locale, slug } = await params;
const category = allCategories.find(
(category) => category.locale === locale && category.slug === slug
);
const category = categorySource.getPage([slug], locale);
if (!category) {
notFound();
}
const currentPage = 1;
const { paginatedPosts, totalPages } = getPaginatedBlogPosts({
locale,
page: currentPage,
category: slug,
const localePosts = blogSource.getPages(locale);
const publishedPosts = localePosts.filter((post) => post.data.published);
const filteredPosts = publishedPosts.filter((post) =>
post.data.categories.some((cat) => cat === category.slugs[0])
);
const sortedPosts = filteredPosts.sort((a, b) => {
return new Date(b.data.date).getTime() - new Date(a.data.date).getTime();
});
const currentPage = 1;
const blogPageSize = websiteConfig.blog.paginationSize;
const paginatedLocalePosts = sortedPosts.slice(
(currentPage - 1) * blogPageSize,
currentPage * blogPageSize
);
const totalPages = Math.ceil(sortedPosts.length / blogPageSize);
return (
<BlogGridWithPagination
posts={paginatedPosts}
locale={locale}
posts={paginatedLocalePosts}
totalPages={totalPages}
routePrefix={`/blog/category/${slug}`}
/>

View File

@ -1,10 +1,9 @@
import BlogGridWithPagination from '@/components/blog/blog-grid-with-pagination';
import { websiteConfig } from '@/config/website';
import { LOCALES } from '@/i18n/routing';
import { getPaginatedBlogPosts } from '@/lib/blog/data';
import { blogSource, categorySource } from '@/lib/docs/source';
import { constructMetadata } from '@/lib/metadata';
import { getUrlWithLocale } from '@/lib/urls/urls';
import { allCategories, allPosts } from 'content-collections';
import type { Locale } from 'next-intl';
import { getTranslations } from 'next-intl/server';
import { notFound } from 'next/navigation';
@ -13,19 +12,19 @@ import { notFound } from 'next/navigation';
export function generateStaticParams() {
const params: { locale: string; slug: string; page: string }[] = [];
for (const locale of LOCALES) {
const localeCategories = allCategories.filter(
(category) => category.locale === locale
);
const localeCategories = categorySource.getPages(locale);
for (const category of localeCategories) {
const totalPages = Math.ceil(
allPosts.filter(
(post) =>
post.locale === locale &&
post.categories.some((cat) => cat && cat.slug === category.slug)
).length / websiteConfig.blog.paginationSize
blogSource
.getPages(locale)
.filter(
(post) =>
post.data.published &&
post.data.categories.some((cat) => cat === category.slugs[0])
).length / websiteConfig.blog.paginationSize
);
for (let page = 2; page <= totalPages; page++) {
params.push({ locale, slug: category.slug, page: String(page) });
params.push({ locale, slug: category.slugs[0], page: String(page) });
}
}
}
@ -35,17 +34,16 @@ export function generateStaticParams() {
// Generate metadata for each static category page (locale + category + pagination)
export async function generateMetadata({ params }: BlogCategoryPageProps) {
const { locale, slug, page } = await params;
const category = allCategories.find(
(category) => category.slug === slug && category.locale === locale
);
const category = categorySource.getPage([slug], locale);
if (!category) {
notFound();
}
const t = await getTranslations({ locale, namespace: 'Metadata' });
const canonicalPath = `/blog/category/${slug}/page/${page}`;
return constructMetadata({
title: `${category.name} | ${t('title')}`,
description: category.description,
title: `${category.data.name} | ${t('title')}`,
description: category.data.description,
canonicalUrl: getUrlWithLocale(canonicalPath, locale),
});
}
@ -62,21 +60,26 @@ export default async function BlogCategoryPage({
params,
}: BlogCategoryPageProps) {
const { locale, slug, page } = await params;
const currentPage = Number(page);
const category = allCategories.find(
(category) => category.slug === slug && category.locale === locale
const localePosts = blogSource.getPages(locale);
const publishedPosts = localePosts.filter((post) => post.data.published);
const filteredPosts = publishedPosts.filter((post) =>
post.data.categories.some((cat) => cat === slug)
);
if (!category) {
notFound();
}
const { paginatedPosts, totalPages } = getPaginatedBlogPosts({
locale,
page: currentPage,
category: slug,
const sortedPosts = filteredPosts.sort((a, b) => {
return new Date(b.data.date).getTime() - new Date(a.data.date).getTime();
});
const currentPage = Number(page);
const blogPageSize = websiteConfig.blog.paginationSize;
const paginatedLocalePosts = sortedPosts.slice(
(currentPage - 1) * blogPageSize,
currentPage * blogPageSize
);
const totalPages = Math.ceil(sortedPosts.length / blogPageSize);
return (
<BlogGridWithPagination
posts={paginatedPosts}
locale={locale}
posts={paginatedLocalePosts}
totalPages={totalPages}
routePrefix={`/blog/category/${slug}`}
/>

View File

@ -1,10 +1,9 @@
import BlogGridWithPagination from '@/components/blog/blog-grid-with-pagination';
import { websiteConfig } from '@/config/website';
import { LOCALES } from '@/i18n/routing';
import { getPaginatedBlogPosts } from '@/lib/blog/data';
import { blogSource } from '@/lib/docs/source';
import { constructMetadata } from '@/lib/metadata';
import { getUrlWithLocale } from '@/lib/urls/urls';
import { allPosts } from 'content-collections';
import type { Locale } from 'next-intl';
import { getTranslations } from 'next-intl/server';
@ -12,32 +11,29 @@ export function generateStaticParams() {
const paginationSize = websiteConfig.blog.paginationSize;
const params: { locale: string; page: string }[] = [];
for (const locale of LOCALES) {
const publishedPosts = allPosts.filter(
(post) => post.published && post.locale === locale
);
const publishedPosts = blogSource
.getPages(locale)
.filter((post) => post.data.published);
const totalPages = Math.max(
1,
Math.ceil(publishedPosts.length / paginationSize)
);
for (let pageNumber = 2; pageNumber <= totalPages; pageNumber++) {
params.push({
locale,
page: String(pageNumber),
});
params.push({ locale, page: String(pageNumber) });
}
}
return params;
}
export async function generateMetadata({ params }: BlogListPageProps) {
const { locale, page } = await params;
const { locale } = await params;
const t = await getTranslations({ locale, namespace: 'Metadata' });
const pt = await getTranslations({ locale, namespace: 'BlogPage' });
const canonicalPath = `/blog/page/${page}`;
return constructMetadata({
title: `${pt('title')} | ${t('title')}`,
description: pt('description'),
canonicalUrl: getUrlWithLocale(canonicalPath, locale),
canonicalUrl: getUrlWithLocale('/blog', locale),
});
}
@ -49,15 +45,24 @@ interface BlogListPageProps {
}
export default async function BlogListPage({ params }: BlogListPageProps) {
const { page, locale } = await params;
const currentPage = Number(page);
const { paginatedPosts, totalPages } = getPaginatedBlogPosts({
locale,
page: currentPage,
const { locale, page } = await params;
const localePosts = blogSource.getPages(locale);
const publishedPosts = localePosts.filter((post) => post.data.published);
const sortedPosts = publishedPosts.sort((a, b) => {
return new Date(b.data.date).getTime() - new Date(a.data.date).getTime();
});
const currentPage = Number(page);
const blogPageSize = websiteConfig.blog.paginationSize;
const paginatedLocalePosts = sortedPosts.slice(
(currentPage - 1) * blogPageSize,
currentPage * blogPageSize
);
const totalPages = Math.ceil(sortedPosts.length / blogPageSize);
return (
<BlogGridWithPagination
posts={paginatedPosts}
locale={locale}
posts={paginatedLocalePosts}
totalPages={totalPages}
routePrefix={'/blog'}
/>