Phase 2: React scaffolding, self-hosted fonts, design tokens

Vite builds to dist/, deliberately not www/. www/ is still produced by
sync-www.sh for the Phase 1 APK, which stays installable throughout the
port; cutover is a one-line webDir change in capacitor.config.json.
base is relative because Capacitor serves the bundle from the APK, where
absolute asset paths would 404.

index.html omits viewport-fit=cover on purpose. That string is what
makes Capacitor's SystemBars plugin pass insets through to the page;
without it the plugin pads the decor view and the layout is always
between the status and gesture bars. Phase 1 learned this the hard way.

Fonts are self-hosted for offline use, latin subsets only: three files
at 68K, against the 133K Barlow costs today. Space Grotesk is variable,
so one file covers 400-700. Dropped latin-ext and vietnamese.

Carets are drawn as SVG, not typed. U+25BE and U+23EE sit outside every
Latin subset and would fall back to a system font mid-label.

base.css carries the settled palette and the measured vertical budget as
tokens, so a component cannot quietly exceed it:
  8 + 44 + 8 + 525 + 8 + 84 + 8 + 50 = 735

Verified: typecheck clean, 103 tests, vite build emits with the fonts
copied, and www/ is untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-17 01:05:09 +03:00
parent ad847faa2e
commit 956dc57763
13 changed files with 369 additions and 5 deletions

View File

@@ -18,7 +18,10 @@
"test": "vitest run",
"test:watch": "vitest",
"typecheck": "tsc --noEmit",
"extract:data": "node scripts/extract-reference-data.mjs"
"extract:data": "node scripts/extract-reference-data.mjs",
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@capacitor/android": "^8.5.2",