import type { SurfaceState } from "./layoutTypes"; /** Design tokens — mirror of DOCS/space-sh.pen variables. Single source for the UI. */ export const COLORS = { accent: "var(--c-accent)", bgApp: "var(--c-bg-app)", bgElevated: "var(--c-bg-elevated)", bgHover: "var(--c-bg-hover)", bgPanel: "var(--c-bg-panel)", bgSidebar: "var(--c-bg-sidebar)", borderStrong: "var(--c-border-strong)", borderSubtle: "var(--c-border-subtle)", textPrimary: "var(--c-text-primary)", textSecondary: "var(--c-text-secondary)", textMuted: "var(--c-text-muted)", stWork: "var(--c-st-work)", stWait: "var(--c-st-wait)", stDone: "var(--c-st-done)", stError: "var(--c-st-error)", stIdle: "var(--c-st-idle)", searchMatch: "var(--c-search-match)", } as const; export const FONT = { ui: "Inter, system-ui, sans-serif", mono: "'JetBrains Mono Variable', 'JetBrains Mono', monospace", } as const; /** Status color by surface state, plus the stopped pseudo-state. */ export const STATE_COLOR: Record = { work: COLORS.stWork, wait: COLORS.stWait, done: COLORS.stDone, error: COLORS.stError, idle: COLORS.stIdle, stopped: COLORS.stIdle, }; // --------------------------------------------------------------------------- // Palettes // --------------------------------------------------------------------------- type Palette = Record; /** Dark palette — hex values identical to what COLORS contained before. */ const DARK: Palette = { "bg-app": "#0E1116", "bg-elevated": "#1A2029", "bg-hover": "#222A35", "bg-panel": "#0A0D12", "bg-sidebar": "#13171F", "border-strong": "#323C49", "border-subtle": "#232A33", "text-primary": "#E6EDF3", "text-secondary": "#8B97A6", "text-muted": "#5A6573", "st-work": "#4C8DFF", "st-wait": "#F2B84B", "st-done": "#3FB950", "st-error": "#F4544E", "st-idle": "#5A6573", "search-match": "#5A4A1F", }; /** Light palette — a readable counterpart for every token. */ const LIGHT: Palette = { "bg-app": "#F5F7FA", "bg-elevated": "#FFFFFF", "bg-hover": "#E8EDF3", "bg-panel": "#EBEEF3", "bg-sidebar": "#DDE3EC", "border-strong": "#B0BAC7", "border-subtle": "#CDD4DE", "text-primary": "#0D1117", "text-secondary": "#4A5568", "text-muted": "#8898AA", "st-work": "#2266CC", "st-wait": "#C07800", "st-done": "#1A7A30", "st-error": "#C4231F", "st-idle": "#8898AA", "search-match": "#FDE68A", }; export const ACCENTS: Record = { blue: "#4C8DFF", teal: "#34D3C2", purple: "#9B7BFF", green: "#3FB950", orange: "#F2934B", }; export type ThemeName = "dark" | "light"; /** Real color values for consumers that can't use var() (xterm). Keys are the kebab tokens plus "accent". */ export function resolvePalette(theme: ThemeName, accent: string): Record { const base = theme === "light" ? LIGHT : DARK; return { ...base, accent: ACCENTS[accent] ?? ACCENTS.blue }; } /** Write the active palette to :root as --c-* custom properties. */ export function applyTheme(theme: ThemeName, accent: string): void { const p = resolvePalette(theme, accent); const root = document.documentElement.style; for (const [k, v] of Object.entries(p)) root.setProperty(`--c-${k}`, v); }