refactor(tokens): replace light and dark with morandi

This commit is contained in:
2026-03-20 16:25:02 +08:00
parent ffa9657ff6
commit af8476820e
6 changed files with 37 additions and 71 deletions
+3 -2
View File
@@ -1,5 +1,6 @@
import {
colorTokens,
defaultTheme,
defaultMotionAccessibility,
defaultMotionPack,
motionTokens,
@@ -194,7 +195,7 @@ function TokensOverview({
</p>
</div>
</div>
<div className="grid gap-4 lg:grid-cols-3">
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
{themeNames.map((themeName) => (
<ThemeCard key={themeName} themeName={themeName} />
))}
@@ -391,7 +392,7 @@ export const Overview: Story = {
args: {
motionAccessibility: defaultMotionAccessibility,
motionPack: defaultMotionPack,
theme: "light"
theme: defaultTheme
},
render: (_args, context) => (
<TokensOverview
+2 -2
View File
@@ -420,7 +420,7 @@ The end state should support runtime switching without remounting components.
Minimum contract:
```ts
type ThemeName = "light" | "dark" | "brand" | "minimal";
type ThemeName = "morandi" | "brand";
type SkinName = "minimal" | "glass" | "pixel";
type MotionPackName = "calm" | "snappy" | "spring";
type MotionAccessibilityName = "system" | "full" | "reduced";
@@ -438,7 +438,7 @@ Provider shape if needed:
```tsx
<StyleProvider
theme="minimal"
theme="morandi"
skin="glass"
motionPack="spring"
motionAccessibility="system"
+5 -9
View File
@@ -1,16 +1,12 @@
export const themeNames = ["light", "dark", "brand"] as const;
export const themeNames = ["morandi", "brand"] as const;
export type ThemeName = (typeof themeNames)[number];
export const defaultTheme: ThemeName = "light";
export const defaultTheme: ThemeName = "morandi";
export const themeDetails = {
light: {
label: "Light",
note: "Warm editorial default"
},
dark: {
label: "Dark",
note: "Warm charcoal default"
morandi: {
label: "Morandi",
note: "Muted dusty neutrals with a calm, understated luxury mood"
},
brand: {
label: "Brand",
+25 -55
View File
@@ -39,64 +39,34 @@
}
:root,
[data-theme="light"] {
[data-theme="morandi"] {
color-scheme: light;
--color-background: oklch(0.985 0.004 85);
--color-foreground: oklch(0.24 0.03 60);
--color-surface: oklch(0.965 0.008 80);
--color-surface-strong: oklch(0.93 0.012 78);
--color-surface-contrast: oklch(0.28 0.028 58);
--color-border: oklch(0.87 0.01 75);
--color-border-strong: oklch(0.72 0.018 68);
--color-background: color-mix(in oklch, #d4b5a0 10%, white 90%);
--color-foreground: #544c46;
--color-surface: color-mix(in oklch, #a6b3a7 12%, white 88%);
--color-surface-strong: color-mix(in oklch, #d4b5a0 20%, white 80%);
--color-surface-contrast: #6a615a;
--color-border: color-mix(in oklch, #9b8e82 34%, white 66%);
--color-border-strong: #9b8e82;
--color-input: var(--color-border);
--color-ring: oklch(0.56 0.12 32);
--color-primary: oklch(0.53 0.15 30);
--color-primary-foreground: oklch(0.98 0.01 80);
--color-secondary: oklch(0.9 0.02 74);
--color-secondary-foreground: oklch(0.26 0.024 60);
--color-muted: oklch(0.94 0.008 78);
--color-muted-foreground: oklch(0.42 0.028 60);
--color-accent: oklch(0.76 0.1 82);
--color-accent-foreground: oklch(0.24 0.03 60);
--color-success: oklch(0.58 0.12 152);
--color-success-foreground: oklch(0.97 0.01 155);
--color-warning: oklch(0.74 0.12 80);
--color-warning-foreground: oklch(0.22 0.02 64);
--color-destructive: oklch(0.51 0.18 28);
--color-destructive-foreground: oklch(0.98 0.01 80);
--color-card: color-mix(in oklch, var(--color-surface) 86%, white 14%);
--color-ring: #8e9aaf;
--color-primary: #6f7785;
--color-primary-foreground: #f7f3ef;
--color-secondary: #a6b3a7;
--color-secondary-foreground: #495247;
--color-muted: color-mix(in oklch, #d4b5a0 18%, white 82%);
--color-muted-foreground: #776c64;
--color-accent: #c4a882;
--color-accent-foreground: #4f4334;
--color-success: #879686;
--color-success-foreground: #f6f1ec;
--color-warning: #ba9c73;
--color-warning-foreground: #4d4031;
--color-destructive: #a7837c;
--color-destructive-foreground: #f9f4ef;
--color-card: color-mix(in oklch, var(--color-surface) 82%, white 18%);
--color-card-foreground: var(--color-foreground);
--color-overlay: oklch(0.12 0.01 40 / 0.48);
}
[data-theme="dark"] {
color-scheme: dark;
--color-background: oklch(0.2 0.015 60);
--color-foreground: oklch(0.94 0.01 80);
--color-surface: oklch(0.26 0.018 60);
--color-surface-strong: oklch(0.31 0.018 60);
--color-surface-contrast: oklch(0.93 0.012 78);
--color-border: oklch(0.4 0.015 60);
--color-border-strong: oklch(0.56 0.028 64);
--color-input: var(--color-border);
--color-ring: oklch(0.7 0.12 35);
--color-primary: oklch(0.72 0.13 40);
--color-primary-foreground: oklch(0.22 0.014 60);
--color-secondary: oklch(0.39 0.035 66);
--color-secondary-foreground: oklch(0.95 0.01 80);
--color-muted: oklch(0.28 0.015 60);
--color-muted-foreground: oklch(0.8 0.02 72);
--color-accent: oklch(0.68 0.09 82);
--color-accent-foreground: oklch(0.17 0.012 60);
--color-success: oklch(0.7 0.12 152);
--color-success-foreground: oklch(0.17 0.012 152);
--color-warning: oklch(0.78 0.12 82);
--color-warning-foreground: oklch(0.16 0.012 64);
--color-destructive: oklch(0.68 0.16 28);
--color-destructive-foreground: oklch(0.16 0.012 60);
--color-card: color-mix(in oklch, var(--color-surface) 90%, black 10%);
--color-card-foreground: var(--color-foreground);
--color-overlay: oklch(0.05 0.01 50 / 0.72);
--color-overlay: rgb(84 76 70 / 0.42);
}
[data-theme="brand"] {
+1 -2
View File
@@ -260,8 +260,7 @@ Deliverables:
- semantic color scale
- radius, shadow, border, typography tokens
- motion duration, easing, distance, and scale tokens
- light theme baseline
- dark theme baseline
- one Morandi theme baseline
- one optional brand theme scaffold
Exit criteria:
+1 -1
View File
@@ -176,7 +176,7 @@ import { setTheme } from "@ai-ui/tokens";
import "./styles.css";
setTheme("light");
setTheme("morandi");
function App() {
return (