Files
arah2/web/src/guidance/glyphs.ts
T
araharah-executor 0023ab3086 feat(06-05): the 8-glyph committed maneuver set + glyphs.ts + the 18 guidance strings keys
- 8 hand-authored 32x32 SVGs per the UI-SPEC geometry table (3px stroke, square caps, orthogonal/45° only; uturn = machined staple, no arc)
- glyphs.ts: GLYPH_KINDS/GLYPHS via Vite ?raw (committed files are the single source) + svgHost — the ONE sanctioned innerHTML site, a static import value
- strings.ts: 18 ShellStrings keys appended in en + ms, values verbatim from the 06-UI-SPEC copywriting contract
- copy-gate: COPY1 floor 40→58 + COPY8 pins all 18 guidance keys verbatim in both locales
2026-10-24 14:08:35 +08:00

72 lines
2.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* glyphs.ts — the 8-glyph committed maneuver set (06-UI-SPEC "The 8-glyph set").
* ------------------------------------------------------------------------------
* The committed SVG files under ./glyphs/ are the SINGLE SOURCE: this module
* imports them verbatim with Vite's `?raw` and never re-states their geometry.
* The same files rasterize once to 256×256 PNGs for the chat turn-cards
* (maintainer `build-glyphs.mjs`, plan 07) — one geometry, two renderings.
* In-app the raw SVG renders inline: 32×32 on the banner's arrow plate,
* 24×24 in the maneuver list. Strokes ride `currentColor` (signal-orange on
* the banner plate, matte-black/outline per list row state) — the PNG build
* injects the token literals; nothing here hardcodes a color (DSGN-01).
*
* svgHost is the shell's ONE sanctioned innerHTML site: the template parses
* a STATIC import value (GLYPHS[kind], committed at build time), never a
* name-derived or runtime string — the surface gate whitelists exactly this
* line (guidance-surface structural case).
*/
import depart from "./glyphs/depart.svg?raw";
import straight from "./glyphs/straight.svg?raw";
import left from "./glyphs/left.svg?raw";
import right from "./glyphs/right.svg?raw";
import slightLeft from "./glyphs/slight-left.svg?raw";
import slightRight from "./glyphs/slight-right.svg?raw";
import uturn from "./glyphs/uturn.svg?raw";
import arrive from "./glyphs/arrive.svg?raw";
/** The maneuver vocabulary the UI-SPEC commits (8 kinds, trip-order names —
* RouteStep.kind maps onto these in the controller). */
export type GlyphKind =
| "depart"
| "straight"
| "left"
| "right"
| "slight-left"
| "slight-right"
| "uturn"
| "arrive";
/** The 8 kinds in committed order (depart → arrive). */
export const GLYPH_KINDS: readonly GlyphKind[] = [
"depart",
"straight",
"left",
"right",
"slight-left",
"slight-right",
"uturn",
"arrive",
];
/** kind → raw SVG string of the committed file (the single source). */
export const GLYPHS: Record<GlyphKind, string> = {
depart,
straight,
left,
right,
"slight-left": slightLeft,
"slight-right": slightRight,
uturn,
arrive,
};
/** Parse a committed glyph into a live inline-SVG element. The caller sizes
* the host (banner 32×32, list 24×24); color rides currentColor. */
export function svgHost(kind: GlyphKind): SVGSVGElement {
const template = document.createElement("template");
// THE one sanctioned innerHTML site: a static import value — never a
// name-derived or runtime string (the surface gate's exact whitelist).
template.innerHTML = GLYPHS[kind];
return template.content.firstElementChild as SVGSVGElement;
}