diff --git a/components.json b/components.json index c8f04c6..c5d91b4 100644 --- a/components.json +++ b/components.json @@ -1,7 +1,7 @@ { "$schema": "https://shadcn-svelte.com/schema.json", "tailwind": { - "css": "src/routes/layout.css", + "css": "src/app.css", "baseColor": "slate" }, "aliases": { diff --git a/src/app.css b/src/app.css new file mode 100644 index 0000000..4d971d0 --- /dev/null +++ b/src/app.css @@ -0,0 +1,241 @@ +@import 'tailwindcss'; + +@import 'tw-animate-css'; + +@custom-variant dark (&:is(.dark *, .frappe *, .macchiato *, .mocha *)); + +:root { + --radius: 0.65rem; + --background: oklch(1 0 0); + --foreground: oklch(0.141 0.005 285.823); + --card: oklch(1 0 0); + --card-foreground: oklch(0.141 0.005 285.823); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.141 0.005 285.823); + --primary: oklch(0.606 0.25 292.717); + --primary-foreground: oklch(0.969 0.016 293.756); + --secondary: oklch(0.967 0.001 286.375); + --secondary-foreground: oklch(0.21 0.006 285.885); + --muted: oklch(0.967 0.001 286.375); + --muted-foreground: oklch(0.552 0.016 285.938); + --accent: oklch(0.967 0.001 286.375); + --accent-foreground: oklch(0.21 0.006 285.885); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.92 0.004 286.32); + --input: oklch(0.92 0.004 286.32); + --ring: oklch(0.606 0.25 292.717); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.141 0.005 285.823); + --sidebar-primary: oklch(0.606 0.25 292.717); + --sidebar-primary-foreground: oklch(0.969 0.016 293.756); + --sidebar-accent: oklch(0.967 0.001 286.375); + --sidebar-accent-foreground: oklch(0.21 0.006 285.885); + --sidebar-border: oklch(0.92 0.004 286.32); + --sidebar-ring: oklch(0.606 0.25 292.717); +} + +.dark { + --background: oklch(0.141 0.005 285.823); + --foreground: oklch(0.985 0 0); + --card: oklch(0.21 0.006 285.885); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.21 0.006 285.885); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.541 0.281 293.009); + --primary-foreground: oklch(0.969 0.016 293.756); + --secondary: oklch(0.274 0.006 286.033); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.274 0.006 286.033); + --muted-foreground: oklch(0.705 0.015 286.067); + --accent: oklch(0.274 0.006 286.033); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.541 0.281 293.009); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.21 0.006 285.885); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.541 0.281 293.009); + --sidebar-primary-foreground: oklch(0.969 0.016 293.756); + --sidebar-accent: oklch(0.274 0.006 286.033); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.541 0.281 293.009); +} + +.latte { + --background: oklch(0.96 0.01 99.45); + --foreground: oklch(0.42 0.02 271.18); + --card: oklch(0.94 0.01 99.45); + --card-foreground: oklch(0.42 0.02 271.18); + --popover: oklch(0.94 0.01 99.45); + --popover-foreground: oklch(0.42 0.02 271.18); + --primary: oklch(0.69 0.15 303.32); + --primary-foreground: oklch(0.96 0.01 99.45); + --secondary: oklch(0.91 0.02 282.74); + --secondary-foreground: oklch(0.42 0.02 271.18); + --muted: oklch(0.91 0.02 282.74); + --muted-foreground: oklch(0.56 0.02 273.46); + --accent: oklch(0.91 0.02 282.74); + --accent-foreground: oklch(0.42 0.02 271.18); + --destructive: oklch(0.65 0.16 16.23); + --destructive-foreground: oklch(0.96 0.01 99.45); + --border: oklch(0.88 0.02 277.33); + --input: oklch(0.88 0.02 277.33); + --ring: oklch(0.69 0.15 303.32); + --sidebar: oklch(0.98 0.01 99.45); + --sidebar-foreground: var(--foreground); + --sidebar-primary: var(--primary); + --sidebar-primary-foreground: var(--primary-foreground); + --sidebar-accent: var(--accent); + --sidebar-accent-foreground: var(--accent-foreground); + --sidebar-border: var(--border); + --sidebar-ring: var(--ring); +} + +.frappe { + --background: oklch(0.31 0.02 271.18); + --foreground: oklch(0.88 0.01 277.33); + --card: oklch(0.28 0.02 273.46); + --card-foreground: oklch(0.88 0.01 277.33); + --popover: oklch(0.28 0.02 273.46); + --popover-foreground: oklch(0.88 0.01 277.33); + --primary: oklch(0.79 0.11 306.98); + --primary-foreground: oklch(0.31 0.02 271.18); + --secondary: oklch(0.42 0.02 271.18); + --secondary-foreground: oklch(0.88 0.01 277.33); + --muted: oklch(0.42 0.02 271.18); + --muted-foreground: oklch(0.69 0.02 279.88); + --accent: oklch(0.42 0.02 271.18); + --accent-foreground: oklch(0.88 0.01 277.33); + --destructive: oklch(0.76 0.11 16.56); + --destructive-foreground: oklch(0.31 0.02 271.18); + --border: oklch(0.49 0.02 275.92); + --input: oklch(0.49 0.02 275.92); + --ring: oklch(0.79 0.11 306.98); + --sidebar: var(--card); + --sidebar-foreground: var(--foreground); + --sidebar-primary: var(--primary); + --sidebar-primary-foreground: var(--primary-foreground); + --sidebar-accent: var(--accent); + --sidebar-accent-foreground: var(--accent-foreground); + --sidebar-border: var(--border); + --sidebar-ring: var(--ring); +} + +.macchiato { + --background: oklch(0.26 0.02 273.46); + --foreground: oklch(0.87 0.01 279.88); + --card: oklch(0.23 0.02 275.92); + --card-foreground: oklch(0.87 0.01 279.88); + --popover: oklch(0.23 0.02 275.92); + --popover-foreground: oklch(0.87 0.01 279.88); + --primary: oklch(0.78 0.11 306.98); + --primary-foreground: oklch(0.26 0.02 273.46); + --secondary: oklch(0.38 0.02 273.46); + --secondary-foreground: oklch(0.87 0.01 279.88); + --muted: oklch(0.38 0.02 273.46); + --muted-foreground: oklch(0.67 0.02 282.74); + --accent: oklch(0.38 0.02 273.46); + --accent-foreground: oklch(0.87 0.01 279.88); + --destructive: oklch(0.75 0.11 16.56); + --destructive-foreground: oklch(0.26 0.02 273.46); + --border: oklch(0.47 0.02 278.4); + --input: oklch(0.47 0.02 278.4); + --ring: oklch(0.78 0.11 306.98); + --sidebar: var(--card); + --sidebar-foreground: var(--foreground); + --sidebar-primary: var(--primary); + --sidebar-primary-foreground: var(--primary-foreground); + --sidebar-accent: var(--accent); + --sidebar-accent-foreground: var(--accent-foreground); + --sidebar-border: var(--border); + --sidebar-ring: var(--ring); +} + +.mocha { + --background: oklch(0.21 0.02 275.92); + --foreground: oklch(0.86 0.01 282.74); + --card: oklch(0.18 0.02 278.4); + --card-foreground: oklch(0.86 0.01 282.74); + --popover: oklch(0.18 0.02 278.4); + --popover-foreground: oklch(0.86 0.01 282.74); + --primary: oklch(0.78 0.11 306.98); + --primary-foreground: oklch(0.21 0.02 275.92); + --secondary: oklch(0.35 0.02 275.92); + --secondary-foreground: oklch(0.86 0.01 282.74); + --muted: oklch(0.35 0.02 275.92); + --muted-foreground: oklch(0.65 0.02 285.82); + --accent: oklch(0.35 0.02 275.92); + --accent-foreground: oklch(0.86 0.01 282.74); + --destructive: oklch(0.74 0.11 16.56); + --destructive-foreground: oklch(0.21 0.02 275.92); + --border: oklch(0.44 0.02 281.25); + --input: oklch(0.44 0.02 281.25); + --ring: oklch(0.78 0.11 306.98); + --sidebar: var(--card); + --sidebar-foreground: var(--foreground); + --sidebar-primary: var(--primary); + --sidebar-primary-foreground: var(--primary-foreground); + --sidebar-accent: var(--accent); + --sidebar-accent-foreground: var(--accent-foreground); + --sidebar-border: var(--border); + --sidebar-ring: var(--ring); +} + +@theme inline { + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --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-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); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/src/lib/theme-switcher.ts b/src/lib/theme-switcher.ts new file mode 100644 index 0000000..ab0cf1b --- /dev/null +++ b/src/lib/theme-switcher.ts @@ -0,0 +1,45 @@ +import { writable } from 'svelte/store'; +import { browser } from '$app/environment'; + +export const themes = ['light', 'dark', 'latte', 'frappe', 'macchiato', 'mocha'] as const; +type Theme = (typeof themes)[number]; + +const createThemeStore = () => { + const { subscribe, set } = writable('light'); + + function applyTheme(theme: Theme) { + if (browser) { + document.documentElement.classList.remove(...themes); + document.documentElement.classList.add(theme); + localStorage.setItem('theme', theme); + set(theme); + } + } + + function initializeTheme() { + if (browser) { + const storedTheme = localStorage.getItem('theme') as Theme | null; + const systemTheme: Theme = window.matchMedia('(prefers-color-scheme: dark)').matches + ? 'dark' + : 'light'; + const initialTheme = storedTheme ?? systemTheme; + applyTheme(initialTheme); + } + } + + function resetToSystem() { + if (browser) { + localStorage.removeItem('theme'); + initializeTheme(); + } + } + + return { + subscribe, + applyTheme, + initializeTheme, + resetToSystem + }; +}; + +export const theme = createThemeStore(); diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index c6ab190..1677837 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,7 +1,13 @@ {@render children()} diff --git a/src/routes/layout.css b/src/routes/layout.css deleted file mode 100644 index e48f5f0..0000000 --- a/src/routes/layout.css +++ /dev/null @@ -1,121 +0,0 @@ -@import "tailwindcss"; - -@import "tw-animate-css"; - -@custom-variant dark (&:is(.dark *)); - -:root { - --radius: 0.625rem; - --background: oklch(1 0 0); - --foreground: oklch(0.129 0.042 264.695); - --card: oklch(1 0 0); - --card-foreground: oklch(0.129 0.042 264.695); - --popover: oklch(1 0 0); - --popover-foreground: oklch(0.129 0.042 264.695); - --primary: oklch(0.208 0.042 265.755); - --primary-foreground: oklch(0.984 0.003 247.858); - --secondary: oklch(0.968 0.007 247.896); - --secondary-foreground: oklch(0.208 0.042 265.755); - --muted: oklch(0.968 0.007 247.896); - --muted-foreground: oklch(0.554 0.046 257.417); - --accent: oklch(0.968 0.007 247.896); - --accent-foreground: oklch(0.208 0.042 265.755); - --destructive: oklch(0.577 0.245 27.325); - --border: oklch(0.929 0.013 255.508); - --input: oklch(0.929 0.013 255.508); - --ring: oklch(0.704 0.04 256.788); - --chart-1: oklch(0.646 0.222 41.116); - --chart-2: oklch(0.6 0.118 184.704); - --chart-3: oklch(0.398 0.07 227.392); - --chart-4: oklch(0.828 0.189 84.429); - --chart-5: oklch(0.769 0.188 70.08); - --sidebar: oklch(0.984 0.003 247.858); - --sidebar-foreground: oklch(0.129 0.042 264.695); - --sidebar-primary: oklch(0.208 0.042 265.755); - --sidebar-primary-foreground: oklch(0.984 0.003 247.858); - --sidebar-accent: oklch(0.968 0.007 247.896); - --sidebar-accent-foreground: oklch(0.208 0.042 265.755); - --sidebar-border: oklch(0.929 0.013 255.508); - --sidebar-ring: oklch(0.704 0.04 256.788); -} - -.dark { - --background: oklch(0.129 0.042 264.695); - --foreground: oklch(0.984 0.003 247.858); - --card: oklch(0.208 0.042 265.755); - --card-foreground: oklch(0.984 0.003 247.858); - --popover: oklch(0.208 0.042 265.755); - --popover-foreground: oklch(0.984 0.003 247.858); - --primary: oklch(0.929 0.013 255.508); - --primary-foreground: oklch(0.208 0.042 265.755); - --secondary: oklch(0.279 0.041 260.031); - --secondary-foreground: oklch(0.984 0.003 247.858); - --muted: oklch(0.279 0.041 260.031); - --muted-foreground: oklch(0.704 0.04 256.788); - --accent: oklch(0.279 0.041 260.031); - --accent-foreground: oklch(0.984 0.003 247.858); - --destructive: oklch(0.704 0.191 22.216); - --border: oklch(1 0 0 / 10%); - --input: oklch(1 0 0 / 15%); - --ring: oklch(0.551 0.027 264.364); - --chart-1: oklch(0.488 0.243 264.376); - --chart-2: oklch(0.696 0.17 162.48); - --chart-3: oklch(0.769 0.188 70.08); - --chart-4: oklch(0.627 0.265 303.9); - --chart-5: oklch(0.645 0.246 16.439); - --sidebar: oklch(0.208 0.042 265.755); - --sidebar-foreground: oklch(0.984 0.003 247.858); - --sidebar-primary: oklch(0.488 0.243 264.376); - --sidebar-primary-foreground: oklch(0.984 0.003 247.858); - --sidebar-accent: oklch(0.279 0.041 260.031); - --sidebar-accent-foreground: oklch(0.984 0.003 247.858); - --sidebar-border: oklch(1 0 0 / 10%); - --sidebar-ring: oklch(0.551 0.027 264.364); -} - -@theme inline { - --radius-sm: calc(var(--radius) - 4px); - --radius-md: calc(var(--radius) - 2px); - --radius-lg: var(--radius); - --radius-xl: calc(var(--radius) + 4px); - --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-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); -} - -@layer base { - * { - @apply border-border outline-ring/50; - } - body { - @apply bg-background text-foreground; - } -} \ No newline at end of file