From 53af36ad013babab11d3750712c8fbb6e1f45a76 Mon Sep 17 00:00:00 2001 From: Padreug Date: Thu, 4 Jun 2026 11:48:39 +0200 Subject: [PATCH] feat(webapp): add color scheme switcher with 7 palettes Replace the bespoke index.css with a shadcn-vue-idiomatic theme.css (Catppuccin Latte/Mocha as the default), and add a palette picker to the profile sheet that swaps between 6 alternative palettes scoped under :root[data-theme=""]: Countryside Castle, Dark Matter, Emerald Forest, Light Green, Neo Brutalist, Starry Night. useTheme() now also persists a 'ui-palette' localStorage key alongside the existing 'ui-theme' (dark/light/system) and applies the choice via a data-theme attribute on . Standalone apps inherit the palette automatically since AppShell already invokes useTheme() on mount. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/assets/index.css | 306 ++++++++++++----------- src/assets/index.css.gruv | 64 ----- src/assets/themes/countrysidecastle.css | 89 +++++++ src/assets/themes/darkmatter.css | 81 ++++++ src/assets/themes/emeraldforest.css | 89 +++++++ src/assets/themes/lightgreen.css | 89 +++++++ src/assets/themes/neobrut.css | 81 ++++++ src/assets/themes/starrynight.css | 81 ++++++ src/components/layout/PreferencesRow.vue | 37 ++- src/components/theme-provider/index.ts | 49 +++- src/i18n/locales/en.ts | 8 + src/i18n/locales/es.ts | 8 + src/i18n/locales/fr.ts | 8 + src/i18n/types.ts | 8 + 14 files changed, 784 insertions(+), 214 deletions(-) delete mode 100644 src/assets/index.css.gruv create mode 100644 src/assets/themes/countrysidecastle.css create mode 100644 src/assets/themes/darkmatter.css create mode 100644 src/assets/themes/emeraldforest.css create mode 100644 src/assets/themes/lightgreen.css create mode 100644 src/assets/themes/neobrut.css create mode 100644 src/assets/themes/starrynight.css diff --git a/src/assets/index.css b/src/assets/index.css index 7d02eaa..36e2976 100644 --- a/src/assets/index.css +++ b/src/assets/index.css @@ -1,179 +1,195 @@ @import 'tailwindcss'; +@import './themes/countrysidecastle.css'; +@import './themes/darkmatter.css'; +@import './themes/emeraldforest.css'; +@import './themes/lightgreen.css'; +@import './themes/neobrut.css'; +@import './themes/starrynight.css'; @plugin 'tailwindcss-animate'; @custom-variant dark (&:is(.dark *)); -@theme { - --radius-lg: var(--radius); - --radius-md: calc(var(--radius) - 2px); +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + + --color-destructive: var(--destructive); + --color-destructive-foreground: var(--destructive-foreground); + + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); + + --font-sans: var(--font-sans); + --font-serif: var(--font-serif); + --font-mono: var(--font-mono); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); - --color-background: oklch(var(--background)); - --color-foreground: oklch(var(--foreground)); + --shadow-2xs: var(--shadow-2xs); + --shadow-xs: var(--shadow-xs); + --shadow-sm: var(--shadow-sm); + --shadow: var(--shadow); + --shadow-md: var(--shadow-md); + --shadow-lg: var(--shadow-lg); + --shadow-xl: var(--shadow-xl); + --shadow-2xl: var(--shadow-2xl); - --color-card: oklch(var(--card)); - --color-card-foreground: oklch(var(--card-foreground)); + --duration-fast: 150ms; + --duration-normal: 200ms; + --duration-slow: 300ms; - --color-popover: oklch(var(--popover)); - --color-popover-foreground: oklch(var(--popover-foreground)); - - --color-primary: oklch(var(--primary)); - --color-primary-foreground: oklch(var(--primary-foreground)); - - --color-secondary: oklch(var(--secondary)); - --color-secondary-foreground: oklch(var(--secondary-foreground)); - - --color-muted: oklch(var(--muted)); - --color-muted-foreground: oklch(var(--muted-foreground)); - - --color-accent: oklch(var(--accent)); - --color-accent-foreground: oklch(var(--accent-foreground)); - - --color-destructive: oklch(var(--destructive)); - --color-destructive-foreground: oklch(var(--destructive-foreground)); - - --color-border: oklch(var(--border)); - --color-input: oklch(var(--input)); - --color-ring: oklch(var(--ring)); - - --color-chart-1: oklch(var(--chart-1)); - --color-chart-2: oklch(var(--chart-2)); - --color-chart-3: oklch(var(--chart-3)); - --color-chart-4: oklch(var(--chart-4)); - --color-chart-5: oklch(var(--chart-5)); + --ease-in: cubic-bezier(0.4, 0, 1, 1); + --ease-out: cubic-bezier(0, 0, 0.2, 1); + --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); --animate-accordion-down: accordion-down 0.2s ease-out; --animate-accordion-up: accordion-up 0.2s ease-out; @keyframes accordion-down { - from { - height: 0; - } - to { - height: var(--reka-accordion-content-height); - } + from { height: 0; } + to { height: var(--reka-accordion-content-height); } } @keyframes accordion-up { - from { - height: var(--reka-accordion-content-height); - } - to { - height: 0; - } + from { height: var(--reka-accordion-content-height); } + to { height: 0; } } - - /* Add standard shadcn animation durations */ - --duration-fast: 150ms; - --duration-normal: 200ms; - --duration-slow: 300ms; - - /* Add standard shadcn easings */ - --ease-in: cubic-bezier(0.4, 0, 1, 1); - --ease-out: cubic-bezier(0, 0, 0.2, 1); - --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); - - /* Add standard shadcn animations */ - --animate-in: animate-in var(--duration-normal) var(--ease-out); - --animate-out: animate-out var(--duration-normal) var(--ease-in); - - --animate-fade-in: fade-in var(--duration-normal) var(--ease-out); - --animate-fade-out: fade-out var(--duration-normal) var(--ease-in); - - --animate-slide-in-from-top: slide-in-from-top var(--duration-normal) var(--ease-out); - --animate-slide-out-to-top: slide-out-to-top var(--duration-normal) var(--ease-in); - - --animate-slide-in-from-bottom: slide-in-from-bottom var(--duration-normal) var(--ease-out); - --animate-slide-out-to-bottom: slide-out-to-bottom var(--duration-normal) var(--ease-in); - - --animate-slide-in-from-left: slide-in-from-left var(--duration-normal) var(--ease-out); - --animate-slide-out-to-left: slide-out-to-left var(--duration-normal) var(--ease-in); - - --animate-slide-in-from-right: slide-in-from-right var(--duration-normal) var(--ease-out); - --animate-slide-out-to-right: slide-out-to-right var(--duration-normal) var(--ease-in); } -/* - The default border color has changed to `currentColor` in Tailwind CSS v4, - so we've added these compatibility styles to make sure everything still - looks the same as it did with Tailwind CSS v3. +/* Default palette: Catppuccin (Latte for light, Mocha for dark). + Other palettes are scoped via :root[data-theme=""] in themes/*.css. */ +:root { + --background: oklch(0.9578 0.0058 264.5321); + --foreground: oklch(0.4355 0.0430 279.3250); + --card: oklch(1.0000 0 0); + --card-foreground: oklch(0.4355 0.0430 279.3250); + --popover: oklch(0.8575 0.0145 268.4756); + --popover-foreground: oklch(0.4355 0.0430 279.3250); + --primary: oklch(0.5547 0.2503 297.0156); + --primary-foreground: oklch(1.0000 0 0); + --secondary: oklch(0.8575 0.0145 268.4756); + --secondary-foreground: oklch(0.4355 0.0430 279.3250); + --muted: oklch(0.9060 0.0117 264.5071); + --muted-foreground: oklch(0.5471 0.0343 279.0837); + --accent: oklch(0.6820 0.1448 235.3822); + --accent-foreground: oklch(1.0000 0 0); + --destructive: oklch(0.5505 0.2155 19.8095); + --destructive-foreground: oklch(1.0000 0 0); + --border: oklch(0.8083 0.0174 271.1982); + --input: oklch(0.8575 0.0145 268.4756); + --ring: oklch(0.5547 0.2503 297.0156); + --chart-1: oklch(0.5547 0.2503 297.0156); + --chart-2: oklch(0.6820 0.1448 235.3822); + --chart-3: oklch(0.6250 0.1772 140.4448); + --chart-4: oklch(0.6920 0.2041 42.4293); + --chart-5: oklch(0.7141 0.1045 33.0967); + --sidebar: oklch(0.9335 0.0087 264.5206); + --sidebar-foreground: oklch(0.4355 0.0430 279.3250); + --sidebar-primary: oklch(0.5547 0.2503 297.0156); + --sidebar-primary-foreground: oklch(1.0000 0 0); + --sidebar-accent: oklch(0.6820 0.1448 235.3822); + --sidebar-accent-foreground: oklch(1.0000 0 0); + --sidebar-border: oklch(0.8083 0.0174 271.1982); + --sidebar-ring: oklch(0.5547 0.2503 297.0156); + --font-sans: Montserrat, sans-serif; + --font-serif: Georgia, serif; + --font-mono: Fira Code, monospace; + --radius: 0.35rem; + --shadow-2xs: 0px 4px 6px 0px hsl(240 30% 25% / 0.06); + --shadow-xs: 0px 4px 6px 0px hsl(240 30% 25% / 0.06); + --shadow-sm: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 1px 2px -1px hsl(240 30% 25% / 0.12); + --shadow: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 1px 2px -1px hsl(240 30% 25% / 0.12); + --shadow-md: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 2px 4px -1px hsl(240 30% 25% / 0.12); + --shadow-lg: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 4px 6px -1px hsl(240 30% 25% / 0.12); + --shadow-xl: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 8px 10px -1px hsl(240 30% 25% / 0.12); + --shadow-2xl: 0px 4px 6px 0px hsl(240 30% 25% / 0.30); +} + +.dark { + --background: oklch(0.2155 0.0254 284.0647); + --foreground: oklch(0.8787 0.0426 272.2767); + --card: oklch(0.2429 0.0304 283.9110); + --card-foreground: oklch(0.8787 0.0426 272.2767); + --popover: oklch(0.4037 0.0320 280.1520); + --popover-foreground: oklch(0.8787 0.0426 272.2767); + --primary: oklch(0.7871 0.1187 304.7693); + --primary-foreground: oklch(0.2429 0.0304 283.9110); + --secondary: oklch(0.4765 0.0340 278.6430); + --secondary-foreground: oklch(0.8787 0.0426 272.2767); + --muted: oklch(0.2973 0.0294 276.2144); + --muted-foreground: oklch(0.7510 0.0396 273.9320); + --accent: oklch(0.8467 0.0833 210.2545); + --accent-foreground: oklch(0.2429 0.0304 283.9110); + --destructive: oklch(0.7556 0.1297 2.7642); + --destructive-foreground: oklch(0.2429 0.0304 283.9110); + --border: oklch(0.3240 0.0319 281.9784); + --input: oklch(0.3240 0.0319 281.9784); + --ring: oklch(0.7871 0.1187 304.7693); + --chart-1: oklch(0.7871 0.1187 304.7693); + --chart-2: oklch(0.8467 0.0833 210.2545); + --chart-3: oklch(0.8577 0.1092 142.7153); + --chart-4: oklch(0.8237 0.1015 52.6294); + --chart-5: oklch(0.9226 0.0238 30.4919); + --sidebar: oklch(0.1828 0.0204 284.2039); + --sidebar-foreground: oklch(0.8787 0.0426 272.2767); + --sidebar-primary: oklch(0.7871 0.1187 304.7693); + --sidebar-primary-foreground: oklch(0.2429 0.0304 283.9110); + --sidebar-accent: oklch(0.8467 0.0833 210.2545); + --sidebar-accent-foreground: oklch(0.2429 0.0304 283.9110); + --sidebar-border: oklch(0.4037 0.0320 280.1520); + --sidebar-ring: oklch(0.7871 0.1187 304.7693); +} - If we ever want to remove these styles, we need to add an explicit border - color utility to any element that depends on these defaults. -*/ @layer base { *, ::after, ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentColor); - } -} - -@layer base { - :root { - /* Catppuccin Latte - Enhanced */ - --background: 0.98 0.005 235; /* base - slightly brighter */ - --foreground: 0.25 0.02 235; /* text - darker for contrast */ - --card: 1.0 0.005 235; /* pure white for cards */ - --card-foreground: 0.25 0.02 235; - --popover: 1.0 0.005 235; - --popover-foreground: 0.25 0.02 235; - --primary: 0.60 0.18 250; /* lavender - more saturated */ - --primary-foreground: 1.0 0.005 235; - --secondary: 0.92 0.04 235; /* surface1 - more distinct */ - --secondary-foreground: 0.25 0.02 235; - --muted: 0.95 0.03 235; /* surface0 - slightly more color */ - --muted-foreground: 0.45 0.03 235; /* subtext0 - better contrast */ - --accent: 0.70 0.18 290; /* mauve - more saturated */ - --accent-foreground: 0.25 0.02 235; - --destructive: 0.70 0.28 0; /* red - more vibrant */ - --destructive-foreground: 1.0 0.005 235; - --border: 0.90 0.04 235; /* surface1 - more visible */ - --input: 0.90 0.04 235; - --ring: 0.60 0.18 250; /* matching primary */ - --chart-1: 0.70 0.28 0; /* red - more vibrant */ - --chart-2: 0.80 0.25 30; /* peach - more saturated */ - --chart-3: 0.85 0.20 90; /* yellow - more saturated */ - --chart-4: 0.75 0.20 150; /* green - more saturated */ - --chart-5: 0.65 0.20 180; /* blue - more saturated */ - --radius: 0.5rem; + border-color: var(--color-border, currentColor); } - .dark { - /* Catppuccin Mocha - Enhanced */ - --background: 0.25 0.03 256; /* base #1e1e2e */ - --foreground: 0.98 0.02 256; /* text #cdd6f4 - slightly brighter */ - --card: 0.27 0.03 256; /* slightly lighter than background */ - --card-foreground: 0.98 0.02 256; - --popover: 0.27 0.03 256; - --popover-foreground: 0.98 0.02 256; - --primary: 0.80 0.15 270; /* lavender #b4befe - more saturated */ - --primary-foreground: 0.20 0.02 256; - --secondary: 0.32 0.04 256; /* surface1 #313244 - more distinct */ - --secondary-foreground: 0.98 0.02 256; - --muted: 0.29 0.03 256; /* surface0 #2a2b3c */ - --muted-foreground: 0.85 0.03 256; /* subtext0 - brighter */ - --accent: 0.75 0.18 300; /* mauve #cba6f7 - more saturated */ - --accent-foreground: 0.20 0.02 256; - --destructive: 0.75 0.28 10; /* red #f38ba8 - more vibrant */ - --destructive-foreground: 0.98 0.02 256; - --border: 0.32 0.04 256; /* slightly more visible borders */ - --input: 0.32 0.04 256; - --ring: 0.80 0.15 270; /* matching primary */ - --chart-1: 0.75 0.28 10; /* red #f38ba8 */ - --chart-2: 0.85 0.22 40; /* peach #fab387 */ - --chart-3: 0.88 0.18 95; /* yellow #f9e2af */ - --chart-4: 0.80 0.18 155; /* green #a6e3a1 */ - --chart-5: 0.70 0.18 190; /* blue #89b4fa */ - } -} - -@layer base { * { - @apply border-border; + @apply border-border outline-ring/50; } + body { @apply bg-background text-foreground; } diff --git a/src/assets/index.css.gruv b/src/assets/index.css.gruv deleted file mode 100644 index 14a0dc8..0000000 --- a/src/assets/index.css.gruv +++ /dev/null @@ -1,64 +0,0 @@ -/* ... add other utility classes as needed ... */ - /* :root { */ - /* /* gruvbox light theme */ */ - /* --color-background: hsl(32 92% 87%); /* bg0 */ */ - /* --color-foreground: hsl(40 13% 23%); /* fg */ */ - /**/ - /* --color-card: hsl(39 59% 88%); /* bg1 */ */ - /* --color-card-foreground: hsl(40 13% 23%); /* fg */ */ - /**/ - /* --color-popover: hsl(39 59% 88%); /* bg1 */ */ - /* --color-popover-foreground: hsl(40 13% 23%); /* fg */ */ - /**/ - /* --color-primary: hsl(0 100% 31%); /* red */ */ - /* --color-primary-foreground: hsl(40 92% 88%); /* bg */ */ - /**/ - /* --color-secondary: hsl(39 46% 81%); /* bg2 */ */ - /* --color-secondary-foreground: hsl(40 13% 23%); /* fg */ */ - /**/ - /* --color-muted: hsl(37 29% 73%); /* bg3 */ */ - /* --color-muted-foreground: hsl(40 4% 36%); /* gray */ */ - /**/ - /* --color-accent: hsl(40 71% 49%); /* yellow */ */ - /* --color-accent-foreground: hsl(0 0% 16%); */ - /**/ - /* --color-destructive: hsl(0 76% 46%); /* bright_red */ */ - /* --color-destructive-foreground: hsl(40 92% 88%); /* bg */ */ - /**/ - /* --color-border: hsl(33 14% 59%); /* fg4 */ */ - /* --color-input: hsl(33 14% 59%); /* fg4 */ */ - /* --color-ring: hsl(0 100% 31%); /* red */ */ - /**/ - /* --radius: 0.5rem; */ - /* } */ - - /* .dark { */ - /* /* gruvbox dark theme */ */ - /* --color-background: hsl(0 0% 16%); /* bg0 */ */ - /* --color-foreground: hsl(40 92% 88%); /* fg */ */ - /**/ - /* --color-card: hsl(0 7% 23%); /* bg1 */ */ - /* --color-card-foreground: hsl(40 92% 88%); /* fg */ */ - /**/ - /* --color-popover: hsl(0 7% 23%); /* bg1 */ */ - /* --color-popover-foreground: hsl(40 92% 88%); /* fg */ */ - /**/ - /* --color-primary: hsl(6 93% 59%); /* red */ */ - /* --color-primary-foreground: hsl(0 0% 16%); /* bg */ */ - /**/ - /* --color-secondary: hsl(0 5% 29%); /* bg2 */ */ - /* --color-secondary-foreground: hsl(40 92% 88%); /* fg */ */ - /**/ - /* --color-muted: hsl(20 6% 36%); /* bg3 */ */ - /* --color-muted-foreground: hsl(33 14% 59%); /* gray */ */ - /**/ - /* --color-accent: hsl(42 95% 58%); /* yellow */ */ - /* --color-accent-foreground: hsl(0 0% 16%); */ - /**/ - /* --color-destructive: hsl(6 93% 59%); /* bright_red */ */ - /* --color-destructive-foreground: hsl(40 92% 88%); /* bg */ */ - /**/ - /* --color-border: hsl(24 10% 51%); /* fg4 */ */ - /* --color-input: hsl(24 10% 51%); /* fg4 */ */ - /* --color-ring: hsl(6 93% 59%); /* red */ */ - /* } */ diff --git a/src/assets/themes/countrysidecastle.css b/src/assets/themes/countrysidecastle.css new file mode 100644 index 0000000..baffcff --- /dev/null +++ b/src/assets/themes/countrysidecastle.css @@ -0,0 +1,89 @@ +:root[data-theme='countrysidecastle'] { + --background: oklch(0.9730 0.0058 84.5664); + --foreground: oklch(0.3247 0.0226 57.3596); + --card: oklch(0.9459 0.0117 84.5794); + --card-foreground: oklch(0.2724 0.0177 57.4319); + --popover: oklch(0.9595 0.0088 84.5733); + --popover-foreground: oklch(0.2175 0.0125 57.5482); + --primary: oklch(0.5698 0.0614 230.9798); + --primary-foreground: oklch(1.0000 0 0); + --secondary: oklch(0.8197 0.0295 76.4350); + --secondary-foreground: oklch(0.3750 0.0273 57.3103); + --muted: oklch(0.8903 0.0080 91.4872); + --muted-foreground: oklch(0.5129 0.0202 57.8140); + --accent: oklch(0.5425 0.0625 154.6280); + --accent-foreground: oklch(1.0000 0 0); + --destructive: oklch(0.5107 0.1226 22.3963); + --destructive-foreground: oklch(1.0000 0 0); + --border: oklch(0.8540 0.0188 76.5358); + --input: oklch(0.9130 0.0111 76.5933); + --ring: oklch(0.5698 0.0614 230.9798); + --chart-1: oklch(0.5698 0.0614 230.9798); + --chart-2: oklch(0.5425 0.0625 154.6280); + --chart-3: oklch(0.6550 0.0929 74.2249); + --chart-4: oklch(0.5570 0.0685 47.4365); + --chart-5: oklch(0.7343 0.0644 91.8078); + --sidebar: oklch(0.9266 0.0069 76.6174); + --sidebar-foreground: oklch(0.4237 0.0317 57.2745); + --sidebar-primary: oklch(0.5698 0.0614 230.9798); + --sidebar-primary-foreground: oklch(1.0000 0 0); + --sidebar-accent: oklch(0.8912 0.0161 156.8939); + --sidebar-accent-foreground: oklch(0.3497 0.0513 153.7441); + --sidebar-border: oklch(0.8649 0.0085 76.6058); + --sidebar-ring: oklch(0.5698 0.0614 230.9798); + --font-sans: Garamond, 'Eb Garamond', serif; + --font-serif: Palatino, 'Palatino Linotype', serif; + --font-mono: monospace; + --radius: 0.3rem; + --shadow-2xs: 0px 4px 12px 2px hsl(25 20% 10% / 0.05); + --shadow-xs: 0px 4px 12px 2px hsl(25 20% 10% / 0.05); + --shadow-sm: 0px 4px 12px 2px hsl(25 20% 10% / 0.10), 0px 1px 2px 1px hsl(25 20% 10% / 0.10); + --shadow: 0px 4px 12px 2px hsl(25 20% 10% / 0.10), 0px 1px 2px 1px hsl(25 20% 10% / 0.10); + --shadow-md: 0px 4px 12px 2px hsl(25 20% 10% / 0.10), 0px 2px 4px 1px hsl(25 20% 10% / 0.10); + --shadow-lg: 0px 4px 12px 2px hsl(25 20% 10% / 0.10), 0px 4px 6px 1px hsl(25 20% 10% / 0.10); + --shadow-xl: 0px 4px 12px 2px hsl(25 20% 10% / 0.10), 0px 8px 10px 1px hsl(25 20% 10% / 0.10); + --shadow-2xl: 0px 4px 12px 2px hsl(25 20% 10% / 0.25); +} + +:root[data-theme='countrysidecastle'].dark { + --background: oklch(0.2299 0.0198 256.8306); + --foreground: oklch(0.8894 0.0105 76.5953); + --card: oklch(0.2605 0.0240 256.8358); + --card-foreground: oklch(0.9266 0.0069 76.6174); + --popover: oklch(0.2090 0.0169 256.8258); + --popover-foreground: oklch(0.9635 0.0034 76.6361); + --primary: oklch(0.7041 0.0385 211.1736); + --primary-foreground: oklch(0.2079 0.0203 256.8404); + --secondary: oklch(0.4265 0.0167 76.4097); + --secondary-foreground: oklch(0.8894 0.0105 76.5953); + --muted: oklch(0.3137 0.0183 256.8010); + --muted-foreground: oklch(0.7169 0.0173 256.7349); + --accent: oklch(0.5342 0.0451 158.8384); + --accent-foreground: oklch(0.9635 0.0034 76.6361); + --destructive: oklch(0.4708 0.1367 24.0033); + --destructive-foreground: oklch(1.0000 0 0); + --border: oklch(0.3591 0.0295 256.8271); + --input: oklch(0.2920 0.0224 256.8218); + --ring: oklch(0.7041 0.0385 211.1736); + --chart-1: oklch(0.7041 0.0385 211.1736); + --chart-2: oklch(0.5810 0.0497 158.8087); + --chart-3: oklch(0.6763 0.0649 75.6254); + --chart-4: oklch(0.6009 0.0747 47.4204); + --chart-5: oklch(0.5781 0.0524 256.8345); + --sidebar: oklch(0.1974 0.0185 256.8372); + --sidebar-foreground: oklch(0.8518 0.0141 76.5687); + --sidebar-primary: oklch(0.7041 0.0385 211.1736); + --sidebar-primary-foreground: oklch(0.2079 0.0203 256.8404); + --sidebar-accent: oklch(0.2920 0.0224 256.8218); + --sidebar-accent-foreground: oklch(0.8544 0.0190 211.0454); + --sidebar-border: oklch(0.3095 0.0306 256.8416); + --sidebar-ring: oklch(0.7041 0.0385 211.1736); + --shadow-2xs: 0px 10px 20px 5px hsl(215 40% 5% / 0.25); + --shadow-xs: 0px 10px 20px 5px hsl(215 40% 5% / 0.25); + --shadow-sm: 0px 10px 20px 5px hsl(215 40% 5% / 0.50), 0px 1px 2px 4px hsl(215 40% 5% / 0.50); + --shadow: 0px 10px 20px 5px hsl(215 40% 5% / 0.50), 0px 1px 2px 4px hsl(215 40% 5% / 0.50); + --shadow-md: 0px 10px 20px 5px hsl(215 40% 5% / 0.50), 0px 2px 4px 4px hsl(215 40% 5% / 0.50); + --shadow-lg: 0px 10px 20px 5px hsl(215 40% 5% / 0.50), 0px 4px 6px 4px hsl(215 40% 5% / 0.50); + --shadow-xl: 0px 10px 20px 5px hsl(215 40% 5% / 0.50), 0px 8px 10px 4px hsl(215 40% 5% / 0.50); + --shadow-2xl: 0px 10px 20px 5px hsl(215 40% 5% / 1.25); +} diff --git a/src/assets/themes/darkmatter.css b/src/assets/themes/darkmatter.css new file mode 100644 index 0000000..1beb5ab --- /dev/null +++ b/src/assets/themes/darkmatter.css @@ -0,0 +1,81 @@ +:root[data-theme='darkmatter'] { + --background: oklch(1.0000 0 0); + --foreground: oklch(0.2101 0.0318 264.6645); + --card: oklch(1.0000 0 0); + --card-foreground: oklch(0.2101 0.0318 264.6645); + --popover: oklch(1.0000 0 0); + --popover-foreground: oklch(0.2101 0.0318 264.6645); + --primary: oklch(0.6716 0.1368 48.5130); + --primary-foreground: oklch(1.0000 0 0); + --secondary: oklch(0.5360 0.0398 196.0280); + --secondary-foreground: oklch(1.0000 0 0); + --muted: oklch(0.9670 0.0029 264.5419); + --muted-foreground: oklch(0.5510 0.0234 264.3637); + --accent: oklch(0.9491 0 0); + --accent-foreground: oklch(0.2101 0.0318 264.6645); + --destructive: oklch(0.6368 0.2078 25.3313); + --destructive-foreground: oklch(0.9851 0 0); + --border: oklch(0.9276 0.0058 264.5313); + --input: oklch(0.9276 0.0058 264.5313); + --ring: oklch(0.6716 0.1368 48.5130); + --chart-1: oklch(0.5940 0.0443 196.0233); + --chart-2: oklch(0.7214 0.1337 49.9802); + --chart-3: oklch(0.8721 0.0864 68.5474); + --chart-4: oklch(0.6268 0 0); + --chart-5: oklch(0.6830 0 0); + --sidebar: oklch(0.9670 0.0029 264.5419); + --sidebar-foreground: oklch(0.2101 0.0318 264.6645); + --sidebar-primary: oklch(0.6716 0.1368 48.5130); + --sidebar-primary-foreground: oklch(1.0000 0 0); + --sidebar-accent: oklch(1.0000 0 0); + --sidebar-accent-foreground: oklch(0.2101 0.0318 264.6645); + --sidebar-border: oklch(0.9276 0.0058 264.5313); + --sidebar-ring: oklch(0.6716 0.1368 48.5130); + --font-sans: Geist Mono, ui-monospace, monospace; + --font-serif: serif; + --font-mono: JetBrains Mono, monospace; + --radius: 0.75rem; + --shadow-2xs: 0px 1px 4px 0px hsl(0 0% 0% / 0.03); + --shadow-xs: 0px 1px 4px 0px hsl(0 0% 0% / 0.03); + --shadow-sm: 0px 1px 4px 0px hsl(0 0% 0% / 0.05), 0px 1px 2px -1px hsl(0 0% 0% / 0.05); + --shadow: 0px 1px 4px 0px hsl(0 0% 0% / 0.05), 0px 1px 2px -1px hsl(0 0% 0% / 0.05); + --shadow-md: 0px 1px 4px 0px hsl(0 0% 0% / 0.05), 0px 2px 4px -1px hsl(0 0% 0% / 0.05); + --shadow-lg: 0px 1px 4px 0px hsl(0 0% 0% / 0.05), 0px 4px 6px -1px hsl(0 0% 0% / 0.05); + --shadow-xl: 0px 1px 4px 0px hsl(0 0% 0% / 0.05), 0px 8px 10px -1px hsl(0 0% 0% / 0.05); + --shadow-2xl: 0px 1px 4px 0px hsl(0 0% 0% / 0.13); +} + +:root[data-theme='darkmatter'].dark { + --background: oklch(0.1797 0.0043 308.1928); + --foreground: oklch(0.8109 0 0); + --card: oklch(0.1822 0 0); + --card-foreground: oklch(0.8109 0 0); + --popover: oklch(0.1797 0.0043 308.1928); + --popover-foreground: oklch(0.8109 0 0); + --primary: oklch(0.7214 0.1337 49.9802); + --primary-foreground: oklch(0.1797 0.0043 308.1928); + --secondary: oklch(0.5940 0.0443 196.0233); + --secondary-foreground: oklch(0.1797 0.0043 308.1928); + --muted: oklch(0.2520 0 0); + --muted-foreground: oklch(0.6268 0 0); + --accent: oklch(0.3211 0 0); + --accent-foreground: oklch(0.8109 0 0); + --destructive: oklch(0.5940 0.0443 196.0233); + --destructive-foreground: oklch(0.1797 0.0043 308.1928); + --border: oklch(0.2520 0 0); + --input: oklch(0.2520 0 0); + --ring: oklch(0.7214 0.1337 49.9802); + --chart-1: oklch(0.5940 0.0443 196.0233); + --chart-2: oklch(0.7214 0.1337 49.9802); + --chart-3: oklch(0.8721 0.0864 68.5474); + --chart-4: oklch(0.6268 0 0); + --chart-5: oklch(0.6830 0 0); + --sidebar: oklch(0.1822 0 0); + --sidebar-foreground: oklch(0.8109 0 0); + --sidebar-primary: oklch(0.7214 0.1337 49.9802); + --sidebar-primary-foreground: oklch(0.1797 0.0043 308.1928); + --sidebar-accent: oklch(0.3211 0 0); + --sidebar-accent-foreground: oklch(0.8109 0 0); + --sidebar-border: oklch(0.2520 0 0); + --sidebar-ring: oklch(0.7214 0.1337 49.9802); +} diff --git a/src/assets/themes/emeraldforest.css b/src/assets/themes/emeraldforest.css new file mode 100644 index 0000000..dc8f9be --- /dev/null +++ b/src/assets/themes/emeraldforest.css @@ -0,0 +1,89 @@ +:root[data-theme='emeraldforest'] { + --background: oklch(0.9793 0.0077 145.5161); + --foreground: oklch(0.2464 0.0358 168.9829); + --card: oklch(0.9649 0.0108 145.4913); + --card-foreground: oklch(0.2464 0.0358 168.9829); + --popover: oklch(0.9793 0.0077 145.5161); + --popover-foreground: oklch(0.2464 0.0358 168.9829); + --primary: oklch(0.5767 0.1258 156.2896); + --primary-foreground: oklch(0.9860 0.0025 165.0756); + --secondary: oklch(0.8935 0.0214 156.7700); + --secondary-foreground: oklch(0.3633 0.0586 159.6692); + --muted: oklch(0.9274 0.0118 150.6461); + --muted-foreground: oklch(0.4883 0.0348 172.3051); + --accent: oklch(0.9398 0.0317 164.2277); + --accent-foreground: oklch(0.4557 0.0902 161.0214); + --destructive: oklch(0.5714 0.2121 27.2502); + --destructive-foreground: oklch(1.0000 0 0); + --border: oklch(0.8935 0.0214 156.7700); + --input: oklch(0.9293 0.0141 156.9525); + --ring: oklch(0.5767 0.1258 156.2896); + --chart-1: oklch(0.6610 0.1560 154.8128); + --chart-2: oklch(0.6335 0.1421 147.0021); + --chart-3: oklch(0.5044 0.0769 179.9212); + --chart-4: oklch(0.7869 0.1601 151.8584); + --chart-5: oklch(0.6954 0.1084 168.3427); + --sidebar: oklch(0.9588 0.0148 147.9012); + --sidebar-foreground: oklch(0.3142 0.0494 168.2500); + --sidebar-primary: oklch(0.5767 0.1258 156.2896); + --sidebar-primary-foreground: oklch(1.0000 0 0); + --sidebar-accent: oklch(0.9168 0.0213 156.7859); + --sidebar-accent-foreground: oklch(0.4542 0.0965 156.7126); + --sidebar-border: oklch(0.9150 0.0170 156.8819); + --sidebar-ring: oklch(0.5767 0.1258 156.2896); + --font-sans: Inter, sans-serif; + --font-serif: Georgia, serif; + --font-mono: JetBrains Mono, monospace; + --radius: 0.5rem; + --shadow-2xs: 0px 2px 10px 0px hsl(160 50% 10% / 0.03); + --shadow-xs: 0px 2px 10px 0px hsl(160 50% 10% / 0.03); + --shadow-sm: 0px 2px 10px 0px hsl(160 50% 10% / 0.05), 0px 1px 2px -1px hsl(160 50% 10% / 0.05); + --shadow: 0px 2px 10px 0px hsl(160 50% 10% / 0.05), 0px 1px 2px -1px hsl(160 50% 10% / 0.05); + --shadow-md: 0px 2px 10px 0px hsl(160 50% 10% / 0.05), 0px 2px 4px -1px hsl(160 50% 10% / 0.05); + --shadow-lg: 0px 2px 10px 0px hsl(160 50% 10% / 0.05), 0px 4px 6px -1px hsl(160 50% 10% / 0.05); + --shadow-xl: 0px 2px 10px 0px hsl(160 50% 10% / 0.05), 0px 8px 10px -1px hsl(160 50% 10% / 0.05); + --shadow-2xl: 0px 2px 10px 0px hsl(160 50% 10% / 0.13); +} + +:root[data-theme='emeraldforest'].dark { + --background: oklch(0.1554 0.0140 178.0345); + --foreground: oklch(0.9650 0.0064 164.9697); + --card: oklch(0.1965 0.0190 176.6910); + --card-foreground: oklch(0.9650 0.0064 164.9697); + --popover: oklch(0.1703 0.0163 177.0235); + --popover-foreground: oklch(0.9650 0.0064 164.9697); + --primary: oklch(0.7355 0.1793 154.0472); + --primary-foreground: oklch(0.1703 0.0163 177.0235); + --secondary: oklch(0.2896 0.0276 171.3798); + --secondary-foreground: oklch(0.9297 0.0128 164.7776); + --muted: oklch(0.2503 0.0187 172.1743); + --muted-foreground: oklch(0.7753 0.0200 164.4487); + --accent: oklch(0.3031 0.0438 164.4442); + --accent-foreground: oklch(0.9059 0.0980 161.8651); + --destructive: oklch(0.5181 0.1747 25.7610); + --destructive-foreground: oklch(1.0000 0 0); + --border: oklch(0.2852 0.0226 172.0143); + --input: oklch(0.3190 0.0263 171.8953); + --ring: oklch(0.7355 0.1793 154.0472); + --chart-1: oklch(0.7355 0.1793 154.0472); + --chart-2: oklch(0.7403 0.1521 151.7821); + --chart-3: oklch(0.6461 0.1081 178.6914); + --chart-4: oklch(0.5457 0.0949 162.7657); + --chart-5: oklch(0.7786 0.0938 157.7379); + --sidebar: oklch(0.1848 0.0187 176.5131); + --sidebar-foreground: oklch(0.9297 0.0128 164.7776); + --sidebar-primary: oklch(0.7355 0.1793 154.0472); + --sidebar-primary-foreground: oklch(0.1703 0.0163 177.0235); + --sidebar-accent: oklch(0.2503 0.0187 172.1743); + --sidebar-accent-foreground: oklch(0.8800 0.1137 161.0658); + --sidebar-border: oklch(0.2737 0.0213 172.0621); + --sidebar-ring: oklch(0.7355 0.1793 154.0472); + --shadow-2xs: 0px 4px 15px 0px hsl(0 0% 0% / 0.20); + --shadow-xs: 0px 4px 15px 0px hsl(0 0% 0% / 0.20); + --shadow-sm: 0px 4px 15px 0px hsl(0 0% 0% / 0.40), 0px 1px 2px -1px hsl(0 0% 0% / 0.40); + --shadow: 0px 4px 15px 0px hsl(0 0% 0% / 0.40), 0px 1px 2px -1px hsl(0 0% 0% / 0.40); + --shadow-md: 0px 4px 15px 0px hsl(0 0% 0% / 0.40), 0px 2px 4px -1px hsl(0 0% 0% / 0.40); + --shadow-lg: 0px 4px 15px 0px hsl(0 0% 0% / 0.40), 0px 4px 6px -1px hsl(0 0% 0% / 0.40); + --shadow-xl: 0px 4px 15px 0px hsl(0 0% 0% / 0.40), 0px 8px 10px -1px hsl(0 0% 0% / 0.40); + --shadow-2xl: 0px 4px 15px 0px hsl(0 0% 0% / 1.00); +} diff --git a/src/assets/themes/lightgreen.css b/src/assets/themes/lightgreen.css new file mode 100644 index 0000000..cf417e8 --- /dev/null +++ b/src/assets/themes/lightgreen.css @@ -0,0 +1,89 @@ +:root[data-theme='lightgreen'] { + --background: oklch(0.9892 0.0054 117.9205); + --foreground: oklch(0.2077 0.0398 265.7549); + --card: oklch(1.0000 0 0); + --card-foreground: oklch(0.2077 0.0398 265.7549); + --popover: oklch(1.0000 0 0); + --popover-foreground: oklch(0.2077 0.0398 265.7549); + --primary: oklch(0.8871 0.2122 128.5041); + --primary-foreground: oklch(0 0 0); + --secondary: oklch(0.3717 0.0392 257.2870); + --secondary-foreground: oklch(0.9842 0.0034 247.8575); + --muted: oklch(0.9683 0.0069 247.8956); + --muted-foreground: oklch(0.5544 0.0407 257.4166); + --accent: oklch(0.9819 0.0181 155.8263); + --accent-foreground: oklch(0.4479 0.1083 151.3277); + --destructive: oklch(0.6368 0.2078 25.3313); + --destructive-foreground: oklch(1.0000 0 0); + --border: oklch(0.9288 0.0126 255.5078); + --input: oklch(0.9288 0.0126 255.5078); + --ring: oklch(0.8871 0.2122 128.5041); + --chart-1: oklch(0.8871 0.2122 128.5041); + --chart-2: oklch(0.3717 0.0392 257.2870); + --chart-3: oklch(0.7227 0.1920 149.5793); + --chart-4: oklch(0.5544 0.0407 257.4166); + --chart-5: oklch(0.7107 0.0351 256.7878); + --sidebar: oklch(1.0000 0 0); + --sidebar-foreground: oklch(0.2077 0.0398 265.7549); + --sidebar-primary: oklch(0.8871 0.2122 128.5041); + --sidebar-primary-foreground: oklch(0 0 0); + --sidebar-accent: oklch(0.9842 0.0034 247.8575); + --sidebar-accent-foreground: oklch(0.2077 0.0398 265.7549); + --sidebar-border: oklch(0.9683 0.0069 247.8956); + --sidebar-ring: oklch(0.8871 0.2122 128.5041); + --font-sans: Inter, system-ui, sans-serif; + --font-serif: Georgia, serif; + --font-mono: JetBrains Mono, monospace; + --radius: 1rem; + --shadow-2xs: 0px 8px 20px 0px hsl(0 0% 0% / 0.03); + --shadow-xs: 0px 8px 20px 0px hsl(0 0% 0% / 0.03); + --shadow-sm: 0px 8px 20px 0px hsl(0 0% 0% / 0.05), 0px 1px 2px -1px hsl(0 0% 0% / 0.05); + --shadow: 0px 8px 20px 0px hsl(0 0% 0% / 0.05), 0px 1px 2px -1px hsl(0 0% 0% / 0.05); + --shadow-md: 0px 8px 20px 0px hsl(0 0% 0% / 0.05), 0px 2px 4px -1px hsl(0 0% 0% / 0.05); + --shadow-lg: 0px 8px 20px 0px hsl(0 0% 0% / 0.05), 0px 4px 6px -1px hsl(0 0% 0% / 0.05); + --shadow-xl: 0px 8px 20px 0px hsl(0 0% 0% / 0.05), 0px 8px 10px -1px hsl(0 0% 0% / 0.05); + --shadow-2xl: 0px 8px 20px 0px hsl(0 0% 0% / 0.13); +} + +:root[data-theme='lightgreen'].dark { + --background: oklch(0.1288 0.0406 264.6952); + --foreground: oklch(0.9842 0.0034 247.8575); + --card: oklch(0.2077 0.0398 265.7549); + --card-foreground: oklch(0.9842 0.0034 247.8575); + --popover: oklch(0.2077 0.0398 265.7549); + --popover-foreground: oklch(0.9842 0.0034 247.8575); + --primary: oklch(0.8871 0.2122 128.5041); + --primary-foreground: oklch(0 0 0); + --secondary: oklch(0.2795 0.0368 260.0310); + --secondary-foreground: oklch(0.9842 0.0034 247.8575); + --muted: oklch(0.2795 0.0368 260.0310); + --muted-foreground: oklch(0.7107 0.0351 256.7878); + --accent: oklch(0.3925 0.0896 152.5353); + --accent-foreground: oklch(0.8871 0.2122 128.5041); + --destructive: oklch(0.4437 0.1613 26.8994); + --destructive-foreground: oklch(1.0000 0 0); + --border: oklch(0.2795 0.0368 260.0310); + --input: oklch(0.2795 0.0368 260.0310); + --ring: oklch(0.8871 0.2122 128.5041); + --chart-1: oklch(0.8871 0.2122 128.5041); + --chart-2: oklch(0.6231 0.1880 259.8145); + --chart-3: oklch(0.7227 0.1920 149.5793); + --chart-4: oklch(0.6268 0.2325 303.9004); + --chart-5: oklch(0.7686 0.1647 70.0804); + --sidebar: oklch(0.1288 0.0406 264.6952); + --sidebar-foreground: oklch(0.9842 0.0034 247.8575); + --sidebar-primary: oklch(0.8871 0.2122 128.5041); + --sidebar-primary-foreground: oklch(0 0 0); + --sidebar-accent: oklch(0.2795 0.0368 260.0310); + --sidebar-accent-foreground: oklch(0.9842 0.0034 247.8575); + --sidebar-border: oklch(0.2795 0.0368 260.0310); + --sidebar-ring: oklch(0.8871 0.2122 128.5041); + --shadow-2xs: 0px 10px 25px 0px hsl(0 0% 0% / 0.20); + --shadow-xs: 0px 10px 25px 0px hsl(0 0% 0% / 0.20); + --shadow-sm: 0px 10px 25px 0px hsl(0 0% 0% / 0.40), 0px 1px 2px -1px hsl(0 0% 0% / 0.40); + --shadow: 0px 10px 25px 0px hsl(0 0% 0% / 0.40), 0px 1px 2px -1px hsl(0 0% 0% / 0.40); + --shadow-md: 0px 10px 25px 0px hsl(0 0% 0% / 0.40), 0px 2px 4px -1px hsl(0 0% 0% / 0.40); + --shadow-lg: 0px 10px 25px 0px hsl(0 0% 0% / 0.40), 0px 4px 6px -1px hsl(0 0% 0% / 0.40); + --shadow-xl: 0px 10px 25px 0px hsl(0 0% 0% / 0.40), 0px 8px 10px -1px hsl(0 0% 0% / 0.40); + --shadow-2xl: 0px 10px 25px 0px hsl(0 0% 0% / 1.00); +} diff --git a/src/assets/themes/neobrut.css b/src/assets/themes/neobrut.css new file mode 100644 index 0000000..2128a26 --- /dev/null +++ b/src/assets/themes/neobrut.css @@ -0,0 +1,81 @@ +:root[data-theme='neobrut'] { + --background: oklch(1.0000 0 0); + --foreground: oklch(0 0 0); + --card: oklch(1.0000 0 0); + --card-foreground: oklch(0 0 0); + --popover: oklch(1.0000 0 0); + --popover-foreground: oklch(0 0 0); + --primary: oklch(0.6489 0.2370 26.9728); + --primary-foreground: oklch(1.0000 0 0); + --secondary: oklch(0.9680 0.2110 109.7692); + --secondary-foreground: oklch(0 0 0); + --muted: oklch(0.9551 0 0); + --muted-foreground: oklch(0.3211 0 0); + --accent: oklch(0.5635 0.2408 260.8178); + --accent-foreground: oklch(1.0000 0 0); + --destructive: oklch(0 0 0); + --destructive-foreground: oklch(1.0000 0 0); + --border: oklch(0 0 0); + --input: oklch(0 0 0); + --ring: oklch(0.6489 0.2370 26.9728); + --chart-1: oklch(0.6489 0.2370 26.9728); + --chart-2: oklch(0.9680 0.2110 109.7692); + --chart-3: oklch(0.5635 0.2408 260.8178); + --chart-4: oklch(0.7323 0.2492 142.4953); + --chart-5: oklch(0.5931 0.2726 328.3634); + --sidebar: oklch(0.9551 0 0); + --sidebar-foreground: oklch(0 0 0); + --sidebar-primary: oklch(0.6489 0.2370 26.9728); + --sidebar-primary-foreground: oklch(1.0000 0 0); + --sidebar-accent: oklch(0.5635 0.2408 260.8178); + --sidebar-accent-foreground: oklch(1.0000 0 0); + --sidebar-border: oklch(0 0 0); + --sidebar-ring: oklch(0.6489 0.2370 26.9728); + --font-sans: DM Sans, sans-serif; + --font-serif: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif; + --font-mono: Space Mono, monospace; + --radius: 0px; + --shadow-2xs: 4px 4px 0px 0px hsl(0 0% 0% / 0.50); + --shadow-xs: 4px 4px 0px 0px hsl(0 0% 0% / 0.50); + --shadow-sm: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 1px 2px -1px hsl(0 0% 0% / 1.00); + --shadow: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 1px 2px -1px hsl(0 0% 0% / 1.00); + --shadow-md: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 2px 4px -1px hsl(0 0% 0% / 1.00); + --shadow-lg: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 4px 6px -1px hsl(0 0% 0% / 1.00); + --shadow-xl: 4px 4px 0px 0px hsl(0 0% 0% / 1.00), 4px 8px 10px -1px hsl(0 0% 0% / 1.00); + --shadow-2xl: 4px 4px 0px 0px hsl(0 0% 0% / 2.50); +} + +:root[data-theme='neobrut'].dark { + --background: oklch(0 0 0); + --foreground: oklch(1.0000 0 0); + --card: oklch(0.3211 0 0); + --card-foreground: oklch(1.0000 0 0); + --popover: oklch(0.3211 0 0); + --popover-foreground: oklch(1.0000 0 0); + --primary: oklch(0.7044 0.1872 23.1858); + --primary-foreground: oklch(0 0 0); + --secondary: oklch(0.9691 0.2005 109.6228); + --secondary-foreground: oklch(0 0 0); + --muted: oklch(0.2178 0 0); + --muted-foreground: oklch(0.8452 0 0); + --accent: oklch(0.6755 0.1765 252.2592); + --accent-foreground: oklch(0 0 0); + --destructive: oklch(1.0000 0 0); + --destructive-foreground: oklch(0 0 0); + --border: oklch(1.0000 0 0); + --input: oklch(1.0000 0 0); + --ring: oklch(0.7044 0.1872 23.1858); + --chart-1: oklch(0.7044 0.1872 23.1858); + --chart-2: oklch(0.9691 0.2005 109.6228); + --chart-3: oklch(0.6755 0.1765 252.2592); + --chart-4: oklch(0.7395 0.2268 142.8504); + --chart-5: oklch(0.6131 0.2458 328.0714); + --sidebar: oklch(0 0 0); + --sidebar-foreground: oklch(1.0000 0 0); + --sidebar-primary: oklch(0.7044 0.1872 23.1858); + --sidebar-primary-foreground: oklch(0 0 0); + --sidebar-accent: oklch(0.6755 0.1765 252.2592); + --sidebar-accent-foreground: oklch(0 0 0); + --sidebar-border: oklch(1.0000 0 0); + --sidebar-ring: oklch(0.7044 0.1872 23.1858); +} diff --git a/src/assets/themes/starrynight.css b/src/assets/themes/starrynight.css new file mode 100644 index 0000000..978bcd4 --- /dev/null +++ b/src/assets/themes/starrynight.css @@ -0,0 +1,81 @@ +:root[data-theme='starrynight'] { + --background: oklch(0.9755 0.0045 258.3245); + --foreground: oklch(0.2558 0.0433 268.0662); + --card: oklch(0.9341 0.0132 251.5628); + --card-foreground: oklch(0.2558 0.0433 268.0662); + --popover: oklch(0.9856 0.0278 98.0540); + --popover-foreground: oklch(0.2558 0.0433 268.0662); + --primary: oklch(0.4815 0.1178 263.3758); + --primary-foreground: oklch(0.9856 0.0278 98.0540); + --secondary: oklch(0.8567 0.1164 81.0092); + --secondary-foreground: oklch(0.2558 0.0433 268.0662); + --muted: oklch(0.9202 0.0080 106.5563); + --muted-foreground: oklch(0.4815 0.1178 263.3758); + --accent: oklch(0.6896 0.0714 234.0387); + --accent-foreground: oklch(0.9856 0.0278 98.0540); + --destructive: oklch(0.2611 0.0376 322.5267); + --destructive-foreground: oklch(0.9856 0.0278 98.0540); + --border: oklch(0.7791 0.0156 251.1926); + --input: oklch(0.6896 0.0714 234.0387); + --ring: oklch(0.8567 0.1164 81.0092); + --chart-1: oklch(0.4815 0.1178 263.3758); + --chart-2: oklch(0.8567 0.1164 81.0092); + --chart-3: oklch(0.6896 0.0714 234.0387); + --chart-4: oklch(0.7791 0.0156 251.1926); + --chart-5: oklch(0.2611 0.0376 322.5267); + --sidebar: oklch(0.9341 0.0132 251.5628); + --sidebar-foreground: oklch(0.2558 0.0433 268.0662); + --sidebar-primary: oklch(0.4815 0.1178 263.3758); + --sidebar-primary-foreground: oklch(0.9856 0.0278 98.0540); + --sidebar-accent: oklch(0.8567 0.1164 81.0092); + --sidebar-accent-foreground: oklch(0.2558 0.0433 268.0662); + --sidebar-border: oklch(0.7791 0.0156 251.1926); + --sidebar-ring: oklch(0.8567 0.1164 81.0092); + --font-sans: Libre Baskerville, serif; + --font-serif: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif; + --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; + --radius: 0.5rem; + --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); + --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); + --shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10); + --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 1px 2px -1px hsl(0 0% 0% / 0.10); + --shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 2px 4px -1px hsl(0 0% 0% / 0.10); + --shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 4px 6px -1px hsl(0 0% 0% / 0.10); + --shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.10), 0 8px 10px -1px hsl(0 0% 0% / 0.10); + --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25); +} + +:root[data-theme='starrynight'].dark { + --background: oklch(0.2204 0.0198 275.8439); + --foreground: oklch(0.9366 0.0129 266.6974); + --card: oklch(0.2703 0.0407 281.3036); + --card-foreground: oklch(0.9366 0.0129 266.6974); + --popover: oklch(0.2703 0.0407 281.3036); + --popover-foreground: oklch(0.9097 0.1440 95.1120); + --primary: oklch(0.4815 0.1178 263.3758); + --primary-foreground: oklch(0.9097 0.1440 95.1120); + --secondary: oklch(0.9097 0.1440 95.1120); + --secondary-foreground: oklch(0.2703 0.0407 281.3036); + --muted: oklch(0.2424 0.0324 281.0890); + --muted-foreground: oklch(0.6243 0.0412 262.0375); + --accent: oklch(0.8469 0.0524 264.7751); + --accent-foreground: oklch(0.2204 0.0198 275.8439); + --destructive: oklch(0.5280 0.1200 357.1130); + --destructive-foreground: oklch(0.9097 0.1440 95.1120); + --border: oklch(0.3072 0.0287 281.7681); + --input: oklch(0.4815 0.1178 263.3758); + --ring: oklch(0.9097 0.1440 95.1120); + --chart-1: oklch(0.4815 0.1178 263.3758); + --chart-2: oklch(0.9097 0.1440 95.1120); + --chart-3: oklch(0.6896 0.0714 234.0387); + --chart-4: oklch(0.6243 0.0412 262.0375); + --chart-5: oklch(0.5280 0.1200 357.1130); + --sidebar: oklch(0.2703 0.0407 281.3036); + --sidebar-foreground: oklch(0.9366 0.0129 266.6974); + --sidebar-primary: oklch(0.4815 0.1178 263.3758); + --sidebar-primary-foreground: oklch(0.9097 0.1440 95.1120); + --sidebar-accent: oklch(0.9097 0.1440 95.1120); + --sidebar-accent-foreground: oklch(0.2703 0.0407 281.3036); + --sidebar-border: oklch(0.3072 0.0287 281.7681); + --sidebar-ring: oklch(0.9097 0.1440 95.1120); +} diff --git a/src/components/layout/PreferencesRow.vue b/src/components/layout/PreferencesRow.vue index 0acfca3..d9a6a98 100644 --- a/src/components/layout/PreferencesRow.vue +++ b/src/components/layout/PreferencesRow.vue @@ -2,9 +2,9 @@ import { computed } from 'vue' import { useI18n } from 'vue-i18n' import { toast } from 'vue-sonner' -import { Sun, Moon, Monitor, Globe, Coins } from 'lucide-vue-next' +import { Sun, Moon, Monitor, Globe, Coins, Palette } from 'lucide-vue-next' import { ChevronRight } from 'lucide-vue-next' -import { useTheme } from '@/components/theme-provider' +import { useTheme, PALETTES, type Palette as PaletteName } from '@/components/theme-provider' import { useLocale } from '@/composables/useLocale' import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, @@ -14,14 +14,14 @@ import { interface Props { /** 'row' = three icon-stacked buttons side-by-side (used by Hub bottom nav). - * 'list' = three full-width list rows (used inside the profile sheet). */ + * 'list' = full-width list rows (used inside the profile sheet). */ layout?: 'row' | 'list' } const props = withDefaults(defineProps(), { layout: 'row' }) const { t } = useI18n() -const { theme, setTheme, currentTheme } = useTheme() +const { theme, setTheme, currentTheme, palette, setPalette } = useTheme() const { currentLocale, locales, setLocale } = useLocale() const ThemeIcon = computed(() => (currentTheme.value === 'dark' ? Moon : Sun)) @@ -29,6 +29,10 @@ const currentLocaleLabel = computed( () => locales.value.find(l => l.code === currentLocale.value)?.name ?? currentLocale.value ) +const paletteLabel = (p: PaletteName) => + t(`common.nav.palette_${p}`) +const currentPaletteLabel = computed(() => paletteLabel(palette.value)) + // Currency picker is intentionally still a placeholder until #45 lands — // the row UX is what we're building here, not the underlying preference. function notImplemented() { @@ -114,6 +118,31 @@ function notImplemented() { + + + + + + + {{ t('common.nav.colorScheme') }} + + + + {{ paletteLabel(p) }} + + + + + diff --git a/src/components/theme-provider/index.ts b/src/components/theme-provider/index.ts index d125042..36b9079 100644 --- a/src/components/theme-provider/index.ts +++ b/src/components/theme-provider/index.ts @@ -2,9 +2,31 @@ import { computed, onMounted, ref, watch } from 'vue' type Theme = 'dark' | 'light' | 'system' +export type Palette = + | 'catppuccin' + | 'countrysidecastle' + | 'darkmatter' + | 'emeraldforest' + | 'lightgreen' + | 'neobrut' + | 'starrynight' + +export const PALETTES: Palette[] = [ + 'catppuccin', + 'countrysidecastle', + 'darkmatter', + 'emeraldforest', + 'lightgreen', + 'neobrut', + 'starrynight', +] + +const DEFAULT_PALETTE: Palette = 'catppuccin' + const useTheme = () => { const theme = ref('dark') const systemTheme = ref<'dark' | 'light'>('light') + const palette = ref(DEFAULT_PALETTE) const updateSystemTheme = () => { systemTheme.value = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' @@ -22,32 +44,57 @@ const useTheme = () => { } } + const applyPalette = () => { + if (palette.value === DEFAULT_PALETTE) { + document.documentElement.removeAttribute('data-theme') + } else { + document.documentElement.setAttribute('data-theme', palette.value) + } + } + onMounted(() => { const stored = localStorage.getItem('ui-theme') if (stored && (stored === 'dark' || stored === 'light' || stored === 'system')) { theme.value = stored as Theme } + const storedPalette = localStorage.getItem('ui-palette') + if (storedPalette && (PALETTES as string[]).includes(storedPalette)) { + palette.value = storedPalette as Palette + } + updateSystemTheme() window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', updateSystemTheme) applyTheme() + applyPalette() }) watch(currentTheme, () => { applyTheme() }) + watch(palette, () => { + applyPalette() + }) + const setTheme = (newTheme: Theme) => { theme.value = newTheme localStorage.setItem('ui-theme', newTheme) } + const setPalette = (newPalette: Palette) => { + palette.value = newPalette + localStorage.setItem('ui-palette', newPalette) + } + return { theme, setTheme, systemTheme, currentTheme, + palette, + setPalette, } } -export { useTheme } +export { useTheme } diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts index 3d0bcfa..19e4ac7 100644 --- a/src/i18n/locales/en.ts +++ b/src/i18n/locales/en.ts @@ -29,6 +29,14 @@ const messages: LocaleMessages = { themeLight: 'Light', themeDark: 'Dark', themeSystem: 'System', + colorScheme: 'Color scheme', + palette_catppuccin: 'Catppuccin', + palette_countrysidecastle: 'Countryside Castle', + palette_darkmatter: 'Dark Matter', + palette_emeraldforest: 'Emerald Forest', + palette_lightgreen: 'Light Green', + palette_neobrut: 'Neo Brutalist', + palette_starrynight: 'Starry Night', language: 'Language', currency: 'Currency', currencyComingSoon: 'Currency picker — coming soon', diff --git a/src/i18n/locales/es.ts b/src/i18n/locales/es.ts index 5da3f51..bd22a88 100644 --- a/src/i18n/locales/es.ts +++ b/src/i18n/locales/es.ts @@ -29,6 +29,14 @@ const messages: LocaleMessages = { themeLight: 'Claro', themeDark: 'Oscuro', themeSystem: 'Sistema', + colorScheme: 'Paleta', + palette_catppuccin: 'Catppuccin', + palette_countrysidecastle: 'Castillo Campestre', + palette_darkmatter: 'Dark Matter', + palette_emeraldforest: 'Bosque Esmeralda', + palette_lightgreen: 'Verde Claro', + palette_neobrut: 'Neo Brutalista', + palette_starrynight: 'Noche Estrellada', language: 'Idioma', currency: 'Moneda', currencyComingSoon: 'Selector de moneda — próximamente', diff --git a/src/i18n/locales/fr.ts b/src/i18n/locales/fr.ts index 96d002d..a6ece4d 100644 --- a/src/i18n/locales/fr.ts +++ b/src/i18n/locales/fr.ts @@ -29,6 +29,14 @@ const messages: LocaleMessages = { themeLight: 'Clair', themeDark: 'Sombre', themeSystem: 'Système', + colorScheme: 'Palette', + palette_catppuccin: 'Catppuccin', + palette_countrysidecastle: 'Château Champêtre', + palette_darkmatter: 'Dark Matter', + palette_emeraldforest: 'Forêt d\'Émeraude', + palette_lightgreen: 'Vert Clair', + palette_neobrut: 'Néo-Brutaliste', + palette_starrynight: 'Nuit Étoilée', language: 'Langue', currency: 'Devise', currencyComingSoon: 'Sélecteur de devise — bientôt disponible', diff --git a/src/i18n/types.ts b/src/i18n/types.ts index 77585f0..1f4e1b9 100644 --- a/src/i18n/types.ts +++ b/src/i18n/types.ts @@ -28,6 +28,14 @@ export interface LocaleMessages { themeLight: string themeDark: string themeSystem: string + colorScheme: string + palette_catppuccin: string + palette_countrysidecastle: string + palette_darkmatter: string + palette_emeraldforest: string + palette_lightgreen: string + palette_neobrut: string + palette_starrynight: string language: string currency: string currencyComingSoon: string