85 lines
2.1 KiB
TypeScript
85 lines
2.1 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
import type { MouseEventHandler, ReactNode } from "react";
|
||
|
|
import Link from "next/link";
|
||
|
|
|
||
|
|
import { cn } from "@/lib/utils";
|
||
|
|
import {
|
||
|
|
Tooltip,
|
||
|
|
TooltipContent,
|
||
|
|
TooltipTrigger,
|
||
|
|
} from "@/components/ui/tooltip";
|
||
|
|
|
||
|
|
export interface SidebarItemProps {
|
||
|
|
href: string;
|
||
|
|
icon: ReactNode;
|
||
|
|
label: string;
|
||
|
|
active?: boolean;
|
||
|
|
collapsed?: boolean;
|
||
|
|
badge?: number;
|
||
|
|
dotColor?: string;
|
||
|
|
onClick?: MouseEventHandler<HTMLAnchorElement>;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function SidebarItem({
|
||
|
|
href,
|
||
|
|
icon,
|
||
|
|
label,
|
||
|
|
active,
|
||
|
|
collapsed,
|
||
|
|
badge,
|
||
|
|
dotColor,
|
||
|
|
onClick,
|
||
|
|
}: SidebarItemProps) {
|
||
|
|
const inner = (
|
||
|
|
<Link
|
||
|
|
href={href}
|
||
|
|
onClick={onClick}
|
||
|
|
className={cn(
|
||
|
|
"group flex min-h-8 w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm text-sidebar-foreground transition-colors duration-150",
|
||
|
|
"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
||
|
|
collapsed && "justify-center gap-0 px-0",
|
||
|
|
active &&
|
||
|
|
"bg-sidebar-accent text-sidebar-accent-foreground shadow-[inset_3px_0_0_0_hsl(var(--primary))]",
|
||
|
|
)}
|
||
|
|
>
|
||
|
|
<span className="flex shrink-0 items-center justify-center text-muted-foreground group-hover:text-sidebar-accent-foreground [&_svg]:size-[18px]">
|
||
|
|
{icon}
|
||
|
|
</span>
|
||
|
|
{dotColor && !collapsed ? (
|
||
|
|
<span
|
||
|
|
className="size-2 shrink-0 rounded-full"
|
||
|
|
style={{ backgroundColor: dotColor }}
|
||
|
|
aria-hidden
|
||
|
|
/>
|
||
|
|
) : null}
|
||
|
|
<span
|
||
|
|
className={cn(
|
||
|
|
"min-w-0 flex-1 truncate text-left font-medium",
|
||
|
|
collapsed && "sr-only",
|
||
|
|
)}
|
||
|
|
>
|
||
|
|
{label}
|
||
|
|
</span>
|
||
|
|
{badge != null && badge > 0 && !collapsed ? (
|
||
|
|
<span className="rounded-full bg-primary/15 px-1.5 py-0 text-[10px] font-semibold tabular-nums text-primary">
|
||
|
|
{badge > 99 ? "99+" : badge}
|
||
|
|
</span>
|
||
|
|
) : null}
|
||
|
|
</Link>
|
||
|
|
);
|
||
|
|
|
||
|
|
if (collapsed) {
|
||
|
|
return (
|
||
|
|
<Tooltip delayDuration={0}>
|
||
|
|
<TooltipTrigger asChild>{inner}</TooltipTrigger>
|
||
|
|
<TooltipContent side="right" className="font-medium">
|
||
|
|
{label}
|
||
|
|
</TooltipContent>
|
||
|
|
</Tooltip>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return inner;
|
||
|
|
}
|