export interface ThemeColors { background: string foreground: string card: string cardForeground: string popover: string popoverForeground: string primary: string primaryForeground: string secondary: string secondaryForeground: string muted: string mutedForeground: string accent: string accentForeground: string destructive: string destructiveForeground: string border: string input: string ring: string sidebar: string sidebarForeground: string sidebarPrimary: string sidebarPrimaryForeground: string sidebarAccent: string sidebarAccentForeground: string sidebarBorder: string } export interface ThemePreset { name: string label: string light: ThemeColors dark: ThemeColors } export const themes: ThemePreset[] = [ { name: 'slate', label: 'Slate', light: { background: '210 20% 97%', foreground: '222 47% 11%', card: '0 0% 100%', cardForeground: '222 47% 11%', popover: '0 0% 100%', popoverForeground: '222 47% 11%', primary: '215 25% 27%', primaryForeground: '210 40% 98%', secondary: '210 40% 94%', secondaryForeground: '222 47% 11%', muted: '210 40% 94%', mutedForeground: '215 16% 47%', accent: '210 40% 94%', accentForeground: '222 47% 11%', destructive: '0 72% 51%', destructiveForeground: '210 40% 98%', border: '214 32% 89%', input: '214 32% 89%', ring: '215 25% 27%', sidebar: '210 25% 95%', sidebarForeground: '215 16% 47%', sidebarPrimary: '215 25% 27%', sidebarPrimaryForeground: '210 40% 98%', sidebarAccent: '210 40% 92%', sidebarAccentForeground: '222 47% 11%', sidebarBorder: '214 32% 89%', }, dark: { background: '222 30% 8%', foreground: '210 20% 86%', card: '222 30% 10%', cardForeground: '210 20% 86%', popover: '222 30% 10%', popoverForeground: '210 20% 86%', primary: '215 20% 72%', primaryForeground: '222 30% 8%', secondary: '217 20% 15%', secondaryForeground: '210 20% 86%', muted: '217 20% 15%', mutedForeground: '215 15% 55%', accent: '217 20% 15%', accentForeground: '210 20% 86%', destructive: '0 55% 48%', destructiveForeground: '210 20% 92%', border: '217 20% 17%', input: '217 20% 17%', ring: '215 20% 55%', sidebar: '222 30% 7%', sidebarForeground: '215 15% 65%', sidebarPrimary: '215 20% 72%', sidebarPrimaryForeground: '0 0% 100%', sidebarAccent: '217 20% 13%', sidebarAccentForeground: '210 20% 86%', sidebarBorder: '217 20% 15%', }, }, { name: 'emerald', label: 'Emerald', light: { background: '150 20% 97%', foreground: '150 40% 10%', card: '0 0% 100%', cardForeground: '150 40% 10%', popover: '0 0% 100%', popoverForeground: '150 40% 10%', primary: '160 84% 29%', primaryForeground: '150 20% 98%', secondary: '150 20% 93%', secondaryForeground: '150 40% 10%', muted: '150 20% 93%', mutedForeground: '150 10% 45%', accent: '150 20% 93%', accentForeground: '150 40% 10%', destructive: '0 72% 51%', destructiveForeground: '150 20% 98%', border: '150 15% 88%', input: '150 15% 88%', ring: '160 84% 29%', sidebar: '150 20% 95%', sidebarForeground: '150 10% 45%', sidebarPrimary: '160 84% 29%', sidebarPrimaryForeground: '150 20% 98%', sidebarAccent: '150 20% 91%', sidebarAccentForeground: '150 40% 10%', sidebarBorder: '150 15% 88%', }, dark: { background: '155 30% 7%', foreground: '150 15% 85%', card: '155 30% 9%', cardForeground: '150 15% 85%', popover: '155 30% 9%', popoverForeground: '150 15% 85%', primary: '160 72% 42%', primaryForeground: '155 30% 7%', secondary: '155 20% 14%', secondaryForeground: '150 15% 85%', muted: '155 20% 14%', mutedForeground: '150 10% 52%', accent: '155 20% 14%', accentForeground: '150 15% 85%', destructive: '0 55% 48%', destructiveForeground: '150 15% 92%', border: '155 20% 16%', input: '155 20% 16%', ring: '160 72% 42%', sidebar: '155 30% 6%', sidebarForeground: '150 10% 62%', sidebarPrimary: '160 72% 42%', sidebarPrimaryForeground: '0 0% 100%', sidebarAccent: '155 20% 12%', sidebarAccentForeground: '150 15% 85%', sidebarBorder: '155 20% 14%', }, }, { name: 'violet', label: 'Violet', light: { background: '260 15% 97%', foreground: '260 40% 11%', card: '0 0% 100%', cardForeground: '260 40% 11%', popover: '0 0% 100%', popoverForeground: '260 40% 11%', primary: '262 83% 58%', primaryForeground: '260 15% 98%', secondary: '260 20% 94%', secondaryForeground: '260 40% 11%', muted: '260 20% 94%', mutedForeground: '260 10% 47%', accent: '260 20% 94%', accentForeground: '260 40% 11%', destructive: '0 72% 51%', destructiveForeground: '260 15% 98%', border: '260 15% 89%', input: '260 15% 89%', ring: '262 83% 58%', sidebar: '260 18% 95%', sidebarForeground: '260 10% 47%', sidebarPrimary: '262 83% 58%', sidebarPrimaryForeground: '260 15% 98%', sidebarAccent: '260 20% 92%', sidebarAccentForeground: '260 40% 11%', sidebarBorder: '260 15% 89%', }, dark: { background: '260 30% 8%', foreground: '260 15% 86%', card: '260 30% 10%', cardForeground: '260 15% 86%', popover: '260 30% 10%', popoverForeground: '260 15% 86%', primary: '262 83% 65%', primaryForeground: '260 30% 8%', secondary: '260 20% 15%', secondaryForeground: '260 15% 86%', muted: '260 20% 15%', mutedForeground: '260 10% 54%', accent: '260 20% 15%', accentForeground: '260 15% 86%', destructive: '0 55% 48%', destructiveForeground: '260 15% 92%', border: '260 20% 17%', input: '260 20% 17%', ring: '262 83% 65%', sidebar: '260 30% 7%', sidebarForeground: '260 10% 64%', sidebarPrimary: '262 83% 65%', sidebarPrimaryForeground: '0 0% 100%', sidebarAccent: '260 20% 13%', sidebarAccentForeground: '260 15% 86%', sidebarBorder: '260 20% 15%', }, }, { name: 'amber', label: 'Amber', light: { background: '36 20% 97%', foreground: '28 40% 10%', card: '0 0% 100%', cardForeground: '28 40% 10%', popover: '0 0% 100%', popoverForeground: '28 40% 10%', primary: '25 95% 40%', primaryForeground: '36 20% 98%', secondary: '36 25% 93%', secondaryForeground: '28 40% 10%', muted: '36 25% 93%', mutedForeground: '28 10% 47%', accent: '36 25% 93%', accentForeground: '28 40% 10%', destructive: '0 72% 51%', destructiveForeground: '36 20% 98%', border: '36 20% 88%', input: '36 20% 88%', ring: '25 95% 40%', sidebar: '36 22% 95%', sidebarForeground: '28 10% 47%', sidebarPrimary: '25 95% 40%', sidebarPrimaryForeground: '36 20% 98%', sidebarAccent: '36 25% 91%', sidebarAccentForeground: '28 40% 10%', sidebarBorder: '36 20% 88%', }, dark: { background: '28 25% 7%', foreground: '36 15% 85%', card: '28 25% 9%', cardForeground: '36 15% 85%', popover: '28 25% 9%', popoverForeground: '36 15% 85%', primary: '30 90% 52%', primaryForeground: '28 25% 7%', secondary: '28 18% 14%', secondaryForeground: '36 15% 85%', muted: '28 18% 14%', mutedForeground: '28 10% 52%', accent: '28 18% 14%', accentForeground: '36 15% 85%', destructive: '0 55% 48%', destructiveForeground: '36 15% 92%', border: '28 18% 16%', input: '28 18% 16%', ring: '30 90% 52%', sidebar: '28 25% 6%', sidebarForeground: '28 10% 62%', sidebarPrimary: '30 90% 52%', sidebarPrimaryForeground: '0 0% 100%', sidebarAccent: '28 18% 12%', sidebarAccentForeground: '36 15% 85%', sidebarBorder: '28 18% 14%', }, }, { name: 'rose', label: 'Rose', light: { background: '350 15% 97%', foreground: '350 40% 10%', card: '0 0% 100%', cardForeground: '350 40% 10%', popover: '0 0% 100%', popoverForeground: '350 40% 10%', primary: '347 77% 50%', primaryForeground: '350 15% 98%', secondary: '350 20% 94%', secondaryForeground: '350 40% 10%', muted: '350 20% 94%', mutedForeground: '350 10% 47%', accent: '350 20% 94%', accentForeground: '350 40% 10%', destructive: '0 72% 51%', destructiveForeground: '350 15% 98%', border: '350 15% 89%', input: '350 15% 89%', ring: '347 77% 50%', sidebar: '350 18% 95%', sidebarForeground: '350 10% 47%', sidebarPrimary: '347 77% 50%', sidebarPrimaryForeground: '350 15% 98%', sidebarAccent: '350 20% 92%', sidebarAccentForeground: '350 40% 10%', sidebarBorder: '350 15% 89%', }, dark: { background: '350 25% 7%', foreground: '350 12% 86%', card: '350 25% 9%', cardForeground: '350 12% 86%', popover: '350 25% 9%', popoverForeground: '350 12% 86%', primary: '347 77% 58%', primaryForeground: '350 25% 7%', secondary: '350 18% 14%', secondaryForeground: '350 12% 86%', muted: '350 18% 14%', mutedForeground: '350 10% 54%', accent: '350 18% 14%', accentForeground: '350 12% 86%', destructive: '0 55% 48%', destructiveForeground: '350 12% 92%', border: '350 18% 16%', input: '350 18% 16%', ring: '347 77% 58%', sidebar: '350 25% 6%', sidebarForeground: '350 10% 62%', sidebarPrimary: '347 77% 58%', sidebarPrimaryForeground: '0 0% 100%', sidebarAccent: '350 18% 12%', sidebarAccentForeground: '350 12% 86%', sidebarBorder: '350 18% 14%', }, }, ] function camelToKebab(str: string): string { return str.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase()) } export function applyThemeColors(colors: ThemeColors) { const root = document.documentElement for (const [key, value] of Object.entries(colors)) { const prop = `--${camelToKebab(key)}` const hsl = `hsl(${value})` root.style.setProperty(prop, hsl) } // Also set on body for portaled components (dialogs, dropdowns, popovers) for (const [key, value] of Object.entries(colors)) { document.body.style.setProperty(`--${camelToKebab(key)}`, `hsl(${value})`) } } export function getThemeByName(name: string): ThemePreset { return themes.find((t) => t.name === name) ?? themes[0] }