gitdataai/src/components/layout/sidebar-user.tsx
ZhenYi aab9f0dbf1 feat(frontend): 替换全屏loading动画为SVG逐帧绘制动画
- 新增 loading-animation.tsx 组件,从 public/load.html 转换
- 动画特性: SVG路径逐条绘制 + 渐变填充,最少展示1.5秒
- 替换 homepage/layout.tsx, workspace/redirect.tsx, protected-route.tsx 中的全屏加载
- 修复 sidebar-user.tsx 中 Invitations 按钮在缩回状态下的居中问题
2026-04-28 19:59:31 +08:00

116 lines
5.4 KiB
TypeScript

import {Avatar, AvatarFallback, AvatarImage} from '@/components/ui/avatar';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import {useUser} from '@/contexts';
import {cn} from '@/lib/utils';
import {UserPlus, Bell} from 'lucide-react';
import {useNavigate} from 'react-router-dom';
const btnClass = 'flex w-full h-9 justify-start items-center rounded-md font-medium hover:bg-muted cursor-pointer bg-transparent border-0 text-left text-sm';
export function SidebarUser({collapsed}: { collapsed: boolean }) {
const {user, logout} = useUser();
const navigate = useNavigate();
return (
<div className="w-full mb-2">
<button type="button" className={cn(btnClass, collapsed ? 'justify-center px-0' : 'px-2')}
onClick={() => navigate('/invitations')}>
<span className={cn('flex h-6 items-center shrink-0 w-6', collapsed && 'justify-center')}>
<UserPlus className="h-4 w-4"/>
</span>
{!collapsed && <span className="text-sm leading-none">Invitations</span>}
</button>
{!collapsed ? (
<button type="button" className={cn(btnClass, 'px-2')}
onClick={() => navigate('/notify')}>
<span className="flex h-6 items-center shrink-0 w-6">
<Bell className="h-4 w-4"/>
</span>
<span className="text-sm leading-none">Notify</span>
</button>
) : (
<button type="button" className={cn(btnClass, 'justify-center px-0')}
onClick={() => navigate('/notify')}>
<span className="flex h-6 items-center shrink-0 w-6 justify-center">
<Bell className="h-4 w-4"/>
</span>
</button>
)}
{user && (
<DropdownMenu>
<DropdownMenuTrigger
render={
<button
type="button"
className={cn(btnClass, collapsed ? 'justify-center px-0' : 'px-2')}
/>
}
>
<span
className={cn('flex h-6 items-center shrink-0', collapsed ? 'w-6 justify-center' : 'w-6')}>
<Avatar className="h-6 w-6">
<AvatarImage src={user.avatar_url || ''}/>
<AvatarFallback>
{user.username?.charAt(0).toUpperCase()}
</AvatarFallback>
</Avatar>
</span>
{!collapsed && <span className="text-sm leading-none">{user.username}</span>}
</DropdownMenuTrigger>
<DropdownMenuContent side="right" align="start">
{!collapsed && (
<DropdownMenuGroup>
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuItem onClick={() => navigate(`/user/${user.username}`)}>
Profile
</DropdownMenuItem>
<DropdownMenuItem onClick={() => navigate('/settings')}>
Settings
</DropdownMenuItem>
<DropdownMenuSeparator/>
<DropdownMenuItem className="text-red-600 focus:text-red-600" onClick={() => logout()}>
Log out
</DropdownMenuItem>
</DropdownMenuGroup>
)}
{collapsed && (
<>
<DropdownMenuItem onClick={() => {
navigate(`/user/${user.username}`);
}}>
<span className="flex h-6 items-center shrink-0">
Profile
</span>
</DropdownMenuItem>
<DropdownMenuItem onClick={() => {
navigate('/settings');
}}>
<span className="flex h-6 items-center shrink-0">
Settings
</span>
</DropdownMenuItem>
<DropdownMenuSeparator/>
<DropdownMenuItem className="text-red-600 focus:text-red-600" onClick={() => logout()}>
<span className="flex h-6 items-center shrink-0">
Log out
</span>
</DropdownMenuItem>
</>
)}
</DropdownMenuContent>
</DropdownMenu>
)}
</div>
);
}