feat: 优化web
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
'use client';
|
||||
|
||||
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
|
||||
import Link from 'next/link';
|
||||
import { useState } from 'react';
|
||||
import { avatarInitials, useUserProfile } from '@/lib/hooks/use-user-profile';
|
||||
import { useMenuNavigation } from '@/lib/hooks/use-menu-navigation';
|
||||
import { useAuthStore } from '@/stores/auth-store';
|
||||
import { useLayoutStore } from '@/stores/layout-store';
|
||||
import { useTabStore } from '@/stores/tab-store';
|
||||
|
||||
export function UserMenu() {
|
||||
const logout = useAuthStore((s) => s.logout);
|
||||
const sidebarMode = useLayoutStore((s) => s.sidebarMode);
|
||||
const setSidebarMode = useLayoutStore((s) => s.setSidebarMode);
|
||||
const { profile, userSub, loading, label } = useUserProfile();
|
||||
const [open, setOpen] = useState(false);
|
||||
const onMenuNavigate = useMenuNavigation();
|
||||
const initials = avatarInitials(profile, userSub);
|
||||
|
||||
return (
|
||||
<DropdownMenu.Root open={open} onOpenChange={setOpen}>
|
||||
<DropdownMenu.Trigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="flex max-w-[min(100vw-8rem,14rem)] items-center gap-2 rounded-lg border-0 bg-white px-2 py-1.5 text-left text-sm text-neutral-800 outline-none hover:bg-neutral-50 data-[state=open]:bg-neutral-50"
|
||||
aria-label="用户菜单"
|
||||
>
|
||||
{profile?.avatar ? (
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img src={profile.avatar} alt="" className="h-8 w-8 shrink-0 rounded-full object-cover" />
|
||||
) : (
|
||||
<span
|
||||
className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-neutral-200 text-xs font-medium text-neutral-700"
|
||||
aria-hidden
|
||||
>
|
||||
{initials}
|
||||
</span>
|
||||
)}
|
||||
<span className="min-w-0 flex-1 truncate font-medium">{label}</span>
|
||||
<span className="shrink-0 text-neutral-400" aria-hidden>
|
||||
{open ? '▴' : '▾'}
|
||||
</span>
|
||||
</button>
|
||||
</DropdownMenu.Trigger>
|
||||
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content
|
||||
className="z-50 w-60 rounded-lg border border-neutral-200 bg-white py-1 shadow-lg outline-none"
|
||||
sideOffset={4}
|
||||
align="end"
|
||||
collisionPadding={8}
|
||||
>
|
||||
<div className="border-b border-neutral-100 px-3 py-2">
|
||||
<p className="truncate text-sm font-medium text-neutral-900">{label}</p>
|
||||
{profile?.email ? (
|
||||
<p className="mt-0.5 truncate text-xs text-neutral-500">{profile.email}</p>
|
||||
) : null}
|
||||
{!profile?.email && userSub ? (
|
||||
<p className="mt-0.5 truncate font-mono text-xs text-neutral-400" title={userSub}>
|
||||
ID {userSub}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<DropdownMenu.Item asChild>
|
||||
<Link
|
||||
href="/dashboard"
|
||||
className="block cursor-pointer px-3 py-2 text-sm text-neutral-800 outline-none data-highlighted:bg-neutral-50"
|
||||
onClick={() => onMenuNavigate('/dashboard', '概览')}
|
||||
>
|
||||
工作台
|
||||
</Link>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item asChild>
|
||||
<Link
|
||||
href="/dashboard/account"
|
||||
className="block cursor-pointer px-3 py-2 text-sm text-neutral-800 outline-none data-highlighted:bg-neutral-50"
|
||||
onClick={() => onMenuNavigate('/dashboard/account', '个人中心')}
|
||||
>
|
||||
个人中心
|
||||
</Link>
|
||||
</DropdownMenu.Item>
|
||||
|
||||
<DropdownMenu.Separator className="my-1 h-px bg-neutral-100" />
|
||||
|
||||
<div className="border-b border-neutral-100 px-3 py-2">
|
||||
<p className="mb-1 text-xs text-neutral-500">侧栏布局</p>
|
||||
<div className="flex gap-1">
|
||||
<button
|
||||
type="button"
|
||||
className={`flex-1 rounded border px-2 py-1 text-xs ${
|
||||
sidebarMode === 'classic'
|
||||
? 'border-neutral-900 bg-neutral-900 text-white'
|
||||
: 'border-neutral-200 bg-white text-neutral-700'
|
||||
}`}
|
||||
onClick={() => setSidebarMode('classic')}
|
||||
>
|
||||
经典
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`flex-1 rounded border px-2 py-1 text-xs ${
|
||||
sidebarMode === 'icon'
|
||||
? 'border-neutral-900 bg-neutral-900 text-white'
|
||||
: 'border-neutral-200 bg-white text-neutral-700'
|
||||
}`}
|
||||
onClick={() => setSidebarMode('icon')}
|
||||
>
|
||||
图标
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DropdownMenu.Item
|
||||
className="cursor-pointer px-3 py-2 text-left text-sm text-red-600 outline-none data-highlighted:bg-red-50"
|
||||
onSelect={() => {
|
||||
void logout();
|
||||
}}
|
||||
>
|
||||
退出登录
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Portal>
|
||||
</DropdownMenu.Root>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user