72 lines
1.9 KiB
TypeScript
72 lines
1.9 KiB
TypeScript
'use client'
|
|
|
|
import { usePathname } from 'next/navigation'
|
|
import { LayoutDashboard, Users, Brain, Settings } from 'lucide-react'
|
|
import { cn } from '@/lib/utils'
|
|
import { useLanguage } from '@/lib/i18n'
|
|
|
|
export interface AdminNavProps {
|
|
className?: string
|
|
}
|
|
|
|
export interface NavItem {
|
|
titleKey: string
|
|
href: string
|
|
icon: React.ReactNode
|
|
}
|
|
|
|
const navItems: NavItem[] = [
|
|
{
|
|
titleKey: 'admin.sidebar.dashboard',
|
|
href: '/admin',
|
|
icon: <LayoutDashboard className="h-4 w-4" />,
|
|
},
|
|
{
|
|
titleKey: 'admin.sidebar.users',
|
|
href: '/admin/users',
|
|
icon: <Users className="h-4 w-4" />,
|
|
},
|
|
{
|
|
titleKey: 'admin.sidebar.aiManagement',
|
|
href: '/admin/ai',
|
|
icon: <Brain className="h-4 w-4" />,
|
|
},
|
|
{
|
|
titleKey: 'admin.sidebar.settings',
|
|
href: '/admin/settings',
|
|
icon: <Settings className="h-4 w-4" />,
|
|
},
|
|
]
|
|
|
|
export function AdminNav({ className }: AdminNavProps) {
|
|
const pathname = usePathname()
|
|
const { t } = useLanguage()
|
|
|
|
return (
|
|
<nav className={cn('flex items-center gap-1', className)}>
|
|
{navItems.map((item) => {
|
|
const isActive = pathname === item.href || (item.href !== '/admin' && pathname?.startsWith(item.href + '/'))
|
|
|
|
return (
|
|
// <a> instead of <Link>: avoids Next.js RSC navigation transitions
|
|
// that trigger React Error #310 (React bug #33580) in production.
|
|
// Full-page reloads are acceptable for admin navigation.
|
|
<a
|
|
key={item.href}
|
|
href={item.href}
|
|
className={cn(
|
|
'flex items-center gap-2 px-3 py-3 text-sm font-medium border-b-2 transition-colors whitespace-nowrap',
|
|
isActive
|
|
? 'border-primary text-primary'
|
|
: 'border-transparent text-muted-foreground hover:text-foreground hover:border-border'
|
|
)}
|
|
>
|
|
{item.icon}
|
|
<span>{t(item.titleKey)}</span>
|
|
</a>
|
|
)
|
|
})}
|
|
</nav>
|
|
)
|
|
}
|