"use client"; import { useEffect, useState } from "react"; import Link from "next/link"; import { usePathname } from "next/navigation"; import Image from "next/image"; import { useAuth } from "@/lib/auth/auth-context"; import { fetchUserWorkspaces } from "@/lib/api/workspaces"; import { useSidebar } from "./SidebarContext"; // --------------------------------------------------------------------------- // Types // --------------------------------------------------------------------------- interface NavBadge { label: string; pulse?: boolean; } interface NavItemConfig { href: string; label: string; icon: React.JSX.Element; badge?: NavBadge; } interface NavGroup { label: string; items: NavItemConfig[]; } // --------------------------------------------------------------------------- // SVG Icons (16x16 viewBox, stroke="currentColor", strokeWidth="1.5") // --------------------------------------------------------------------------- function IconDashboard(): React.JSX.Element { return ( ); } function IconProjects(): React.JSX.Element { return ( ); } function IconProjectWorkspace(): React.JSX.Element { return ( ); } function IconKanban(): React.JSX.Element { return ( ); } function IconFileManager(): React.JSX.Element { return ( ); } function IconLogs(): React.JSX.Element { return ( ); } function IconTerminal(): React.JSX.Element { return ( ); } function IconSettings(): React.JSX.Element { return ( ); } function IconChevronLeft(): React.JSX.Element { return ( ); } function IconChevronRight(): React.JSX.Element { return ( ); } // --------------------------------------------------------------------------- // Nav groups definition // --------------------------------------------------------------------------- const NAV_GROUPS: NavGroup[] = [ { label: "Overview", items: [ { href: "/", label: "Dashboard", icon: , badge: { label: "live", pulse: true }, }, ], }, { label: "Workspace", items: [ { href: "/projects", label: "Projects", icon: , }, { href: "/workspace", label: "Project Workspace", icon: , }, { href: "/kanban", label: "Kanban", icon: , }, { href: "/files", label: "File Manager", icon: , }, ], }, { label: "Operations", items: [ { href: "/logs", label: "Logs & Telemetry", icon: , badge: { label: "live", pulse: true }, }, { href: "/terminal", label: "Terminal", icon: , }, ], }, { label: "System", items: [ { href: "/settings", label: "Settings", icon: , }, ], }, ]; // --------------------------------------------------------------------------- // Helper: derive initials from display name // --------------------------------------------------------------------------- function getInitials(name: string): string { const parts = name.trim().split(/\s+/); const first = parts[0] ?? ""; if (parts.length === 1) { return first.slice(0, 2).toUpperCase(); } const last = parts[parts.length - 1] ?? ""; return ((first[0] ?? "") + (last[0] ?? "")).toUpperCase(); } // --------------------------------------------------------------------------- // NavBadge component // --------------------------------------------------------------------------- interface NavBadgeProps { badge: NavBadge; } function NavBadgeChip({ badge }: NavBadgeProps): React.JSX.Element { const pulseStyle: React.CSSProperties = badge.pulse ? { background: "rgba(47,128,255,0.15)", color: "var(--primary-l)", } : { background: "var(--surface-2)", color: "var(--muted)", }; return ( {badge.pulse && ( ); } // --------------------------------------------------------------------------- // NavItem component // --------------------------------------------------------------------------- interface NavItemProps { item: NavItemConfig; isActive: boolean; collapsed: boolean; } function NavItem({ item, isActive, collapsed }: NavItemProps): React.JSX.Element { const baseStyle: React.CSSProperties = { display: "flex", alignItems: "center", gap: "11px", padding: "9px 10px", borderRadius: "var(--r-sm)", fontSize: "0.875rem", fontWeight: 500, color: isActive ? "var(--text)" : "var(--muted)", background: isActive ? "var(--surface)" : "transparent", position: "relative", transition: "background 0.12s ease, color 0.12s ease", textDecoration: "none", justifyContent: collapsed ? "center" : undefined, whiteSpace: "nowrap", overflow: "hidden", }; const iconStyle: React.CSSProperties = { width: "16px", height: "16px", flexShrink: 0, opacity: isActive ? 1 : 0.7, transition: "opacity 0.12s ease", }; const content = ( <> {/* Active left accent bar */} {isActive && (