diff --git a/frontend/src/components/layout/Header.tsx b/frontend/src/components/layout/Header.tsx index 0f5e8df..05d8cb9 100644 --- a/frontend/src/components/layout/Header.tsx +++ b/frontend/src/components/layout/Header.tsx @@ -18,7 +18,8 @@ import { } from '@/components/ui/popover' import { ScrollArea } from '@/components/ui/scroll-area' import { Separator } from '@/components/ui/separator' -import { Bell, CheckCheck, LogOut, Menu } from 'lucide-react' +import { Bell, CheckCheck, LogOut, Menu, Moon, Sun } from 'lucide-react' +import { useTheme } from '@/hooks/useTheme' interface HeaderProps { onToggleSidebar: () => void @@ -27,6 +28,7 @@ interface HeaderProps { export function Header({ onToggleSidebar }: HeaderProps) { const { user, logout } = useAuth() const { notifications, unreadCount, markAsRead, markAllAsRead } = useNotifications() + const { theme, toggleTheme } = useTheme() const initials = user?.username ? user.username @@ -54,6 +56,12 @@ export function Header({ onToggleSidebar }: HeaderProps) {
+ {/* Dark mode toggle */} + + {/* Notification bell with dropdown */} diff --git a/frontend/src/hooks/useTheme.ts b/frontend/src/hooks/useTheme.ts new file mode 100644 index 0000000..a3d54d8 --- /dev/null +++ b/frontend/src/hooks/useTheme.ts @@ -0,0 +1,29 @@ +import { useCallback, useEffect, useState } from 'react' + +type Theme = 'light' | 'dark' + +const STORAGE_KEY = 'dak-theme' + +export function useTheme() { + const [theme, setThemeState] = useState(() => { + const stored = localStorage.getItem(STORAGE_KEY) + if (stored === 'dark' || stored === 'light') return stored + return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' + }) + + useEffect(() => { + const root = document.documentElement + if (theme === 'dark') { + root.classList.add('dark') + } else { + root.classList.remove('dark') + } + localStorage.setItem(STORAGE_KEY, theme) + }, [theme]) + + const toggleTheme = useCallback(() => { + setThemeState((prev) => (prev === 'dark' ? 'light' : 'dark')) + }, []) + + return { theme, toggleTheme } +} diff --git a/frontend/src/pages/LoginPage.tsx b/frontend/src/pages/LoginPage.tsx index 3ff1678..4aa0bb9 100644 --- a/frontend/src/pages/LoginPage.tsx +++ b/frontend/src/pages/LoginPage.tsx @@ -9,7 +9,8 @@ import { Input } from '@/components/ui/input' import { Button } from '@/components/ui/button' import { Label } from '@/components/ui/label' import { Alert, AlertDescription } from '@/components/ui/alert' -import { AlertCircle, Loader2 } from 'lucide-react' +import { AlertCircle, Loader2, Moon, Sun } from 'lucide-react' +import { useTheme } from '@/hooks/useTheme' const loginSchema = z.object({ email: z.string().email('Bitte geben Sie eine gueltige E-Mail-Adresse ein'), @@ -21,6 +22,7 @@ type LoginFormValues = z.infer export function LoginPage() { const { login } = useAuth() + const { theme, toggleTheme } = useTheme() const navigate = useNavigate() const [error, setError] = useState(null) const [showMfa, setShowMfa] = useState(false) @@ -70,6 +72,15 @@ export function LoginPage() { return (
+ DAK Portal