diff --git a/src/components/ModeToggle.tsx b/src/components/ModeToggle.tsx new file mode 100644 index 0000000..e022aca --- /dev/null +++ b/src/components/ModeToggle.tsx @@ -0,0 +1,97 @@ +import * as React from "react"; +import { Moon, Sun, Laptop } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; + +const THEME_KEY = "theme"; + +type Theme = "light" | "dark" | "system"; + +function getSystemTheme(): Theme { + if (typeof window !== "undefined" && window.matchMedia) { + return window.matchMedia("(prefers-color-scheme: dark)").matches + ? "dark" + : "light"; + } + return "light"; +} + +function getStoredTheme(): Theme | null { + if (typeof localStorage !== "undefined") { + const t = localStorage.getItem(THEME_KEY); + if (t === "light" || t === "dark" || t === "system") return t; + } + return null; +} + +function setStoredTheme(theme: Theme | null) { + if (typeof localStorage !== "undefined") { + if (theme) { + localStorage.setItem(THEME_KEY, theme); + } else { + localStorage.removeItem(THEME_KEY); + } + } +} + +function applyTheme(theme: Theme) { + const root = document.documentElement; + if (theme === "system") { + root.classList.toggle("dark", getSystemTheme() === "dark"); + } else { + root.classList.toggle("dark", theme === "dark"); + } +} + +export function ModeToggle() { + const [theme, setTheme] = React.useState( + () => getStoredTheme() || "system" + ); + + React.useEffect(() => { + const stored = getStoredTheme(); + if (stored) setTheme(stored); + }, []); + + React.useEffect(() => { + setStoredTheme(theme === "system" ? null : theme); + applyTheme(theme); + }, [theme]); + + React.useEffect(() => { + if (theme === "system") { + const mq = window.matchMedia("(prefers-color-scheme: dark)"); + const handler = () => applyTheme("system"); + mq.addEventListener("change", handler); + return () => mq.removeEventListener("change", handler); + } + }, [theme]); + + return ( + + + + + + setTheme("light")}> + Light + + setTheme("dark")}> + Dark + + setTheme("system")}> + System + + + + ); +} diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 41de8b0..b167611 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -11,6 +11,7 @@ import { } from '@/components/ui/dropdown-menu'; import { Avatar, AvatarFallback } from '@/components/ui/avatar'; import { BarChart3, LogOut, User as UserIcon } from 'lucide-react'; +import { ModeToggle } from './ModeToggle'; export function Navbar() { const [user, setUser] = useState(null); @@ -39,21 +40,22 @@ export function Navbar() { }; return ( -