feat: add dark mode toggle in header and login page

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
CCS Admin 2026-02-24 10:02:41 +00:00
parent 9d79ba35bc
commit 1edf5835be
3 changed files with 50 additions and 2 deletions

View file

@ -18,7 +18,8 @@ import {
} from '@/components/ui/popover' } from '@/components/ui/popover'
import { ScrollArea } from '@/components/ui/scroll-area' import { ScrollArea } from '@/components/ui/scroll-area'
import { Separator } from '@/components/ui/separator' 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 { interface HeaderProps {
onToggleSidebar: () => void onToggleSidebar: () => void
@ -27,6 +28,7 @@ interface HeaderProps {
export function Header({ onToggleSidebar }: HeaderProps) { export function Header({ onToggleSidebar }: HeaderProps) {
const { user, logout } = useAuth() const { user, logout } = useAuth()
const { notifications, unreadCount, markAsRead, markAllAsRead } = useNotifications() const { notifications, unreadCount, markAsRead, markAllAsRead } = useNotifications()
const { theme, toggleTheme } = useTheme()
const initials = user?.username const initials = user?.username
? user.username ? user.username
@ -54,6 +56,12 @@ export function Header({ onToggleSidebar }: HeaderProps) {
<div className="flex-1" /> <div className="flex-1" />
{/* Dark mode toggle */}
<Button variant="ghost" size="icon" onClick={toggleTheme}>
{theme === 'dark' ? <Sun className="h-5 w-5" /> : <Moon className="h-5 w-5" />}
<span className="sr-only">Design umschalten</span>
</Button>
{/* Notification bell with dropdown */} {/* Notification bell with dropdown */}
<Popover> <Popover>
<PopoverTrigger asChild> <PopoverTrigger asChild>

View file

@ -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<Theme>(() => {
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 }
}

View file

@ -9,7 +9,8 @@ import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { Label } from '@/components/ui/label' import { Label } from '@/components/ui/label'
import { Alert, AlertDescription } from '@/components/ui/alert' 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({ const loginSchema = z.object({
email: z.string().email('Bitte geben Sie eine gueltige E-Mail-Adresse ein'), email: z.string().email('Bitte geben Sie eine gueltige E-Mail-Adresse ein'),
@ -21,6 +22,7 @@ type LoginFormValues = z.infer<typeof loginSchema>
export function LoginPage() { export function LoginPage() {
const { login } = useAuth() const { login } = useAuth()
const { theme, toggleTheme } = useTheme()
const navigate = useNavigate() const navigate = useNavigate()
const [error, setError] = useState<string | null>(null) const [error, setError] = useState<string | null>(null)
const [showMfa, setShowMfa] = useState(false) const [showMfa, setShowMfa] = useState(false)
@ -70,6 +72,15 @@ export function LoginPage() {
return ( return (
<div className="flex min-h-screen items-center justify-center bg-background px-4"> <div className="flex min-h-screen items-center justify-center bg-background px-4">
<Button
variant="ghost"
size="icon"
onClick={toggleTheme}
className="absolute top-4 right-4"
>
{theme === 'dark' ? <Sun className="h-5 w-5" /> : <Moon className="h-5 w-5" />}
<span className="sr-only">Design umschalten</span>
</Button>
<Card className="w-full max-w-md"> <Card className="w-full max-w-md">
<CardHeader className="text-center"> <CardHeader className="text-center">
<CardTitle className="text-2xl">DAK Portal</CardTitle> <CardTitle className="text-2xl">DAK Portal</CardTitle>