File size: 6,383 Bytes
bbb1195 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | import { Link, useLocation } from 'react-router-dom';
import { Sun, Moon } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { useConfigStore } from '../../stores/useConfigStore';
function Navbar() {
const location = useLocation();
const { t, i18n } = useTranslation();
const { config, saveConfig } = useConfigStore();
const navItems = [
{ path: '/', label: t('nav.dashboard') },
{ path: '/accounts', label: t('nav.accounts') },
{ path: '/api-proxy', label: t('nav.proxy') },
{ path: '/settings', label: t('nav.settings') },
];
const isActive = (path: string) => {
if (path === '/') {
return location.pathname === '/';
}
return location.pathname.startsWith(path);
};
const toggleTheme = async (event: React.MouseEvent<HTMLButtonElement>) => {
if (!config) return;
const newTheme = config.theme === 'light' ? 'dark' : 'light';
// 如果浏览器支持 View Transition API
if ('startViewTransition' in document) {
const x = event.clientX;
const y = event.clientY;
const endRadius = Math.hypot(
Math.max(x, window.innerWidth - x),
Math.max(y, window.innerHeight - y)
);
// @ts-ignore
const transition = document.startViewTransition(async () => {
await saveConfig({
...config,
theme: newTheme,
language: config.language
});
});
transition.ready.then(() => {
const clipPath = [
`circle(0px at ${x}px ${y}px)`,
`circle(${endRadius}px at ${x}px ${y}px)`
];
document.documentElement.animate(
{
clipPath: clipPath
},
{
duration: 500,
easing: 'ease-in-out',
pseudoElement: '::view-transition-new(root)'
}
);
});
} else {
// 降级方案:直接切换
await saveConfig({
...config,
theme: newTheme,
language: config.language
});
}
};
const toggleLanguage = async () => {
if (!config) return;
const newLang = config.language === 'zh' ? 'en' : 'zh';
await saveConfig({
...config,
language: newLang,
theme: config.theme
});
i18n.changeLanguage(newLang);
};
return (
<nav
style={{ position: 'sticky', top: 0, zIndex: 50 }}
className="pt-9 transition-all duration-200 bg-[#FAFBFC] dark:bg-base-300"
>
{/* 窗口拖拽区域 2 - 覆盖导航栏内容区域(在交互元素下方) */}
<div
className="absolute top-9 left-0 right-0 h-16"
style={{ zIndex: 5, backgroundColor: 'rgba(0,0,0,0.001)' }}
data-tauri-drag-region
/>
<div className="max-w-7xl mx-auto px-8 relative" style={{ zIndex: 10 }}>
<div className="flex items-center justify-between h-16">
{/* Logo - 左侧 */}
<div className="flex items-center">
<Link to="/" className="text-xl font-semibold text-gray-900 dark:text-base-content flex items-center gap-2">
Antigravity Tools
</Link>
</div>
{/* 药丸形状的导航标签 - 居中 */}
<div className="flex items-center gap-1 bg-gray-100 dark:bg-base-200 rounded-full p-1">
{navItems.map((item) => (
<Link
key={item.path}
to={item.path}
className={`px-6 py-2 rounded-full text-sm font-medium transition-all ${isActive(item.path)
? 'bg-gray-900 text-white shadow-sm dark:bg-white dark:text-gray-900'
: 'text-gray-700 hover:text-gray-900 hover:bg-gray-200 dark:text-gray-400 dark:hover:text-base-content dark:hover:bg-base-100'
}`}
>
{item.label}
</Link>
))}
</div>
{/* 右侧快捷设置按钮 */}
<div className="flex items-center gap-2">
{/* 主题切换按钮 */}
<button
onClick={toggleTheme}
className="w-10 h-10 rounded-full bg-gray-100 dark:bg-base-200 hover:bg-gray-200 dark:hover:bg-base-100 flex items-center justify-center transition-colors"
title={config?.theme === 'light' ? '切换到深色模式' : '切换到浅色模式'}
>
{config?.theme === 'light' ? (
<Moon className="w-5 h-5 text-gray-700 dark:text-gray-300" />
) : (
<Sun className="w-5 h-5 text-gray-700 dark:text-gray-300" />
)}
</button>
{/* 语言切换按钮 */}
<button
onClick={toggleLanguage}
className="w-10 h-10 rounded-full bg-gray-100 dark:bg-base-200 hover:bg-gray-200 dark:hover:bg-base-100 flex items-center justify-center transition-colors"
title={config?.language === 'zh' ? 'Switch to English' : '切换到中文'}
>
<span className="text-sm font-bold text-gray-700 dark:text-gray-300">
{config?.language === 'zh' ? 'EN' : '中'}
</span>
</button>
</div>
</div>
</div>
</nav>
);
}
export default Navbar;
|