diff --git a/src/app/discover/page.tsx b/src/app/discover/page.tsx index 29f69c1d..cbb3a52a 100644 --- a/src/app/discover/page.tsx +++ b/src/app/discover/page.tsx @@ -1,122 +1,17 @@ -import { createServerClient, type Storyline } from "../../../lib/supabase"; -import { getTrendingStorylines, getRisingStorylines } from "../../../lib/ranking"; -import { StoryCard } from "../../components/StoryCard"; -import { TabNav } from "../../components/TabNav"; -import { - WriterFilter, - type WriterFilterValue, -} from "../../components/WriterFilter"; +import { redirect } from "next/navigation"; -export const revalidate = 120; // ISR: regenerate at most every 2 minutes +type SearchParams = Promise>; -type SearchParams = Promise<{ tab?: string; writer?: string }>; - -const TABS = ["new", "trending", "rising", "completed"] as const; -type Tab = (typeof TABS)[number]; - -const WRITER_VALUES: WriterFilterValue[] = ["all", "human", "agent"]; - -export default async function DiscoverPage({ +export default async function DiscoverRedirect({ searchParams, }: { searchParams: SearchParams; }) { - const { tab: rawTab, writer: rawWriter } = 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 supabase = createServerClient(); - if (!supabase) { - return ( -
-

Database unavailable

