"use client"; import { ChevronDown, Menu, Search, X } from "lucide-react"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { useEffect, useRef, useState } from "react"; import { Logo } from "@/components/brand/logo"; import { openPalette } from "@/components/command-palette"; import { ThemeToggle } from "@/components/theme"; import { IconButton } from "@/components/ui/button"; import { cn } from "@/components/ui/cn"; import { Kbd } from "@/components/ui/kbd"; import { NAV_MORE, NAV_PRIMARY, routes } from "@/lib/routes"; /** "More" menu groups (§102) built from NAV_MORE so new routes only need lib/routes.ts. */ const MORE_GROUPS: Array<{ title: string; hrefs: string[] }> = [ { title: "Index", hrefs: [routes.countries(), routes.cloudRegions(), routes.ixps(), routes.power(), routes.connectivity(), routes.rankings()] }, { title: "Intelligence", hrefs: [routes.pulse(), routes.explore(), routes.compareOperators(), routes.coverage(), routes.watchlist()] }, { title: "Reference", hrefs: [routes.sources(), routes.methodology(), routes.download(), routes.apiDocsPage(), routes.about()] }, ]; function isActive(path: string, href: string): boolean { if (href === "/") return path === "/"; if (href === "/datacenters") return path.startsWith("/datacenters") && !path.startsWith("/datacenters/markets"); return path === href || path.startsWith(`${href}/`) || path.startsWith(`${href}?`); } export function Header() { const path = usePathname(); const [menu, setMenu] = useState(false); const [more, setMore] = useState(false); const [menuPath, setMenuPath] = useState(path); const moreRef = useRef(null); if (menuPath !== path) { setMenuPath(path); setMenu(false); setMore(false); } useEffect(() => { if (!menu) return; const onKey = (e: KeyboardEvent) => e.key === "Escape" && setMenu(false); document.addEventListener("keydown", onKey); document.body.style.overflow = "hidden"; return () => { document.removeEventListener("keydown", onKey); document.body.style.overflow = ""; }; }, [menu]); useEffect(() => { if (!more) return; const onDoc = (e: MouseEvent) => { if (!moreRef.current?.contains(e.target as Node)) setMore(false); }; const onKey = (e: KeyboardEvent) => e.key === "Escape" && setMore(false); document.addEventListener("mousedown", onDoc); document.addEventListener("keydown", onKey); return () => { document.removeEventListener("mousedown", onDoc); document.removeEventListener("keydown", onKey); }; }, [more]); const isMap = path === "/map"; const moreActive = NAV_MORE.some((n) => isActive(path, n.href)); const byHref = new Map(NAV_MORE.map((n) => [n.href, n] as const)); return (
openPalette()}> setMenu((m) => !m)} aria-expanded={menu} aria-controls="site-menu" className="lg:hidden"> {menu ? : }
{menu && ( )}
); }