YYayaw

Design Tokens

Runtime semantic token overrides for non-dashboard pages.

Overview

Yayaw supports runtime design token overrides without rebuilding the app.

Scope for this feature:

  • targets pages outside /dashboard/* and /auth/*
  • supports global overrides and organization-scoped overrides for public organization hosts
  • supports semantic colors (including chart colors), layout tokens (radius, spacing, tracking-normal), typography tokens (font-sans, font-serif, font-mono), and shadow tokens (shadow-*)

CMS Role

Design tokens are the public presentation layer for CMS-rendered pages and previews. They let operators adjust semantic color, radius, spacing, typography, tracking, and shadow values without editing page documents, section definitions, or component source.

Use tokens for theme-level visual decisions. Use page documents and sections for content structure, and keep dashboard/auth styling on their dedicated app-shell scope.

Data Model

The payload is versioned and stored as semantic token maps:

interface DesignTokensV1 {
  version: 1;
  light: Partial<Record<DesignToken, string>>;
  dark: Partial<Record<DesignToken, string>>;
}

Storage:

  • global scope: system_settings using key design-tokens.non-dashboard.v1
  • organization scope: organization_settings.designTokens

Runtime Resolution

Resolution pipeline:

  1. load the global token payload
  2. load the active organization token payload when the request resolves to an organization public host or organization-scoped preview
  3. merge organization values over global values for each light/dark token
  4. generate scoped CSS variables:
    • .scope-nondashboard:not(.dark) { ... }
    • .scope-nondashboard.dark { ... }

The scope class is applied only on pages outside dashboard/auth routes. Verified custom public hosts apply the owning organization's effective token payload after the global baseline, so one organization can theme its public pages without changing the canonical Yayaw site or another organization's host.

Dashboard routes intentionally keep their app-shell styling independent from public-site token overrides. If a future dashboard theming feature is needed, add a separate scope and storage key instead of reusing design-tokens.non-dashboard.v1.

Token Families

Token families include:

  • semantic colors such as background, foreground, primary, secondary, accent, muted, destructive, border, input, ring, card, popover, and chart colors
  • layout tokens such as radius and spacing
  • typography tokens such as sans, serif, and mono font stacks
  • tracking tokens such as tracking-normal
  • shadow tokens such as shadow-sm, shadow-md, and related depth values

Only declared Yayaw tokens are accepted. Unknown CSS variables from imported themes are ignored.

Editing Flow

Admin UI route:

  • /dashboard/content/design-tokens

Behavior:

  • immediate save (no draft/publish split)
  • token fields are initialized from repository baseline values in theme-vars.css
  • color tokens use a picker with HEX input
  • the brush icon on each color input copies the current HEX value with inline success feedback
  • layout tokens use a numeric input with selectable unit
  • typography tokens use a preset select with optional custom font stack input and are shared across light/dark
  • shadow tokens use direct text inputs
  • font tokens currently store CSS font-family stacks (for example Inter, sans-serif); font file upload and font catalog selection are not part of this UI yet
  • dark values can be left unset to inherit light first, then baseline dark (or baseline light when no dark baseline exists)
  • color values are canonicalized and stored in OKLCH format
  • import by URL is available directly in the editor (current provider support: TweakCN URLs like https://tweakcn.com/editor/theme?theme=neo-brutalism)
  • import by shadcn CLI command is available directly in the editor (for example bunx --bun shadcn@latest add @ss-themes/ghibli-studio or pnpm dlx shadcn@latest add https://shadcnthemer.com/r/themes/<id>.json; package-manager agnostic)
  • import by pasted CSS is available directly in the editor (:root { ... } and optional .dark { ... })
  • theme import uses a single "Import Theme" dropdown that opens a method-specific modal (URL, command, or CSS) with contextual guidance
  • importing fills the current scope editor state; you still explicitly save to publish

Theme Import Parsing

The parser is provider-based and currently includes one implementation:

  • tweakcn: accepts editor/theme URLs, resolves the slug, then fetches https://tweakcn.com/r/themes/{slug}.json
    • if the registry JSON endpoint fails for a valid theme page URL (for example https://tweakcn.com/themes/{id}), Yayaw falls back to parsing the server-rendered theme payload from the theme page
  • shadcn-registry: accepts a shadcn CLI add command (or direct @scope/item reference), resolves the registry alias, then fetches the registry JSON item endpoint
  • css: parses pasted CSS with :root and optional .dark variable blocks

Normalization rules:

  • only known Yayaw tokens are imported
  • color tokens are converted to canonical OKLCH
  • text/layout/typography/shadow tokens are validated with the same token value constraints as manual editing
  • unsupported or invalid token values are ignored

Runtime Consumers

Effective tokens are consumed by:

  • public generated pages
  • docs/public layout wrappers outside dashboard/auth
  • component catalog previews when validating token-aware recipes
  • generated section runtime previews

The component catalog applies effective runtime tokens to preview surfaces so authors can validate imported or local components against the current public theme.

Permissions

Editing requires:

  • global-variables:manage

Organization-scoped token saves also require the caller to operate inside the active organization context that owns the override.

Read access still allows opening the page in read-only mode.

Validation

Useful checks after design token changes:

bun test src/lib/server/services/design-tokens/design-tokens.test.ts
bun run check
bunx tsc --noEmit