From 65f89a624c1db125cc95d4c71526cff8b636b8d4 Mon Sep 17 00:00:00 2001 From: evisdren Date: Tue, 10 Feb 2026 14:58:37 -0800 Subject: [PATCH] new dark mode Entire-Checkpoint: da5656f7aad9 --- app/globals.css | 8 +++--- app/layout.tsx | 3 ++- app/page.tsx | 25 ++++++++++++++--- app/theme-provider.tsx | 61 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 9 deletions(-) create mode 100644 app/theme-provider.tsx diff --git a/app/globals.css b/app/globals.css index 1a5b43a..d0bf08c 100644 --- a/app/globals.css +++ b/app/globals.css @@ -12,11 +12,9 @@ --font-mono: var(--font-geist-mono); } -@media (prefers-color-scheme: dark) { - :root { - --background: #2a2a2a; - --foreground: #ededed; - } +.dark { + --background: #18181b; + --foreground: #fafafa; } body { diff --git a/app/layout.tsx b/app/layout.tsx index e8ca119..cd32a9b 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,6 +1,7 @@ import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; +import { ThemeProvider } from "./theme-provider"; const geistSans = Geist({ variable: "--font-geist-sans", @@ -27,7 +28,7 @@ export default function RootLayout({ - {children} + {children} ); diff --git a/app/page.tsx b/app/page.tsx index 0306b78..59b51e0 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,6 +1,7 @@ "use client"; import { useState, useEffect, DragEvent } from "react"; +import { useTheme } from "./theme-provider"; interface Todo { id: number; @@ -20,6 +21,7 @@ const columns = [ ]; export default function Home() { + const { theme, toggleTheme } = useTheme(); const [todos, setTodos] = useState([]); const [inputValue, setInputValue] = useState(""); const [isLoaded, setIsLoaded] = useState(false); @@ -165,9 +167,26 @@ export default function Home() { return (
-

- Kanban Board -

+
+

+ Kanban Board +

+ +
void; +} + +const ThemeContext = createContext(undefined); + +export function ThemeProvider({ children }: { children: React.ReactNode }) { + const [theme, setTheme] = useState("light"); + const [mounted, setMounted] = useState(false); + + useEffect(() => { + const stored = localStorage.getItem("theme") as Theme | null; + if (stored) { + setTheme(stored); + } else if (window.matchMedia("(prefers-color-scheme: dark)").matches) { + setTheme("dark"); + } + setMounted(true); + }, []); + + useEffect(() => { + if (!mounted) return; + + const root = document.documentElement; + if (theme === "dark") { + root.classList.add("dark"); + } else { + root.classList.remove("dark"); + } + localStorage.setItem("theme", theme); + }, [theme, mounted]); + + const toggleTheme = () => { + setTheme((prev) => (prev === "light" ? "dark" : "light")); + }; + + if (!mounted) { + return <>{children}; + } + + return ( + + {children} + + ); +} + +export function useTheme() { + const context = useContext(ThemeContext); + if (!context) { + throw new Error("useTheme must be used within a ThemeProvider"); + } + return context; +}