From e0ced601c487ae6a4a857be6a0a39515055859e1 Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Mon, 16 Mar 2026 18:54:45 +0000 Subject: [PATCH 1/2] [#207] Add pagination to home page story grid - PAGE_SIZE = 24, uses supabase .range() for offset pagination - Prev/Next buttons with page number, preserves tab + writer params - Works with all sort options and writer filter - Trending/rising use PAGE_SIZE instead of hardcoded 20 Fixes #207 Co-Authored-By: Claude Opus 4.6 (1M context) --- src/app/page.tsx | 51 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/src/app/page.tsx b/src/app/page.tsx index 38c003da..8ae308a8 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -12,27 +12,30 @@ type Tab = (typeof TABS)[number]; const WRITER_VALUES: WriterFilterValue[] = ["all", "human", "agent"]; -type SearchParams = Promise<{ tab?: string; writer?: string }>; +const PAGE_SIZE = 24; + +type SearchParams = Promise<{ tab?: string; writer?: string; page?: string }>; export default async function Home({ searchParams, }: { searchParams: SearchParams; }) { - const { tab: rawTab, writer: rawWriter } = await searchParams; + const { tab: rawTab, writer: rawWriter, page: rawPage } = await searchParams; const tab: Tab = TABS.includes(rawTab as Tab) ? (rawTab as Tab) : "new"; const writer: WriterFilterValue = WRITER_VALUES.includes( rawWriter as WriterFilterValue, ) ? (rawWriter as WriterFilterValue) : "all"; + const page = Math.max(1, parseInt(rawPage ?? "1", 10) || 1); const supabase = createServerClient(); let storylines: Storyline[] = []; const previews: Record = {}; if (supabase) { - storylines = await queryTab(supabase, tab, writer); + storylines = await queryTab(supabase, tab, writer, page); // Fetch genesis plot previews if (storylines.length > 0) { // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -75,6 +78,29 @@ export default async function Home({ ))} + {/* Pagination */} + {(page > 1 || storylines.length === PAGE_SIZE) && ( +
+ {page > 1 && ( + + ← Previous + + )} + Page {page} + {storylines.length === PAGE_SIZE && ( + + Next → + + )} +
+ )} + {storylines.length === 0 && (
@@ -95,11 +121,22 @@ export default async function Home({ ); } +function buildPageHref(tab: string, writer: string, page: number): string { + const params = new URLSearchParams({ tab }); + if (writer !== "all") params.set("writer", writer); + if (page > 1) params.set("page", String(page)); + return `/?${params.toString()}`; +} + async function queryTab( supabase: ReturnType & object, tab: Tab, writer: WriterFilterValue, + page: number, ): Promise { + const from = (page - 1) * PAGE_SIZE; + const to = from + PAGE_SIZE - 1; + switch (tab) { case "new": { let q = supabase @@ -111,7 +148,7 @@ async function queryTab( if (writer === "agent") q = q.eq("writer_type", 1); const { data } = await q .order("block_timestamp", { ascending: false }) - .limit(50) + .range(from, to) .returns(); return data ?? []; } @@ -126,19 +163,19 @@ async function queryTab( if (writer === "agent") q = q.eq("writer_type", 1); const { data } = await q .order("plot_count", { ascending: false }) - .limit(50) + .range(from, to) .returns(); return data ?? []; } case "trending": { const wt = writer === "human" ? 0 : writer === "agent" ? 1 : undefined; - return getTrendingStorylines(supabase, 20, wt); + return getTrendingStorylines(supabase, PAGE_SIZE, wt); } case "rising": { const wt = writer === "human" ? 0 : writer === "agent" ? 1 : undefined; - return getRisingStorylines(supabase, 20, wt); + return getRisingStorylines(supabase, PAGE_SIZE, wt); } } } From 04e55b13fec5a910e3a511971e98563c326ecc76 Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Mon, 16 Mar 2026 18:58:07 +0000 Subject: [PATCH 2/2] [#207] Fix pagination for trending/rising tabs Add offset param to getTrendingStorylines and getRisingStorylines. Page 2+ now correctly advances results for all sort options. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/ranking.ts | 6 ++++-- src/app/page.tsx | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/ranking.ts b/lib/ranking.ts index 8fd22391..5a8a6079 100644 --- a/lib/ranking.ts +++ b/lib/ranking.ts @@ -118,6 +118,7 @@ export async function getTrendingStorylines( supabase: SupabaseClient, limit = 20, writerType?: number, + offset = 0, ): Promise { const { storylines, ratingMap } = await fetchCandidatesAndRatings(supabase, writerType); if (storylines.length === 0) return []; @@ -141,7 +142,7 @@ export async function getTrendingStorylines( ); enriched.sort((a, b) => b.trendScore - a.trendScore); - return enriched.slice(0, limit); + return enriched.slice(offset, offset + limit); } /** @@ -157,6 +158,7 @@ export async function getRisingStorylines( supabase: SupabaseClient, limit = 20, writerType?: number, + offset = 0, ): Promise { const { storylines } = await fetchCandidatesAndRatings(supabase, writerType); if (storylines.length === 0) return []; @@ -260,5 +262,5 @@ export async function getRisingStorylines( }); enriched.sort((a, b) => b.trendScore - a.trendScore); - return enriched.filter((s) => s.trendScore > 1).slice(0, limit); + return enriched.filter((s) => s.trendScore > 1).slice(offset, offset + limit); } diff --git a/src/app/page.tsx b/src/app/page.tsx index 8ae308a8..b4012006 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -170,12 +170,12 @@ async function queryTab( case "trending": { const wt = writer === "human" ? 0 : writer === "agent" ? 1 : undefined; - return getTrendingStorylines(supabase, PAGE_SIZE, wt); + return getTrendingStorylines(supabase, PAGE_SIZE, wt, from); } case "rising": { const wt = writer === "human" ? 0 : writer === "agent" ? 1 : undefined; - return getRisingStorylines(supabase, PAGE_SIZE, wt); + return getRisingStorylines(supabase, PAGE_SIZE, wt, from); } } }