SUSupaUI

Theming

One-token rethemes.

SupaUI separates colour, type, and depth into three layers. Components only ever read the top two — primitives stay untouched so consumers can re-skin without rewriting CSS.

The three layers

  1. Primitives. Raw axes: --supa-color-blue-500, --supa-size-md, --supa-leading-snug. Components never read these directly.
  2. Semantic roles. --supa-color-accent, --supa-color-paper, --supa-color-rule. This is what every component actually consumes.
  3. shadcn aliases. --background, --foreground, --primary. Mapped onto our semantic roles, so shadcn-style utilities (bg-background) keep working out of the box.

Re-skin in three lines

Override the role layer on .supa-root (or :root) and every component that reads accent flips.

css
.supa-root {
  --supa-color-accent:        var(--supa-color-purple-500);
  --supa-color-accent-strong: var(--supa-color-purple-600);
  --supa-color-accent-ink:    white;
}

Dark mode

Toggle data-theme="dark" or the .dark class anywhere in the tree. We rebind the role layer only — palette ramps stay shared.

tsx
<html className={isDark ? "dark" : undefined}>...

Type voices

Three font roles + one pixel face. Wired to next/font + a self-hosted Departure Mono.

  • --supa-font-display → Gloock — landing headlines, hero pages.
  • --supa-font-serif → Source Serif 4 — long-form prose.
  • --supa-font-sans → Inter — body, UI text, forms.
  • --supa-font-pixel → Departure Mono — buttons, badges, pixel labels, code.