feat: implement pagination utility and refactor static paths for blog, category, and tag pages

This commit is contained in:
Thuan Bui
2026-03-19 17:41:42 +07:00
parent f1ae037d93
commit 7919848fcd
6 changed files with 99 additions and 63 deletions
+8 -3
View File
@@ -4,15 +4,20 @@ import { getCollection } from "astro:content";
import Headline from "@/components/ui/Headline.astro";
import Pagination from "@/components/ui/Pagination.astro";
import PostItem from "@/components/blog/PostItem.astro";
import type { GetStaticPathsOptions } from "astro";
import { buildPaginatedPaths } from "@/utils/paginate";
export async function getStaticPaths({ paginate }: GetStaticPathsOptions) {
export async function getStaticPaths() {
const blogEntries = await getCollection("blog");
const sortedPosts = blogEntries
.filter((post) => post.data && post.data.pubDate)
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
return paginate(sortedPosts, { pageSize: 6 });
return buildPaginatedPaths(sortedPosts, "/blog").map(
({ pageParam, page }) => ({
params: { page: pageParam },
props: { page },
}),
);
}
const { page } = Astro.props;
+12 -24
View File
@@ -4,16 +4,14 @@ import { getCollection } from "astro:content";
import Headline from "@/components/ui/Headline.astro";
import PostItem from "@/components/blog/PostItem.astro";
import Pagination from "@/components/ui/Pagination.astro";
import type { Page } from "astro";
import type { CollectionEntry } from "astro:content";
import {
getTaxonomyMap,
getTaxonomyPath,
type TaxonomyItem,
} from "@/utils/taxonomy";
import { buildPaginatedPaths } from "@/utils/paginate";
export async function getStaticPaths() {
const PAGE_SIZE = 6;
const allPosts = await getCollection("blog");
const posts = allPosts.filter((post) => post.data && post.data.pubDate);
@@ -31,32 +29,22 @@ export async function getStaticPaths() {
const cat =
getTaxonomyMap("category").get(slug) ??
({ slug, name: slug } as TaxonomyItem);
const totalPages = Math.max(1, Math.ceil(catPosts.length / PAGE_SIZE));
return Array.from({ length: totalPages }, (_, i) => {
const pageNum = i + 1;
return {
params: { rest: pageNum === 1 ? fullPath : `${fullPath}/${pageNum}` },
return buildPaginatedPaths(catPosts, `/category/${fullPath}`).map(
({ pageParam, page }) => ({
params: { rest: pageParam ? `${fullPath}/${pageParam}` : fullPath },
props: {
cat,
fullPath,
posts: catPosts.slice(i * PAGE_SIZE, (i + 1) * PAGE_SIZE),
currentPage: pageNum,
lastPage: totalPages,
total: catPosts.length,
prevUrl:
pageNum === 1
? undefined
: pageNum === 2
? `/category/${fullPath}`
: `/category/${fullPath}/${pageNum - 1}`,
nextUrl:
pageNum === totalPages
? undefined
: `/category/${fullPath}/${pageNum + 1}`,
posts: page.data,
currentPage: page.currentPage,
lastPage: page.lastPage,
total: page.total,
prevUrl: page.url.prev,
nextUrl: page.url.next,
},
};
});
}),
);
});
}
@@ -4,10 +4,10 @@ import { getCollection } from "astro:content";
import Headline from "@/components/ui/Headline.astro";
import PostItem from "@/components/blog/PostItem.astro";
import Pagination from "@/components/ui/Pagination.astro";
import type { GetStaticPathsOptions } from "astro";
import { getTaxonomyMap } from "@/utils/taxonomy";
import { buildPaginatedPaths } from "@/utils/paginate";
export async function getStaticPaths({ paginate }: GetStaticPathsOptions) {
export async function getStaticPaths() {
const allPosts = await getCollection("blog");
const posts = allPosts.filter((post) => post.data && post.data.pubDate);
@@ -21,10 +21,12 @@ export async function getStaticPaths({ paginate }: GetStaticPathsOptions) {
.filter((post) => post.data.categories?.includes(category))
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
return paginate(categoryPosts, {
params: { category },
pageSize: 6,
});
return buildPaginatedPaths(categoryPosts, `/category/${category}`).map(
({ pageParam, page }) => ({
params: { category, page: pageParam },
props: { page },
}),
);
});
}
+12 -24
View File
@@ -4,16 +4,14 @@ import { getCollection } from "astro:content";
import Headline from "@/components/ui/Headline.astro";
import PostItem from "@/components/blog/PostItem.astro";
import Pagination from "@/components/ui/Pagination.astro";
import type { Page } from "astro";
import type { CollectionEntry } from "astro:content";
import {
getTaxonomyMap,
getTaxonomyPath,
type TaxonomyItem,
} from "@/utils/taxonomy";
import { buildPaginatedPaths } from "@/utils/paginate";
export async function getStaticPaths() {
const PAGE_SIZE = 6;
const allPosts = await getCollection("blog");
const posts = allPosts.filter((post) => post.data && post.data.pubDate);
@@ -31,32 +29,22 @@ export async function getStaticPaths() {
const dest =
getTaxonomyMap("destination").get(slug) ??
({ slug, name: slug } as TaxonomyItem);
const totalPages = Math.max(1, Math.ceil(destPosts.length / PAGE_SIZE));
return Array.from({ length: totalPages }, (_, i) => {
const pageNum = i + 1;
return {
params: { rest: pageNum === 1 ? fullPath : `${fullPath}/${pageNum}` },
return buildPaginatedPaths(destPosts, `/destination/${fullPath}`).map(
({ pageParam, page }) => ({
params: { rest: pageParam ? `${fullPath}/${pageParam}` : fullPath },
props: {
dest,
fullPath,
posts: destPosts.slice(i * PAGE_SIZE, (i + 1) * PAGE_SIZE),
currentPage: pageNum,
lastPage: totalPages,
total: destPosts.length,
prevUrl:
pageNum === 1
? undefined
: pageNum === 2
? `/destination/${fullPath}`
: `/destination/${fullPath}/${pageNum - 1}`,
nextUrl:
pageNum === totalPages
? undefined
: `/destination/${fullPath}/${pageNum + 1}`,
posts: page.data,
currentPage: page.currentPage,
lastPage: page.lastPage,
total: page.total,
prevUrl: page.url.prev,
nextUrl: page.url.next,
},
};
});
}),
);
});
}
+8 -6
View File
@@ -4,10 +4,10 @@ import { getCollection } from "astro:content";
import Headline from "@/components/ui/Headline.astro";
import PostItem from "@/components/blog/PostItem.astro";
import Pagination from "@/components/ui/Pagination.astro";
import type { GetStaticPathsOptions } from "astro";
import { getTaxonomyMap } from "@/utils/taxonomy";
import { buildPaginatedPaths } from "@/utils/paginate";
export async function getStaticPaths({ paginate }: GetStaticPathsOptions) {
export async function getStaticPaths() {
const allPosts = await getCollection("blog");
const posts = allPosts.filter((post) => post.data && post.data.pubDate);
@@ -21,10 +21,12 @@ export async function getStaticPaths({ paginate }: GetStaticPathsOptions) {
.filter((post) => post.data.tags?.includes(tag))
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
return paginate(tagPosts, {
params: { tag },
pageSize: 6,
});
return buildPaginatedPaths(tagPosts, `/tag/${tag}`).map(
({ pageParam, page }) => ({
params: { tag, page: pageParam },
props: { page },
}),
);
});
}