97 lines
3.9 KiB
TypeScript
97 lines
3.9 KiB
TypeScript
|
|
import { DatabaseBackup, Image, LayoutGrid, LogOut, Settings, X } from 'lucide-react';
|
||
|
|
import { useNavigation } from '../../contexts/NavigationContext';
|
||
|
|
import { useSession } from '../../contexts/SessionContext';
|
||
|
|
import { useIsMobile } from '../../hooks/useIsMobile';
|
||
|
|
import { useStorageSummary } from '../../hooks/useStorageSummary';
|
||
|
|
import type { NavKey } from '../../types';
|
||
|
|
import { TripoliLogo, TripoliWordmark } from './TripoliLogo';
|
||
|
|
|
||
|
|
const NAV_ITEMS: Array<{ key: NavKey; label: string; icon: typeof LayoutGrid }> = [
|
||
|
|
{ key: 'dashboard', label: 'Tableau de bord', icon: LayoutGrid },
|
||
|
|
{ key: 'photos', label: 'Photos', icon: Image },
|
||
|
|
{ key: 'backups', label: 'Sauvegardes', icon: DatabaseBackup },
|
||
|
|
{ key: 'settings', label: 'Réglages', icon: Settings },
|
||
|
|
];
|
||
|
|
|
||
|
|
export function TripoliSidebar() {
|
||
|
|
const { nav, goTo, drawerOpen, closeDrawer } = useNavigation();
|
||
|
|
const { user, logout } = useSession();
|
||
|
|
const isMobile = useIsMobile();
|
||
|
|
const summary = useStorageSummary();
|
||
|
|
|
||
|
|
if (isMobile && !drawerOpen) return null;
|
||
|
|
|
||
|
|
return (
|
||
|
|
<aside
|
||
|
|
className={`z-40 flex w-64 flex-none flex-col gap-6 border-r border-line bg-panel2 p-[18px] pt-6 backdrop-blur-2xl ${
|
||
|
|
isMobile ? 'fixed inset-y-0 left-0 min-h-screen' : 'sticky top-0 min-h-screen'
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
<div className="flex items-center justify-between gap-2.5 px-1.5">
|
||
|
|
<div className="flex items-center gap-2.5">
|
||
|
|
<TripoliLogo size={28} />
|
||
|
|
<TripoliWordmark className="text-ink" />
|
||
|
|
</div>
|
||
|
|
{isMobile && (
|
||
|
|
<button
|
||
|
|
type="button"
|
||
|
|
onClick={closeDrawer}
|
||
|
|
aria-label="Fermer le menu"
|
||
|
|
className="flex h-[30px] w-[30px] items-center justify-center rounded-[9px] border border-line text-ink"
|
||
|
|
>
|
||
|
|
<X size={15} />
|
||
|
|
</button>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<nav className="flex flex-col gap-[3px]">
|
||
|
|
{NAV_ITEMS.map(({ key, label, icon: Icon }) => {
|
||
|
|
const active = nav === key;
|
||
|
|
return (
|
||
|
|
<button
|
||
|
|
key={key}
|
||
|
|
type="button"
|
||
|
|
onClick={() => goTo(key)}
|
||
|
|
className={`flex items-center gap-2.5 rounded-[11px] px-3 py-2.5 text-left text-sm font-semibold transition-colors ${
|
||
|
|
active ? 'bg-selected text-ink' : 'bg-transparent text-ink-soft hover:bg-field'
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
<Icon size={17} strokeWidth={1.8} />
|
||
|
|
{label}
|
||
|
|
</button>
|
||
|
|
);
|
||
|
|
})}
|
||
|
|
</nav>
|
||
|
|
|
||
|
|
<div className="rounded-2xl border border-line bg-panel p-4">
|
||
|
|
<div className="flex justify-between gap-2 text-xs font-semibold">
|
||
|
|
<span className="text-ink">Stockage</span>
|
||
|
|
<span className="text-ink-soft">{summary?.label ?? '—'}</span>
|
||
|
|
</div>
|
||
|
|
<div className="my-2.5 h-[7px] overflow-hidden rounded-full bg-field">
|
||
|
|
<div className="h-[7px] rounded-full bg-brand-gradient" style={{ width: `${summary?.percent ?? 0}%` }} />
|
||
|
|
</div>
|
||
|
|
<p className="m-0 text-[11.5px] leading-relaxed text-ink-soft">{summary?.sealedNote ?? ''}</p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="mt-auto flex items-center gap-2.5 rounded-2xl border border-line bg-panel p-2.5">
|
||
|
|
<span className="flex h-[34px] w-[34px] flex-none items-center justify-center rounded-[11px] bg-brand-gradient text-[12.5px] font-bold text-white">
|
||
|
|
{user?.initials ?? '??'}
|
||
|
|
</span>
|
||
|
|
<div className="min-w-0 flex-1">
|
||
|
|
<p className="m-0 truncate text-[13px] font-semibold text-ink">{user?.name ?? 'Invité'}</p>
|
||
|
|
<p className="m-0 text-[11.5px] text-ink-soft">{user?.role ?? ''}</p>
|
||
|
|
</div>
|
||
|
|
<button
|
||
|
|
type="button"
|
||
|
|
onClick={logout}
|
||
|
|
aria-label="Se déconnecter"
|
||
|
|
className="flex h-7 w-7 flex-none items-center justify-center rounded-lg text-ink-soft"
|
||
|
|
>
|
||
|
|
<LogOut size={16} strokeWidth={1.8} />
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</aside>
|
||
|
|
);
|
||
|
|
}
|