--- import { metaData, API_URL } from "../config"; import { Icon } from "astro-icon/components"; import { requireAuthHook } from "@/hooks/requireAuthHook"; import { userIconSvg, externalLinkIconSvg } from "@/utils/navAssets"; import "@/assets/styles/nav.css"; const user = await requireAuthHook(Astro); // Nav is the standard site navigation — whitelabel logic belongs in SubNav const isLoggedIn = Boolean(user); const userDisplayName = user?.user ?? null; const isAdmin = user?.roles?.includes('admin') ?? false; type NavItem = { label: string; href: string; icon?: string; auth?: boolean; adminOnly?: boolean; guestOnly?: boolean; onclick?: string; children?: NavItem[]; }; const baseNavItems: NavItem[] = [ { label: "Home", href: "/" }, { label: "Radio", href: "/radio" }, { label: "Memes", href: "/memes" }, { label: "Git", href: "https://kode.boatson.boats", icon: "external" }, { label: "TRip", href: "/TRip", auth: true, icon: "pirate", children: [ { label: "Submit Request", href: "/TRip", auth: true }, { label: "Manage Requests", href: "/TRip/requests", auth: true }, ], }, { label: "Discord Logs", href: "/discord-logs", auth: true }, { label: "Admin", href: "javascript:void(0)", auth: true, adminOnly: true, children: [ { label: "Lighting", href: "/lighting", auth: true, adminOnly: true }, { label: "Glances", href: "https://_gl.codey.horse", auth: true, icon: "external", adminOnly: true }, { label: "PSQL", href: "https://_pg.codey.horse", auth: true, icon: "external", adminOnly: true }, { label: "SQLite", href: "https://_sqlite.codey.horse", auth: true, icon: "external", adminOnly: true }, { label: "qBitTorrent", href: "https://_qb.codey.horse", auth: true, icon: "external", adminOnly: true }, { label: "RQ", href: "https://_rq.codey.horse", auth: true, icon: "external", adminOnly: true }, { label: "RI", href: "https://_r0.codey.horse", auth: true, icon: "external", adminOnly: true }, ], }, { label: "Login", href: "/login", guestOnly: true }, ...(isLoggedIn ? [{ label: "Logout", href: "#logout", onclick: "handleLogout()" }] : []), ]; // Fold any adminOnly root items into the Admin group automatically const adminContainerIndex = baseNavItems.findIndex((item) => item.label === "Admin"); const adminContainer: NavItem = adminContainerIndex >= 0 ? baseNavItems[adminContainerIndex] : { label: "Admin", href: "#admin", auth: true, adminOnly: true, children: [] }; const adminChildren: NavItem[] = [...(adminContainer.children ?? [])]; const groupedNavItems: NavItem[] = []; baseNavItems.forEach((item, idx) => { if (item.label === "Admin") return; // defer insertion if (item.adminOnly) { adminChildren.push(item); } else { groupedNavItems.push(item); } }); if (adminChildren.length > 0) { const adminItem: NavItem = { ...adminContainer, children: adminChildren }; // Insert Admin before Login/Logout (which are always last) const loginIdx = groupedNavItems.findIndex((item) => item.label === "Login" || item.label === "Logout"); const insertAt = loginIdx >= 0 ? loginIdx : groupedNavItems.length; groupedNavItems.splice(insertAt, 0, adminItem); } const isItemVisible = (item: NavItem): boolean => { if (item.auth && !isLoggedIn) return false; if (item.adminOnly && !isAdmin) return false; if (item.guestOnly && isLoggedIn) return false; return true; }; const visibleNavItems = groupedNavItems .filter(isItemVisible) .map((item): NavItem => { const visibleChildren = item.children?.filter(isItemVisible); return visibleChildren ? { ...item, children: visibleChildren } : item; }) .filter((item) => !item.children || item.children.length > 0); const normalize = (url: string) => (url || '/').replace(/\/+$/, '') || '/'; const normalizedCurrent = normalize(Astro.url.pathname); // For parent items: active if exact match OR if path starts with href (prefix matching) const isPathActive = (href: string) => { const normalizedHref = normalize(href); if (!href || href.startsWith('http')) return false; return normalizedHref === '/' ? normalizedCurrent === '/' : normalizedCurrent === normalizedHref || normalizedCurrent.startsWith(`${normalizedHref}/`); }; // For dropdown children: active only on exact match (no prefix matching) const isPathActiveExact = (href: string) => { const normalizedHref = normalize(href); if (!href || href.startsWith('http')) return false; return normalizedCurrent === normalizedHref; }; ---