From 0f727aa36a44c31bc51f20f3be34e7639b76e375 Mon Sep 17 00:00:00 2001 From: Haitao Pan Date: Tue, 11 Nov 2025 13:42:11 +0800 Subject: [PATCH] feat: add pagination and fix blog post links MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Changes to Blog Listing Page (src/app/blog/page.tsx): 1. **Implemented Pagination** - Added support for `page` query parameter (e.g., `/blog?page=2`) - Displays 10 posts per page - Shows pagination controls with Previous/Next buttons - Page numbers displayed as clickable buttons - Active page highlighted with brand color - Handles edge cases (invalid page numbers, out of bounds) 2. **Fixed "Read more" Links** - Changed from `/blog` to `/blog/${post.slug}` - Each blog card's "Read more" now links to individual article page - Clicking "Read more" on Cloud-Neutral-Hybrid-Network-Architecture → `/blog/Cloud-Neutral-Hybrid-Network-Architecture` 3. **Features** - **Server-side pagination**: Posts are sliced on the server - **URL-based navigation**: Pagination state in URL - **Responsive design**: Clean pagination controls - **Error handling**: 404 for invalid pages - **Navigation**: Previous/Next buttons with disabled states - **Accessibility**: aria-disabled attribute on navigation ### Example URLs: - `/blog` - First page (default) - `/blog?page=1` - First page - `/blog?page=2` - Second page - Each post card → `/blog/[post-slug]` ### Result: - ✅ Blog list supports pagination - ✅ "Read more" links work correctly - ✅ Better UX for browsing multiple blog posts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- dashboard/src/app/blog/page.tsx | 138 +++++++++++++++++++++++--------- 1 file changed, 99 insertions(+), 39 deletions(-) diff --git a/dashboard/src/app/blog/page.tsx b/dashboard/src/app/blog/page.tsx index 0040e6c..75f0813 100644 --- a/dashboard/src/app/blog/page.tsx +++ b/dashboard/src/app/blog/page.tsx @@ -1,6 +1,7 @@ import Link from 'next/link' import { getHomepagePosts } from '@cms/content' import type { Metadata } from 'next' +import { notFound } from 'next/navigation' export const metadata: Metadata = { title: 'Blog | Cloud-Neutral', @@ -27,8 +28,23 @@ function formatDate(dateStr: string | undefined, language: 'zh' | 'en'): string } } -export default async function BlogPage() { +type PageProps = { + searchParams: { page?: string } +} + +export default async function BlogPage({ searchParams }: PageProps) { const posts = await getHomepagePosts() + const postsPerPage = 10 + const currentPage = parseInt(searchParams.page || '1', 10) + const totalPages = Math.ceil(posts.length / postsPerPage) + + if (currentPage < 1 || currentPage > totalPages) { + notFound() + } + + const startIndex = (currentPage - 1) * postsPerPage + const endIndex = startIndex + postsPerPage + const paginatedPosts = posts.slice(startIndex, endIndex) return (
@@ -45,48 +61,92 @@ export default async function BlogPage() {

暂无博客文章

) : ( -
- {posts.map((post) => ( -
-
- Blog - {post.date && ( - - )} -
-

{post.title}

- {post.author && ( -

By {post.author}

- )} -

{post.excerpt}

-
- {post.tags && post.tags.length > 0 && ( -
- {post.tags.map((tag) => ( - - {tag} - - ))} -
+ <> +
+ {paginatedPosts.map((post) => ( +
+
+ Blog + {post.date && ( + + )} +
+

{post.title}

+ {post.author && ( +

By {post.author}

)} +

{post.excerpt}

+
+ {post.tags && post.tags.length > 0 && ( +
+ {post.tags.map((tag) => ( + + {tag} + + ))} +
+ )} + + Read more → + +
+
+ ))} +
+ + {totalPages > 1 && ( +
-
- ))} -
+ ))} + + + Next + + + )} + )}