- 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
72 lines
2.6 KiB
TypeScript
72 lines
2.6 KiB
TypeScript
/*
|
||
* 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;
|
||
}
|