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
This commit is contained in:
araharah-executor
2026-10-24 14:08:35 +08:00
parent 46acbf4a53
commit 0023ab3086
11 changed files with 232 additions and 2 deletions
+84 -1
View File
@@ -6,7 +6,8 @@
* module, and the copy gate (web/test/copy-gate.test.mjs COPY1..COPY7) keeps
* it verbatim against the approved UI-SPEC table in en + ms. Register labels
* (`BOOT-01 //`, `BOOT-02 //`, `GEO // LOCATION`, `SYS // POSITION`, `ROUTE`,
* `ROUTE // ROUTER`) are instrument vocabulary: identical in both locales by
* `ROUTE // ROUTER`, `GUIDE`) are instrument vocabulary: identical in both
* locales by
* design. Tone is clinical + honest (D-01): plain statements of what is
* stored and what is not.
*
@@ -58,6 +59,48 @@ export interface ShellStrings {
ariaRouteAlternatives: string;
/** Template — {n}/{min}/{km} placeholders are replaced in code. */
ariaRouteChip: string;
/* — Phase 6 guidance chrome (06-UI-SPEC §Copywriting Contract; D-06/D-09/D-14).
Every guidance word lives here in en + ms — never inline (the copy gates).
Register labels (GUIDE, GUIDE // NEXT/REROUTING/…, GUIDE // T-nn) are
instrument vocabulary composed in code from guideRegister. Tone: clinical,
honest — the privacy promise stated once, at the exact moment it executes. */
/** The banner/card register base word — composed with the state word in code. */
guideRegister: string;
/** Fallback street line for an unnamed OSM segment (D-06 street slot). */
guideStreetUnnamed: string;
/** REROUTING calm-state line — no blame, no apology (D-04). */
guideReroutingLine: string;
/** RESUMING projected-state line until the first live fix (D-06/D-11). */
guideResumingLine: string;
/** NO REROUTE banner line — router-pending degradation (D-03). */
guideNoRerouteLine: string;
/** NO REROUTE card state line — the longer honest copy (D-03). */
guideNoRerouteBody: string;
/** Banner toggle word, collapsed state (real-word affordance, no chevron). */
ctaBannerList: string;
/** Banner toggle word, expanded state. */
ctaBannerClose: string;
/** The guidance card's ONLY action — opens the abandon confirm card (D-09). */
ctaEndTrip: string;
/** The abandon-route confirm card (D-09/PX-03) — the one destructive guard. */
guideConfirmHeadline: string;
/** The privacy clause stated at the exact moment it executes (D-14/PRIV-01). */
guideConfirmBody: string;
/** Confirm primary CTA — deliberately NOT red (deliberate, not an error). */
ctaConfirmAbandon: string;
/** Confirm dismiss — guidance continues. */
ctaConfirmContinue: string;
/** Trip-ended card (D-14) — ONE card for arrival and abandon. */
guideEndHeadline: string;
/** Trip-end deletion copy — the TTL law's promise, visible. */
guideEndBody: string;
/** The maneuver list region label (list = labelled region of real text rows). */
ariaManeuverList: string;
/** The banner button label (one toggle: aria-expanded + aria-controls). */
ariaBannerToggle: string;
/** The guidance card's progress bar label. */
ariaTripProgress: string;
}
export type Locale = "en" | "ms";
@@ -106,6 +149,26 @@ export const strings: Record<Locale, ShellStrings> = {
ctaSearchAgain: "SEARCH AGAIN",
ariaRouteAlternatives: "Alternative routes",
ariaRouteChip: "Route {n}: {min} minutes, {km} kilometres",
guideRegister: "GUIDE",
guideStreetUnnamed: "Unnamed road",
guideReroutingLine: "Finding a new route from where you are.",
guideResumingLine: "Resuming from your last known progress.",
guideNoRerouteLine: "Rerouting unavailable on this server.",
guideNoRerouteBody: "No road graph here — follow the drawn route; recalculation is unavailable.",
ctaBannerList: "LIST",
ctaBannerClose: "CLOSE",
ctaEndTrip: "END TRIP",
guideConfirmHeadline: "Abandon route?",
guideConfirmBody: "Guidance stops and this trip's record is deleted. Nothing is stored.",
ctaConfirmAbandon: "YES, ABANDON",
ctaConfirmContinue: "CONTINUE",
guideEndHeadline: "Trip ended",
guideEndBody:
"Route guidance stopped and the trip record is deleted — nothing about this drive remains.",
ariaManeuverList: "Full maneuver list",
ariaBannerToggle: "Next maneuver",
ariaTripProgress: "Trip progress",
},
ms: {
bootValidatingRegister: "BOOT-01 // SESSION",
@@ -150,6 +213,26 @@ export const strings: Record<Locale, ShellStrings> = {
ctaSearchAgain: "CARI SEMULA",
ariaRouteAlternatives: "Laluan alternatif",
ariaRouteChip: "Laluan {n}: {min} minit, {km} kilometer",
guideRegister: "GUIDE",
guideStreetUnnamed: "Jalan tanpa nama",
guideReroutingLine: "Mencari laluan baharu dari kedudukan anda.",
guideResumingLine: "Sambung semula dari kemajuan terakhir anda.",
guideNoRerouteLine: "Pengiraan semula tiada pada pelayan ini.",
guideNoRerouteBody: "Tiada graf jalan di sini — ikut laluan yang dilukis; pengiraan semula tidak tersedia.",
ctaBannerList: "SENARAI",
ctaBannerClose: "TUTUP",
ctaEndTrip: "TAMAT PERJALANAN",
guideConfirmHeadline: "Tinggalkan laluan?",
guideConfirmBody: "Panduan berhenti dan rekod perjalanan ini dipadam. Tiada apa-apa disimpan.",
ctaConfirmAbandon: "YA, TINGGALKAN",
ctaConfirmContinue: "TERUSKAN",
guideEndHeadline: "Perjalanan tamat",
guideEndBody:
"Panduan laluan dihentikan dan rekod perjalanan dipadam — tiada apa-apa tentang pemanduan ini kekal.",
ariaManeuverList: "Senarai penuh manuver",
ariaBannerToggle: "Manuver seterusnya",
ariaTripProgress: "Kemajuan perjalanan",
},
};