export type ThemeId = | "zai-light" | "zai-dark" | "chatgpt-dark" | "zai-sky" | "zai-violet" | "zai-emerald" | "zai-rose" | "absolutely-dark" | "raycast-dark" | "midnight" | "slate" | "graphite" | "espresso" | "forest" | "nordic-light" | "solarized-dark" | "paper"; export type FontFamilyId = "openai" | "geist" | "system" | "avenir" | "serif" | "mono" | "rounded"; export interface ThemeTokens { bg: string; fg: string; dim: string; border: string; surface: string; accent: string; hl1: string; hl2: string; hl3: string; err: string; } export interface ThemeMeta { id: ThemeId; name: string; description: string; group: string; swatches: [string, string, string, string]; tokens: ThemeTokens; fontFamilyId: FontFamilyId; ui?: Partial; } export interface ThemeUiTokens { "surface-2": string; "surface-3": string; rail: string; border: string; separator: string; hover: string; active: string; composer: string; "composer-footer": string; bubble: string; } const THEME_FONT_FAMILY_BY_ID: Partial> = { "chatgpt-dark": "openai", "absolutely-dark": "system", "raycast-dark": "system", midnight: "avenir", slate: "system", espresso: "serif", forest: "rounded", "nordic-light": "avenir", "solarized-dark": "system", paper: "serif", }; const createTheme = ( id: ThemeId, name: string, description: string, group: string, tokens: ThemeTokens, ): ThemeMeta => ({ id, name, description, group, swatches: [tokens.bg, tokens.surface, tokens.accent, tokens.fg], tokens, fontFamilyId: THEME_FONT_FAMILY_BY_ID[id] ?? "geist", }); // Canonical surfaces, expressed as concrete values (the bootstrap script // writes them inline before paint). These mirror the `.theme-zai-*` blocks in // tokens.css exactly. const ZAI_LIGHT: ThemeTokens = { bg: "#ffffff", fg: "#1a1c1f", dim: "#5f6165", border: "#1a1c1f14", surface: "#ffffff", accent: "#0d0d0d", hl1: "#5f6165", hl2: "#8c8e91", hl3: "#8f8f8f", err: "#e02e2a", }; const ZAI_DARK: ThemeTokens = { bg: "#181818", fg: "#ffffff", dim: "#ffffffb3", border: "#ffffff14", surface: "#212121", accent: "#ffffff", hl1: "#ffffffb3", hl2: "#ffffff80", hl3: "#8f8f8f", err: "#ff6764", }; const CHATGPT_DARK: ThemeTokens = { bg: "#191919", fg: "#d9d9d8", dim: "#a0a09f", border: "#ffffff0d", surface: "#202020", accent: "#d9d9d8", hl1: "#a0a09f", hl2: "#7b7b7b", hl3: "#626262", err: "#ff6764", }; const CHATGPT_DARK_UI: Partial = { "surface-2": "#202020", "surface-3": "#282828", rail: "#212121", border: "#ffffff0d", separator: "#ffffff08", hover: "#282828", active: "#2e2e2e", composer: "#282828", "composer-footer": "#282828", bubble: "#232323", }; // Accent variants keep the canonical dark surfaces; only the brand // accent + hl1 (the data/links color) shift. const skyAccent = (base: ThemeTokens): ThemeTokens => ({ ...base, accent: "#339cff", }); const violetAccent = (base: ThemeTokens): ThemeTokens => ({ ...base, accent: "#ad7bf9", }); const emeraldAccent = (base: ThemeTokens): ThemeTokens => ({ ...base, accent: "#40c977", }); const roseAccent = (base: ThemeTokens): ThemeTokens => ({ ...base, accent: "#ff6764", }); // Derive the supporting tokens from a bg/fg/surface/accent quartet so new // themes stay consistent with the workbench ratios. const darkTheme = (bg: string, fg: string, surface: string, accent: string): ThemeTokens => ({ bg, fg, dim: `${fg}b3`, border: `${fg}14`, surface, accent, hl1: `${fg}b3`, hl2: `${fg}80`, hl3: "#8f8f8f", err: "#ff6764", }); const lightTheme = (bg: string, fg: string, surface: string, accent: string): ThemeTokens => ({ bg, fg, dim: `${fg}b3`, border: `${fg}1f`, surface, accent, hl1: `${fg}b3`, hl2: `${fg}80`, hl3: "#8f8f8f", err: "#e02e2a", }); export const THEMES: ThemeMeta[] = [ createTheme( "zai-dark", "Studio Dark", "Unified charcoal canvas, hairline borders, one blue accent", "Studio", ZAI_DARK, ), createTheme( "zai-light", "Studio Light", "Pure white canvas, near-black brand, one blue accent", "Studio", ZAI_LIGHT, ), { ...createTheme( "chatgpt-dark", "ChatGPT Dark", "ChatGPT app charcoal surfaces paired with OpenAI Sans", "Reference", CHATGPT_DARK, ), ui: CHATGPT_DARK_UI, }, createTheme( "zai-sky", "Sky", "Dark with a sky-blue brand accent", "Accents", skyAccent(ZAI_DARK), ), createTheme( "zai-violet", "Violet", "Dark with a violet brand accent", "Accents", violetAccent(ZAI_DARK), ), createTheme( "zai-emerald", "Emerald", "Dark with an emerald brand accent", "Accents", emeraldAccent(ZAI_DARK), ), createTheme("zai-rose", "Rose", "Dark with a rose brand accent", "Accents", roseAccent(ZAI_DARK)), createTheme( "absolutely-dark", "Absolutely Dark", "Warm charcoal with a terracotta accent, ported from Codex", "Ported", darkTheme("#2d2d2b", "#f9f9f7", "#373735", "#cc7d5e"), ), createTheme( "raycast-dark", "Raycast Dark", "Near-black launcher tones with an electric blue accent", "Ported", darkTheme("#141414", "#ffffff", "#1e1e1e", "#4fa3f8"), ), createTheme( "midnight", "Midnight", "Blue-black canvas with a soft azure accent", "Atmosphere", darkTheme("#0d1117", "#e6edf3", "#161b22", "#58a6ff"), ), createTheme( "slate", "Slate", "Cool graphite blues with a periwinkle accent", "Atmosphere", darkTheme("#12151a", "#e2e8f0", "#1a1f27", "#7aa2f7"), ), createTheme( "graphite", "Graphite", "Ultra-dark neutral with a pure white accent", "Atmosphere", darkTheme("#0d0d0d", "#ededed", "#171717", "#ffffff"), ), createTheme( "espresso", "Espresso", "Roasted browns with a caramel accent", "Atmosphere", darkTheme("#1a1512", "#f2e9df", "#241d18", "#d9954a"), ), createTheme( "forest", "Forest", "Deep evergreen with a spring-green accent", "Atmosphere", darkTheme("#0f1512", "#e8f2ec", "#18211b", "#4fd08a"), ), createTheme( "nordic-light", "Nordic Light", "Cool daylight neutrals with crisp indigo controls", "Studio", lightTheme("#f4f6f8", "#20242a", "#ffffff", "#5e6ad2"), ), createTheme( "solarized-dark", "Solarized Dark", "Low-contrast blue-green surfaces with a cyan accent", "Reference", darkTheme("#002b36", "#eee8d5", "#073642", "#2aa198"), ), createTheme( "paper", "Paper", "Warm paper white with a burnt-sienna accent", "Studio", lightTheme("#faf8f2", "#2a2723", "#ffffff", "#b05f2d"), ), ];