import { useState, useRef, useEffect } from 'react'; import { Link } from 'react-router-dom'; import { ChevronDown, MoreVertical, Sun, Moon, LogOut, Minimize2 } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import type { NavItem, Language } from './constants'; import { isTauri } from '../../utils/env'; import { useViewStore } from '../../stores/useViewStore'; // useClickOutside Hook export function useClickOutside( ref: React.RefObject, handler: () => void ) { useEffect(() => { const listener = (event: MouseEvent) => { if (!ref.current || ref.current.contains(event.target as Node)) { return; } handler(); }; document.addEventListener('mousedown', listener); return () => document.removeEventListener('mousedown', listener); }, [ref, handler]); } // 语言下拉菜单组件 interface LanguageDropdownProps { currentLanguage: string; languages: Language[]; onLanguageChange: (langCode: string) => void; className?: string; } export function LanguageDropdown({ currentLanguage, languages, onLanguageChange, className = '' }: LanguageDropdownProps) { const [isOpen, setIsOpen] = useState(false); const menuRef = useRef(null); const { t } = useTranslation(); useClickOutside(menuRef, () => setIsOpen(false)); const handleLanguageChange = (langCode: string) => { onLanguageChange(langCode); setIsOpen(false); }; return (
{/* 下拉菜单 */} {isOpen && (
{languages.map((lang) => ( ))}
)}
); } // 导航下拉菜单组件 (< 375px) interface NavigationDropdownProps { navItems: NavItem[]; isActive: (path: string) => boolean; getCurrentNavItem: () => NavItem | undefined; onNavigate: () => void; showLabel?: boolean; // 是否显示文字标签 } export function NavigationDropdown({ navItems, isActive, getCurrentNavItem, onNavigate, showLabel = true // 默认显示文字 }: NavigationDropdownProps) { const [isOpen, setIsOpen] = useState(false); const menuRef = useRef(null); useClickOutside(menuRef, () => setIsOpen(false)); const handleNavItemClick = () => { setIsOpen(false); onNavigate(); }; const currentItem = getCurrentNavItem(); const CurrentIcon = currentItem?.icon; // 如果没有当前项,不渲染 if (!currentItem || !CurrentIcon) return null; return (
{/* 下拉菜单 */} {isOpen && (
{navItems.map((item) => ( {item.label} ))}
)}
); } // 更多菜单组件 (< 480px) interface MoreDropdownProps { theme: 'light' | 'dark'; currentLanguage: string; languages: Language[]; onThemeToggle: (event: React.MouseEvent) => void; onLanguageChange: (langCode: string) => void; } export function MoreDropdown({ theme, currentLanguage, languages, onThemeToggle, onLanguageChange }: MoreDropdownProps) { const [isOpen, setIsOpen] = useState(false); const menuRef = useRef(null); const { t } = useTranslation(); const { setMiniView } = useViewStore(); useClickOutside(menuRef, () => setIsOpen(false)); const handleThemeToggle = (event: React.MouseEvent) => { onThemeToggle(event); setIsOpen(false); }; const handleLanguageChange = (langCode: string) => { onLanguageChange(langCode); setIsOpen(false); }; const handleLogout = () => { sessionStorage.removeItem('abv_admin_api_key'); localStorage.removeItem('abv_admin_api_key'); window.location.reload(); }; return (
{/* 下拉菜单 */} {isOpen && (
{/* 迷你视图 */} {/* 主题切换 */} {/* 分隔线 */}
{/* 语言选择 */} {languages.map((lang) => ( ))} {/* 登出按钮 - 仅 Web 模式显示 */} {!isTauri() && ( <>
)}
)}
); }