SPB Git forge

spb/fetcha

Public
11commits 1branches 0releases
1.5 MBsize
maindefault branch
16 days agolast push
TypeScript 97.5% SQL 1.4% Python 0.8%
3.2 KB · 69 lines tsx
Raw Blame History
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