diff --git a/frontend/src/app/App.tsx b/frontend/src/app/App.tsx index 4d15e6f..99c569e 100644 --- a/frontend/src/app/App.tsx +++ b/frontend/src/app/App.tsx @@ -1,14 +1,17 @@ import { AppShell } from './layout/AppShell' import { Router } from './router' +import { AppThemeProvider } from '@/components/app/AppThemeProvider' import { AuthProvider, useAuth } from '@/features/auth/AuthProvider' import { LoginPage } from '@/features/auth/LoginPage' import { Skeleton } from '@/components/ui/skeleton' export function App() { return ( - - - + + + + + ) } diff --git a/frontend/src/components/app/AppThemeProvider.tsx b/frontend/src/components/app/AppThemeProvider.tsx new file mode 100644 index 0000000..6c5061c --- /dev/null +++ b/frontend/src/components/app/AppThemeProvider.tsx @@ -0,0 +1,14 @@ +import type * as React from 'react' +import { ThemeProvider } from 'next-themes' + +type AppThemeProviderProps = { + children: React.ReactNode +} + +export function AppThemeProvider({ children }: AppThemeProviderProps) { + return ( + + {children} + + ) +} diff --git a/frontend/src/components/app/AppThemeToggle.tsx b/frontend/src/components/app/AppThemeToggle.tsx new file mode 100644 index 0000000..0387103 --- /dev/null +++ b/frontend/src/components/app/AppThemeToggle.tsx @@ -0,0 +1,53 @@ +import { Laptop, Moon, Sun } from 'lucide-react' +import { useTheme } from 'next-themes' + +import { Button } from '@/components/ui/button' +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuLabel, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuTrigger +} from '@/components/ui/dropdown-menu' + +const themeOptions = [ + { value: 'light', label: '亮色', icon: Sun }, + { value: 'dark', label: '暗色', icon: Moon }, + { value: 'system', label: '跟随系统', icon: Laptop } +] + +export function AppThemeToggle() { + const { theme = 'system', setTheme } = useTheme() + const activeTheme = themeOptions.find((option) => option.value === theme) ?? themeOptions[2] + const ActiveIcon = activeTheme.icon + + return ( + + + + + + 界面主题 + + + + {themeOptions.map((option) => { + const Icon = option.icon + return ( + + + {option.label} + + ) + })} + + + + + ) +} diff --git a/frontend/src/components/app/AppTopbar.tsx b/frontend/src/components/app/AppTopbar.tsx index 86213aa..a90d54d 100644 --- a/frontend/src/components/app/AppTopbar.tsx +++ b/frontend/src/components/app/AppTopbar.tsx @@ -1,5 +1,6 @@ import { Bell, ChevronRight, LogOut, Menu, UserRound } from 'lucide-react' +import { AppThemeToggle } from '@/components/app/AppThemeToggle' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Separator } from '@/components/ui/separator' @@ -34,6 +35,7 @@ export function AppTopbar({ onMobileMenuClick }: AppTopbarProps) { +