Menu
uses useState
The menu down the side: every page, numbered, under its section, and the sections of the one being read (toc). A
filter at the top narrows it to the pages whose names have what's typed; it's kept as the pages change.
import { hrefFor } from "#codebase/tcmts/site"; import type { Page } from "#codebase/tcmts/site"; import { Fragment, useState } from "react"; import type { ReactNode } from "react"; export function Menu({ pages, here, toc }: { pages: Page[]; here: string; toc: ReactNode }) { const [q, setQ] = useState(""); const shown = pages.filter((p) => !q || p.label.includes(q.trim().toLowerCase())); return ( <> <input className="filter" type="search" placeholder="filter pages" aria-label="filter pages" value={q} onChange={(e) => setQ(e.target.value)} /> <ol> {shown.map((p, i) => ( <Fragment key={p.file}> {p.section && p.section !== shown[i - 1]?.section && <li className="section">{p.section.toLowerCase()}</li>} <li className={p.file === here ? "here" : undefined}> {p.file === here ? <span>[{p.n}] {p.label}</span> : <a href={hrefFor(p.file, true)}>[{p.n}] {p.label}</a>} {p.file === here && toc} </li> </Fragment> ))} </ol> </> ); }