Menu

tcmts.site.Menu · #qh5iaex7 · term · runs in the browser

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>
    </>
  );
}

uses

used by