xpeditis2.0/apps/frontend/src/components/shell/bottom-nav.tsx
2026-08-13 17:43:11 +02:00

82 lines
2.8 KiB
TypeScript

'use client';
import * as React from 'react';
import { FileText, Home, MoreHorizontal, Package, Search } from 'lucide-react';
import { Link } from '@/i18n/navigation';
import { cn } from '@/lib/utils';
/**
* Navigation mobile.
*
* Quatre destinations frequentes plus une entree « Plus » qui ouvre la
* navigation complete : aucune section n'est inaccessible depuis le mobile,
* contrairement a la version precedente qui n'exposait que 5 des 8 entrees.
*/
interface BottomNavProps {
pathname: string;
labels: {
home: string;
bookings: string;
documents: string;
tracking: string;
more: string;
};
onMore: () => void;
}
export function BottomNav({ pathname, labels, onMore }: BottomNavProps) {
const items = [
{ href: '/dashboard', icon: Home, label: labels.home, exact: true },
{ href: '/dashboard/bookings', icon: Package, label: labels.bookings },
{ href: '/dashboard/documents', icon: FileText, label: labels.documents },
{ href: '/dashboard/track-trace', icon: Search, label: labels.tracking },
];
const itemClass = (active: boolean) =>
cn(
'flex min-h-[44px] flex-col items-center justify-center gap-0.5 transition-colors',
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset',
active ? 'text-brand-navy' : 'text-neutral-500 hover:text-brand-navy'
);
return (
<nav
aria-label={labels.more}
className="fixed inset-x-0 bottom-0 z-30 border-t border-border bg-white pb-[env(safe-area-inset-bottom)] lg:hidden"
>
<div className="grid grid-cols-5">
{items.map(item => {
const active = item.exact
? pathname === item.href
: pathname === item.href || pathname.startsWith(item.href + '/');
const Icon = item.icon;
return (
<Link
key={item.href}
href={item.href}
aria-current={active ? 'page' : undefined}
className={itemClass(active)}
>
<span className="relative">
<Icon className="size-5" aria-hidden="true" />
{active && (
<span
aria-hidden="true"
className="absolute -top-1.5 left-1/2 h-0.5 w-4 -translate-x-1/2 rounded-full bg-brand-blue"
/>
)}
</span>
<span className="text-[10px] font-medium leading-tight">{item.label}</span>
</Link>
);
})}
<button type="button" onClick={onMore} className={itemClass(false)}>
<MoreHorizontal className="size-5" aria-hidden="true" />
<span className="text-[10px] font-medium leading-tight">{labels.more}</span>
</button>
</div>
</nav>
);
}