168 lines
6.2 KiB
JavaScript
168 lines
6.2 KiB
JavaScript
import {
|
||
displayName,
|
||
escapeSearchHtml,
|
||
formatSearchPrice,
|
||
loadSearchCatalog,
|
||
searchCatalogProducts,
|
||
} from "/js/search-catalog.js?v=persianCopyRtl2";
|
||
import { initCardShadePickers } from "/js/buy.js?v=priceSort2";
|
||
import { refreshProductFilters } from "/js/filters.js?v=priceSort2";
|
||
import { loveYourEyesPillHtml } from "/js/love-your-eyes.js?v=lyeOff";
|
||
|
||
function shadeDots(p) {
|
||
const variants = p.colorVariants;
|
||
if (!variants || variants.length < 2) return "";
|
||
const shown = variants.slice(0, 5);
|
||
const extra = variants.length - shown.length;
|
||
return `<div class="shade-dots" role="listbox" aria-label="رنگ">${shown
|
||
.map((v) => {
|
||
const active = v.slug === p.slug ? " is-active" : "";
|
||
const bg = v.heroImage
|
||
? `background-image:url('${escapeSearchHtml(v.heroImage)}')`
|
||
: "";
|
||
const href = `/products/${escapeSearchHtml(v.slug)}/`;
|
||
return `<button
|
||
type="button"
|
||
class="shade-dot${active}"
|
||
style="${bg}"
|
||
title="${escapeSearchHtml(v.shade)}"
|
||
aria-label="${escapeSearchHtml(v.shade)}"
|
||
aria-selected="${active ? "true" : "false"}"
|
||
data-card-shade
|
||
data-slug="${escapeSearchHtml(v.slug)}"
|
||
data-image="${escapeSearchHtml(v.heroImage || "")}"
|
||
data-price="${v.price}"
|
||
data-compare="${v.compareAtPrice ?? ""}"
|
||
data-href="${href}"
|
||
></button>`;
|
||
})
|
||
.join("")}${
|
||
extra > 0
|
||
? `<span class="shade-dot-more">+${extra.toLocaleString("fa-IR")} عدد</span>`
|
||
: ""
|
||
}</div>`;
|
||
}
|
||
|
||
function cardIsInStock(p) {
|
||
const variants = p.colorVariants;
|
||
if (variants && variants.length > 1) {
|
||
return variants.some((v) => Number(v.stock) > 0);
|
||
}
|
||
return Number(p.stock) > 0;
|
||
}
|
||
|
||
function stockBadge(p) {
|
||
if (cardIsInStock(p)) return "";
|
||
return `<span class="stock-badge stock-badge--oos">نا موجود</span>`;
|
||
}
|
||
|
||
function filterAttrs(p) {
|
||
const updated = p.updatedAt ? new Date(p.updatedAt).getTime() : 0;
|
||
const discount =
|
||
p.compareAtPrice && p.compareAtPrice > p.price
|
||
? Math.round((1 - p.price / p.compareAtPrice) * 100)
|
||
: 0;
|
||
const prices = [Number(p.price) || 0];
|
||
for (const v of p.colorVariants || []) {
|
||
const n = Number(v.price);
|
||
if (Number.isFinite(n)) prices.push(n);
|
||
}
|
||
const min = Math.min(...prices);
|
||
const max = Math.max(...prices);
|
||
return [
|
||
`data-category="${escapeSearchHtml(p.category || "")}"`,
|
||
`data-category-fa="${escapeSearchHtml(p.categoryFa || "")}"`,
|
||
`data-price="${p.price}"`,
|
||
`data-price-min="${min}"`,
|
||
`data-price-max="${max}"`,
|
||
`data-name="${escapeSearchHtml(p.name)}"`,
|
||
`data-updated="${Number.isFinite(updated) ? updated : 0}"`,
|
||
`data-rating="${p.ratingAvg || 0}"`,
|
||
`data-reviews="${p.reviewCount || 0}"`,
|
||
`data-featured="${p.featured ? 1 : 0}"`,
|
||
`data-in-stock="${cardIsInStock(p) ? 1 : 0}"`,
|
||
`data-discount="${discount}"`,
|
||
].join(" ");
|
||
}
|
||
|
||
function productCardHtml(p) {
|
||
const title = displayName(p);
|
||
const href = `/products/${escapeSearchHtml(p.slug)}/`;
|
||
const discount =
|
||
p.compareAtPrice && p.compareAtPrice > p.price
|
||
? Math.round((1 - p.price / p.compareAtPrice) * 100)
|
||
: 0;
|
||
const badge =
|
||
discount >= 1 ? `<span class="offer-badge">−${discount}%</span>` : "";
|
||
const priceHtml =
|
||
discount >= 1
|
||
? `<p class="price price--offer" data-card-price>
|
||
<span class="price-now">${formatSearchPrice(p.price)}</span>
|
||
<span class="price-was">${formatSearchPrice(p.compareAtPrice)}</span>
|
||
</p>`
|
||
: `<p class="price" data-card-price>${formatSearchPrice(p.price)}</p>`;
|
||
return `<article class="product-card${discount >= 1 ? " product-card--offer" : ""}" data-product-card ${filterAttrs(p)}>
|
||
<a class="thumb" href="${href}" data-card-link>
|
||
${badge}
|
||
${stockBadge(p)}
|
||
${
|
||
p.heroImage
|
||
? `<img src="${escapeSearchHtml(p.heroImage)}" alt="${escapeSearchHtml(title)}" loading="lazy" data-card-image />`
|
||
: ""
|
||
}
|
||
</a>
|
||
<div class="meta">
|
||
${loveYourEyesPillHtml(p.slug)}
|
||
<p class="name"><a href="${href}" data-card-link>${escapeSearchHtml(title)}</a></p>
|
||
${shadeDots(p)}
|
||
<div class="card-action-row">
|
||
${priceHtml}
|
||
<button type="button" class="card-add-btn" data-add-to-cart data-product-id="${escapeSearchHtml(p.id)}" data-slug="${escapeSearchHtml(p.slug)}" data-name="${escapeSearchHtml(title)}" data-price="${p.price}" data-image="${escapeSearchHtml(p.heroImage || "")}" data-category="${escapeSearchHtml(p.category || "")}" data-category-fa="${escapeSearchHtml(p.categoryFa || "")}" aria-label="افزودن به سبد خرید">
|
||
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z"/><line x1="3" y1="6" x2="21" y2="6"/><path d="M16 10a4 4 0 0 1-8 0"/></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</article>`;
|
||
}
|
||
|
||
const params = new URLSearchParams(location.search);
|
||
const q = (params.get("q") || "").trim();
|
||
|
||
const titleEl = document.querySelector("[data-search-title]");
|
||
const resultsEl = document.querySelector("[data-search-results]");
|
||
const emptyEl = document.querySelector("[data-search-empty]");
|
||
const countEl = document.querySelector("[data-listing-count]");
|
||
const resultPill = document.querySelector("[data-filters-result-count]");
|
||
|
||
if (titleEl && q) titleEl.textContent = `نتایج برای «${q}»`;
|
||
|
||
try {
|
||
const products = await loadSearchCatalog();
|
||
const hits = searchCatalogProducts(products, q);
|
||
|
||
if (!resultsEl) {
|
||
/* no-op */
|
||
} else if (!hits.length) {
|
||
if (emptyEl) emptyEl.hidden = false;
|
||
resultsEl.innerHTML = "";
|
||
if (countEl) countEl.textContent = "۰";
|
||
if (resultPill) resultPill.textContent = "۰";
|
||
} else {
|
||
if (emptyEl) emptyEl.hidden = true;
|
||
|
||
resultsEl.innerHTML = hits.map(productCardHtml).join("");
|
||
const n = hits.length.toLocaleString("fa-IR");
|
||
if (countEl) countEl.textContent = n;
|
||
if (resultPill) resultPill.textContent = n;
|
||
|
||
initCardShadePickers();
|
||
refreshProductFilters();
|
||
}
|
||
} catch {
|
||
if (emptyEl) {
|
||
emptyEl.hidden = false;
|
||
emptyEl.querySelector("p") &&
|
||
(emptyEl.querySelector("p").textContent = "بارگذاری نتایج ممکن نشد.");
|
||
}
|
||
}
|