feat(appearance): rename default theme, add real brand-accurate Stalwart theme
The color theme previously named "Stalwart" was actually just the neutral black/white default — it never used Stalwart's own brand color. Renamed it to "Default" (ColorTheme 'stalwart' -> 'default' value; label/i18n key updated) and added a genuinely new "Stalwart" theme in its place. Colors sourced directly from the official site's own design tokens (D:\project\stalwart_website/src/styles/tokens.css): brand red/pink #db2d54 (light primary/ring) and #ff4570 (--brand-hi, dark primary/ring), converted to oklch via the sRGB->OKLab->OKLCH matrix transform to match this project's existing token format. Neutrals use near-true-gray values (also converted from the site's actual light/ dark backgrounds and text colors) rather than being re-hued toward the brand color like the other theme presets — matching how the real site treats color (saturated only on the accent, neutral everywhere else). Verified in the running dev server: Default reverts to the original neutral look, Stalwart renders the brand red across primary buttons, active nav state, checkboxes, and badges in both light and dark mode. No regression (243 tests, typecheck, lint all pass).
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
"switchToLight": "Switch to light mode",
|
||||
"theme": {
|
||||
"amber": "Amber",
|
||||
"default": "Default",
|
||||
"forest": "Forest",
|
||||
"ocean": "Ocean",
|
||||
"rose": "Rose",
|
||||
|
||||
+46
-1
@@ -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);
|
||||
|
||||
+10
-4
@@ -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)' },
|
||||
|
||||
Reference in New Issue
Block a user