/* =========================================================== Header: sticky bar, mega-menu, PartSearch, mobile drawer =========================================================== */ function PartSearch({ variant = "header", onNavigate }) { const [q, setQ] = useState(""); const [focused, setFocused] = useState(false); const [hl, setHl] = useState(-1); const { navigate } = useRouter(); const boxRef = useRef(null); const results = useMemo(() => (q.trim() ? window.DATA.search(q).slice(0, 6) : []), [q]); useEffect(() => { const onKey = (e) => { if ((e.metaKey || e.ctrlKey) && e.key === "k") { e.preventDefault(); boxRef.current && boxRef.current.focus(); } }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, []); const go = (slug) => { setFocused(false); setQ(""); onNavigate && onNavigate(); navigate("/p/" + slug); }; const submit = () => { if (!q.trim()) return; setFocused(false); onNavigate && onNavigate(); navigate("/search?q=" + encodeURIComponent(q.trim())); }; const onKeyDown = (e) => { if (e.key === "ArrowDown") { e.preventDefault(); setHl(h => Math.min(results.length - 1, h + 1)); } else if (e.key === "ArrowUp") { e.preventDefault(); setHl(h => Math.max(-1, h - 1)); } else if (e.key === "Enter") { if (hl >= 0 && results[hl]) go(results[hl].product_slug); else submit(); } else if (e.key === "Escape") { setFocused(false); boxRef.current && boxRef.current.blur(); } }; const matchLabel = { exact_pn: "Exact PN", prefix_pn: "PN", fuzzy_pn: "PN~", keyword: "Keyword" }; return React.createElement("div", { className: "hsearch" + (focused ? " focused" : ""), role: "search" }, React.createElement(Icon, { name: "search", size: 18, className: "sicon" }), React.createElement("input", { ref: boxRef, className: "hsearch-input", value: q, placeholder: variant === "header" ? "Search part # or interchange…" : "Search by part number…", "aria-label": "Search parts", onChange: e => { setQ(e.target.value); setHl(-1); }, onFocus: () => setFocused(true), onBlur: () => setTimeout(() => setFocused(false), 160), onKeyDown }), !focused && variant === "header" ? React.createElement("kbd", null, "⌘K") : null, focused && q.trim() ? React.createElement("div", { className: "suggest" }, React.createElement("div", { className: "suggest-head" }, results.length ? "Parts matching “" + q + "”" : "No matches — try fewer characters"), results.map((r, i) => React.createElement("div", { key: r.variant_id, className: "suggest-item" + (i === hl ? " hl" : ""), onMouseDown: (e) => { e.preventDefault(); go(r.product_slug); } }, React.createElement("div", { className: "si-ph ph", "data-label": "" }), React.createElement("div", { style: { minWidth: 0, flex: 1 } }, React.createElement("div", { className: "si-name" }, r.name), React.createElement("div", { className: "si-sku mono" }, r.sku) ), React.createElement("span", { className: "chip suggest-match" }, matchLabel[r.match_type]) )), results.length ? React.createElement("div", { className: "suggest-item", style: { color: "var(--blue)", fontWeight: 600, justifyContent: "center" }, onMouseDown: (e) => { e.preventDefault(); submit(); } }, "See all results for “" + q + "”") : null ) : null ); } const NAV = [ { label: "Products", mega: true }, { label: "Quote Builder", to: "/quote", highlight: true }, { label: "Diamond Brakes", to: "/info/diamond-brakes" }, { label: "About", to: "/about" }, { label: "Support", to: "/policies" }, ]; function MegaMenu({ open, onClose }) { if (!open) return null; const cats = window.DATA.categories; return React.createElement(React.Fragment, null, React.createElement("div", { className: "mega-backdrop", onMouseEnter: onClose }), React.createElement("div", { className: "mega anim", onMouseLeave: onClose }, React.createElement("div", { className: "mega-grid" }, cats.slice(0, 8).map(c => React.createElement("div", { key: c.id, className: "mega-col" }, React.createElement(Link, { to: "/c/" + c.slug, className: "mega-cat", onClick: onClose }, React.createElement("span", { className: "dotmark" }), c.name), c.children.map(ch => React.createElement(Link, { key: ch.slug, to: "/c/" + c.slug, className: "mega-child", onClick: onClose }, ch.name)) )), React.createElement("div", { className: "mega-feature" }, React.createElement("span", { className: "eyebrow" }, "Flagship tool"), React.createElement("h4", null, "Build a quote in minutes"), React.createElement("p", { className: "muted", style: { fontSize: 13.5, marginBottom: 14 } }, "Mix catalog parts and custom line items, then email yourself a formatted quote."), React.createElement(Link, { to: "/quote", className: "btn btn-purple btn-sm", onClick: onClose }, React.createElement(Icon, { name: "quote", size: 16 }), "Open Quote Builder"), React.createElement(Link, { to: "/c/heavy-duty-clutches", className: "seeall", style: { marginTop: 14, fontSize: 14 }, onClick: onClose }, "Browse all 12 categories", React.createElement(Icon, { name: "arrow", size: 15 })) ) ) ) ); } function Header() { const [mega, setMega] = useState(false); const [drawer, setDrawer] = useState(false); const { path, navigate } = useRouter(); const cart = useCart(); const quote = useQuote(); const closeTimer = useRef(null); const openMega = () => { clearTimeout(closeTimer.current); setMega(true); }; const closeMega = () => { closeTimer.current = setTimeout(() => setMega(false), 80); }; useEffect(() => { setDrawer(false); setMega(false); }, [path]); return React.createElement(React.Fragment, null, React.createElement("header", { className: "header" }, React.createElement("div", { className: "wrap header-bar" }, React.createElement("button", { className: "icon-btn hamburger", onClick: () => setDrawer(true), "aria-label": "Menu" }, React.createElement(Icon, { name: "menu" })), React.createElement(Logo, null), React.createElement("nav", { className: "header-nav hide-on-mobile" }, NAV.map(n => n.mega ? React.createElement("div", { key: n.label, className: "mega-wrap", onMouseEnter: openMega, onMouseLeave: closeMega }, React.createElement("button", { className: "navlink" + (mega ? " active" : ""), onClick: () => setMega(m => !m), "aria-expanded": mega }, n.label, React.createElement(Icon, { name: "chevdown", size: 15 }))) : React.createElement(Link, { key: n.label, to: n.to, className: "navlink" + (path === n.to ? " active" : "") + (n.highlight ? " navlink-hl" : "") }, n.highlight ? React.createElement(Icon, { name: "quote", size: 16 }) : null, n.label) ) ), React.createElement("div", { className: "header-spacer" }), React.createElement("div", { className: "hide-on-mobile", style: { flex: "0 1 360px" } }, React.createElement(PartSearch, null)), React.createElement("div", { className: "header-actions" }, React.createElement("button", { className: "icon-btn only-mobile-inline", onClick: () => navigate("/search?q="), "aria-label": "Search" }, React.createElement(Icon, { name: "search" })), React.createElement(Link, { to: "/quote", className: "icon-btn", "aria-label": "Quote list" }, React.createElement(Icon, { name: "quote" }), quote.count ? React.createElement("span", { className: "dot" }, quote.count) : null), React.createElement(Link, { to: "/cart", className: "icon-btn", "aria-label": "Cart" }, React.createElement(Icon, { name: "cart" }), cart.count ? React.createElement("span", { className: "dot blue" }, cart.count) : null), React.createElement(Link, { to: "/account", className: "icon-btn hide-on-mobile", "aria-label": "Account" }, React.createElement(Icon, { name: "user" })) ) ), React.createElement(MegaMenu, { open: mega, onClose: () => setMega(false) }) ), React.createElement(MobileDrawer, { open: drawer, onClose: () => setDrawer(false) }) ); } function MobileDrawer({ open, onClose }) { const cats = window.DATA.categories; const [expanded, setExpanded] = useState(null); return React.createElement("div", { className: "drawer-root" + (open ? " open" : ""), "aria-hidden": !open }, React.createElement("div", { className: "drawer-backdrop", onClick: onClose }), React.createElement("aside", { className: "drawer" }, React.createElement("div", { className: "drawer-head" }, React.createElement(Logo, null), React.createElement("button", { className: "icon-btn", onClick: onClose, "aria-label": "Close" }, React.createElement(Icon, { name: "close" })) ), React.createElement("div", { className: "drawer-search" }, React.createElement(PartSearch, { variant: "drawer", onNavigate: onClose })), React.createElement("div", { className: "drawer-body" }, React.createElement(Link, { to: "/quote", className: "drawer-cta", onClick: onClose }, React.createElement(Icon, { name: "quote", size: 18 }), "Quote Builder"), React.createElement("div", { className: "drawer-label" }, "Shop by category"), cats.map(c => React.createElement("div", { key: c.id, className: "drawer-cat" }, React.createElement("button", { className: "drawer-cat-head", onClick: () => setExpanded(e => e === c.id ? null : c.id) }, React.createElement("span", null, c.name), React.createElement(Icon, { name: "chevdown", size: 16, style: { transform: expanded === c.id ? "rotate(180deg)" : "none", transition: "transform .2s" } })), expanded === c.id ? React.createElement("div", { className: "drawer-children" }, React.createElement(Link, { to: "/c/" + c.slug, className: "drawer-child", onClick: onClose }, "All " + c.name), c.children.map(ch => React.createElement(Link, { key: ch.slug, to: "/c/" + c.slug, className: "drawer-child", onClick: onClose }, ch.name)) ) : null )), React.createElement("div", { className: "drawer-label" }, "Company"), ["/about", "/videos", "/policies", "/warranties", "/contact", "/b2b", "/account"].map(p => React.createElement(Link, { key: p, to: p, className: "drawer-link", onClick: onClose }, p.replace("/", "").replace("-", " ").replace(/\b\w/g, c => c.toUpperCase()) || "Home")) ) ) ); } Object.assign(window, { PartSearch, Header, MegaMenu, MobileDrawer });