From a4db53f44dcca12a467fb7a1ce9aa04cff1efb58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=BCger?= Date: Sat, 15 Aug 2026 21:11:27 +0200 Subject: [PATCH] Add dark theme support with a toggle shadcn had already generated full light/dark CSS variable sets in globals.css (keyed off a .dark class via @custom-variant), but nothing ever added that class - the app was always light regardless of OS preference. Wires up next-themes (already a dependency, pulled in by sonner.tsx but never provided) with attribute="class", defaulting to the system preference. Adds a sun/moon ThemeToggle button - in the header for the authenticated app, and in the top-right corner of the login page since that route sits outside the header layout. suppressHydrationWarning moves to too (next-themes sets the class there via a pre-hydration script, so server/client will legitimately differ on first paint). Co-Authored-By: Claude Sonnet 5 --- app/src/app/layout.tsx | 17 ++++++++++---- app/src/app/login/page.tsx | 6 ++++- app/src/components/layout/nav.tsx | 26 +++++++++++++--------- app/src/components/layout/theme-toggle.tsx | 22 ++++++++++++++++++ 4 files changed, 55 insertions(+), 16 deletions(-) create mode 100644 app/src/components/layout/theme-toggle.tsx diff --git a/app/src/app/layout.tsx b/app/src/app/layout.tsx index 5b89b27..e2c2539 100644 --- a/app/src/app/layout.tsx +++ b/app/src/app/layout.tsx @@ -1,5 +1,6 @@ import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; +import { ThemeProvider } from "next-themes"; import { TooltipProvider } from "@/components/ui/tooltip"; import { Toaster } from "@/components/ui/sonner"; import "./globals.css"; @@ -31,15 +32,23 @@ export default function RootLayout({ - - {children} - - + + + {children} + + + ); diff --git a/app/src/app/login/page.tsx b/app/src/app/login/page.tsx index b39710a..243a47c 100644 --- a/app/src/app/login/page.tsx +++ b/app/src/app/login/page.tsx @@ -4,6 +4,7 @@ import type { Metadata } from "next"; import { redirect } from "next/navigation"; import { getConfig } from "@/lib/config/load"; import { getSession } from "@/lib/auth/session"; +import { ThemeToggle } from "@/components/layout/theme-toggle"; import { LoginForm } from "./login-form"; export const metadata: Metadata = { title: "Sign in" }; @@ -16,7 +17,10 @@ export default async function LoginPage() { if (session.userId) redirect("/"); return ( -
+
+
+ +
); diff --git a/app/src/components/layout/nav.tsx b/app/src/components/layout/nav.tsx index da3ed8c..273609d 100644 --- a/app/src/components/layout/nav.tsx +++ b/app/src/components/layout/nav.tsx @@ -5,6 +5,7 @@ import { usePathname, useRouter } from "next/navigation"; import { Terminal, History, LogOut } from "lucide-react"; import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; +import { ThemeToggle } from "./theme-toggle"; const links = [ { href: "/", label: "Scripts", icon: Terminal }, @@ -54,17 +55,20 @@ export function Nav({ ))}
- {authEnabled && ( -
- - {username} - - -
- )} +
+ + {authEnabled && ( + <> + + {username} + + + + )} +
); diff --git a/app/src/components/layout/theme-toggle.tsx b/app/src/components/layout/theme-toggle.tsx new file mode 100644 index 0000000..dfc7b5c --- /dev/null +++ b/app/src/components/layout/theme-toggle.tsx @@ -0,0 +1,22 @@ +"use client"; + +import { Moon, Sun } from "lucide-react"; +import { useTheme } from "next-themes"; +import { Button } from "@/components/ui/button"; + +export function ThemeToggle() { + const { resolvedTheme, setTheme } = useTheme(); + + return ( + + ); +}