Files
cucinafood/js/site.js
T
mo 10e510682c Eerste merksite voor Cucina Food.
Statische HTML/CSS/JS: homepage, productlijnen, recepten, zoekbare winkelvinder.
2026-08-29 14:34:18 +02:00

138 lines
4.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(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);
});
})();