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 38c003da..b4012006 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, from); } case "rising": { const wt = writer === "human" ? 0 : writer === "agent" ? 1 : undefined; - return getRisingStorylines(supabase, 20, wt); + return getRisingStorylines(supabase, PAGE_SIZE, wt, from); } } }