44 lines
1.7 KiB
TypeScript
44 lines
1.7 KiB
TypeScript
![]() |
import { motion } from 'framer-motion';
|
||
|
import { useNavigate, useLocation } from 'react-router-dom';
|
||
|
import { NavItem } from '@nicestack/client';
|
||
|
|
||
|
interface SidebarProps {
|
||
|
navItems: Array<NavItem>;
|
||
|
}
|
||
|
|
||
|
export function Sidebar({ navItems }: SidebarProps) {
|
||
|
const navigate = useNavigate();
|
||
|
const location = useLocation();
|
||
|
return (
|
||
|
<motion.aside
|
||
|
initial={{ x: -300, opacity: 0 }}
|
||
|
animate={{ x: 0, opacity: 1 }}
|
||
|
exit={{ x: -300, opacity: 0 }}
|
||
|
transition={{ type: "spring", bounce: 0.1, duration: 0.5 }}
|
||
|
className="fixed left-0 top-16 bottom-0 w-64 bg-white border-r border-gray-200 z-40"
|
||
|
>
|
||
|
<div className="p-4 space-y-2">
|
||
|
{navItems.map((item, index) => {
|
||
|
const isActive = location.pathname === item.path;
|
||
|
return (
|
||
|
<motion.button
|
||
|
key={index}
|
||
|
whileHover={{ x: 5 }}
|
||
|
onClick={() => {
|
||
|
navigate(item.path)
|
||
|
}}
|
||
|
className={`flex items-center gap-3 w-full p-3 rounded-lg transition-colors
|
||
|
${isActive
|
||
|
? 'bg-blue-50 text-blue-600'
|
||
|
: 'text-gray-700 hover:bg-blue-50 hover:text-blue-600'
|
||
|
}`}
|
||
|
>
|
||
|
{item.icon}
|
||
|
<span className="font-medium">{item.label}</span>
|
||
|
</motion.button>
|
||
|
);
|
||
|
})}
|
||
|
</div>
|
||
|
</motion.aside>
|
||
|
);
|
||
|
}
|