63 lines
2.3 KiB
TypeScript
63 lines
2.3 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { usePathname } from "next/navigation";
|
|
import type { NavGroup } from "@/lib/nav";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface NavLinksProps {
|
|
groups: NavGroup[];
|
|
badgeCount?: number;
|
|
onNavigate?: () => void;
|
|
compact?: boolean;
|
|
}
|
|
|
|
export function NavLinks({ groups, badgeCount = 0, onNavigate, compact }: NavLinksProps) {
|
|
const pathname = usePathname();
|
|
|
|
return (
|
|
<div className={cn("space-y-5", compact && "space-y-4")}>
|
|
{groups.map((group, groupIndex) => (
|
|
<div key={group.label}>
|
|
{groupIndex > 0 && <div className="mb-3 border-t border-border" />}
|
|
<p className="mb-1.5 px-2 text-[11px] text-muted-foreground">{group.label}</p>
|
|
<ul className="space-y-px">
|
|
{group.items.map((item) => {
|
|
const active = pathname === item.href;
|
|
const Icon = item.icon;
|
|
const badge = item.showBadge && badgeCount > 0 ? badgeCount : 0;
|
|
return (
|
|
<li key={item.href}>
|
|
<Link
|
|
href={item.href}
|
|
onClick={onNavigate}
|
|
className={cn(
|
|
"nav-item group flex h-8 items-center gap-2.5 rounded-md px-2 text-[13px] outline-none transition-colors",
|
|
active ? "nav-item-active" : "nav-item-idle"
|
|
)}
|
|
>
|
|
<Icon
|
|
className={cn(
|
|
"h-[15px] w-[15px] shrink-0 transition-colors",
|
|
active
|
|
? "text-primary"
|
|
: "text-muted-foreground group-hover:text-foreground group-focus-visible:text-foreground"
|
|
)}
|
|
strokeWidth={active ? 2.25 : 1.75}
|
|
/>
|
|
<span className="min-w-0 flex-1 truncate">{item.label}</span>
|
|
{badge > 0 && (
|
|
<span className="flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-primary/90 px-1 text-[10px] font-medium leading-none text-primary-foreground">
|
|
{badge > 99 ? "99+" : badge}
|
|
</span>
|
|
)}
|
|
</Link>
|
|
</li>
|
|
);
|
|
})}
|
|
</ul>
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
} |