diff --git a/app/blog/page.tsx b/app/blog/page.tsx
index f261033..f3fe372 100644
--- a/app/blog/page.tsx
+++ b/app/blog/page.tsx
@@ -1,5 +1,5 @@
import { getAllPostsSorted } from '@/lib/posts';
-import { PostListItem } from '@/components/post-list-item';
+import { PostListWithControls } from '@/components/post-list-with-controls';
export const metadata = {
title: '所有文章'
@@ -13,11 +13,7 @@ export default function BlogIndexPage() {
所有文章
-
- {posts.map((post) => (
-
- ))}
-
+
);
}
diff --git a/app/tags/[tag]/page.tsx b/app/tags/[tag]/page.tsx
index 6aefb07..38781c1 100644
--- a/app/tags/[tag]/page.tsx
+++ b/app/tags/[tag]/page.tsx
@@ -1,6 +1,6 @@
import type { Metadata } from 'next';
import { allPosts } from 'contentlayer/generated';
-import { PostListItem } from '@/components/post-list-item';
+import { PostListWithControls } from '@/components/post-list-with-controls';
import { getTagSlug } from '@/lib/posts';
export function generateStaticParams() {
@@ -47,11 +47,7 @@ export default function TagPage({ params }: Props) {
標籤:{tagLabel}
-
- {posts.map((post) => (
-
- ))}
-
+
);
}
diff --git a/components/post-list-with-controls.tsx b/components/post-list-with-controls.tsx
new file mode 100644
index 0000000..c06f34b
--- /dev/null
+++ b/components/post-list-with-controls.tsx
@@ -0,0 +1,132 @@
+'use client';
+
+import { useMemo, useState } from 'react';
+import type { Post } from 'contentlayer/generated';
+import { siteConfig } from '@/lib/config';
+import { PostListItem } from './post-list-item';
+
+interface Props {
+ posts: Post[];
+ pageSize?: number;
+}
+
+type SortOrder = 'new' | 'old';
+
+export function PostListWithControls({ posts, pageSize }: Props) {
+ const [sortOrder, setSortOrder] = useState('new');
+ const [page, setPage] = useState(1);
+
+ const size = pageSize ?? siteConfig.postsPerPage ?? 5;
+
+ const sortedPosts = useMemo(() => {
+ const arr = [...posts];
+ arr.sort((a, b) => {
+ const aDate = a.published_at
+ ? new Date(a.published_at).getTime()
+ : 0;
+ const bDate = b.published_at
+ ? new Date(b.published_at).getTime()
+ : 0;
+ return sortOrder === 'new' ? bDate - aDate : aDate - bDate;
+ });
+ return arr;
+ }, [posts, sortOrder]);
+
+ const totalPages = Math.max(1, Math.ceil(sortedPosts.length / size));
+ const currentPage = Math.min(page, totalPages);
+ const start = (currentPage - 1) * size;
+ const currentPosts = sortedPosts.slice(start, start + size);
+
+ const handleChangeSort = (order: SortOrder) => {
+ setSortOrder(order);
+ setPage(1);
+ };
+
+ const goToPage = (p: number) => {
+ if (p < 1 || p > totalPages) return;
+ setPage(p);
+ };
+
+ return (
+
+
+
+ 排序:
+
+
+
+
+ 第 {currentPage} / {totalPages} 頁
+
+
+
+
+ {currentPosts.map((post) => (
+
+ ))}
+
+
+ {totalPages > 1 && (
+
+ )}
+
+ );
+}
+