Merge pull request 'feat(webapp): add color scheme switcher with 7 palettes' (#90) from feat/color-scheme-switcher into dev

Reviewed-on: #90
This commit is contained in:
padreug 2026-06-04 09:51:43 +00:00
commit ce2488941f
14 changed files with 775 additions and 205 deletions

View file

@ -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="<name>"] 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;
}

View file

@ -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 */ */
/* } */

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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<Props>(), { 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() {
</DropdownMenuContent>
</DropdownMenu>
<!-- Color scheme (palette) -->
<DropdownMenu>
<DropdownMenuTrigger as-child>
<button class="flex items-center justify-between gap-3 px-3 py-3 hover:bg-accent rounded-md transition-colors text-left">
<div class="flex items-center gap-3">
<Palette class="w-5 h-5 text-muted-foreground" />
<span class="text-sm font-medium">{{ t('common.nav.colorScheme') }}</span>
</div>
<div class="flex items-center gap-1 text-sm text-muted-foreground">
<span>{{ currentPaletteLabel }}</span>
<ChevronRight class="w-4 h-4" />
</div>
</button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" class="w-48">
<DropdownMenuLabel>{{ t('common.nav.colorScheme') }}</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuRadioGroup :model-value="palette" @update:model-value="(v) => v != null && setPalette(v as PaletteName)">
<DropdownMenuRadioItem v-for="p in PALETTES" :key="p" :value="p">
{{ paletteLabel(p) }}
</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
<!-- Language -->
<DropdownMenu>
<DropdownMenuTrigger as-child>

View file

@ -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<Theme>('dark')
const systemTheme = ref<'dark' | 'light'>('light')
const palette = ref<Palette>(DEFAULT_PALETTE)
const updateSystemTheme = () => {
systemTheme.value = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
@ -22,31 +44,56 @@ 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,
}
}

View file

@ -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',

View file

@ -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',

View file

@ -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',

View file

@ -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