Files
plagiat/src/widgets/cabinet/ui/Sidebar.tsx
nabijonovdavronbek619@gmail.com db0fad7e00 profile page ui complated
2026-04-06 17:55:54 +05:00

153 lines
5.3 KiB
TypeScript

'use client';
import React from 'react';
import {
LayoutDashboard,
FileSearch,
BrainCircuit,
CreditCard,
User,
Home,
X,
} from 'lucide-react';
import { Link } from '@/shared/config/i18n/navigation';
import type { CabinetSection } from '../lib/types';
// ─── Nav items ─────────────────────────────────────────────────────────────────
type NavItemDef =
| { id: CabinetSection; label: string; icon: React.ElementType; href?: never }
| { id: 'home'; label: string; icon: React.ElementType; href: string };
const NAV_ITEMS: NavItemDef[] = [
{ id: 'home', label: 'Bosh sahifa', icon: Home, href: '/' },
{ id: 'dashboard', label: 'Dashboard', icon: LayoutDashboard },
{ id: 'plagiat', label: 'Plagiat', icon: FileSearch },
{ id: 'si', label: 'SI detektor', icon: BrainCircuit },
{ id: 'payments', label: "To'lovlar tarixi", icon: CreditCard },
{ id: 'profile', label: 'Profil', icon: User },
];
// ─── Props ─────────────────────────────────────────────────────────────────────
interface SidebarProps {
active: CabinetSection;
onNavigate: (section: CabinetSection) => void;
isOpen: boolean;
onClose: () => void;
userName: string;
}
// ─── Component ─────────────────────────────────────────────────────────────────
export const Sidebar: React.FC<SidebarProps> = ({
active,
onNavigate,
isOpen,
onClose,
userName,
}) => (
<>
{/* Mobile backdrop */}
{isOpen && (
<div
className="fixed inset-0 z-30 bg-black/30 backdrop-blur-sm lg:hidden"
onClick={onClose}
/>
)}
<aside
className={`
fixed top-0 left-0 z-40 h-full w-60 bg-white border-r border-slate-100
flex flex-col shadow-xl
transition-transform duration-300 ease-out
lg:sticky lg:top-0 lg:h-screen lg:translate-x-0 lg:shadow-none lg:z-auto
${isOpen ? 'translate-x-0' : '-translate-x-full'}
`}
>
{/* Brand */}
<div className="flex items-center justify-between px-5 py-4 border-b border-slate-100">
<div className="flex items-center gap-2.5">
<div className="w-7 h-7 rounded-lg bg-blue-500 flex items-center justify-center">
<span className="text-white text-xs font-bold">P</span>
</div>
<span className="font-semibold text-slate-800 text-sm">Plagat</span>
</div>
<button
onClick={onClose}
className="lg:hidden p-1.5 rounded-lg text-slate-400 hover:text-slate-600 hover:bg-slate-100 transition-colors"
aria-label="Yopish"
>
<X size={15} />
</button>
</div>
{/* User pill */}
<div className="px-3 pt-4 pb-2">
<div className="flex items-center gap-3 px-3 py-2.5 rounded-xl bg-slate-50 border border-slate-100">
<div className="w-8 h-8 rounded-full bg-blue-100 flex items-center justify-center shrink-0">
<span className="text-blue-600 text-xs font-semibold">
{userName.charAt(0).toUpperCase()}
</span>
</div>
<div className="min-w-0">
<p className="text-sm font-medium text-slate-800 truncate">
{userName}
</p>
<p className="text-[11px] text-slate-400">Shaxsiy kabinet</p>
</div>
</div>
</div>
{/* Navigation */}
<nav className="flex-1 px-3 py-2 space-y-0.5 overflow-y-auto">
{NAV_ITEMS.map((item) => {
const Icon = item.icon;
if (item.id === 'home') {
return (
<Link
key="home"
href={item.href}
className="flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm font-medium text-slate-500 hover:text-slate-800 hover:bg-slate-50 transition-all duration-150"
>
<Icon size={17} />
<span>{item.label}</span>
</Link>
);
}
const isActive = item.id === active;
return (
<button
key={item.id}
onClick={() => onNavigate(item.id as CabinetSection)}
className={`
w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm font-medium
transition-all duration-150
${
isActive
? 'bg-blue-50 text-blue-600'
: 'text-slate-500 hover:text-slate-800 hover:bg-slate-50'
}
`}
>
<Icon size={17} />
<span>{item.label}</span>
{isActive && (
<span className="ml-auto w-1.5 h-1.5 rounded-full bg-blue-500 shrink-0" />
)}
</button>
);
})}
</nav>
{/* Footer */}
<div className="px-4 py-4 border-t border-slate-100">
<p className="text-[11px] text-slate-400 text-center">
© 2026 Plagat.uz
</p>
</div>
</aside>
</>
);