From 0ae53fa9c26f5187bd304d1844ed98741fd0b2f6 Mon Sep 17 00:00:00 2001 From: DavidBabinec Date: Tue, 13 Oct 2026 16:25:54 +0200 Subject: [PATCH 1/4] feat(fonts): seed heading, body and mono font role tokens on new sites New sites had no font tokens and the codebase disagreed on names (docs said font-primary, the AI prompt said font-heading), so content made for one site did not resolve in another. Every brand-new site now starts with fallback-only font-heading, font-body and font-mono tokens, the Core preset adds any a site lacks without touching existing ones, and docs, schema comments and the AI prompt use the role names. Existing sites are not migrated. --- docs/editor.md | 2 +- docs/features/agent.md | 2 +- docs/features/publisher.md | 2 +- docs/features/site-import.md | 2 +- docs/features/site-shell.md | 17 +- server/ai/tools/site/systemPrompt.ts | 7 +- server/ai/tools/site/writeTools.ts | 2 +- server/handlers/cms/setup.ts | 6 +- server/repositories/setup.ts | 17 ++ server/repositories/site.ts | 2 +- src/__tests__/agent/tokenDigest.test.ts | 13 ++ src/__tests__/agent/tokenTools.test.ts | 32 +++- src/__tests__/fonts/fontRoleTokens.test.ts | 146 ++++++++++++++++++ src/__tests__/server/setupFontRoles.test.ts | 44 ++++++ .../dashboard/components/OnboardingPanel.tsx | 4 +- .../FontsSection/FontTokenDialog.tsx | 7 +- .../FontsSection/FontsSection.tsx | 6 +- .../pages/site/store/slices/site/defaults.ts | 4 +- .../store/slices/site/framework/manage.ts | 10 +- .../FrameworkManagerDialog.tsx | 12 +- src/core/fonts/css.ts | 2 +- src/core/fonts/describe.ts | 6 +- src/core/fonts/index.ts | 1 + src/core/fonts/roles.ts | 84 ++++++++++ src/core/fonts/schemas.ts | 6 +- src/core/framework/manageFramework.ts | 42 +++-- src/core/page-tree/index.ts | 2 +- src/core/page-tree/siteSettings.ts | 21 ++- src/core/siteImport/types.ts | 6 +- 29 files changed, 452 insertions(+), 55 deletions(-) create mode 100644 src/__tests__/fonts/fontRoleTokens.test.ts create mode 100644 src/__tests__/server/setupFontRoles.test.ts create mode 100644 src/core/fonts/roles.ts diff --git a/docs/editor.md b/docs/editor.md index 8ed3fdb9b..69a8b69f8 100644 --- a/docs/editor.md +++ b/docs/editor.md @@ -564,7 +564,7 @@ Property controls are driven by the selected node's module schema (`src/core/mod At the top of the Properties Panel, the selector picker is the single entry point for CSS rules that affect the selected element. Assigned class rules render as removable `TagPill` chips and are stored on `node.classIds`; matching ambient rules render as non-removable `TagPill` chips because they apply by selector matching, not assignment. Ambient rules that match only through a universal subject (`*`, `body.x *`, `*::before`) never render as pills — they style every element in their scope and stay reachable through the dropdown and the Selectors panel instead. The dropdown searches both class rules and ambient selectors, is capped to the picker width budget, and ellipsizes long selector labels instead of expanding across the editor. Ambient rows that do not match the selected canvas element stay visible but disabled with the mismatch reason, and selector-shaped input such as `.hero .title`, `h1`, or `a:hover` creates an ambient rule instead of a class. -The Framework panel's **Type** tab stores Google/custom font assets and editable font tokens together under `site.settings.fonts`. Installed font assets own the self-hosted `@font-face` files; font tokens own the builder-facing variables such as `--font-primary`, the assigned font asset, and the fallback stack. The property-panel `font-family` control is a rich picker: token rows write `var(--font-primary)` so the selected node or class keeps following future token swaps, direct font rows write a concrete family stack as an escape hatch, and the text input still accepts manual values. +The Framework panel's **Type** tab stores Google/custom font assets and editable font tokens together under `site.settings.fonts`. Installed font assets own the self-hosted `@font-face` files; font tokens own the builder-facing variables such as `--font-heading`, the assigned font asset, and the fallback stack. New sites start with the three role tokens `--font-heading`, `--font-body` and `--font-mono` as system-font fallbacks, and the "Manage framework" dialog adds any of them a site lacks (see [site-shell.md](features/site-shell.md) → font role tokens); the new-token dialog pre-fills the first missing role name. The property-panel `font-family` control is a rich picker: token rows write `var(--font-heading)` so the selected node or class keeps following future token swaps, direct font rows write a concrete family stack as an escape hatch, and the text input still accepts manual values. When the user clicks a rule in the Selectors Panel, the Properties Panel switches to **selector-editing mode** — the body shows style controls for that rule directly, and the header renders `SelectorHeader` with the rule's CSS selector, an inline rename input, and a delete button. The delete and rename actions are only shown for non-generated rules and require `site.style.edit`. diff --git a/docs/features/agent.md b/docs/features/agent.md index 699dc72a5..012768c08 100644 --- a/docs/features/agent.md +++ b/docs/features/agent.md @@ -577,7 +577,7 @@ Drivers that support explicit prompt-cache controls (Anthropic) apply `cache_con `SYSTEM_PROMPT_DYNAMIC_BOUNDARY` is the literal `'__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__'`, declared **once** in `server/ai/runtime/types.ts` and imported everywhere — prompt builders and every driver. A duplicate definition would silently break prompt caching on whichever driver drifted. Gated by `ai-driver-shared-helpers.test.ts`. **Static prefix key rules** (full text lives in `server/ai/tools/site/systemPrompt.ts`): -- **Design system first.** Establish or reuse tokens before/while building (`site_set_color_tokens`, `site_set_type_scale`, `site_set_spacing_scale`, `site_set_font_tokens`), then reference them in CSS (`var(--)`, `var(--text-l)`, `var(--space-m)`, `var(--)`) instead of raw hex/px/font-family. The dynamic suffix's `Tokens —` line shows what already exists; `(none …)` means no design system yet. +- **Design system first.** Establish or reuse tokens before/while building (`site_set_color_tokens`, `site_set_type_scale`, `site_set_spacing_scale`, `site_set_font_tokens`), then reference them in CSS (`var(--)`, `var(--text-l)`, `var(--space-m)`, `var(--font-heading)`) instead of raw hex/px/font-family. Fonts use the role tokens `font-heading`, `font-body` and `font-mono`, which new sites already have; the prompt tells the model to change a typeface by updating the role token rather than inventing a new font variable. The dynamic suffix's `Tokens —` line shows what already exists; `(none …)` means no design system yet. - Structure as HTML (`site_insert_html` / `site_replace_node_html`); style with CSS in the same payload — a `