Files
cucinafood/js/site.js
T

138 lines
4.4 KiB
JavaScript
Raw Normal View History

2026-08-29 14:34:18 +02:00
(function () {
const header = document.querySelector("[data-header]");
const toggle = document.querySelector(".nav-toggle");
if (toggle && header) {
toggle.addEventListener("click", () => {
const open = header.classList.toggle("is-open");
toggle.setAttribute("aria-expanded", open ? "true" : "false");
});
}
const path = location.pathname.replace(/index\.html$/, "");
document.querySelectorAll(".site-nav a[href]").forEach((a) => {
const href = a.getAttribute("href");
if (!href || href === "/") return;
if (path === href || path.startsWith(href)) a.setAttribute("aria-current", "page");
});
const dialog = document.getElementById("product-drawer");
if (dialog) {
document.querySelectorAll("[data-product]").forEach((btn) => {
btn.addEventListener("click", () => {
const d = JSON.parse(btn.getAttribute("data-product"));
dialog.querySelector("[data-d-img]").src = d.image;
dialog.querySelector("[data-d-img]").alt = d.name;
dialog.querySelector("[data-d-name]").textContent = d.name;
dialog.querySelector("[data-d-blurb]").textContent = d.blurb || "";
const link = dialog.querySelector("[data-d-recipe]");
if (d.recipe) {
link.hidden = false;
link.href = "/recepten/" + d.recipe + "/";
} else {
link.hidden = true;
}
dialog.showModal();
});
});
dialog.querySelector(".drawer-close").addEventListener("click", () => dialog.close());
dialog.addEventListener("click", (e) => {
if (e.target === dialog) dialog.close();
});
}
const form = document.querySelector("[data-mailto]");
if (form) {
form.addEventListener("submit", (e) => {
e.preventDefault();
const fd = new FormData(form);
const subject = encodeURIComponent(fd.get("onderwerp") || "Bericht via cucinafood.nl");
const lines = [];
fd.forEach((v, k) => {
if (k !== "onderwerp") lines.push(k + ": " + v);
});
const body = encodeURIComponent(lines.join("\n"));
location.href = "mailto:info@cucinafood.nl?subject=" + subject + "&body=" + body;
});
}
const root = document.querySelector("[data-finder]");
if (!root) return;
const input = root.querySelector("input[type=search]");
const out = root.querySelector("[data-results]");
const status = root.querySelector("[data-status]");
let stores = [];
const norm = (s) =>
(s || "")
.toLowerCase()
.normalize("NFD")
.replace(/[\u0300-\u036f]/g, "")
.replace(/['’`]/g, "");
function search(q) {
q = norm(q).trim();
if (q.length < 2) return [];
const hits = [];
for (const s of stores) {
const blob = norm([s.city, s.address, s.id, s.label].join(" "));
if (blob.includes(q)) hits.push(s);
if (hits.length >= 40) break;
}
return hits;
}
function render(hits, q) {
if (q.trim().length < 2) {
status.textContent = "Typ een plaats of postcode. We tonen geen muur van adressen.";
out.innerHTML = "";
return;
}
if (!hits.length) {
status.textContent = "Geen winkels voor “" + q + "”. Probeer een stad, zoals Amsterdam of Gent.";
out.innerHTML = "";
return;
}
status.textContent = hits.length + (hits.length === 40 ? "+" : "") + " winkels bij “" + q + "”";
out.innerHTML = hits
.map((s) => {
const maps = s.maps
? s.maps
: "https://www.google.com/maps/search/?api=1&query=" +
encodeURIComponent(s.address + " " + s.city);
return (
"<li><div><strong>" +
s.city +
"</strong><small>" +
s.address +
"</small></div><a class='btn' href='" +
maps +
"' target='_blank' rel='noopener'>Maps</a></li>"
);
})
.join("");
}
fetch("/data/stores.json")
.then((r) => r.json())
.then((data) => {
stores = data;
const start = new URLSearchParams(location.search).get("q") || "";
if (start) input.value = start;
render(search(input.value), input.value);
})
.catch(() => {
status.textContent = "De winkellijst kon niet geladen worden.";
});
let t;
input.addEventListener("input", () => {
clearTimeout(t);
t = setTimeout(() => render(search(input.value), input.value), 80);
});
root.querySelector("form").addEventListener("submit", (e) => {
e.preventDefault();
render(search(input.value), input.value);
});
})();