feat: add theme selection and customization

This commit is contained in:
2026-07-07 22:59:03 -04:00
parent 49df5195bd
commit fe39b2196d
26 changed files with 3485 additions and 0 deletions
+254
View File
@@ -0,0 +1,254 @@
import type { ThemerPreset } from '@/types'
export const DEFAULT_PRESET_ID = 'default'
export const DEFAULT_FONT = 'Public Sans'
/**
* Preset palettes are sparse overrides: any token not listed falls back to the
* app-default palette (captured by the themer store at boot). Curated presets
* define their own `on-*` accents where the default white foreground would not
* hold enough contrast.
*/
export const PRESETS: ThemerPreset[] = [
{
id: 'default',
label: 'Indigo',
l10n: 'presets.default',
light: { colors: {} },
dark: { colors: {} },
},
{
id: 'emerald',
label: 'Emerald',
l10n: 'presets.emerald',
light: {
colors: {
'primary': '#059669',
'primary-darken-1': '#047857',
'primary-lighten-1': '#34D399',
'secondary': '#0D9488',
'secondary-darken-1': '#0F766E',
'secondary-lighten-1': '#2DD4BF',
'background': '#F4FAF7',
'surface-variant': '#EBF4EF',
'grey-lighten-4': '#EBF4EF',
'grey-lighten-5': '#F4FAF7',
'track-bg': '#EBF4EF',
},
variables: { 'border-color': '#DCE8E2' },
},
dark: {
colors: {
'primary': '#34D399',
'on-primary': '#052E1C',
'primary-darken-1': '#10B981',
'primary-lighten-1': '#6EE7B7',
'secondary': '#2DD4BF',
'on-secondary': '#042F2E',
'secondary-darken-1': '#14B8A6',
'secondary-lighten-1': '#5EEAD4',
'background': '#0B1512',
'surface': '#14201B',
'surface-bright': '#1E2E27',
'surface-variant': '#14201B',
'grey-lighten-3': '#24352E',
'grey-lighten-4': '#14201B',
'grey-lighten-5': '#0B1512',
'perfect-scrollbar-thumb': '#2F443B',
'track-bg': '#1E2E27',
},
variables: { 'border-color': '#24352E' },
},
},
{
id: 'rose',
label: 'Rose',
l10n: 'presets.rose',
light: {
colors: {
'primary': '#E11D48',
'primary-darken-1': '#BE123C',
'primary-lighten-1': '#FB7185',
'secondary': '#DB2777',
'secondary-darken-1': '#BE185D',
'secondary-lighten-1': '#F472B6',
'background': '#FDF7F8',
'surface-variant': '#FBEFF2',
'grey-lighten-4': '#FBEFF2',
'grey-lighten-5': '#FDF7F8',
'track-bg': '#FBEFF2',
},
variables: { 'border-color': '#F1DFE4' },
},
dark: {
colors: {
'primary': '#FB7185',
'on-primary': '#40060F',
'primary-darken-1': '#F43F5E',
'primary-lighten-1': '#FDA4AF',
'secondary': '#F472B6',
'on-secondary': '#3E0524',
'secondary-darken-1': '#EC4899',
'secondary-lighten-1': '#F9A8D4',
'background': '#171013',
'surface': '#231A1E',
'surface-bright': '#32232A',
'surface-variant': '#231A1E',
'grey-lighten-3': '#3A2A31',
'grey-lighten-4': '#231A1E',
'grey-lighten-5': '#171013',
'perfect-scrollbar-thumb': '#4C323A',
'track-bg': '#32232A',
},
variables: { 'border-color': '#3A2A31' },
},
},
{
id: 'amber',
label: 'Amber',
l10n: 'presets.amber',
light: {
colors: {
'primary': '#D97706',
'primary-darken-1': '#B45309',
'primary-lighten-1': '#F59E0B',
'secondary': '#EA580C',
'secondary-darken-1': '#C2410C',
'secondary-lighten-1': '#FB923C',
'warning': '#EAB308',
'background': '#FCFAF5',
'surface-variant': '#F8F1E7',
'grey-lighten-4': '#F8F1E7',
'grey-lighten-5': '#FCFAF5',
'track-bg': '#F8F1E7',
},
variables: { 'border-color': '#EDE3D0' },
},
dark: {
colors: {
'primary': '#FBBF24',
'on-primary': '#422006',
'primary-darken-1': '#F59E0B',
'primary-lighten-1': '#FCD34D',
'secondary': '#FB923C',
'on-secondary': '#431407',
'secondary-darken-1': '#F97316',
'secondary-lighten-1': '#FDBA74',
'warning': '#FACC15',
'background': '#15120B',
'surface': '#211C10',
'surface-bright': '#2E2718',
'surface-variant': '#211C10',
'grey-lighten-3': '#383018',
'grey-lighten-4': '#211C10',
'grey-lighten-5': '#15120B',
'perfect-scrollbar-thumb': '#4A3F21',
'track-bg': '#2E2718',
},
variables: { 'border-color': '#383018' },
},
},
{
id: 'ocean',
label: 'Ocean',
l10n: 'presets.ocean',
light: {
colors: {
'primary': '#0284C7',
'primary-darken-1': '#0369A1',
'primary-lighten-1': '#38BDF8',
'secondary': '#0891B2',
'secondary-darken-1': '#0E7490',
'secondary-lighten-1': '#22D3EE',
'background': '#F4F9FC',
'surface-variant': '#E9F3F9',
'grey-lighten-4': '#E9F3F9',
'grey-lighten-5': '#F4F9FC',
'track-bg': '#E9F3F9',
},
variables: { 'border-color': '#DBE9F1' },
},
dark: {
colors: {
'primary': '#38BDF8',
'on-primary': '#082F49',
'primary-darken-1': '#0EA5E9',
'primary-lighten-1': '#7DD3FC',
'secondary': '#22D3EE',
'on-secondary': '#083344',
'secondary-darken-1': '#06B6D4',
'secondary-lighten-1': '#67E8F9',
'background': '#0B141B',
'surface': '#132029',
'surface-bright': '#1C2E3A',
'surface-variant': '#132029',
'grey-lighten-3': '#223648',
'grey-lighten-4': '#132029',
'grey-lighten-5': '#0B141B',
'perfect-scrollbar-thumb': '#2E4557',
'track-bg': '#1C2E3A',
},
variables: { 'border-color': '#223648' },
},
},
{
id: 'graphite',
label: 'Graphite',
l10n: 'presets.graphite',
light: {
colors: {
'primary': '#334155',
'primary-darken-1': '#1E293B',
'primary-lighten-1': '#64748B',
'secondary': '#64748B',
'secondary-darken-1': '#475569',
'secondary-lighten-1': '#94A3B8',
'background': '#F6F7F9',
},
},
dark: {
colors: {
'primary': '#94A3B8',
'on-primary': '#0F172A',
'primary-darken-1': '#64748B',
'primary-lighten-1': '#CBD5E1',
'secondary': '#CBD5E1',
'on-secondary': '#0F172A',
'secondary-darken-1': '#94A3B8',
'secondary-lighten-1': '#E2E8F0',
'background': '#0B0F17',
'surface': '#151A23',
'surface-bright': '#232A36',
'surface-variant': '#151A23',
'grey-lighten-3': '#2A3240',
'grey-lighten-4': '#151A23',
'grey-lighten-5': '#0B0F17',
'perfect-scrollbar-thumb': '#3A4353',
'track-bg': '#232A36',
},
variables: { 'border-color': '#2A3240' },
},
},
]
export function getPreset(id: string | null | undefined): ThemerPreset | undefined {
if (!id) return undefined
return PRESETS.find(preset => preset.id === id)
}
/** Curated font choices; only Public Sans is bundled, the rest are web-safe stacks. */
export const FONT_OPTIONS = [
'Public Sans',
'Arial',
'Verdana',
'Tahoma',
'Trebuchet MS',
'Georgia',
'Times New Roman',
'Courier New',
]