Files
hlae-site/web/src/components/SiteNavbar.tsx
purp1e 35d835f68c chore: 统一代码格式并配置开发工具
- 添加 ESLint 和 Prettier 配置以统一代码风格
- 配置项目级 TypeScript 设置
- 更新前后端依赖版本
- 修复代码格式问题(引号、分号、尾随逗号等)
- 优化文件结构和导入路径
2026-03-10 18:24:19 +08:00

130 lines
4.3 KiB
TypeScript

import { Button, Avatar, Dropdown, Label } from '@heroui/react'
import { buttonVariants } from '@heroui/styles'
import { useEffect, useState } from 'react'
import { useSession, signOut } from '../lib/auth-client'
import { SunIcon, MoonIcon } from '@heroicons/react/24/outline'
import { Link as RouterLink } from 'react-router-dom'
export function SiteNavbar() {
const { data: session } = useSession()
const [theme, setTheme] = useState<'light' | 'dark'>(() => {
if (typeof window !== 'undefined') {
return document.documentElement.classList.contains('dark')
? 'dark'
: 'light'
}
return 'light'
})
useEffect(() => {
// Sync theme on mount if needed, but the state is already initialized
}, [])
const toggleTheme = () => {
const nextTheme = theme === 'dark' ? 'light' : 'dark'
document.documentElement.classList.remove('light', 'dark')
document.documentElement.classList.add(nextTheme)
document.documentElement.setAttribute('data-theme', nextTheme)
localStorage.setItem('theme', nextTheme)
setTheme(nextTheme)
}
return (
<nav className="bg-background/70 border-default-100 sticky top-0 z-50 flex w-full items-center justify-between border-b px-8 py-4 backdrop-blur-md">
<div className="flex items-center gap-4">
<RouterLink
to="/"
className="text-foreground text-xl font-bold text-inherit no-underline"
>
HLAE中文站
</RouterLink>
</div>
<div className="flex items-center gap-8">
<div className="hidden items-center gap-8 sm:flex">
<RouterLink
to="/"
className="text-foreground/80 hover:text-foreground font-medium transition-colors"
>
</RouterLink>
<RouterLink
to="/demo"
className="text-foreground/80 hover:text-foreground font-medium transition-colors"
>
</RouterLink>
<RouterLink
to="/about"
className="text-foreground/80 hover:text-foreground font-medium transition-colors"
>
</RouterLink>
</div>
<div className="flex items-center gap-4">
<Button
isIconOnly
variant="ghost"
onPress={toggleTheme}
className="text-foreground/80"
>
{theme === 'dark' ? (
<SunIcon className="h-5 w-5" />
) : (
<MoonIcon className="h-5 w-5" />
)}
</Button>
{session ? (
<Dropdown>
<Dropdown.Trigger>
<Button isIconOnly variant="tertiary" className="rounded-full">
<Avatar size="sm" color="accent">
<Avatar.Image
alt={session.user.name || '用户头像'}
src={session.user.image || ''}
/>
<Avatar.Fallback>
{(session.user.name || 'U').slice(0, 2).toUpperCase()}
</Avatar.Fallback>
</Avatar>
</Button>
</Dropdown.Trigger>
<Dropdown.Popover>
<Dropdown.Menu aria-label="Profile Actions">
<Dropdown.Item id="profile" textValue="Profile">
<Label className="font-semibold">
{session.user.email}
</Label>
</Dropdown.Item>
<Dropdown.Item
id="logout"
textValue="Logout"
variant="danger"
onPress={() => signOut()}
>
<Label className="text-danger">退</Label>
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown.Popover>
</Dropdown>
) : (
<div className="flex items-center gap-4">
<RouterLink
to="/login"
className={buttonVariants({
variant: 'ghost',
className: 'text-foreground font-medium',
})}
>
</RouterLink>
</div>
)}
</div>
</div>
</nav>
)
}