TypeScript 97.5%
SQL 1.4%
Python 0.8%
1"use client";2import Link from "next/link";3import { usePathname } from "next/navigation";4import { Activity, BarChart3, BookOpen, CreditCard, FolderKanban, KeyRound, LayoutDashboard, ListTree, Network, Play, Settings, Shield, Waypoints } from "lucide-react";5import { cn } from "@/lib/utils";6import { Logo } from "@/components/ui/logo";78export const DASHBOARD_NAV = [9 { href: "/dashboard", label: "Overview", icon: LayoutDashboard, exact: true },10 { href: "/dashboard/playground", label: "Playground", icon: Play },11 { href: "/dashboard/api-keys", label: "API Keys", icon: KeyRound },12 { href: "/dashboard/projects", label: "Projects", icon: FolderKanban },13 { href: "/dashboard/requests", label: "Requests", icon: ListTree },14 { href: "/dashboard/crawls", label: "Crawls", icon: Network },15 { href: "/dashboard/sessions", label: "Sessions", icon: Waypoints },16 { href: "/dashboard/usage", label: "Usage", icon: Activity },17 { href: "/dashboard/analytics", label: "Analytics", icon: BarChart3 },18 { href: "/dashboard/billing", label: "Billing", icon: CreditCard },19 { href: "/docs", label: "Documentation", icon: BookOpen, external: true },20 { href: "/dashboard/settings", label: "Settings", icon: Settings },21] as const;2223export function SidebarNav({ isAdmin, onNavigate, className }: { isAdmin?: boolean; onNavigate?: () => void; className?: string }) {24 const pathname = usePathname();25 const items = [...DASHBOARD_NAV, ...(isAdmin ? [{ href: "/admin", label: "Admin", icon: Shield } as const] : [])];26 return (27 <nav className={cn("flex flex-col gap-0.5", className)} aria-label="Dashboard">28 {items.map((item) => {29 const active = "exact" in item && item.exact ? pathname === item.href : pathname === item.href || pathname.startsWith(item.href + "/");30 const Icon = item.icon;31 return (32 <Link33 key={item.href}34 href={item.href}35 onClick={onNavigate}36 target={"external" in item && item.external ? "_blank" : undefined}37 className={cn(38 "group flex h-8 items-center gap-2.5 rounded-md px-2.5 text-[13.5px] font-medium transition-colors",39 active ? "bg-bg-muted text-fg" : "text-fg-muted hover:bg-bg-subtle hover:text-fg",40 )}41 aria-current={active ? "page" : undefined}42 >43 <Icon className={cn("size-4 shrink-0", active ? "text-fg" : "text-fg-subtle group-hover:text-fg-muted")} aria-hidden />44 {item.label}45 </Link>46 );47 })}48 </nav>49 );50}5152export function Sidebar({ isAdmin }: { isAdmin?: boolean }) {53 return (54 <aside className="hidden lg:flex w-[232px] shrink-0 flex-col border-r border-border bg-bg-subtle/60">55 <div className="flex h-14 items-center px-5">56 <Logo href="/dashboard" size="sm" />57 </div>58 <div className="flex-1 overflow-y-auto px-3 pb-4 scrollbar-thin">59 <SidebarNav isAdmin={isAdmin} />60 </div>61 <div className="border-t border-border px-4 py-3 text-[11.5px] text-fg-subtle">62 <a href="/status" className="hover:text-fg" target="_blank" rel="noreferrer">63 <span className="mr-1.5 inline-block size-1.5 rounded-full bg-success align-middle" /> All systems operational64 </a>65 </div>66 </aside>67 );68}69