From ab3ca64ec9bab4b840edad1061f84cc62577bf25 Mon Sep 17 00:00:00 2001 From: Kunthawat Greethong Date: Wed, 1 Jul 2026 14:35:55 +0700 Subject: [PATCH] feat: add pagination to blog listing (12 posts per page) - Use Astro's paginate() with pageSize: 12 - Add prev/next navigation with page counter - Generate /blog/, /blog/2/, /blog/3/ etc. --- src/pages/blog.astro | 78 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 5 deletions(-) diff --git a/src/pages/blog.astro b/src/pages/blog.astro index f68a3e9..d86c7c7 100644 --- a/src/pages/blog.astro +++ b/src/pages/blog.astro @@ -2,12 +2,18 @@ import PageShell from '../components/PageShell.astro'; import { getCollection } from 'astro:content'; -const posts = (await getCollection('blog', ({ data }) => !data.draft)).sort( - (a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(), -); +export async function getStaticPaths({ paginate }) { + const posts = (await getCollection('blog', ({ data }) => !data.draft)).sort( + (a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(), + ); + + return paginate(posts, { pageSize: 12 }); +} + +const { page } = Astro.props; // Collect all unique categories -const allCategories = [...new Set(posts.map((p) => p.data.category))].sort(); +const allCategories = [...new Set(page.data.map((p) => p.data.category))].sort(); --- p.data.category))].sort();
- {posts.map((post) => { + {page.data.map((post) => { const fmt = new Intl.DateTimeFormat('th-TH', { day: '2-digit', month: 'short', year: '2-digit' }).format(post.data.pubDate); return ( @@ -51,6 +57,31 @@ const allCategories = [...new Set(posts.map((p) => p.data.category))].sort();
+ + + {page.lastPage > 1 && ( + + )}
@@ -143,6 +174,43 @@ const allCategories = [...new Set(posts.map((p) => p.data.category))].sort(); padding: clamp(40px, 6vw, 80px) 0; } + /* Pagination */ + .blog-pagination { + display: flex; + align-items: center; + justify-content: center; + gap: 16px; + margin-top: clamp(32px, 4vw, 56px); + padding: 20px 0; + } + .pagination-btn { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 10px 20px; + border-radius: 999px; + border: 1px solid var(--line); + background: rgb(255 255 255 / .60); + color: var(--ink); + font-size: 0.88rem; + font-weight: 700; + text-decoration: none; + transition: all .2s var(--ease); + } + .pagination-btn:hover { + background: var(--yellow); + border-color: var(--yellow); + } + .pagination-btn--disabled { + opacity: 0.4; + cursor: not-allowed; + pointer-events: none; + } + .pagination-info { + color: var(--muted); + font-size: 0.85rem; + } + @media (max-width: 820px) { .blog-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }