Next.js 15 App Router mit öffentlicher Übersicht und geschütztem Admin-Bereich zur Pflege von Datenschutzerklärungen nach Art. 12ff. DSGVO. - Oberfläche auf Basis von shadcn/ui, Inter lokal eingebunden - Prisma/SQLite, Auth.js mit Credentials-Provider und Rollen - Massenimport der Merkblätter des Amtes Leezen aus PDF - Docker-Image (standalone) und Gitea-Workflow zur Veröffentlichung Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
50 lines
1.5 KiB
TypeScript
50 lines
1.5 KiB
TypeScript
"use client"
|
|
|
|
import { Check, Monitor, Moon, Sun } from "lucide-react"
|
|
|
|
import { Button } from "@/components/ui/button"
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuTrigger,
|
|
} from "@/components/ui/dropdown-menu"
|
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
|
|
import { useTheme } from "@/hooks/use-theme"
|
|
|
|
const options = [
|
|
{ value: "light", label: "Hell", icon: Sun },
|
|
{ value: "dark", label: "Dunkel", icon: Moon },
|
|
{ value: "system", label: "System", icon: Monitor },
|
|
] as const
|
|
|
|
export function ThemeToggle() {
|
|
const { theme, setTheme, resolvedTheme } = useTheme()
|
|
|
|
return (
|
|
<DropdownMenu>
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button variant="ghost" size="icon">
|
|
{resolvedTheme === "dark" ? <Moon /> : <Sun />}
|
|
<span className="sr-only">Design-Modus wechseln</span>
|
|
</Button>
|
|
</DropdownMenuTrigger>
|
|
</TooltipTrigger>
|
|
<TooltipContent>Design-Modus</TooltipContent>
|
|
</Tooltip>
|
|
|
|
<DropdownMenuContent align="end">
|
|
{options.map(({ value, label, icon: Icon }) => (
|
|
<DropdownMenuItem key={value} onSelect={() => setTheme(value)}>
|
|
<Icon />
|
|
{label}
|
|
{theme === value && <Check className="ml-auto size-4 text-foreground" />}
|
|
</DropdownMenuItem>
|
|
))}
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
)
|
|
}
|