import {
hydrateCart,
subscribe,
getSnapshot,
formatPrice,
} from "/js/cart.js";
function qs(sel, root = document) {
return root.querySelector(sel);
}
function qsa(sel, root = document) {
return [...root.querySelectorAll(sel)];
}
function escapeHtml(s) {
return String(s)
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """);
}
export function initHeader() {
hydrateCart();
const header = qs(".site-header");
const mega = qs(".mega-panel");
const backdrop = qs(".mega-backdrop");
const drawer = qs(".mobile-drawer");
const badge = qs("[data-cart-count]");
const cartMenu = qs("[data-cart-menu]");
const cartTrigger = qs("[data-cart-trigger]");
const cartPreview = qs("[data-cart-preview]");
const cartList = qs("[data-cart-preview-list]");
const cartEmpty = qs("[data-cart-preview-empty]");
const cartFoot = qs("[data-cart-preview-foot]");
const cartTotal = qs("[data-cart-preview-total]");
const fineHover =
typeof window.matchMedia === "function" &&
window.matchMedia("(hover: hover) and (pointer: fine)").matches;
function syncBadge(snap) {
if (!badge) return;
badge.textContent = String(snap.itemCount);
badge.classList.toggle("is-visible", snap.hydrated && snap.itemCount > 0);
}
function renderCartPreview(snap) {
if (!cartList || !cartEmpty || !cartFoot || !cartTotal) return;
const empty = !snap.items.length;
cartEmpty.hidden = !empty;
cartFoot.hidden = empty;
cartList.hidden = empty;
cartTotal.textContent = formatPrice(snap.subtotal);
if (empty) {
cartList.innerHTML = "";
return;
}
cartList.innerHTML = snap.items
.slice(0, 8)
.map((item) => {
const href = `/products/${escapeHtml(item.slug)}/`;
const img = item.image
? ``
: `
${formatPrice(item.price * item.quantity)}
`; }) .join(""); } function setCartPreviewOpen(open) { if (!cartMenu || !cartPreview || !cartTrigger) return; cartMenu.classList.toggle("is-open", open); cartPreview.classList.toggle("is-open", open); if (open) cartPreview.removeAttribute("hidden"); else cartPreview.setAttribute("hidden", ""); cartTrigger.setAttribute("aria-expanded", open ? "true" : "false"); } function closeCartPreview() { setCartPreviewOpen(false); } function openCartPreview() { setCartPreviewOpen(true); } const sideNav = qs(".side-nav"); const sideNavToggle = qs("[data-side-nav-toggle]"); const SIDE_NAV_KEY = "kikomiko-side-nav-collapsed"; function setSideNavCollapsed(collapsed) { if (!sideNav || !sideNavToggle) return; sideNav.classList.toggle("is-collapsed", collapsed); sideNavToggle.setAttribute("aria-expanded", collapsed ? "false" : "true"); const label = collapsed ? "نمایش منو" : "پنهان کردن منو"; sideNavToggle.setAttribute("aria-label", label); sideNavToggle.setAttribute("title", label); try { localStorage.setItem(SIDE_NAV_KEY, collapsed ? "1" : "0"); } catch { /* ignore */ } if (collapsed) closeMega(); } function hideDesktopMenu() { closeMega(); setSideNavCollapsed(true); } subscribe((snap) => { syncBadge(snap); renderCartPreview(snap); }); const initial = getSnapshot(); syncBadge(initial); renderCartPreview(initial); if (cartMenu && cartTrigger && cartPreview) { cartTrigger.addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); const open = cartMenu.classList.contains("is-open"); if (open) closeCartPreview(); else { closeMega(); openCartPreview(); } }); if (fineHover) { let leaveTimer = 0; cartMenu.addEventListener("mouseenter", () => { window.clearTimeout(leaveTimer); openCartPreview(); }); cartMenu.addEventListener("mouseleave", () => { leaveTimer = window.setTimeout(closeCartPreview, 180); }); } document.addEventListener("click", (e) => { if (!(e.target instanceof Element)) return; if (!cartMenu.contains(e.target)) closeCartPreview(); }); document.addEventListener("keydown", (e) => { if (e.key === "Escape") closeCartPreview(); }); } function closeMega() { mega?.classList.remove("is-open"); mega?.removeAttribute("data-active"); backdrop?.classList.remove("is-open"); backdrop?.setAttribute("hidden", ""); header?.classList.remove("is-open"); qsa("[data-mega-key]").forEach((b) => b.classList.remove("is-active")); qsa("[data-mega-pane]").forEach((pane) => { pane.hidden = true; }); // Restore home highlight when on home const home = qs('.side-nav-link[href="/"]'); if (home && (location.pathname === "/" || location.pathname === "/fa")) { home.classList.add("is-active"); } } function openMega(key) { if (!mega) return; closeCartPreview(); // Keep the side panel open while browsing mega categories if (sideNav?.classList.contains("is-collapsed")) { setSideNavCollapsed(false); } mega.setAttribute("data-active", key); mega.classList.add("is-open"); header?.classList.add("is-open"); backdrop?.classList.add("is-open"); backdrop?.removeAttribute("hidden"); qsa("[data-mega-pane]").forEach((pane) => { pane.hidden = pane.getAttribute("data-mega-pane") !== key; }); qsa(".side-nav-link").forEach((b) => b.classList.remove("is-active")); qsa("[data-mega-key]").forEach((b) => b.classList.toggle("is-active", b.getAttribute("data-mega-key") === key) ); } qsa("[data-mega-key]").forEach((btn) => { btn.addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); const key = btn.getAttribute("data-mega-key"); if (!key) return; const open = mega?.getAttribute("data-active") === key; if (open) { closeMega(); return; } openMega(key); }); }); // Close mega immediately when any link inside it is chosen // (categories, view-all, featured products, collection title). mega?.addEventListener( "click", (e) => { const link = e.target instanceof Element ? e.target.closest("a[href]") : null; if (!link || !mega.contains(link)) return; hideDesktopMenu(); }, true ); // Home / offers links in side nav should close mega + collapse panel qsa(".side-nav-link[href]").forEach((link) => { link.addEventListener("click", () => hideDesktopMenu()); }); // Highlight active offers item if (location.pathname.startsWith("/offers")) { qsa(".side-nav-link").forEach((el) => el.classList.remove("is-active")); qs( '.side-nav-link[href="/offers/"], .side-nav-link[href="/offers"]' )?.classList.add("is-active"); } // Do not use mouseleave — it fights with clicks on mega links. backdrop?.addEventListener("click", closeMega); qs("[data-mega-close]")?.addEventListener("click", closeMega); function closeDrawer(e) { e?.preventDefault?.(); e?.stopPropagation?.(); drawer?.classList.remove("is-open"); drawer?.setAttribute("aria-hidden", "true"); document.body.style.overflow = ""; qsa("[data-mobile-sub]").forEach((p) => p.classList.remove("is-open")); qsa(".mobile-cat").forEach((c) => c.classList.remove("is-expanded")); } function openDrawer(e) { e?.preventDefault?.(); drawer?.classList.add("is-open"); drawer?.setAttribute("aria-hidden", "false"); document.body.style.overflow = "hidden"; closeMega(); closeCartPreview(); } qs("[data-menu-open]")?.addEventListener("click", openDrawer); qsa("[data-menu-close]").forEach((el) => { el.addEventListener("click", closeDrawer); }); qsa("[data-mobile-expand]").forEach((btn) => { btn.addEventListener("click", () => { const id = btn.getAttribute("data-mobile-expand"); const panel = qs(`[data-mobile-sub="${id}"]`); const cat = btn.closest(".mobile-cat"); const open = panel?.classList.contains("is-open"); qsa("[data-mobile-sub]").forEach((p) => p.classList.remove("is-open")); qsa(".mobile-cat").forEach((c) => c.classList.remove("is-expanded")); if (!open) { panel?.classList.add("is-open"); cat?.classList.add("is-expanded"); } }); }); // Highlight current route in the mobile drawer const path = window.location.pathname.replace(/\/+$/, "") || "/"; qsa(".mobile-nav a[href]").forEach((a) => { const href = (a.getAttribute("href") || "").replace(/\/+$/, "") || "/"; if (href === path || (href !== "/" && path.startsWith(href))) { a.setAttribute("aria-current", "page"); a.classList.add("is-active"); } }); try { if (localStorage.getItem(SIDE_NAV_KEY) === "1") { setSideNavCollapsed(true); } } catch { /* ignore */ } sideNavToggle?.addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); setSideNavCollapsed(!sideNav?.classList.contains("is-collapsed")); }); document.addEventListener("keydown", (e) => { if (e.key === "Escape") { closeMega(); closeDrawer(); closeCartPreview(); } }); }