diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css
index e777f75..65ad00e 100644
--- a/frontend/src/app/globals.css
+++ b/frontend/src/app/globals.css
@@ -160,14 +160,52 @@
--yellow: #d29922;
}
+/* Light theme */
+[data-theme='light'] {
+ --background: #ffffff;
+ --surface-1: #f6f8fa;
+ --surface-2: #eaeef2;
+ --border-1: #d0d7de;
+ --border-2: #d8dee4;
+ --border-3: #b1bac4;
+ --text-1: #24292f;
+ --text-2: #424a53;
+ --text-3: #656d76;
+ --blue: #0969da;
+ --purple: #8250df;
+ --green: #1a7f37;
+ --red: #d1242f;
+ --yellow: #9e6a03;
+}
+
+/* Dark theme (default) */
+[data-theme='dark'] {
+ --background: #0d1117;
+ --surface-1: #161b22;
+ --surface-2: #0d1117;
+ --border-1: #30363d;
+ --border-2: #21262d;
+ --border-3: #444c56;
+ --text-1: #e6edf3;
+ --text-2: #c9d1d9;
+ --text-3: #8b949e;
+ --blue: #4f8ef7;
+ --purple: #7c5cfc;
+ --green: #3fb950;
+ --red: #f85149;
+ --yellow: #d29922;
+}
+
+
* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
- background: #0d1117;
- color: #e6edf3;
+ background: var(--background);
+ color: var(--text-1);
font-family: 'Silkscreen', system-ui, sans-serif;
+ transition: background-color 0.2s ease, color 0.2s ease;
-webkit-font-smoothing: antialiased;
}
diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx
index 8eed44a..bf4d4fc 100644
--- a/frontend/src/app/layout.tsx
+++ b/frontend/src/app/layout.tsx
@@ -56,6 +56,11 @@ export default function RootLayout({ children }: { children: React.ReactNode })
}),
}}
/>
+
{children}
diff --git a/frontend/src/components/Topbar.tsx b/frontend/src/components/Topbar.tsx
index a8b5ba6..09a618f 100644
--- a/frontend/src/components/Topbar.tsx
+++ b/frontend/src/components/Topbar.tsx
@@ -1,6 +1,7 @@
'use client';
import { useEffect, useState } from 'react';
-import { Loader2, CheckCircle, XCircle, Github, Terminal } from 'lucide-react';
+import { Loader2, CheckCircle, XCircle, Github, Terminal, Sun, Moon } from 'lucide-react';
+import { useTheme } from '@/lib/useTheme';
import { Logo } from './Logo';
import type { ScanStatus } from '@/lib/types';
@@ -28,6 +29,7 @@ function useDateTime() {
export function Topbar({ status, onHome }: Props) {
const { date, time } = useDateTime();
+ const { theme, toggleTheme, mounted } = useTheme();
return (
@@ -77,6 +79,14 @@ export function Topbar({ status, onHome }: Props) {
)}
+
('dark');
+ const [mounted, setMounted] = useState(false);
+
+ useEffect(() => {
+ // Get saved theme from localStorage or system preference
+ const saved = localStorage.getItem('theme') as 'light' | 'dark' | null;
+ const initial = saved || (window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark');
+
+ setTheme(initial);
+ document.documentElement.setAttribute('data-theme', initial);
+ setMounted(true);
+ }, []);
+
+ const toggleTheme = () => {
+ const newTheme = theme === 'dark' ? 'light' : 'dark';
+ setTheme(newTheme);
+ localStorage.setItem('theme', newTheme);
+ document.documentElement.setAttribute('data-theme', newTheme);
+ };
+
+ return { theme, toggleTheme, mounted };
+}