feat(shell-ui): vendor Commissioner + Fraunces web fonts locally (offline/CSP)#268
Merged
Conversation
…line/CSP) The shipped UI still loaded web fonts from fonts.googleapis.com — the last external asset dependency (tailwind + lucide are already vendored). Vendor the fonts too so the webview never makes an external request: works fully offline and under a strict CSP, and preserves the no-telemetry posture. - Downloaded the variable-weight woff2 files Google's css2 endpoint serves for the exact axes the UI requested (Commissioner wght@200..900, Fraunces opsz,wght@9..144,300..900), latin + latin-ext subsets. - Dashboard: woff2 under shell/ui/dashboard/vendor/fonts/, @font-face in style.css, served verbatim (copied like the existing vendor/). Commissioner only — the Dashboard has no Fraunces display moment. - Settings: woff2 under shell/ui/settings/vendor/fonts/, @font-face in an inline <style> in index.html; build-ui.ts now copies the settings vendor/ dir into the bundle so the bare relative url()s resolve. Both Fraunces (display) + Commissioner (body). - Removed the fonts.googleapis.com <link rel="stylesheet"> from both index.html files. (No preconnect links existed.) woff2 files (variable, one per subset): commissioner-latin.woff2 36,696 B commissioner-latin-ext.woff2 30,840 B fraunces-latin.woff2 67,388 B fraunces-latin-ext.woff2 59,540 B Smoke: headless Chrome against the built UI (ui-harness) with fonts.googleapis.com / fonts.gstatic.com resolver-mapped to 0.0.0.0 (hard-blocked). Both pages render the correct self-hosted faces — Fraunces headings + Commissioner body on Settings, Commissioner on Dashboard. Artifacts under .github/pr-artifacts/.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
The shipped UI still loaded its web fonts from
fonts.googleapis.com— the last external asset dependency in the UI (Tailwind + Lucide are already vendored undershell/ui/dashboard/vendor/). This vendors the fonts too, so the webview never makes an external request: the app works fully offline and under a strict CSP, and it preserves the no-telemetry posture.How
css2endpoint serves for the exact axes the UI requested (Commissioner wght@200..900,Fraunces opsz,wght@9..144,300..900) using a modern browser UA. Captured the latin + latin-ext subsets so accented logins / model names render without falling back.shell/ui/dashboard/vendor/fonts/,@font-faceadded tostyle.css. Served verbatim (the dashboardvendor/dir is already copied wholesale by the build). Commissioner only — the Dashboard has no Fraunces display moment (native titlebar carries the page name).shell/ui/settings/vendor/fonts/,@font-facein an inline<style>inindex.html.scripts/build-ui.tsnow copies the settingsvendor/dir into the bundle output so the bare relativeurl()s resolve at/ui/settings/vendor/fonts/*(Bun's HTML bundler leaves bare relative url()s untouched). Fraunces (display) + Commissioner (body).fonts.googleapis.com<link rel="stylesheet">from bothindex.htmlfiles. There were nopreconnectlinks to remove.Content-Type: font/woff2(already mapped inweb-content-types.ts); production embed picks them up automatically (gen-ui-embed.tswalks the whole dist tree).woff2 files added (variable font, one per subset)
commissioner-latin.woff2commissioner-latin-ext.woff2fraunces-latin.woff2fraunces-latin-ext.woff2Commissioner is vendored under both surfaces (dashboard + settings) since the build serves them independently; Fraunces only under settings.
Smoke — CDN hard-blocked
Headless Chrome against the freshly-built UI (via
ui-harness, serving the realshell/dist), withfonts.googleapis.comandfonts.gstatic.comresolver-mapped to0.0.0.0(--host-resolver-rules). Both pages render the correct self-hosted faces — Fraunces headings + Commissioner body on Settings, Commissioner on Dashboard. Had the local woff2 failed to load, text would fall back to the generic Georgia / Segoe stack (visibly different). Level achieved: full offline / CDN-blocked render.(The Dashboard's "Usage request failed 404" banner is a ui-harness limitation — the mock backend doesn't serve the token-usage endpoint — not a font issue; the Period selector + banner text render in Commissioner.)
Settings (CDN blocked)
Dashboard (CDN blocked)
Checks
bun run build:uiclean; shelltsc --noEmitclean (Bun.build doesn't typecheck)bun run typecheckcleanbun run lintclean