92 lines
3.6 KiB
TypeScript
92 lines
3.6 KiB
TypeScript
|
|
|
|||
|
|
import React from 'react';
|
|||
|
|
import { NavItem } from '../types';
|
|||
|
|
import { NAV_ITEMS } from '../constants';
|
|||
|
|
|
|||
|
|
interface SidebarProps {
|
|||
|
|
activeTab: string;
|
|||
|
|
setActiveTab: (id: string) => void;
|
|||
|
|
isMobileOpen: boolean;
|
|||
|
|
setIsMobileOpen: (open: boolean) => void;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export const Sidebar: React.FC<SidebarProps> = ({ activeTab, setActiveTab, isMobileOpen, setIsMobileOpen }) => {
|
|||
|
|
return (
|
|||
|
|
<>
|
|||
|
|
{/* Mobile Overlay */}
|
|||
|
|
{isMobileOpen && (
|
|||
|
|
<div
|
|||
|
|
className="fixed inset-0 bg-black/50 z-40 lg:hidden backdrop-blur-sm"
|
|||
|
|
onClick={() => setIsMobileOpen(false)}
|
|||
|
|
/>
|
|||
|
|
)}
|
|||
|
|
|
|||
|
|
{/* Sidebar Container */}
|
|||
|
|
<aside
|
|||
|
|
className={`
|
|||
|
|
fixed top-0 left-0 z-50 h-full w-64 bg-slate-850 text-white transition-transform duration-300 ease-in-out
|
|||
|
|
lg:translate-x-0 lg:static lg:block shadow-2xl
|
|||
|
|
${isMobileOpen ? 'translate-x-0' : '-translate-x-full'}
|
|||
|
|
`}
|
|||
|
|
>
|
|||
|
|
<div className="flex flex-col h-full">
|
|||
|
|
{/* Logo Area */}
|
|||
|
|
<div className="p-6 border-b border-slate-700">
|
|||
|
|
<div className="flex items-center gap-3">
|
|||
|
|
<div className="w-8 h-8 rounded-lg bg-primary-500 flex items-center justify-center">
|
|||
|
|
<svg className="w-5 h-5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|||
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
|
|||
|
|
</svg>
|
|||
|
|
</div>
|
|||
|
|
<h1 className="text-base font-bold tracking-tight leading-tight">Центр управления<br/>домами</h1>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Navigation Items */}
|
|||
|
|
<nav className="flex-1 overflow-y-auto py-4">
|
|||
|
|
<ul className="space-y-1 px-3">
|
|||
|
|
{NAV_ITEMS.map((item) => {
|
|||
|
|
const Icon = item.icon;
|
|||
|
|
const isActive = activeTab === item.id;
|
|||
|
|
return (
|
|||
|
|
<li key={item.id}>
|
|||
|
|
<button
|
|||
|
|
onClick={() => {
|
|||
|
|
setActiveTab(item.id);
|
|||
|
|
setIsMobileOpen(false);
|
|||
|
|
}}
|
|||
|
|
className={`
|
|||
|
|
w-full flex items-center gap-3 px-3 py-3 rounded-lg text-sm font-medium transition-all duration-200
|
|||
|
|
${isActive
|
|||
|
|
? 'bg-primary-600 text-white shadow-lg shadow-primary-900/20'
|
|||
|
|
: 'text-slate-400 hover:bg-slate-800 hover:text-white'}
|
|||
|
|
`}
|
|||
|
|
>
|
|||
|
|
<Icon className={`w-5 h-5 ${isActive ? 'text-white' : 'text-slate-400'}`} />
|
|||
|
|
{item.label}
|
|||
|
|
</button>
|
|||
|
|
</li>
|
|||
|
|
);
|
|||
|
|
})}
|
|||
|
|
</ul>
|
|||
|
|
</nav>
|
|||
|
|
|
|||
|
|
{/* User Profile Snippet */}
|
|||
|
|
<div className="p-4 border-t border-slate-700">
|
|||
|
|
<div className="flex items-center gap-3">
|
|||
|
|
<img
|
|||
|
|
src="https://picsum.photos/id/1005/64/64"
|
|||
|
|
alt="Admin"
|
|||
|
|
className="w-10 h-10 rounded-full border-2 border-slate-600"
|
|||
|
|
/>
|
|||
|
|
<div className="overflow-hidden">
|
|||
|
|
<p className="text-sm font-medium text-white truncate">Алексей Петров</p>
|
|||
|
|
<p className="text-xs text-slate-400 truncate">Главный инженер</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</aside>
|
|||
|
|
</>
|
|||
|
|
);
|
|||
|
|
};
|