import {
displayName,
escapeSearchHtml,
formatSearchPrice,
loadSearchCatalog,
searchCatalogProducts,
} from "/js/search-catalog.js?v=persianCopyRtl2";
const PREVIEW_COUNT = 4;
const MIN_CHARS = 2;
const DEBOUNCE_MS = 180;
function debounce(fn, ms) {
let t = 0;
return (...args) => {
window.clearTimeout(t);
t = window.setTimeout(() => fn(...args), ms);
};
}
function suggestItemHtml(p) {
const title = displayName(p);
const href = `/products/${escapeSearchHtml(p.slug)}/`;
const img = p.heroImage
? `
`
: ``;
return `
${img}
${escapeSearchHtml(title)}
${formatSearchPrice(p.price)}
`;
}
function bindSearchInput(input, panel) {
if (!input || !panel) return;
let products = null;
let active = -1;
loadSearchCatalog()
.then((list) => {
products = list;
})
.catch(() => {
products = [];
});
function close() {
panel.hidden = true;
panel.innerHTML = "";
active = -1;
input.setAttribute("aria-expanded", "false");
}
function open() {
panel.hidden = false;
input.setAttribute("aria-expanded", "true");
}
function render(q) {
if (!products) return;
const hits = searchCatalogProducts(products, q, PREVIEW_COUNT);
if (!hits.length) {
close();
return;
}
const allHref = `/search/?q=${encodeURIComponent(q.trim())}`;
panel.innerHTML =
hits.map(suggestItemHtml).join("") +
`مشاهده همه نتایج`;
open();
active = -1;
}
const onInput = debounce(() => {
const q = input.value.trim();
if (q.length < MIN_CHARS) {
close();
return;
}
render(q);
}, DEBOUNCE_MS);
input.addEventListener("input", onInput);
input.addEventListener("focus", () => {
const q = input.value.trim();
if (q.length >= MIN_CHARS) render(q);
});
input.addEventListener("keydown", (e) => {
const items = [...panel.querySelectorAll(".search-suggest-item, .search-suggest-all")];
if (!items.length || panel.hidden) return;
if (e.key === "ArrowDown") {
e.preventDefault();
active = Math.min(active + 1, items.length - 1);
items.forEach((el, i) => el.classList.toggle("is-active", i === active));
items[active]?.scrollIntoView({ block: "nearest" });
} else if (e.key === "ArrowUp") {
e.preventDefault();
active = Math.max(active - 1, 0);
items.forEach((el, i) => el.classList.toggle("is-active", i === active));
items[active]?.scrollIntoView({ block: "nearest" });
} else if (e.key === "Enter" && active >= 0) {
e.preventDefault();
items[active].click();
} else if (e.key === "Escape") {
close();
input.blur();
}
});
document.addEventListener("click", (e) => {
if (!(e.target instanceof Element)) return;
if (input.contains(e.target) || panel.contains(e.target)) return;
close();
});
}
export function initSearchSuggest() {
document.querySelectorAll(".search-shell").forEach((shell) => {
const input = shell.querySelector('input[type="search"]');
const panel = shell.querySelector("[data-search-suggest]");
bindSearchInput(input, panel);
});
document.querySelectorAll(".mobile-search").forEach((form) => {
const input = form.querySelector('input[type="search"]');
let panel = form.querySelector("[data-search-suggest]");
if (!panel) {
panel = document.createElement("div");
panel.className = "search-suggest search-suggest--mobile";
panel.setAttribute("data-search-suggest", "");
panel.hidden = true;
form.appendChild(panel);
}
bindSearchInput(input, panel);
});
const params = new URLSearchParams(location.search);
const q = params.get("q");
if (q && location.pathname.replace(/\/+$/, "").endsWith("/search")) {
document.querySelectorAll('.search-form input[name="q"], .mobile-search input[name="q"]').forEach((input) => {
input.value = q;
});
}
}