diff --git a/src/i18n/en.json b/src/i18n/en.json index a6d6b24..3e40111 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -17,6 +17,7 @@ "switchToLight": "Switch to light mode", "theme": { "amber": "Amber", + "default": "Default", "forest": "Forest", "ocean": "Ocean", "rose": "Rose", diff --git a/src/index.css b/src/index.css index a9ce6ab..49a91d7 100644 --- a/src/index.css +++ b/src/index.css @@ -100,11 +100,56 @@ /* Color themes. Each theme re-hues the neutral tokens at the same lightness and chroma as the default palette (contrast is preserved) and replaces - primary/ring with the theme color. The default "Stalwart" theme is the + primary/ring with the theme color. The neutral "Default" theme is the bare :root/.dark above and needs no data-theme attribute. Dark theme blocks must stay after their light counterpart: both selectors have the same specificity, so source order decides. */ +/* "Stalwart" theme: matches the brand colors from stalw.art's own site + (src/styles/tokens.css there) — brand red #db2d54/#ff4570 converted to + oklch, neutrals kept close to true gray (unlike the other theme + presets below, which lightly re-hue their neutrals) since that's what + the real site does: saturated color only on the accent, not the + backdrop. */ +:root[data-theme='stalwart'] { + --foreground: oklch(0.147 0.009 285.3); + --content-background: oklch(0.974 0.003 286.4); + --primary: oklch(0.586 0.207 14.6); + --primary-foreground: oklch(0.985 0.002 285.3); + --secondary: oklch(0.965 0.005 285.3); + --secondary-foreground: oklch(0.205 0.017 285.3); + --muted: oklch(0.93 0.005 285.3); + --muted-foreground: oklch(0.431 0.016 285.7); + --accent: oklch(0.965 0.005 285.3); + --accent-foreground: oklch(0.205 0.017 285.3); + --border: oklch(0.926 0.005 286.3); + --input: oklch(0.926 0.005 286.3); + --ring: oklch(0.586 0.207 14.6); + --chart-1: 350 65% 52%; +} + +.dark[data-theme='stalwart'] { + --background: oklch(0.136 0.007 285.5); + --foreground: oklch(0.968 0.003 286.4); + --card: oklch(0.19 0.012 285.2); + --card-foreground: oklch(0.968 0.003 286.4); + --popover: oklch(0.221 0.016 285.1); + --popover-foreground: oklch(0.968 0.003 286.4); + --content-background: oklch(0.11 0.006 285.5); + --primary: oklch(0.672 0.221 12.3); + --primary-foreground: oklch(0.15 0.03 14.6); + --secondary: oklch(0.256 0.019 285); + --secondary-foreground: oklch(0.968 0.003 286.4); + --muted: oklch(0.256 0.019 285); + --muted-foreground: oklch(0.719 0.014 286); + --accent: oklch(0.28 0.02 285.1); + --accent-foreground: oklch(0.968 0.003 286.4); + --border: oklch(0.272 0.017 285.2); + --input: oklch(0.272 0.017 285.2); + --ring: oklch(0.672 0.221 12.3); + --chart-1: 350 80% 65%; +} + :root[data-theme='ocean'] { --foreground: oklch(0.145 0.02 264); --content-background: oklch(0.965 0.008 264); diff --git a/src/stores/uiStore.ts b/src/stores/uiStore.ts index fa621bd..3705103 100644 --- a/src/stores/uiStore.ts +++ b/src/stores/uiStore.ts @@ -8,7 +8,7 @@ import { create } from 'zustand'; import { persist } from 'zustand/middleware'; export type Theme = 'light' | 'dark'; -export type ColorTheme = 'stalwart' | 'ocean' | 'forest' | 'violet' | 'rose' | 'amber' | 'teal'; +export type ColorTheme = 'default' | 'stalwart' | 'ocean' | 'forest' | 'violet' | 'rose' | 'amber' | 'teal'; export type Radius = 'rounded' | 'square'; interface UIState { @@ -35,8 +35,8 @@ function applyThemeClass(theme: Theme) { } function applyColorThemeAttribute(colorTheme: ColorTheme) { - // The default theme is defined directly on :root/.dark, so it needs no attribute. - if (colorTheme === 'stalwart') { + // The neutral "Default" theme is defined directly on :root/.dark, so it needs no attribute. + if (colorTheme === 'default') { document.documentElement.removeAttribute('data-theme'); } else { document.documentElement.dataset.theme = colorTheme; @@ -48,11 +48,17 @@ function applyRadiusAttribute(radius: Radius) { } export const COLOR_THEMES: { value: ColorTheme; labelKey: string; fallback: string; swatch: string }[] = [ + { + value: 'default', + labelKey: 'appearance.theme.default', + fallback: 'Default', + swatch: 'linear-gradient(135deg, oklch(0.205 0.017 285.823) 50%, oklch(0.92 0.007 285.823) 50%)', + }, { value: 'stalwart', labelKey: 'appearance.theme.stalwart', fallback: 'Stalwart', - swatch: 'linear-gradient(135deg, oklch(0.205 0.017 285.823) 50%, oklch(0.92 0.007 285.823) 50%)', + swatch: 'oklch(0.586 0.207 14.6)', }, { value: 'ocean', labelKey: 'appearance.theme.ocean', fallback: 'Ocean', swatch: 'oklch(0.546 0.215 262.9)' }, { value: 'forest', labelKey: 'appearance.theme.forest', fallback: 'Forest', swatch: 'oklch(0.527 0.137 150.1)' },