feat: implement pagination for blog posts and enhance NavLink component with class support

This commit is contained in:
fiatcode 2026-01-22 18:40:39 +07:00
parent ca2c54de0e
commit 6b831e7100
5 changed files with 87 additions and 39 deletions

View file

@ -11,13 +11,13 @@ npm run dev
## Commands
| Command | Action |
| :---------------- | :------------------------------------------ |
| `npm install` | Install dependencies |
| `npm run dev` | Start dev server at `localhost:4321` |
| `npm run build` | Build production site to `./dist/` |
| `npm run preview` | Preview production build locally |
| `npm run format` | Format code with Prettier |
| Command | Action |
| :---------------- | :----------------------------------- |
| `npm install` | Install dependencies |
| `npm run dev` | Start dev server at `localhost:4321` |
| `npm run build` | Build production site to `./dist/` |
| `npm run preview` | Preview production build locally |
| `npm run format` | Format code with Prettier |
## Tech Stack

View file

@ -2,14 +2,15 @@
interface Props {
href: string;
ariaLabel?: string;
class?: string;
}
const { href, ariaLabel } = Astro.props;
const { href, ariaLabel, class: className } = Astro.props;
---
<a
href={href}
class="hover:underline underline-offset-4 decoration-transparent hover:decoration-current transition-colors duration-300 aria-[current]:underline aria-[current]:decoration-current aria-[current]:font-semibold"
class={`hover:underline underline-offset-4 decoration-transparent hover:decoration-current transition-colors duration-300 aria-[current]:underline aria-[current]:decoration-current aria-[current]:font-semibold ${className ?? ""}`}
aria-label={ariaLabel}
>
<slot />

View file

@ -0,0 +1,26 @@
---
import NavLink from "./NavLink.astro";
interface Props {
currentPage: number;
lastPage: number;
getPageUrl: (page: number) => string;
}
const { currentPage, lastPage, getPageUrl } = Astro.props;
---
<nav aria-label="Pagination Navigation" class="flex py-6">
{
currentPage > 1 && (
<NavLink href={getPageUrl(currentPage - 1)}>« Previous</NavLink>
)
}
{
currentPage < lastPage && (
<NavLink href={getPageUrl(currentPage + 1)} class="ml-auto">
Next »
</NavLink>
)
}
</nav>

View file

@ -0,0 +1,51 @@
---
import type { PaginateFunction, Page } from "astro";
import { getCollection } from "astro:content";
import Layout from "@/layouts/Layout.astro";
import BlogPostCard from "@/components/BlogPostCard.astro";
import PageTitle from "@/components/PageTitle.astro";
import type { CollectionEntry } from "astro:content";
import Pagination from "@/components/Pagination.astro";
export async function getStaticPaths({
paginate,
}: {
paginate: PaginateFunction;
}) {
const posts = await getCollection("blog");
posts.sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
return paginate(posts, { pageSize: 5 });
}
interface Props {
page: Page<CollectionEntry<"blog">>;
}
const { page } = Astro.props;
---
<Layout
title="Posts - Dhemas Nurjaya"
description="Read the latest blog posts by Dhemas Nurjaya"
>
<PageTitle title="Posts" />
<ul class="space-y-4">
{
page.data.map((post) => (
<li>
<BlogPostCard
id={post.id}
title={post.data.title}
date={post.data.date}
description={post.data.description}
/>
</li>
))
}
</ul>
<Pagination
currentPage={page.currentPage}
lastPage={page.lastPage}
getPageUrl={(page) => (page === 1 ? `/posts/` : `/posts/${page}/`)}
/>
</Layout>

View file

@ -1,30 +0,0 @@
---
import { getCollection } from "astro:content";
import Layout from "@/layouts/Layout.astro";
import BlogPostCard from "@/components/BlogPostCard.astro";
import PageTitle from "@/components/PageTitle.astro";
const posts = await getCollection("blog");
posts.sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
---
<Layout
title="Posts - Dhemas Nurjaya"
description="Read the latest blog posts by Dhemas Nurjaya"
>
<PageTitle title="Posts" />
<ul class="space-y-4">
{
posts.map((post) => (
<li>
<BlogPostCard
id={post.id}
title={post.data.title}
date={post.data.date}
description={post.data.description}
/>
</li>
))
}
</ul>
</Layout>