/** * Explore: pick a mode and a layer, then read what the panel lights up. * * Angular: useState is roughly a component field plus change detection. Setting * it re-runs this function, so derived values are recomputed each render; * useMemo is the explicit opt-out when that stops being cheap. */ import { useMemo, useState } from "react"; import { ENTRIES } from "./domain/entries"; import { controlName } from "./domain/format"; import { CTX, CTXHINT } from "./domain/labels"; import { entriesByTarget, entriesForLayer, layerCounts, orderLayerKeys, } from "./domain/layers"; import type { ContextCode, ControlId, Entry } from "./domain/types"; import { InfoCard } from "./ui/InfoCard"; import { Panel } from "./ui/Panel"; import styles from "./App.module.css"; const TABS = ["Explore", "Drill", "Find", "Rules"] as const; /** Drawn, not typed: caret glyphs sit outside every Latin font subset. */ function Caret() { return ( ); } const layerLabel = (key: string): string => key === "" ? "NO MODIFIER" : key.split("+").map(controlName).join(" + "); export function App() { const [ctx, setCtx] = useState("S"); const [layer, setLayer] = useState(""); const [selected, setSelected] = useState(null); const [tab, setTab] = useState<(typeof TABS)[number]>("Explore"); const counts = useMemo(() => layerCounts(ENTRIES, ctx), [ctx]); const layers = useMemo(() => orderLayerKeys(counts.keys()), [counts]); // Changing mode can strip the held layer out from under us. const activeLayer = counts.has(layer) ? layer : ""; const onLayer = useMemo( () => entriesForLayer(ENTRIES, ctx, activeLayer), [ctx, activeLayer], ); const lit = useMemo(() => entriesByTarget(onLayer), [onLayer]); const held = activeLayer === "" ? [] : activeLayer.split("+"); /** A control can carry several functions; pressing it again cycles them. */ function press(id: ControlId) { const here = lit.get(id); if (!here || here.length === 0) { setSelected(null); return; } const at = selected ? here.indexOf(selected) : -1; setSelected(here[(at + 1) % here.length]!); } function chooseCtx() { const order = Object.keys(CTX) as ContextCode[]; setCtx(order[(order.indexOf(ctx) + 1) % order.length]!); setSelected(null); } function chooseLayer() { const at = layers.indexOf(activeLayer); setLayer(layers[(at + 1) % layers.length]!); setSelected(null); } return (
e.short), }} />
); }