import Link from "next/link"; import { notFound } from "next/navigation"; import BrowseHeader from "@/components/BrowseHeader"; import ProjectView from "@/components/projects/ProjectView"; import ProjectGrid from "@/components/projects/ProjectGrid"; import { listProjects, resolveProjectPath } from "@/lib/projects"; export const dynamic = "force-dynamic"; // --------------------------------------------------------------------------- // Everything below /browse that is not a tool page. // // This replaced app/browse/[song]/ rather than joining it: two dynamic segments // at the same level is a Next routing conflict, so it is a delete-and-move. The // song pages themselves are unchanged -- they moved to components/projects/ and // are handed an id instead of awaiting params. /browse/yoshi/wide is still the // same URL and still renders the same page. // // Resolution is LONGEST-PREFIX: a project id is a path, so `a/b` being a project // must not stop `a/b/c` from being one too. Whatever is left over is a VIEW, and // which views exist is the kind's business, not this file's. // --------------------------------------------------------------------------- export default async function BrowsePathPage({ params, searchParams, }: { params: Promise<{ path?: string[] }>; searchParams: Promise>; }) { const { path: segments = [] } = await params; const search = await searchParams; const resolved = await resolveProjectPath(segments); if (!resolved) notFound(); if (resolved.project) { return ; } // Two projects answer to the same bare name. Which one you meant is not // guessable, and guessing is how a link quietly starts pointing at the wrong // thing -- so the page says so and offers both canonical paths. if ("ambiguous" in resolved && resolved.ambiguous) { return (

{segments[0]} is the name of more than one project, so it cannot be a shortcut to any of them. Use a full path:

    {resolved.ambiguous.map((p) => (
  • `/${s}`).join("")}`} className="font-mono text-[12px] text-[var(--color-sel)] hover:underline" > /browse/{p.id}
  • ))}
); } // A folder: the same grid, filtered to what is under it. const folder = resolved.folder; if (!folder) notFound(); const all = await listProjects(); const mine = all.filter((p) => p.id.startsWith(`${folder.path}/`)); return (
); }