diff --git a/frontend/package.json b/frontend/package.json index 2f78ce9..e673692 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -27,7 +27,9 @@ }, "dependencies": { "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-dropdown-menu": "^2.1.16", "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-tooltip": "^1.2.8", "@tailwindcss/postcss": "^4.2.2", "@tanstack/react-query": "^5.97.0", "class-variance-authority": "^0.7.1", diff --git a/frontend/src/components/layout/Sidebar.tsx b/frontend/src/components/layout/Sidebar.tsx index 1ed7f2b..2d49572 100644 --- a/frontend/src/components/layout/Sidebar.tsx +++ b/frontend/src/components/layout/Sidebar.tsx @@ -11,6 +11,7 @@ import { Languages, Moon, Sun, + Check, LogOut, X, PanelLeftClose, @@ -22,6 +23,13 @@ import { useAuthStore } from "@/store/auth"; import { useState } from "react"; import { useTranslation } from "react-i18next"; import { changeLanguage, SUPPORTED_LANGUAGES, type SupportedLanguage } from "@/i18n"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; type NavGroup = "overview" | "management" | "tools" | "system"; @@ -77,11 +85,10 @@ export function Sidebar({ return "light"; }); - const toggleTheme = () => { - const newTheme = theme === "light" ? "dark" : "light"; - setTheme(newTheme); - localStorage.setItem("theme", newTheme); - if (newTheme === "dark") { + const setThemeMode = (nextTheme: "light" | "dark") => { + setTheme(nextTheme); + localStorage.setItem("theme", nextTheme); + if (nextTheme === "dark") { document.documentElement.classList.add("dark"); } else { document.documentElement.classList.remove("dark"); @@ -91,16 +98,17 @@ export function Sidebar({ const langLabels: Record = { "zh-CN": t("language.zhCN"), "zh-TW": t("language.zhTW"), - "en": t("language.en"), + en: t("language.en"), }; - const cycleLang = () => { - const currentIndex = SUPPORTED_LANGUAGES.indexOf(i18n.language as SupportedLanguage); - const nextIndex = (currentIndex + 1) % SUPPORTED_LANGUAGES.length; - changeLanguage(SUPPORTED_LANGUAGES[nextIndex]); - }; - - const currentLangLabel = langLabels[i18n.language as SupportedLanguage] || langLabels["zh-CN"]; + const currentLanguage = SUPPORTED_LANGUAGES.includes(i18n.language as SupportedLanguage) + ? (i18n.language as SupportedLanguage) + : "zh-CN"; + const currentLangLabel = langLabels[currentLanguage]; + const actionButtonClassName = cn( + "flex h-9 items-center justify-center rounded-md text-muted-foreground transition-colors duration-150 hover:bg-muted/70 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 data-[state=open]:bg-muted/80 data-[state=open]:text-foreground", + collapsed ? "w-10" : "w-full", + ); const handleLogout = async () => { await logout(); @@ -185,7 +193,10 @@ export function Sidebar({ {/* Navigation */}