-
- ); - } - - const storylines = await queryTab(supabase, tab, writer); - - const extraParams = - writer !== "all" ? { writer } : undefined; - - return ( -
-

- Discover -

-

Browse stories on PlotLink

- - - - - -
- {storylines.map((s) => ( - - ))} - {storylines.length === 0 && ( -

- No stories found. -

- )} -
-
- ); -} - -async function queryTab( - supabase: ReturnType & object, - tab: Tab, - writer: WriterFilterValue, -): Promise { - switch (tab) { - case "new": { - let q = supabase - .from("storylines") - .select("*") - .eq("hidden", false) - .eq("sunset", false); - if (writer === "human") q = q.eq("writer_type", 0); - if (writer === "agent") q = q.eq("writer_type", 1); - const { data } = await q - .order("block_timestamp", { ascending: false }) - .limit(50) - .returns(); - return data ?? []; - } - - case "completed": { - let q = supabase - .from("storylines") - .select("*") - .eq("hidden", false) - .eq("sunset", true); - if (writer === "human") q = q.eq("writer_type", 0); - if (writer === "agent") q = q.eq("writer_type", 1); - const { data } = await q - .order("plot_count", { ascending: false }) - .limit(50) - .returns(); - return data ?? []; - } - - case "trending": { - const wt = writer === "human" ? 0 : writer === "agent" ? 1 : undefined; - return getTrendingStorylines(supabase, 20, wt); - } - - case "rising": { - const wt = writer === "human" ? 0 : writer === "agent" ? 1 : undefined; - return getRisingStorylines(supabase, 20, wt); - } + const params = await searchParams; + const qs = new URLSearchParams(); + for (const [k, v] of Object.entries(params)) { + if (typeof v === "string") qs.set(k, v); } + const query = qs.toString(); + redirect(query ? `/?${query}` : "/"); } diff --git a/src/app/page.tsx b/src/app/page.tsx index 4a3fb2a0..62f3747c 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,34 +1,43 @@ import { createServerClient, type Storyline } from "../../lib/supabase"; -import { getTrendingStorylines } from "../../lib/ranking"; +import { getTrendingStorylines, getRisingStorylines } from "../../lib/ranking"; import { StoryCard } from "../components/StoryCard"; +import { TabNav } from "../components/TabNav"; +import { WriterFilter, type WriterFilterValue } from "../components/WriterFilter"; import Link from "next/link"; export const revalidate = 120; -export default async function Home() { - const supabase = createServerClient(); +const TABS = ["new", "trending", "rising", "completed"] as const; +type Tab = (typeof TABS)[number]; + +const WRITER_VALUES: WriterFilterValue[] = ["all", "human", "agent"]; - let recent: Storyline[] = []; - let trending: Storyline[] = []; +type SearchParams = Promise<{ tab?: string; writer?: string }>; +export default async function Home({ + searchParams, +}: { + searchParams: SearchParams; +}) { + const { tab: rawTab, writer: rawWriter } = 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 supabase = createServerClient(); + + let storylines: Storyline[] = []; if (supabase) { - const { data } = await supabase - .from("storylines") - .select("*") - .eq("hidden", false) - .eq("sunset", false) - .order("block_timestamp", { ascending: false }) - .limit(8) - .returns(); - - recent = data ?? []; - trending = await getTrendingStorylines(supabase, 4).catch(() => []); + storylines = await queryTab(supabase, tab, writer); } - const hasContent = recent.length > 0; + const extraParams = writer !== "all" ? { writer } : undefined; return ( -
+
{/* Compact hero */}

@@ -39,48 +48,20 @@ export default async function Home() {

- {hasContent ? ( - <> - {/* Trending section */} - {trending.length > 0 && ( -
-
-

- #trending -

-
-
- {trending.map((s) => ( - - ))} -
-
- )} - - {/* Recent feed */} -
-
-

- #recent -

- - view all → - -
-
- {recent.map((s) => ( - - ))} -
-
- - ) : ( - /* Empty state */ + {/* Filter bar */} + + + + {/* Story grid */} +
+ {storylines.map((s) => ( + + ))} +
+ + {storylines.length === 0 && (
-
+
$ no storylines found

@@ -97,3 +78,51 @@ export default async function Home() {

); } + +async function queryTab( + supabase: ReturnType & object, + tab: Tab, + writer: WriterFilterValue, +): Promise { + switch (tab) { + case "new": { + let q = supabase + .from("storylines") + .select("*") + .eq("hidden", false) + .eq("sunset", false); + if (writer === "human") q = q.eq("writer_type", 0); + if (writer === "agent") q = q.eq("writer_type", 1); + const { data } = await q + .order("block_timestamp", { ascending: false }) + .limit(50) + .returns(); + return data ?? []; + } + + case "completed": { + let q = supabase + .from("storylines") + .select("*") + .eq("hidden", false) + .eq("sunset", true); + if (writer === "human") q = q.eq("writer_type", 0); + if (writer === "agent") q = q.eq("writer_type", 1); + const { data } = await q + .order("plot_count", { ascending: false }) + .limit(50) + .returns(); + return data ?? []; + } + + case "trending": { + const wt = writer === "human" ? 0 : writer === "agent" ? 1 : undefined; + return getTrendingStorylines(supabase, 20, wt); + } + + case "rising": { + const wt = writer === "human" ? 0 : writer === "agent" ? 1 : undefined; + return getRisingStorylines(supabase, 20, wt); + } + } +} diff --git a/src/components/NavBar.tsx b/src/components/NavBar.tsx index 59648408..52674a05 100644 --- a/src/components/NavBar.tsx +++ b/src/components/NavBar.tsx @@ -6,7 +6,6 @@ import { usePathname } from "next/navigation"; import { ConnectWallet } from "./ConnectWallet"; const NAV_LINKS = [ - { href: "/discover", label: "discover" }, { href: "/create", label: "create" }, { href: "/dashboard/writer", label: "writer" }, { href: "/dashboard/reader", label: "reader" }, diff --git a/src/components/TabNav.tsx b/src/components/TabNav.tsx index e9883577..2f3ed4ac 100644 --- a/src/components/TabNav.tsx +++ b/src/components/TabNav.tsx @@ -4,11 +4,13 @@ export function TabNav({ tabs, active, className, + basePath = "/", extraParams, }: { tabs: readonly string[]; active: string; className?: string; + basePath?: string; extraParams?: Record; }) { function buildHref(tab: string) { @@ -18,7 +20,7 @@ export function TabNav({ params.set(k, v); } } - return `/discover?${params.toString()}`; + return `${basePath}?${params.toString()}`; } return ( diff --git a/src/components/WriterFilter.tsx b/src/components/WriterFilter.tsx index 7ceeb7ae..0eb357da 100644 --- a/src/components/WriterFilter.tsx +++ b/src/components/WriterFilter.tsx @@ -12,10 +12,12 @@ export function WriterFilter({ active, tab, className, + basePath = "/", }: { active: WriterFilterValue; tab: string; className?: string; + basePath?: string; }) { return (
@@ -23,7 +25,7 @@ export function WriterFilter({ {WRITER_OPTIONS.map(({ value, label }) => (