107 lines
2.8 KiB
TypeScript
Executable File
107 lines
2.8 KiB
TypeScript
Executable File
'use client';
|
|
|
|
import { IconCirclePlusFilled, IconMail, type Icon } from '@tabler/icons-react';
|
|
import Link from 'next/link';
|
|
import { usePathname } from 'next/navigation';
|
|
|
|
import { Button } from '@nice/ui/components/button';
|
|
import { Badge } from '@nice/ui/components/badge';
|
|
import {
|
|
SidebarGroup,
|
|
SidebarGroupContent,
|
|
SidebarGroupLabel,
|
|
SidebarMenu,
|
|
SidebarMenuButton,
|
|
SidebarMenuItem,
|
|
} from '@nice/ui/components/sidebar';
|
|
|
|
interface NavItem {
|
|
title: string;
|
|
url: string;
|
|
icon?: Icon;
|
|
badge?: string;
|
|
}
|
|
|
|
export function NavMain({
|
|
items,
|
|
title,
|
|
showQuickActions = false,
|
|
}: {
|
|
items: NavItem[];
|
|
title?: string;
|
|
showQuickActions?: boolean;
|
|
}) {
|
|
const pathname = usePathname();
|
|
|
|
// 检查路径是否激活的函数
|
|
const isPathActive = (itemUrl: string) => {
|
|
// 移除语言前缀进行比较
|
|
const cleanPathname = pathname.replace(/^\/[a-z]{2}(-[A-Z]{2})?/, '') || '/';
|
|
|
|
|
|
// 精确匹配
|
|
if (cleanPathname === itemUrl) {
|
|
return true;
|
|
}
|
|
|
|
// 对于非根路径,检查是否以该路径开头
|
|
if (itemUrl !== '/' && cleanPathname.startsWith(itemUrl + '/')) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
return (
|
|
<SidebarGroup>
|
|
{title && <SidebarGroupLabel>{title}</SidebarGroupLabel>}
|
|
<SidebarGroupContent className="flex flex-col gap-2">
|
|
{showQuickActions && (
|
|
<SidebarMenu>
|
|
<SidebarMenuItem className="flex items-center gap-2">
|
|
<SidebarMenuButton
|
|
tooltip="快速创建"
|
|
className="bg-primary text-primary-foreground hover:bg-primary/90 hover:text-primary-foreground active:bg-primary/90 active:text-primary-foreground min-w-8 duration-200 ease-linear"
|
|
asChild
|
|
>
|
|
<Link href="/create">
|
|
<IconCirclePlusFilled />
|
|
<span>快速创建</span>
|
|
</Link>
|
|
</SidebarMenuButton>
|
|
<Button size="icon" className="size-8 group-data-[collapsible=icon]:opacity-0" variant="outline" asChild>
|
|
<Link href="/notifications">
|
|
<IconMail />
|
|
<span className="sr-only">消息</span>
|
|
</Link>
|
|
</Button>
|
|
</SidebarMenuItem>
|
|
</SidebarMenu>
|
|
)}
|
|
<SidebarMenu>
|
|
{items.map((item) => {
|
|
const isActive = isPathActive(item.url);
|
|
return (
|
|
<SidebarMenuItem key={item.title}>
|
|
<SidebarMenuButton tooltip={item.title} isActive={isActive} asChild>
|
|
<Link href={item.url} className="flex items-center justify-between">
|
|
<div className="flex items-center gap-3">
|
|
{item.icon && <item.icon />}
|
|
<span>{item.title}</span>
|
|
</div>
|
|
{item.badge && (
|
|
<Badge variant="secondary" className="ml-auto text-xs">
|
|
{item.badge}
|
|
</Badge>
|
|
)}
|
|
</Link>
|
|
</SidebarMenuButton>
|
|
</SidebarMenuItem>
|
|
);
|
|
})}
|
|
</SidebarMenu>
|
|
</SidebarGroupContent>
|
|
</SidebarGroup>
|
|
);
|
|
}
|