diff --git a/client/index.html b/client/index.html
index 16ee1c9..08b5fa8 100644
--- a/client/index.html
+++ b/client/index.html
@@ -6,7 +6,7 @@
GoAway
-
+
diff --git a/client/src/app/theme/theme-context.tsx b/client/src/app/theme/theme-context.tsx
new file mode 100644
index 0000000..cdc30a8
--- /dev/null
+++ b/client/src/app/theme/theme-context.tsx
@@ -0,0 +1,88 @@
+import { createContext } from "react";
+import {
+ MoonIcon,
+ SunIcon,
+ DropIcon,
+ TreeIcon,
+ SparkleIcon,
+ FlowerIcon,
+ MonitorIcon,
+ BookOpenIcon,
+ CloudIcon,
+ FireIcon,
+ GameControllerIcon,
+ LeafIcon,
+ LightningIcon,
+ MoonStarsIcon,
+ PaintBrushIcon,
+ PaletteIcon,
+ SnowflakeIcon,
+ WavesIcon
+} from "@phosphor-icons/react";
+import { MountainIcon } from "lucide-react";
+
+export const themes = [
+ "system",
+ "light",
+ "dark",
+ "blue",
+ "sunset",
+ "forest",
+ "purple",
+ "rose",
+ "cyberpunk",
+ "cotton-candy",
+ "midnight",
+ "amber",
+ "emerald",
+ "slate",
+ "ocean",
+ "crimson",
+ "nord",
+ "vintage",
+ "neon",
+ "dusk",
+ "pastel"
+] as const;
+
+export const themesConfig: Record<
+ Theme,
+ { label: string; icon: React.ComponentType<{ className?: string }> }
+> = {
+ light: { label: "Light", icon: SunIcon },
+ dark: { label: "Dark", icon: MoonIcon },
+ blue: { label: "Blue Ocean", icon: DropIcon },
+ sunset: { label: "Sunset", icon: SunIcon },
+ forest: { label: "Forest", icon: TreeIcon },
+ purple: { label: "Purple Dream", icon: SparkleIcon },
+ rose: { label: "Rose", icon: FlowerIcon },
+ system: { label: "System", icon: MonitorIcon },
+ cyberpunk: { label: "Cyberpunk", icon: GameControllerIcon },
+ "cotton-candy": { label: "Cotton Candy", icon: CloudIcon },
+ midnight: { label: "Midnight", icon: MoonStarsIcon },
+ amber: { label: "Amber", icon: SunIcon },
+ emerald: { label: "Emerald", icon: LeafIcon },
+ slate: { label: "Slate", icon: PaletteIcon },
+ ocean: { label: "Ocean", icon: WavesIcon },
+ crimson: { label: "Crimson", icon: FireIcon },
+ nord: { label: "Nord", icon: SnowflakeIcon },
+ vintage: { label: "Vintage", icon: BookOpenIcon },
+ neon: { label: "Neon", icon: LightningIcon },
+ dusk: { label: "Dusk", icon: MountainIcon },
+ pastel: { label: "Pastel", icon: PaintBrushIcon }
+};
+
+export type Theme = (typeof themes)[number];
+
+export type ThemeProviderState = {
+ theme: Theme;
+ setTheme: (theme: Theme) => void;
+};
+
+export const initialState: ThemeProviderState = {
+ theme: "system",
+ setTheme: () => null
+};
+
+export const ThemeProviderContext =
+ createContext(initialState);
diff --git a/client/src/components/theme-provider.tsx b/client/src/app/theme/theme-provider.tsx
similarity index 84%
rename from client/src/components/theme-provider.tsx
rename to client/src/app/theme/theme-provider.tsx
index 82359fb..6139486 100644
--- a/client/src/components/theme-provider.tsx
+++ b/client/src/app/theme/theme-provider.tsx
@@ -2,7 +2,8 @@ import React, { useEffect, useState } from "react";
import {
ThemeProviderContext,
ThemeProviderState,
- Theme
+ Theme,
+ themes
} from "./theme-context";
type ThemeProviderProps = {
@@ -24,18 +25,20 @@ export function ThemeProvider({
useEffect(() => {
const root = window.document.documentElement;
- root.classList.remove("light", "dark");
+ for (const theme of themes) {
+ root.classList.remove(`theme-${theme}`);
+ }
if (theme === "system") {
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
.matches
? "dark"
: "light";
- root.classList.add(systemTheme);
+ root.classList.add(`theme-${systemTheme}`);
return;
}
- root.classList.add(theme);
+ root.classList.add(`theme-${theme}`);
}, [theme]);
const value: ThemeProviderState = {
diff --git a/client/src/app/theme/toggle-theme.tsx b/client/src/app/theme/toggle-theme.tsx
new file mode 100644
index 0000000..d914e33
--- /dev/null
+++ b/client/src/app/theme/toggle-theme.tsx
@@ -0,0 +1,50 @@
+import { Button } from "@/components/ui/button";
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger
+} from "@/components/ui/dropdown-menu";
+import { SunIcon } from "@phosphor-icons/react";
+import { themes, themesConfig } from "./theme-context";
+import { useTheme } from "./use-theme";
+
+export function ModeToggle() {
+ const { theme, setTheme } = useTheme();
+ const CurrentIcon = themesConfig[theme]?.icon || SunIcon;
+
+ return (
+
+
+
+
+
+ {themes.map((themeName) => {
+ const { label, icon: Icon } = themesConfig[themeName];
+ const isActive = theme === themeName;
+
+ return (
+ setTheme(themeName)}
+ className="cursor-pointer flex items-center gap-2"
+ >
+
+
+ {label}
+
+ {isActive && ✓}
+
+ );
+ })}
+
+
+ );
+}
diff --git a/client/src/components/use-theme.ts b/client/src/app/theme/use-theme.ts
similarity index 100%
rename from client/src/components/use-theme.ts
rename to client/src/app/theme/use-theme.ts
diff --git a/client/src/components/site-header.tsx b/client/src/components/site-header.tsx
index 679ea09..81aa6ed 100644
--- a/client/src/components/site-header.tsx
+++ b/client/src/components/site-header.tsx
@@ -3,7 +3,7 @@ import { SidebarTrigger } from "@/components/ui/sidebar";
import { useLocation } from "react-router-dom";
import { NavActions } from "./nav-actions";
import Notifications from "./notifications";
-import { ModeToggle } from "./theme-toggle";
+import { ModeToggle } from "@/app/theme/toggle-theme";
interface PageInfo {
title: string;
diff --git a/client/src/components/theme-context.tsx b/client/src/components/theme-context.tsx
deleted file mode 100644
index e0e71ac..0000000
--- a/client/src/components/theme-context.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { createContext } from "react";
-
-export type Theme = "dark" | "light" | "system";
-
-export type ThemeProviderState = {
- theme: Theme;
- setTheme: (theme: Theme) => void;
-};
-
-export const initialState: ThemeProviderState = {
- theme: "system",
- setTheme: () => null
-};
-
-export const ThemeProviderContext =
- createContext(initialState);
diff --git a/client/src/components/theme-toggle.tsx b/client/src/components/theme-toggle.tsx
deleted file mode 100644
index 33c995e..0000000
--- a/client/src/components/theme-toggle.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { Button } from "@/components/ui/button";
-import { MoonIcon, SunIcon } from "@phosphor-icons/react";
-import { useTheme } from "./use-theme";
-
-export function ModeToggle() {
- const { theme, setTheme } = useTheme();
-
- const toggleTheme = () => {
- setTheme(theme === "dark" ? "light" : "dark");
- };
-
- return (
-
- );
-}
diff --git a/client/src/index.css b/client/src/index.css
index 02536d5..4bad98b 100644
--- a/client/src/index.css
+++ b/client/src/index.css
@@ -1,10 +1,14 @@
@import "tailwindcss";
@import "tw-animate-css";
-@custom-variant dark (&:is(.dark *));
+@custom-variant dark (&:is(.theme-dark *));
:root {
--radius: 0.65rem;
+}
+
+:root,
+.theme-light {
--background: oklch(1 0 0);
--foreground: oklch(0.141 0.005 285.823);
--card: oklch(1 0 0);
@@ -38,7 +42,7 @@
--sidebar-ring: oklch(0.723 0.219 149.579);
}
-.dark {
+.theme-dark {
--background: oklch(0.141 0.005 285.823);
--foreground: oklch(0.985 0 0);
--card: oklch(0.21 0.006 285.885);
@@ -72,6 +76,618 @@
--sidebar-ring: oklch(0.527 0.154 150.069);
}
+.theme-blue {
+ --background: oklch(0.15 0.02 240);
+ --foreground: oklch(0.95 0.01 240);
+ --card: oklch(0.2 0.03 240);
+ --card-foreground: oklch(0.95 0.01 240);
+ --popover: oklch(0.2 0.03 240);
+ --popover-foreground: oklch(0.95 0.01 240);
+ --primary: oklch(0.6 0.2 220);
+ --primary-foreground: oklch(0.98 0.01 220);
+ --secondary: oklch(0.3 0.04 240);
+ --secondary-foreground: oklch(0.95 0.01 240);
+ --muted: oklch(0.3 0.04 240);
+ --muted-foreground: oklch(0.7 0.05 240);
+ --accent: oklch(0.35 0.08 200);
+ --accent-foreground: oklch(0.95 0.01 200);
+ --destructive: oklch(0.6 0.25 29.223);
+ --border: oklch(0.3 0.05 240);
+ --input: oklch(0.25 0.04 240);
+ --ring: oklch(0.6 0.2 220);
+ --chart-1: oklch(0.6 0.2 220);
+ --chart-2: oklch(0.65 0.18 200);
+ --chart-3: oklch(0.7 0.15 180);
+ --chart-4: oklch(0.55 0.22 260);
+ --chart-5: oklch(0.5 0.2 240);
+ --sidebar: oklch(0.18 0.025 240);
+ --sidebar-foreground: oklch(0.95 0.01 240);
+ --sidebar-primary: oklch(0.6 0.2 220);
+ --sidebar-primary-foreground: oklch(0.98 0.01 220);
+ --sidebar-accent: oklch(0.3 0.04 240);
+ --sidebar-accent-foreground: oklch(0.95 0.01 240);
+ --sidebar-border: oklch(0.3 0.05 240);
+ --sidebar-ring: oklch(0.6 0.2 220);
+}
+
+.theme-sunset {
+ --background: oklch(0.95 0.03 40);
+ --foreground: oklch(0.2 0.04 30);
+ --card: oklch(0.98 0.02 40);
+ --card-foreground: oklch(0.2 0.04 30);
+ --popover: oklch(0.98 0.02 40);
+ --popover-foreground: oklch(0.2 0.04 30);
+ --primary: oklch(0.65 0.22 30);
+ --primary-foreground: oklch(0.98 0.01 30);
+ --secondary: oklch(0.88 0.05 50);
+ --secondary-foreground: oklch(0.25 0.04 30);
+ --muted: oklch(0.88 0.05 50);
+ --muted-foreground: oklch(0.5 0.08 35);
+ --accent: oklch(0.75 0.18 20);
+ --accent-foreground: oklch(0.98 0.01 20);
+ --destructive: oklch(0.62 0.26 29.223);
+ --border: oklch(0.85 0.06 45);
+ --input: oklch(0.9 0.04 40);
+ --ring: oklch(0.65 0.22 30);
+ --chart-1: oklch(0.65 0.22 30);
+ --chart-2: oklch(0.7 0.2 15);
+ --chart-3: oklch(0.75 0.18 50);
+ --chart-4: oklch(0.6 0.24 350);
+ --chart-5: oklch(0.68 0.2 60);
+ --sidebar: oklch(0.97 0.02 40);
+ --sidebar-foreground: oklch(0.2 0.04 30);
+ --sidebar-primary: oklch(0.65 0.22 30);
+ --sidebar-primary-foreground: oklch(0.98 0.01 30);
+ --sidebar-accent: oklch(0.88 0.05 50);
+ --sidebar-accent-foreground: oklch(0.25 0.04 30);
+ --sidebar-border: oklch(0.85 0.06 45);
+ --sidebar-ring: oklch(0.65 0.22 30);
+}
+
+.theme-forest {
+ --background: oklch(0.16 0.03 140);
+ --foreground: oklch(0.92 0.02 140);
+ --card: oklch(0.22 0.04 140);
+ --card-foreground: oklch(0.92 0.02 140);
+ --popover: oklch(0.22 0.04 140);
+ --popover-foreground: oklch(0.92 0.02 140);
+ --primary: oklch(0.6 0.18 150);
+ --primary-foreground: oklch(0.98 0.01 150);
+ --secondary: oklch(0.3 0.05 140);
+ --secondary-foreground: oklch(0.92 0.02 140);
+ --muted: oklch(0.3 0.05 140);
+ --muted-foreground: oklch(0.65 0.08 140);
+ --accent: oklch(0.55 0.15 120);
+ --accent-foreground: oklch(0.98 0.01 120);
+ --destructive: oklch(0.62 0.26 29.223);
+ --border: oklch(0.3 0.06 140);
+ --input: oklch(0.25 0.05 140);
+ --ring: oklch(0.6 0.18 150);
+ --chart-1: oklch(0.6 0.18 150);
+ --chart-2: oklch(0.65 0.16 130);
+ --chart-3: oklch(0.7 0.14 160);
+ --chart-4: oklch(0.55 0.2 110);
+ --chart-5: oklch(0.58 0.17 170);
+ --sidebar: oklch(0.19 0.035 140);
+ --sidebar-foreground: oklch(0.92 0.02 140);
+ --sidebar-primary: oklch(0.6 0.18 150);
+ --sidebar-primary-foreground: oklch(0.98 0.01 150);
+ --sidebar-accent: oklch(0.3 0.05 140);
+ --sidebar-accent-foreground: oklch(0.92 0.02 140);
+ --sidebar-border: oklch(0.3 0.06 140);
+ --sidebar-ring: oklch(0.6 0.18 150);
+}
+
+.theme-purple {
+ --background: oklch(0.14 0.04 290);
+ --foreground: oklch(0.94 0.02 290);
+ --card: oklch(0.2 0.05 290);
+ --card-foreground: oklch(0.94 0.02 290);
+ --popover: oklch(0.2 0.05 290);
+ --popover-foreground: oklch(0.94 0.02 290);
+ --primary: oklch(0.65 0.22 285);
+ --primary-foreground: oklch(0.98 0.01 285);
+ --secondary: oklch(0.28 0.06 290);
+ --secondary-foreground: oklch(0.94 0.02 290);
+ --muted: oklch(0.28 0.06 290);
+ --muted-foreground: oklch(0.68 0.1 290);
+ --accent: oklch(0.6 0.2 310);
+ --accent-foreground: oklch(0.98 0.01 310);
+ --destructive: oklch(0.62 0.26 29.223);
+ --border: oklch(0.3 0.08 290);
+ --input: oklch(0.25 0.06 290);
+ --ring: oklch(0.65 0.22 285);
+ --chart-1: oklch(0.65 0.22 285);
+ --chart-2: oklch(0.7 0.2 270);
+ --chart-3: oklch(0.6 0.24 300);
+ --chart-4: oklch(0.68 0.21 320);
+ --chart-5: oklch(0.63 0.23 260);
+ --sidebar: oklch(0.17 0.045 290);
+ --sidebar-foreground: oklch(0.94 0.02 290);
+ --sidebar-primary: oklch(0.65 0.22 285);
+ --sidebar-primary-foreground: oklch(0.98 0.01 285);
+ --sidebar-accent: oklch(0.28 0.06 290);
+ --sidebar-accent-foreground: oklch(0.94 0.02 290);
+ --sidebar-border: oklch(0.3 0.08 290);
+ --sidebar-ring: oklch(0.65 0.22 285);
+}
+
+.theme-rose {
+ --background: oklch(0.96 0.02 350);
+ --foreground: oklch(0.2 0.03 350);
+ --card: oklch(0.98 0.015 350);
+ --card-foreground: oklch(0.2 0.03 350);
+ --popover: oklch(0.98 0.015 350);
+ --popover-foreground: oklch(0.2 0.03 350);
+ --primary: oklch(0.62 0.23 350);
+ --primary-foreground: oklch(0.98 0.01 350);
+ --secondary: oklch(0.9 0.04 340);
+ --secondary-foreground: oklch(0.25 0.03 340);
+ --muted: oklch(0.9 0.04 340);
+ --muted-foreground: oklch(0.55 0.1 345);
+ --accent: oklch(0.75 0.18 5);
+ --accent-foreground: oklch(0.98 0.01 5);
+ --destructive: oklch(0.62 0.26 29.223);
+ --border: oklch(0.88 0.05 345);
+ --input: oklch(0.92 0.03 350);
+ --ring: oklch(0.62 0.23 350);
+ --chart-1: oklch(0.62 0.23 350);
+ --chart-2: oklch(0.68 0.2 330);
+ --chart-3: oklch(0.7 0.18 10);
+ --chart-4: oklch(0.65 0.22 320);
+ --chart-5: oklch(0.6 0.24 340);
+ --sidebar: oklch(0.97 0.018 350);
+ --sidebar-foreground: oklch(0.2 0.03 350);
+ --sidebar-primary: oklch(0.62 0.23 350);
+ --sidebar-primary-foreground: oklch(0.98 0.01 350);
+ --sidebar-accent: oklch(0.9 0.04 340);
+ --sidebar-accent-foreground: oklch(0.25 0.03 340);
+ --sidebar-border: oklch(0.88 0.05 345);
+ --sidebar-ring: oklch(0.62 0.23 350);
+}
+
+.theme-cyberpunk {
+ --background: oklch(0.05 0.08 260);
+ --foreground: oklch(0.95 0.2 120);
+ --card: oklch(0.08 0.1 260);
+ --card-foreground: oklch(0.95 0.2 120);
+ --popover: oklch(0.08 0.1 260);
+ --popover-foreground: oklch(0.95 0.2 120);
+ --primary: oklch(0.85 0.25 120);
+ --primary-foreground: oklch(0.05 0.08 260);
+ --secondary: oklch(0.15 0.15 300);
+ --secondary-foreground: oklch(0.95 0.2 120);
+ --muted: oklch(0.15 0.12 260);
+ --muted-foreground: oklch(0.7 0.18 120);
+ --accent: oklch(0.9 0.3 350);
+ --accent-foreground: oklch(0.05 0.08 260);
+ --destructive: oklch(0.85 0.3 30);
+ --border: oklch(0.95 0.2 120 / 0.3);
+ --input: oklch(0.95 0.2 120 / 0.2);
+ --ring: oklch(0.85 0.25 120);
+ --chart-1: oklch(0.85 0.25 120);
+ --chart-2: oklch(0.9 0.3 350);
+ --chart-3: oklch(0.8 0.28 240);
+ --chart-4: oklch(0.75 0.22 180);
+ --chart-5: oklch(0.9 0.25 60);
+ --sidebar: oklch(0.07 0.09 260);
+ --sidebar-foreground: oklch(0.95 0.2 120);
+ --sidebar-primary: oklch(0.85 0.25 120);
+ --sidebar-primary-foreground: oklch(0.05 0.08 260);
+ --sidebar-accent: oklch(0.15 0.15 300);
+ --sidebar-accent-foreground: oklch(0.95 0.2 120);
+ --sidebar-border: oklch(0.95 0.2 120 / 0.3);
+ --sidebar-ring: oklch(0.85 0.25 120);
+}
+
+.theme-cotton-candy {
+ --background: oklch(0.98 0.02 320);
+ --foreground: oklch(0.25 0.08 290);
+ --card: oklch(1 0 0);
+ --card-foreground: oklch(0.25 0.08 290);
+ --popover: oklch(1 0 0);
+ --popover-foreground: oklch(0.25 0.08 290);
+ --primary: oklch(0.75 0.18 320);
+ --primary-foreground: oklch(1 0 0);
+ --secondary: oklch(0.95 0.05 290);
+ --secondary-foreground: oklch(0.3 0.09 290);
+ --muted: oklch(0.95 0.05 290);
+ --muted-foreground: oklch(0.6 0.12 290);
+ --accent: oklch(0.8 0.15 350);
+ --accent-foreground: oklch(0.25 0.08 290);
+ --destructive: oklch(0.85 0.25 30);
+ --border: oklch(0.9 0.08 320);
+ --input: oklch(0.92 0.06 320);
+ --ring: oklch(0.75 0.18 320);
+ --chart-1: oklch(0.75 0.18 320);
+ --chart-2: oklch(0.8 0.15 350);
+ --chart-3: oklch(0.7 0.2 290);
+ --chart-4: oklch(0.85 0.12 260);
+ --chart-5: oklch(0.78 0.16 10);
+ --sidebar: oklch(0.99 0.01 320);
+ --sidebar-foreground: oklch(0.25 0.08 290);
+ --sidebar-primary: oklch(0.75 0.18 320);
+ --sidebar-primary-foreground: oklch(1 0 0);
+ --sidebar-accent: oklch(0.95 0.05 290);
+ --sidebar-accent-foreground: oklch(0.3 0.09 290);
+ --sidebar-border: oklch(0.9 0.08 320);
+ --sidebar-ring: oklch(0.75 0.18 320);
+}
+
+.theme-midnight {
+ --background: oklch(0.05 0.01 250);
+ --foreground: oklch(0.98 0.01 250);
+ --card: oklch(0.1 0.02 250);
+ --card-foreground: oklch(0.98 0.01 250);
+ --popover: oklch(0.1 0.02 250);
+ --popover-foreground: oklch(0.98 0.01 250);
+ --primary: oklch(0.65 0.18 240);
+ --primary-foreground: oklch(0.98 0.01 240);
+ --secondary: oklch(0.15 0.03 250);
+ --secondary-foreground: oklch(0.98 0.01 250);
+ --muted: oklch(0.15 0.03 250);
+ --muted-foreground: oklch(0.7 0.05 250);
+ --accent: oklch(0.55 0.15 220);
+ --accent-foreground: oklch(0.98 0.01 220);
+ --destructive: oklch(0.7 0.25 30);
+ --border: oklch(0.2 0.04 250);
+ --input: oklch(0.12 0.03 250);
+ --ring: oklch(0.65 0.18 240);
+ --chart-1: oklch(0.65 0.18 240);
+ --chart-2: oklch(0.6 0.2 220);
+ --chart-3: oklch(0.55 0.22 260);
+ --chart-4: oklch(0.7 0.15 200);
+ --chart-5: oklch(0.5 0.25 280);
+ --sidebar: oklch(0.08 0.02 250);
+ --sidebar-foreground: oklch(0.98 0.01 250);
+ --sidebar-primary: oklch(0.65 0.18 240);
+ --sidebar-primary-foreground: oklch(0.98 0.01 240);
+ --sidebar-accent: oklch(0.15 0.03 250);
+ --sidebar-accent-foreground: oklch(0.98 0.01 250);
+ --sidebar-border: oklch(0.2 0.04 250);
+ --sidebar-ring: oklch(0.65 0.18 240);
+}
+
+.theme-amber {
+ --background: oklch(0.99 0.02 80);
+ --foreground: oklch(0.2 0.1 70);
+ --card: oklch(1 0 0);
+ --card-foreground: oklch(0.2 0.1 70);
+ --popover: oklch(1 0 0);
+ --popover-foreground: oklch(0.2 0.1 70);
+ --primary: oklch(0.7 0.2 70);
+ --primary-foreground: oklch(0.98 0.05 70);
+ --secondary: oklch(0.95 0.1 75);
+ --secondary-foreground: oklch(0.25 0.1 70);
+ --muted: oklch(0.95 0.1 75);
+ --muted-foreground: oklch(0.55 0.15 70);
+ --accent: oklch(0.65 0.25 50);
+ --accent-foreground: oklch(0.98 0.05 50);
+ --destructive: oklch(0.65 0.3 30);
+ --border: oklch(0.9 0.15 75);
+ --input: oklch(0.93 0.12 75);
+ --ring: oklch(0.7 0.2 70);
+ --chart-1: oklch(0.7 0.2 70);
+ --chart-2: oklch(0.65 0.25 50);
+ --chart-3: oklch(0.75 0.18 90);
+ --chart-4: oklch(0.8 0.15 110);
+ --chart-5: oklch(0.6 0.22 30);
+ --sidebar: oklch(0.995 0.015 80);
+ --sidebar-foreground: oklch(0.2 0.1 70);
+ --sidebar-primary: oklch(0.7 0.2 70);
+ --sidebar-primary-foreground: oklch(0.98 0.05 70);
+ --sidebar-accent: oklch(0.95 0.1 75);
+ --sidebar-accent-foreground: oklch(0.25 0.1 70);
+ --sidebar-border: oklch(0.9 0.15 75);
+ --sidebar-ring: oklch(0.7 0.2 70);
+}
+
+.theme-emerald {
+ --background: oklch(0.97 0.02 160);
+ --foreground: oklch(0.15 0.08 160);
+ --card: oklch(0.99 0.01 160);
+ --card-foreground: oklch(0.15 0.08 160);
+ --popover: oklch(0.99 0.01 160);
+ --popover-foreground: oklch(0.15 0.08 160);
+ --primary: oklch(0.6 0.2 160);
+ --primary-foreground: oklch(0.98 0.02 160);
+ --secondary: oklch(0.9 0.05 160);
+ --secondary-foreground: oklch(0.2 0.08 160);
+ --muted: oklch(0.9 0.05 160);
+ --muted-foreground: oklch(0.5 0.1 160);
+ --accent: oklch(0.55 0.25 140);
+ --accent-foreground: oklch(0.98 0.02 140);
+ --destructive: oklch(0.65 0.3 30);
+ --border: oklch(0.85 0.08 160);
+ --input: oklch(0.92 0.06 160);
+ --ring: oklch(0.6 0.2 160);
+ --chart-1: oklch(0.6 0.2 160);
+ --chart-2: oklch(0.55 0.25 140);
+ --chart-3: oklch(0.65 0.18 180);
+ --chart-4: oklch(0.5 0.22 120);
+ --chart-5: oklch(0.7 0.15 200);
+ --sidebar: oklch(0.98 0.015 160);
+ --sidebar-foreground: oklch(0.15 0.08 160);
+ --sidebar-primary: oklch(0.6 0.2 160);
+ --sidebar-primary-foreground: oklch(0.98 0.02 160);
+ --sidebar-accent: oklch(0.9 0.05 160);
+ --sidebar-accent-foreground: oklch(0.2 0.08 160);
+ --sidebar-border: oklch(0.85 0.08 160);
+ --sidebar-ring: oklch(0.6 0.2 160);
+}
+
+.theme-slate {
+ --background: oklch(0.96 0.005 260);
+ --foreground: oklch(0.18 0.01 260);
+ --card: oklch(0.98 0.002 260);
+ --card-foreground: oklch(0.18 0.01 260);
+ --popover: oklch(0.98 0.002 260);
+ --popover-foreground: oklch(0.18 0.01 260);
+ --primary: oklch(0.4 0.02 260);
+ --primary-foreground: oklch(0.98 0.002 260);
+ --secondary: oklch(0.9 0.008 260);
+ --secondary-foreground: oklch(0.2 0.01 260);
+ --muted: oklch(0.9 0.008 260);
+ --muted-foreground: oklch(0.5 0.015 260);
+ --accent: oklch(0.35 0.03 240);
+ --accent-foreground: oklch(0.98 0.002 240);
+ --destructive: oklch(0.6 0.2 30);
+ --border: oklch(0.85 0.01 260);
+ --input: oklch(0.88 0.01 260);
+ --ring: oklch(0.4 0.02 260);
+ --chart-1: oklch(0.4 0.02 260);
+ --chart-2: oklch(0.35 0.03 240);
+ --chart-3: oklch(0.45 0.025 280);
+ --chart-4: oklch(0.3 0.035 220);
+ --chart-5: oklch(0.5 0.015 300);
+ --sidebar: oklch(0.97 0.004 260);
+ --sidebar-foreground: oklch(0.18 0.01 260);
+ --sidebar-primary: oklch(0.4 0.02 260);
+ --sidebar-primary-foreground: oklch(0.98 0.002 260);
+ --sidebar-accent: oklch(0.9 0.008 260);
+ --sidebar-accent-foreground: oklch(0.2 0.01 260);
+ --sidebar-border: oklch(0.85 0.01 260);
+ --sidebar-ring: oklch(0.4 0.02 260);
+}
+
+.theme-ocean {
+ --background: oklch(0.95 0.03 210);
+ --foreground: oklch(0.15 0.05 210);
+ --card: oklch(0.98 0.01 210);
+ --card-foreground: oklch(0.15 0.05 210);
+ --popover: oklch(0.98 0.01 210);
+ --popover-foreground: oklch(0.15 0.05 210);
+ --primary: oklch(0.5 0.15 210);
+ --primary-foreground: oklch(0.98 0.02 210);
+ --secondary: oklch(0.85 0.06 210);
+ --secondary-foreground: oklch(0.2 0.06 210);
+ --muted: oklch(0.85 0.06 210);
+ --muted-foreground: oklch(0.45 0.09 210);
+ --accent: oklch(0.6 0.12 190);
+ --accent-foreground: oklch(0.98 0.02 190);
+ --destructive: oklch(0.65 0.25 30);
+ --border: oklch(0.8 0.08 210);
+ --input: oklch(0.88 0.05 210);
+ --ring: oklch(0.5 0.15 210);
+ --chart-1: oklch(0.5 0.15 210);
+ --chart-2: oklch(0.6 0.12 190);
+ --chart-3: oklch(0.55 0.14 230);
+ --chart-4: oklch(0.45 0.16 170);
+ --chart-5: oklch(0.65 0.1 250);
+ --sidebar: oklch(0.965 0.02 210);
+ --sidebar-foreground: oklch(0.15 0.05 210);
+ --sidebar-primary: oklch(0.5 0.15 210);
+ --sidebar-primary-foreground: oklch(0.98 0.02 210);
+ --sidebar-accent: oklch(0.85 0.06 210);
+ --sidebar-accent-foreground: oklch(0.2 0.06 210);
+ --sidebar-border: oklch(0.8 0.08 210);
+ --sidebar-ring: oklch(0.5 0.15 210);
+}
+
+.theme-crimson {
+ --background: oklch(0.98 0.02 10);
+ --foreground: oklch(0.2 0.1 10);
+ --card: oklch(1 0 0);
+ --card-foreground: oklch(0.2 0.1 10);
+ --popover: oklch(1 0 0);
+ --popover-foreground: oklch(0.2 0.1 10);
+ --primary: oklch(0.65 0.25 10);
+ --primary-foreground: oklch(0.98 0.02 10);
+ --secondary: oklch(0.93 0.05 10);
+ --secondary-foreground: oklch(0.25 0.09 10);
+ --muted: oklch(0.93 0.05 10);
+ --muted-foreground: oklch(0.55 0.12 10);
+ --accent: oklch(0.7 0.2 350);
+ --accent-foreground: oklch(0.98 0.02 350);
+ --destructive: oklch(0.7 0.3 30);
+ --border: oklch(0.88 0.08 10);
+ --input: oklch(0.9 0.06 10);
+ --ring: oklch(0.65 0.25 10);
+ --chart-1: oklch(0.65 0.25 10);
+ --chart-2: oklch(0.7 0.2 350);
+ --chart-3: oklch(0.6 0.22 30);
+ --chart-4: oklch(0.75 0.18 330);
+ --chart-5: oklch(0.55 0.24 20);
+ --sidebar: oklch(0.99 0.015 10);
+ --sidebar-foreground: oklch(0.2 0.1 10);
+ --sidebar-primary: oklch(0.65 0.25 10);
+ --sidebar-primary-foreground: oklch(0.98 0.02 10);
+ --sidebar-accent: oklch(0.93 0.05 10);
+ --sidebar-accent-foreground: oklch(0.25 0.09 10);
+ --sidebar-border: oklch(0.88 0.08 10);
+ --sidebar-ring: oklch(0.65 0.25 10);
+}
+
+.theme-nord {
+ --background: oklch(0.96 0.01 240);
+ --foreground: oklch(0.2 0.02 240);
+ --card: oklch(0.98 0.005 240);
+ --card-foreground: oklch(0.2 0.02 240);
+ --popover: oklch(0.98 0.005 240);
+ --popover-foreground: oklch(0.2 0.02 240);
+ --primary: oklch(0.45 0.1 220);
+ --primary-foreground: oklch(0.98 0.01 220);
+ --secondary: oklch(0.9 0.02 240);
+ --secondary-foreground: oklch(0.25 0.02 240);
+ --muted: oklch(0.9 0.02 240);
+ --muted-foreground: oklch(0.5 0.03 240);
+ --accent: oklch(0.6 0.08 210);
+ --accent-foreground: oklch(0.98 0.01 210);
+ --destructive: oklch(0.65 0.2 30);
+ --border: oklch(0.85 0.03 240);
+ --input: oklch(0.88 0.025 240);
+ --ring: oklch(0.45 0.1 220);
+ --chart-1: oklch(0.45 0.1 220);
+ --chart-2: oklch(0.6 0.08 210);
+ --chart-3: oklch(0.5 0.12 190);
+ --chart-4: oklch(0.55 0.09 240);
+ --chart-5: oklch(0.4 0.11 260);
+ --sidebar: oklch(0.97 0.008 240);
+ --sidebar-foreground: oklch(0.2 0.02 240);
+ --sidebar-primary: oklch(0.45 0.1 220);
+ --sidebar-primary-foreground: oklch(0.98 0.01 220);
+ --sidebar-accent: oklch(0.9 0.02 240);
+ --sidebar-accent-foreground: oklch(0.25 0.02 240);
+ --sidebar-border: oklch(0.85 0.03 240);
+ --sidebar-ring: oklch(0.45 0.1 220);
+}
+
+.theme-vintage {
+ --background: oklch(0.95 0.03 40);
+ --foreground: oklch(0.25 0.08 40);
+ --card: oklch(0.98 0.02 40);
+ --card-foreground: oklch(0.25 0.08 40);
+ --popover: oklch(0.98 0.02 40);
+ --popover-foreground: oklch(0.25 0.08 40);
+ --primary: oklch(0.55 0.2 40);
+ --primary-foreground: oklch(0.98 0.03 40);
+ --secondary: oklch(0.88 0.05 40);
+ --secondary-foreground: oklch(0.3 0.07 40);
+ --muted: oklch(0.88 0.05 40);
+ --muted-foreground: oklch(0.5 0.1 40);
+ --accent: oklch(0.65 0.15 70);
+ --accent-foreground: oklch(0.98 0.03 70);
+ --destructive: oklch(0.6 0.25 30);
+ --border: oklch(0.8 0.08 40);
+ --input: oklch(0.9 0.06 40);
+ --ring: oklch(0.55 0.2 40);
+ --chart-1: oklch(0.55 0.2 40);
+ --chart-2: oklch(0.65 0.15 70);
+ --chart-3: oklch(0.5 0.18 20);
+ --chart-4: oklch(0.6 0.12 90);
+ --chart-5: oklch(0.45 0.22 10);
+ --sidebar: oklch(0.965 0.025 40);
+ --sidebar-foreground: oklch(0.25 0.08 40);
+ --sidebar-primary: oklch(0.55 0.2 40);
+ --sidebar-primary-foreground: oklch(0.98 0.03 40);
+ --sidebar-accent: oklch(0.88 0.05 40);
+ --sidebar-accent-foreground: oklch(0.3 0.07 40);
+ --sidebar-border: oklch(0.8 0.08 40);
+ --sidebar-ring: oklch(0.55 0.2 40);
+}
+
+.theme-neon {
+ --background: oklch(0.05 0.05 280);
+ --foreground: oklch(0.95 0.15 120);
+ --card: oklch(0.1 0.07 280);
+ --card-foreground: oklch(0.95 0.15 120);
+ --popover: oklch(0.1 0.07 280);
+ --popover-foreground: oklch(0.95 0.15 120);
+ --primary: oklch(0.85 0.3 120);
+ --primary-foreground: oklch(0.05 0.05 280);
+ --secondary: oklch(0.2 0.1 300);
+ --secondary-foreground: oklch(0.95 0.15 120);
+ --muted: oklch(0.15 0.08 280);
+ --muted-foreground: oklch(0.8 0.2 120);
+ --accent: oklch(0.9 0.25 350);
+ --accent-foreground: oklch(0.05 0.05 280);
+ --destructive: oklch(0.9 0.3 30);
+ --border: oklch(0.95 0.15 120 / 0.4);
+ --input: oklch(0.95 0.15 120 / 0.2);
+ --ring: oklch(0.85 0.3 120);
+ --chart-1: oklch(0.85 0.3 120);
+ --chart-2: oklch(0.9 0.25 350);
+ --chart-3: oklch(0.8 0.28 240);
+ --chart-4: oklch(0.75 0.22 180);
+ --chart-5: oklch(0.9 0.2 60);
+ --sidebar: oklch(0.08 0.06 280);
+ --sidebar-foreground: oklch(0.95 0.15 120);
+ --sidebar-primary: oklch(0.85 0.3 120);
+ --sidebar-primary-foreground: oklch(0.05 0.05 280);
+ --sidebar-accent: oklch(0.2 0.1 300);
+ --sidebar-accent-foreground: oklch(0.95 0.15 120);
+ --sidebar-border: oklch(0.95 0.15 120 / 0.4);
+ --sidebar-ring: oklch(0.85 0.3 120);
+}
+
+.theme-dusk {
+ --background: oklch(0.12 0.04 280);
+ --foreground: oklch(0.92 0.03 280);
+ --card: oklch(0.18 0.05 280);
+ --card-foreground: oklch(0.92 0.03 280);
+ --popover: oklch(0.18 0.05 280);
+ --popover-foreground: oklch(0.92 0.03 280);
+ --primary: oklch(0.6 0.15 280);
+ --primary-foreground: oklch(0.98 0.02 280);
+ --secondary: oklch(0.25 0.06 280);
+ --secondary-foreground: oklch(0.92 0.03 280);
+ --muted: oklch(0.25 0.06 280);
+ --muted-foreground: oklch(0.65 0.08 280);
+ --accent: oklch(0.5 0.2 310);
+ --accent-foreground: oklch(0.98 0.02 310);
+ --destructive: oklch(0.65 0.25 30);
+ --border: oklch(0.3 0.07 280);
+ --input: oklch(0.2 0.05 280);
+ --ring: oklch(0.6 0.15 280);
+ --chart-1: oklch(0.6 0.15 280);
+ --chart-2: oklch(0.5 0.2 310);
+ --chart-3: oklch(0.65 0.12 250);
+ --chart-4: oklch(0.55 0.18 320);
+ --chart-5: oklch(0.45 0.22 290);
+ --sidebar: oklch(0.15 0.045 280);
+ --sidebar-foreground: oklch(0.92 0.03 280);
+ --sidebar-primary: oklch(0.6 0.15 280);
+ --sidebar-primary-foreground: oklch(0.98 0.02 280);
+ --sidebar-accent: oklch(0.25 0.06 280);
+ --sidebar-accent-foreground: oklch(0.92 0.03 280);
+ --sidebar-border: oklch(0.3 0.07 280);
+ --sidebar-ring: oklch(0.6 0.15 280);
+}
+
+.theme-pastel {
+ --background: oklch(0.985 0.01 290);
+ --foreground: oklch(0.25 0.05 290);
+ --card: oklch(1 0 0);
+ --card-foreground: oklch(0.25 0.05 290);
+ --popover: oklch(1 0 0);
+ --popover-foreground: oklch(0.25 0.05 290);
+ --primary: oklch(0.75 0.1 290);
+ --primary-foreground: oklch(0.98 0.02 290);
+ --secondary: oklch(0.95 0.03 290);
+ --secondary-foreground: oklch(0.3 0.04 290);
+ --muted: oklch(0.95 0.03 290);
+ --muted-foreground: oklch(0.55 0.06 290);
+ --accent: oklch(0.8 0.08 320);
+ --accent-foreground: oklch(0.98 0.02 320);
+ --destructive: oklch(0.85 0.15 30);
+ --border: oklch(0.9 0.04 290);
+ --input: oklch(0.93 0.035 290);
+ --ring: oklch(0.75 0.1 290);
+ --chart-1: oklch(0.75 0.1 290);
+ --chart-2: oklch(0.8 0.08 320);
+ --chart-3: oklch(0.7 0.12 260);
+ --chart-4: oklch(0.85 0.06 350);
+ --chart-5: oklch(0.65 0.14 230);
+ --sidebar: oklch(0.99 0.008 290);
+ --sidebar-foreground: oklch(0.25 0.05 290);
+ --sidebar-primary: oklch(0.75 0.1 290);
+ --sidebar-primary-foreground: oklch(0.98 0.02 290);
+ --sidebar-accent: oklch(0.95 0.03 290);
+ --sidebar-accent-foreground: oklch(0.3 0.04 290);
+ --sidebar-border: oklch(0.9 0.04 290);
+ --sidebar-ring: oklch(0.75 0.1 290);
+}
+
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
diff --git a/client/src/pages/app.tsx b/client/src/pages/app.tsx
index 82634a7..56970c6 100644
--- a/client/src/pages/app.tsx
+++ b/client/src/pages/app.tsx
@@ -1,4 +1,3 @@
-import { ThemeProvider } from "@/components/theme-provider";
import { Toaster } from "@/components/ui/sonner";
import { AnimatePresence } from "motion/react";
import { Route, Routes, useLocation } from "react-router-dom";
@@ -16,6 +15,7 @@ import { Whitelist } from "./whitelist";
import { GenerateQuote } from "@/quotes";
import Login from "./login";
import { FileXIcon } from "@phosphor-icons/react";
+import { ThemeProvider } from "@/app/theme/theme-provider";
function NotFound() {
return (