Fonts: carry uploaded faces through export/import + embed in SVG export

This commit is contained in:
2026-06-16 23:52:16 +03:00
parent 2ed9db3792
commit d8a7bcb7c1
16 changed files with 810 additions and 90 deletions
+21
View File
@@ -100,6 +100,7 @@ Some preferences persist independently of _UserSettings_ so they can update freq
| Snippet store | All _Snippet_ records | Local, with a practical budget of about 5 MB. A storage monitor tracks usage and surfaces warnings as the budget fills (see _Snippet Library_). |
| Dataset store | All _Dataset_ records | Local, in a separate, much higher-capacity store, suited to larger payloads. |
| Theme store | All _CustomTheme_ records (G) | Local, separate store; records are small (a config object plus metadata). |
| Font store | All _FontAsset_ records (H) | Local, separate store; holds raw font-file bytes, so it is sized like the dataset tier (per-face cap ~10 MB). |
| Settings & preferences | _UserSettings_ plus the app/UI preferences in (D) | Local, small. |
Everything stays in the browser — no server or account is involved. All tiers survive reload and function offline. Because capacity is finite and per-browser, _Import & Export_ is the supported path for backup and for moving data between browsers or devices.
@@ -127,3 +128,23 @@ A **CustomTheme** is a user-named Vega-Lite config saved in the library and offe
| `modified` | ISO-timestamp string | When the theme was last changed. |
Selection is keyed by `id` (not name) so renaming a theme never invalidates the persisted `ui.chartTheme`. A persisted `custom:<id>` whose record no longer exists is not an error: charts render with the house style until the record appears (themes hydrate asynchronously), and deleting the actively-selected theme resets the selection to `astrolabe` explicitly. Custom themes travel in the _Import & Export_ envelope alongside snippets and datasets (spec §08).
## H. FontAsset
A **FontAsset** is a user-uploaded font face stored once and reused across themes and snippets. It is added and managed in the _Theme Builder → Type_ panel (see _Live Preview_), and referenced from a config's font slots by its `family` — exactly as a dataset is referenced by name. The raw bytes are registered as a live `FontFace` so a chart measures and renders the real face.
| Field | Type | Meaning |
| ---------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `id` | number | Unique numeric identifier (store key). |
| `version` | number | Schema version of this record, for read-time migration (see _Schema versioning_ above). |
| `family` | string | Unique CSS family name — the key configs reference (case-insensitive uniqueness, like datasets/themes). |
| `data` | bytes | The raw font-file bytes (registered as a `FontFace`). In an export envelope these are **base64-encoded** (spec §08). |
| `format` | `woff2`/`woff`/`ttf`/`otf` | Container format, from the file extension. |
| `fileName` | string | Original file name, kept for display and provenance. |
| `source` | `file`/`google` | Provenance. Only `file` (an upload) ships today; `google` is reserved for a later keyless-catalog tier. |
| `axes` | array, optional | Variation axes for a variable font (parsed from `fvar`); drives the `FontFace` weight/width ranges. Absent for a static face. |
| `size` | number | Byte length of `data`. |
| `created` | ISO-timestamp string | When the font was first added. |
| `modified` | ISO-timestamp string | When the font was last changed (e.g. renamed). |
A font is identified by its `family`. No theme or snippet stores a font field: the faces a config uses are derived by scanning its font slots (the config is the source of truth), so a snippet can use a font with no theme to carry it. Fonts travel in the _Import & Export_ envelope alongside snippets, datasets, and themes; on import a family clash **skips** the incoming face rather than renaming it (spec §08 → Name conflicts).