haixunMaster/components/layout/nav-links.tsx

63 lines
2.3 KiB
TypeScript
Raw Normal View History

2026-06-21 12:50:31 +00:00
"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>
);
}