10e510682c
Statische HTML/CSS/JS: homepage, productlijnen, recepten, zoekbare winkelvinder.
138 lines
4.4 KiB
JavaScript
138 lines
4.4 KiB
JavaScript
(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);
|
||
});
|
||
})();
|