feat: add pagination for tag and category

This commit is contained in:
2026-03-18 13:10:21 +09:00
parent 06a723c15d
commit 13a637ab32
2 changed files with 39 additions and 39 deletions
@@ -3,30 +3,32 @@ import BaseLayout from "@/layouts/BaseLayout.astro";
import { getCollection } from "astro:content"; import { getCollection } from "astro:content";
import Headline from "@/components/ui/Headline.astro"; import Headline from "@/components/ui/Headline.astro";
import PostItem from "@/components/blog/PostItem.astro"; import PostItem from "@/components/blog/PostItem.astro";
import Pagination from "@/components/ui/Pagination.astro";
import type { GetStaticPathsOptions } from "astro";
export async function getStaticPaths() { export async function getStaticPaths({ paginate }: GetStaticPathsOptions) {
const allPosts = await getCollection("blog"); const allPosts = await getCollection("blog");
const posts = allPosts.filter((post) => post.data && post.data.pubDate); // Ensure published const posts = allPosts.filter((post) => post.data && post.data.pubDate);
const categories = new Set(); const categories = new Set<string>();
posts.forEach((post) => { posts.forEach((post) => {
post.data.categories?.forEach((tag) => categories.add(tag)); post.data.categories?.forEach((cat) => categories.add(cat));
}); });
return Array.from(categories).map((category) => { return Array.from(categories).flatMap((category) => {
return { const categoryPosts = posts
params: { category: category as string }, .filter((post) => post.data.categories?.includes(category))
props: { .sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
category,
posts: posts.filter((post) => return paginate(categoryPosts, {
post.data.categories?.includes(category as string), params: { category },
), pageSize: 6,
}, });
};
}); });
} }
const { category, posts } = Astro.props; const { page } = Astro.props;
const { category } = Astro.params;
const metadata = { const metadata = {
title: `Category: ${category}`, title: `Category: ${category}`,
@@ -40,7 +42,7 @@ const metadata = {
<Headline <Headline
tagline="Category" tagline="Category"
title={category} title={category}
subtitle={`Showing ${posts.length} article${posts.length === 1 ? "" : "s"}.`} subtitle={`Showing ${page.total} article${page.total === 1 ? "" : "s"}.`}
classes={{ classes={{
container: "mb-12 text-center", container: "mb-12 text-center",
title: title:
@@ -54,12 +56,9 @@ const metadata = {
</div> </div>
<div class="grid gap-8 md:grid-cols-2 lg:grid-cols-3"> <div class="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
{ {page.data.map((post) => <PostItem post={post} />)}
posts
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf())
.map((post) => <PostItem post={post} />)
}
</div> </div>
<Pagination page={page} />
</div> </div>
</section> </section>
</BaseLayout> </BaseLayout>
@@ -3,28 +3,32 @@ import BaseLayout from "@/layouts/BaseLayout.astro";
import { getCollection } from "astro:content"; import { getCollection } from "astro:content";
import Headline from "@/components/ui/Headline.astro"; import Headline from "@/components/ui/Headline.astro";
import PostItem from "@/components/blog/PostItem.astro"; import PostItem from "@/components/blog/PostItem.astro";
import Pagination from "@/components/ui/Pagination.astro";
import type { GetStaticPathsOptions } from "astro";
export async function getStaticPaths() { export async function getStaticPaths({ paginate }: GetStaticPathsOptions) {
const allPosts = await getCollection("blog"); const allPosts = await getCollection("blog");
const posts = allPosts.filter((post) => post.data && post.data.pubDate); // Ensure published const posts = allPosts.filter((post) => post.data && post.data.pubDate);
const tags = new Set(); const tags = new Set<string>();
posts.forEach((post) => { posts.forEach((post) => {
post.data.tags?.forEach((tag) => tags.add(tag)); post.data.tags?.forEach((tag) => tags.add(tag));
}); });
return Array.from(tags).map((tag) => { return Array.from(tags).flatMap((tag) => {
return { const tagPosts = posts
params: { tag: tag as string }, .filter((post) => post.data.tags?.includes(tag))
props: { .sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
tag,
posts: posts.filter((post) => post.data.tags?.includes(tag as string)), return paginate(tagPosts, {
}, params: { tag },
}; pageSize: 6,
});
}); });
} }
const { tag, posts } = Astro.props; const { page } = Astro.props;
const { tag } = Astro.params;
const metadata = { const metadata = {
title: `Posts tagged with '${tag}'`, title: `Posts tagged with '${tag}'`,
@@ -38,7 +42,7 @@ const metadata = {
<Headline <Headline
tagline="Tag" tagline="Tag"
title={`#${tag}`} title={`#${tag}`}
subtitle={`Showing ${posts.length} article${posts.length === 1 ? "" : "s"}.`} subtitle={`Showing ${page.total} article${page.total === 1 ? "" : "s"}.`}
classes={{ classes={{
container: "mb-12 text-center", container: "mb-12 text-center",
title: title:
@@ -52,12 +56,9 @@ const metadata = {
</div> </div>
<div class="grid gap-8 md:grid-cols-2 lg:grid-cols-3"> <div class="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
{ {page.data.map((post) => <PostItem post={post} />)}
posts
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf())
.map((post) => <PostItem post={post} />)
}
</div> </div>
<Pagination page={page} />
</div> </div>
</section> </section>
</BaseLayout> </BaseLayout>