@@ -68,13 +67,7 @@ export function Layout({ children, currentPage, onNavigate }: LayoutProps) {
-
+
diff --git a/app/components/ui/LegalNav.tsx b/app/components/ui/LegalNav.tsx
new file mode 100644
index 0000000..e9a40a7
--- /dev/null
+++ b/app/components/ui/LegalNav.tsx
@@ -0,0 +1,29 @@
+'use client'
+
+import { ArrowLeft } from 'lucide-react'
+import Link from 'next/link'
+import { ThemeToggle } from './ThemeToggle'
+
+export function LegalNav() {
+ return (
+
+
+
+

+
DumpIt
+
+
+
+
+
+
Back to Home
+
Home
+
+
+
+
+ )
+}
diff --git a/app/components/ui/ThemeToggle.tsx b/app/components/ui/ThemeToggle.tsx
new file mode 100644
index 0000000..afe44ab
--- /dev/null
+++ b/app/components/ui/ThemeToggle.tsx
@@ -0,0 +1,78 @@
+'use client'
+
+import { Monitor, Moon, Sun } from 'lucide-react'
+import { useTheme, type ThemeMode } from '../../contexts/ThemeContext'
+
+const options: { mode: ThemeMode; Icon: typeof Sun; label: string }[] = [
+ { mode: 'light', Icon: Sun, label: 'Light mode' },
+ { mode: 'system', Icon: Monitor, label: 'System mode' },
+ { mode: 'dark', Icon: Moon, label: 'Dark mode' },
+]
+
+interface ThemeToggleProps {
+ /** 'pill' = compact 3-icon pill (default for navbars). 'row' = full-width row items for sidebars. */
+ variant?: 'pill' | 'row'
+ className?: string
+}
+
+export function ThemeToggle({ variant = 'pill', className = '' }: ThemeToggleProps) {
+ const { themeMode, setThemeMode } = useTheme()
+
+ if (variant === 'row') {
+ return (
+
+ {options.map(({ mode, Icon, label }) => {
+ const active = themeMode === mode
+ return (
+
+ )
+ })}
+
+ )
+ }
+
+ // Pill variant
+ return (
+
+ {options.map(({ mode, Icon, label }) => {
+ const active = themeMode === mode
+ return (
+
+ )
+ })}
+
+ )
+}
diff --git a/app/contexts/ThemeContext.tsx b/app/contexts/ThemeContext.tsx
index 54aad7e..878014d 100644
--- a/app/contexts/ThemeContext.tsx
+++ b/app/contexts/ThemeContext.tsx
@@ -2,36 +2,70 @@
import { createContext, useContext, useEffect, useState, ReactNode } from 'react';
-type Theme = 'light' | 'dark';
+export type ThemeMode = 'light' | 'dark' | 'system';
interface ThemeContextType {
- theme: Theme;
+ /** The currently active rendered theme (always 'light' or 'dark') */
+ resolvedTheme: 'light' | 'dark';
+ /** The user's saved preference, including 'system' */
+ themeMode: ThemeMode;
+ setThemeMode: (mode: ThemeMode) => void;
+ /** Legacy: kept for backwards compatibility with components that used toggleTheme */
toggleTheme: () => void;
}
const ThemeContext = createContext
(undefined);
+function getSystemTheme(): 'light' | 'dark' {
+ if (typeof window === 'undefined') return 'light';
+ return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
+}
+
+function applyTheme(resolved: 'light' | 'dark') {
+ document.documentElement.classList.toggle('dark', resolved === 'dark');
+}
+
export function ThemeProvider({ children }: { children: ReactNode }) {
- const [theme, setTheme] = useState('light');
+ const [themeMode, setThemeModeState] = useState('system');
+ const [resolvedTheme, setResolvedTheme] = useState<'light' | 'dark'>('light');
+ // On mount: read saved preference, apply it
useEffect(() => {
- // Check for saved theme preference or system preference
- const savedTheme = localStorage.getItem('theme') as Theme;
- const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
- const initialTheme = savedTheme || systemTheme;
- setTheme(initialTheme);
- document.documentElement.classList.toggle('dark', initialTheme === 'dark');
+ const saved = (localStorage.getItem('theme-mode') as ThemeMode) || 'system';
+ const resolved = saved === 'system' ? getSystemTheme() : saved;
+ setThemeModeState(saved);
+ setResolvedTheme(resolved);
+ applyTheme(resolved);
}, []);
+ // Listen for system preference changes when in 'system' mode
+ useEffect(() => {
+ if (themeMode !== 'system') return;
+ const mq = window.matchMedia('(prefers-color-scheme: dark)');
+ const handler = (e: MediaQueryListEvent) => {
+ const resolved = e.matches ? 'dark' : 'light';
+ setResolvedTheme(resolved);
+ applyTheme(resolved);
+ };
+ mq.addEventListener('change', handler);
+ return () => mq.removeEventListener('change', handler);
+ }, [themeMode]);
+
+ const setThemeMode = (mode: ThemeMode) => {
+ const resolved = mode === 'system' ? getSystemTheme() : mode;
+ setThemeModeState(mode);
+ setResolvedTheme(resolved);
+ localStorage.setItem('theme-mode', mode);
+ applyTheme(resolved);
+ };
+
+ // Legacy compat: toggle between light and dark (skips system)
const toggleTheme = () => {
- const newTheme = theme === 'light' ? 'dark' : 'light';
- setTheme(newTheme);
- localStorage.setItem('theme', newTheme);
- document.documentElement.classList.toggle('dark', newTheme === 'dark');
+ setThemeMode(resolvedTheme === 'light' ? 'dark' : 'light');
};
return (
-
+
{children}
);
diff --git a/app/privacy/page.tsx b/app/privacy/page.tsx
index 44f03b1..c4cec1c 100644
--- a/app/privacy/page.tsx
+++ b/app/privacy/page.tsx
@@ -1,6 +1,6 @@
import type { Metadata } from 'next'
-import { ArrowLeft, Shield, Lock, Eye, FileText, Database, ShieldAlert } from 'lucide-react'
-import Link from 'next/link'
+import { Shield, Lock, Eye, FileText, Database, ShieldAlert } from 'lucide-react'
+import { LegalNav } from '../components/ui/LegalNav'
import Footer from '../components/landing/Footer'
export const metadata: Metadata = {
@@ -82,22 +82,7 @@ const sections = [
export default function PrivacyPolicy() {
return (
- {/* Sticky Header */}
-
-
-
-

-
DumpIt
-
-
-
- Back to Home
-
-
-
+
{/* Hero */}
diff --git a/app/terms/page.tsx b/app/terms/page.tsx
index c06f409..9a1c905 100644
--- a/app/terms/page.tsx
+++ b/app/terms/page.tsx
@@ -1,6 +1,6 @@
import type { Metadata } from 'next'
-import { ArrowLeft, Scale, ShieldAlert, Key, UserCheck, AlertTriangle, HelpCircle } from 'lucide-react'
-import Link from 'next/link'
+import { Scale, ShieldAlert, Key, UserCheck, AlertTriangle, HelpCircle } from 'lucide-react'
+import { LegalNav } from '../components/ui/LegalNav'
import Footer from '../components/landing/Footer'
export const metadata: Metadata = {
@@ -79,22 +79,7 @@ const sections = [
export default function TermsOfService() {
return (
- {/* Sticky Header */}
-
-
-
-

-
DumpIt
-
-
-
- Back to Home
-
-
-
+
{/* Hero */}