From 85adcdfe54daba804fb6873da649f6ec5c095dde Mon Sep 17 00:00:00 2001 From: Joe Blau Date: Sat, 3 Oct 2026 09:20:52 -0700 Subject: [PATCH] fix(docs): finish the Bloxwap font migration in the embedded chart demo 86010a7 stripped the playground's Geist @font-face rules from the docs copy but left the SDK chrome (--cts-font / --cts-mono in TOOLBAR_CSS) asking for Geist, so the header, rails, menus and dialogs fell back to system-ui, and only theme.fontFamily was overridden, so the bloxwapDark preset kept the canvas status line, drawing labels and scales on system-ui. - Point .cts-theme --cts-font / --cts-mono at Bloxwap Sans / Mono (doubled class so it outranks the runtime-injected TOOLBAR_CSS). - Override monoFamily and scaleFontFamily with Bloxwap Mono alongside fontFamily, and fail the script if any Geist reference survives. - Stop copying the now-unreferenced Geist woff2 files into chart-demo and require the Bloxwap Mono face in check-export instead. - Copy only the Latin BloxwapSans/BloxwapMono faces with a trimmed stylesheet (13 MB -> 1.3 MB of demo font payload per deploy). - Describe the demo font handling accurately in apps/docs/README.md. Co-Authored-By: Claude Opus 5.5 --- apps/docs/README.md | 13 ++++++---- apps/docs/scripts/check-export.mjs | 2 +- apps/docs/scripts/prepare-demo.mjs | 38 ++++++++++++++++++++++-------- 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/apps/docs/README.md b/apps/docs/README.md index beb821f..6c98b1b 100644 --- a/apps/docs/README.md +++ b/apps/docs/README.md @@ -70,8 +70,8 @@ For a `/chart` build, preview the homepage image at The `predev` and `prebuild` scripts compile the library and run `scripts/prepare-demo.mjs`. It copies `apps/playground/index.html`, -`packages/chart/dist/`, and `packages/chart/assets/fonts/` from the repository -into the ignored `public/chart-demo/` directory. Both the homepage and the +`packages/chart/dist/`, and the Latin Bloxwap Sans/Mono faces from +`@bloxwap/font` into the ignored `public/chart-demo/` directory. Both the homepage and the playground guide embed this same demo; edit the original instead of making a separate docs implementation. Restart `docs:dev` after changing the demo or library to refresh the copied assets. The export checker validates the iframe @@ -88,7 +88,10 @@ documents building and installing its local tarball; update that note and the homepage's release badge after the first public release. The exact `@bloxwap/font@0.1.1` dependency supplies self-hosted Sans/Mono Next.js -loaders. The embedded playground copies the package stylesheet and fonts and -explicitly sets `theme.fontFamily` to Bloxwap Sans before drawing its canvas; -the standalone playground and SDK presets retain their existing font defaults. +loaders. The embedded playground copies a stylesheet trimmed to the Latin Sans +and Mono faces, replaces the playground's Geist faces with them, points the SDK +chrome's `--cts-font`/`--cts-mono` at Bloxwap Sans/Mono, and sets the canvas +`theme.fontFamily` to Bloxwap Sans and `monoFamily`/`scaleFontFamily` (status +line, drawing labels and scales) to Bloxwap Mono. The standalone playground and +SDK presets retain their existing font defaults. Static social-image font provenance is recorded in `fonts/README.md`. diff --git a/apps/docs/scripts/check-export.mjs b/apps/docs/scripts/check-export.mjs index cf64673..c35cab0 100644 --- a/apps/docs/scripts/check-export.mjs +++ b/apps/docs/scripts/check-export.mjs @@ -16,7 +16,7 @@ for (const required of [ 'index.html', '404.html', 'docs/index.html', 'developers/index.html', 'search.json', 'icon.svg', 'llms.txt', 'robots.txt', 'openapi.json', '404.md', 'chart-demo/demo/index.html', 'chart-demo/dist/index.js', 'chart-demo/dist/ui/index.js', 'chart-demo/dist/datafeed/index.js', - 'chart-demo/assets/bloxwap-font/fonts/BloxwapSans/BloxwapSans-Variable.woff2', 'chart-demo/assets/bloxwap-font/bloxwap-font.css', 'chart-demo/assets/fonts/Geist-Regular.woff2', 'chart-demo/assets/fonts/GeistMono-Regular.woff2', + 'chart-demo/assets/bloxwap-font/fonts/BloxwapSans/BloxwapSans-Variable.woff2', 'chart-demo/assets/bloxwap-font/fonts/BloxwapMono/BloxwapMono-Variable.woff2', 'chart-demo/assets/bloxwap-font/bloxwap-font.css', ]) { if (!await exists(join(root, required))) failures.push(`Missing ${required}`); } diff --git a/apps/docs/scripts/prepare-demo.mjs b/apps/docs/scripts/prepare-demo.mjs index d8a1415..7091ddb 100644 --- a/apps/docs/scripts/prepare-demo.mjs +++ b/apps/docs/scripts/prepare-demo.mjs @@ -3,29 +3,47 @@ import { cp, mkdir, rm, readFile, writeFile } from 'node:fs/promises'; const repository = new URL('../../../', import.meta.url); const output = new URL('../public/chart-demo/', import.meta.url); -// Preserve the demo's relative imports and fonts. There is only one playground +// Preserve the demo's relative imports. There is only one playground // implementation: the same HTML served by `npm run demo` is published with docs. +// Its Geist assets are not copied: the docs copy below swaps every Geist +// reference for Bloxwap Sans/Mono. await rm(output, { recursive: true, force: true }); await mkdir(new URL('demo/', output), { recursive: true }); await Promise.all([ cp(new URL('apps/playground/index.html', repository), new URL('demo/index.html', output)), cp(new URL('packages/chart/dist/', repository), new URL('dist/', output), { recursive: true }), - cp(new URL('packages/chart/assets/fonts/', repository), new URL('assets/fonts/', output), { recursive: true }), ]); -console.log('Prepared the complete chart demo for the documentation site.'); -// The embedded documentation example explicitly overrides the canvas preset's -// family; an iframe cannot inherit the parent's Next.js font variables. +// An iframe cannot inherit the parent's Next.js font variables, so the demo +// ships its own copy of the Latin Bloxwap Sans/Mono faces. The package's other +// script companions (CJK, Arabic, ...) are left out; the demo never shows them. const fontPackage = new URL('../../../node_modules/@bloxwap/font/', import.meta.url); -await cp(new URL('fonts/', fontPackage), new URL('assets/bloxwap-font/fonts/', output), { recursive: true }); -await cp(new URL('bloxwap-font.css', fontPackage), new URL('assets/bloxwap-font/bloxwap-font.css', output)); -await cp(new URL('LICENSE', fontPackage), new URL('assets/bloxwap-font/LICENSE', output)); +const fontOutput = new URL('assets/bloxwap-font/', output); +const families = ['BloxwapSans', 'BloxwapMono']; +await Promise.all([ + ...families.map((family) => cp(new URL(`fonts/${family}/`, fontPackage), new URL(`fonts/${family}/`, fontOutput), { recursive: true })), + cp(new URL('LICENSE', fontPackage), new URL('LICENSE', fontOutput)), +]); +const packageCss = await readFile(new URL('bloxwap-font.css', fontPackage), 'utf8'); +const license = packageCss.split('\n').find((line) => line.includes('Open Font License')); +const faces = packageCss.match(/@font-face \{[^}]+\}/g) + .filter((face) => families.some((family) => face.includes(`./fonts/${family}/`))); +if (faces.length !== 4) throw new Error(`Expected 4 Latin Bloxwap Sans/Mono faces, found ${faces.length}.`); +await writeFile(new URL('bloxwap-font.css', fontOutput), `/*\n * Latin Bloxwap Sans and Mono, trimmed from @bloxwap/font/bloxwap-font.css by apps/docs/scripts/prepare-demo.mjs.\n${license}\n */\n${faces.join('\n')}\n`); + +const SANS = '"Bloxwap Sans", system-ui, sans-serif'; +const MONO = '"Bloxwap Mono", ui-monospace, monospace'; const demo = new URL('demo/index.html', output); const html = (await readFile(demo, 'utf8')) - .replace('