206 lines
6.8 KiB
TypeScript
206 lines
6.8 KiB
TypeScript
import { NavLink } from "react-router";
|
|
|
|
const navItems = [
|
|
{
|
|
label: "Обзор",
|
|
path: "/dashboard",
|
|
icon: (
|
|
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24">
|
|
<path
|
|
stroke="currentColor"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth="2"
|
|
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"
|
|
/>
|
|
</svg>
|
|
),
|
|
},
|
|
{
|
|
label: "Транзакции",
|
|
path: "/dashboard/transactions",
|
|
icon: (
|
|
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24">
|
|
<path
|
|
stroke="currentColor"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth="2"
|
|
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01"
|
|
/>
|
|
</svg>
|
|
),
|
|
},
|
|
{
|
|
label: "Категории",
|
|
path: "/dashboard/categories",
|
|
icon: (
|
|
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24">
|
|
<path
|
|
stroke="currentColor"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth="2"
|
|
d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"
|
|
/>
|
|
</svg>
|
|
),
|
|
},
|
|
{
|
|
label: "Бюджет",
|
|
path: "/dashboard/budgets",
|
|
icon: (
|
|
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24">
|
|
<path
|
|
stroke="currentColor"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth="2"
|
|
d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"
|
|
/>
|
|
</svg>
|
|
),
|
|
},
|
|
{
|
|
label: "Цели",
|
|
path: "/dashboard/goals",
|
|
icon: (
|
|
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24">
|
|
<path
|
|
stroke="currentColor"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth="2"
|
|
d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z"
|
|
/>
|
|
</svg>
|
|
),
|
|
},
|
|
{
|
|
label: "Рекомендации",
|
|
path: "/dashboard/recommendations",
|
|
icon: (
|
|
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24">
|
|
<path
|
|
stroke="currentColor"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth="2"
|
|
d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"
|
|
/>
|
|
</svg>
|
|
),
|
|
},
|
|
{
|
|
label: "Аналитика",
|
|
path: "/dashboard/analytics",
|
|
icon: (
|
|
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24">
|
|
<path
|
|
stroke="currentColor"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth="2"
|
|
d="M7 12l3-3 3 3 4-4M8 21l4-4 4 4M3 4h18M4 4h16v12a1 1 0 01-1 1H5a1 1 0 01-1-1V4z"
|
|
/>
|
|
</svg>
|
|
),
|
|
},
|
|
{
|
|
label: "Настройки",
|
|
path: "/dashboard/settings",
|
|
icon: (
|
|
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24">
|
|
<path
|
|
stroke="currentColor"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth="2"
|
|
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
|
|
/>
|
|
<path
|
|
stroke="currentColor"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth="2"
|
|
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
|
/>
|
|
</svg>
|
|
),
|
|
},
|
|
];
|
|
|
|
interface SidebarProps {
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
}
|
|
|
|
export const Sidebar = ({ isOpen, onClose }: SidebarProps) => {
|
|
return (
|
|
<>
|
|
{/* Mobile overlay */}
|
|
{isOpen && (
|
|
<div
|
|
className="fixed inset-0 z-40 bg-black/50 lg:hidden"
|
|
onClick={onClose}
|
|
/>
|
|
)}
|
|
|
|
{/* Sidebar */}
|
|
<aside
|
|
className={`fixed inset-y-0 left-0 z-50 flex w-64 flex-col border-r border-slate-200 bg-white transition-transform lg:static lg:translate-x-0 ${
|
|
isOpen ? "translate-x-0" : "-translate-x-full"
|
|
}`}
|
|
>
|
|
{/* Logo */}
|
|
<div className="flex h-16 items-center gap-3 border-b border-slate-200 px-6">
|
|
<div className="flex h-9 w-9 items-center justify-center rounded-xl bg-slate-900 text-white">
|
|
<svg viewBox="0 0 24 24" className="h-5 w-5" fill="none">
|
|
<path
|
|
d="M5 12.5l4 4L19 7.5"
|
|
stroke="currentColor"
|
|
strokeWidth="2"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
/>
|
|
</svg>
|
|
</div>
|
|
<span className="text-base font-semibold tracking-tight">
|
|
Finance App
|
|
</span>
|
|
</div>
|
|
|
|
{/* Navigation */}
|
|
<nav className="flex-1 overflow-y-auto p-4">
|
|
<ul className="space-y-1">
|
|
{navItems.map((item) => (
|
|
<li key={item.path}>
|
|
<NavLink
|
|
to={item.path}
|
|
end={item.path === "/dashboard"}
|
|
onClick={onClose}
|
|
className={({ isActive }) =>
|
|
`flex items-center gap-3 rounded-xl px-3 py-2.5 text-sm font-medium transition-colors ${
|
|
isActive
|
|
? "bg-slate-900 text-white"
|
|
: "text-slate-600 hover:bg-slate-100 hover:text-slate-900"
|
|
}`
|
|
}
|
|
>
|
|
{item.icon}
|
|
{item.label}
|
|
</NavLink>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</nav>
|
|
|
|
{/* Footer */}
|
|
<div className="border-t border-slate-200 p-4">
|
|
<p className="text-xs text-slate-400">© 2025 Finance App</p>
|
|
</div>
|
|
</aside>
|
|
</>
|
|
);
|
|
};
|