104 lines
2.4 KiB
TypeScript
Executable File
104 lines
2.4 KiB
TypeScript
Executable File
'use client';
|
|
|
|
import React from 'react';
|
|
import { cn } from '@nice/ui/lib/utils';
|
|
import { Button } from '@nice/ui/components/button';
|
|
import { ScrollArea } from '@nice/ui/components/scroll-area';
|
|
import {
|
|
Users,
|
|
UserCheck,
|
|
ChevronLeft,
|
|
ChevronRight
|
|
} from 'lucide-react';
|
|
|
|
interface MenuItem {
|
|
key: string;
|
|
label: string;
|
|
icon: React.ComponentType<any>;
|
|
description?: string;
|
|
}
|
|
|
|
const menuItems: MenuItem[] = [
|
|
{
|
|
key: 'overview',
|
|
label: '人员总览',
|
|
icon: Users,
|
|
},
|
|
{
|
|
key: 'elite',
|
|
label: '骨干名册',
|
|
icon: UserCheck,
|
|
}
|
|
];
|
|
|
|
interface ProfileSidebarProps {
|
|
activeItem: string;
|
|
onItemChange: (key: string) => void;
|
|
collapsed?: boolean;
|
|
onToggleCollapse?: () => void;
|
|
}
|
|
|
|
export function ProfileSidebar({
|
|
activeItem,
|
|
onItemChange,
|
|
collapsed = false,
|
|
onToggleCollapse
|
|
}: ProfileSidebarProps) {
|
|
return (
|
|
<div className={cn(
|
|
"h-full bg-white border-r border-gray-200 flex flex-col transition-all duration-300 ease-in-out",
|
|
collapsed ? "w-16" : "w-42"
|
|
)}>
|
|
{/* 菜单区域 */}
|
|
<ScrollArea className="flex-1">
|
|
<div className="p-3 ">
|
|
<nav className="space-y-2">
|
|
{menuItems.map((item) => {
|
|
const Icon = item.icon;
|
|
const isActive = activeItem === item.key;
|
|
|
|
return (
|
|
<Button
|
|
key={item.key}
|
|
variant="ghost"
|
|
onClick={() => onItemChange(item.key)}
|
|
className={cn(
|
|
"w-full transition-all duration-200 ease-in-out",
|
|
collapsed
|
|
? "h-12 justify-center p-0"
|
|
: "h-auto justify-start p-3 text-left",
|
|
isActive
|
|
? "bg-blue-50 text-blue-600"
|
|
: "text-gray-600 hover:bg-gray-50 hover:text-gray-900"
|
|
)}
|
|
>
|
|
<div className={cn(
|
|
"flex items-center transition-all duration-200 cursor-pointer",
|
|
collapsed ? "justify-center" : "space-x-3"
|
|
)}>
|
|
<Icon className="w-5 h-5 flex-shrink-0" />
|
|
|
|
{!collapsed && (
|
|
<div className="flex-1 min-w-0 opacity-100 cursor-pointer transition-opacity duration-200">
|
|
<div className="font-medium text-sm">
|
|
{item.label}
|
|
</div>
|
|
{item.description && (
|
|
<div className="text-xs text-gray-500 mt-0.5">
|
|
{item.description}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</Button>
|
|
);
|
|
})}
|
|
</nav>
|
|
</div>
|
|
</ScrollArea>
|
|
|
|
|
|
</div>
|
|
);
|
|
}
|