Eerste merksite voor Cucina Food.
Statische HTML/CSS/JS: homepage, productlijnen, recepten, zoekbare winkelvinder.
This commit is contained in:
+137
@@ -0,0 +1,137 @@
|
||||
(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);
|
||||
});
|
||||
})();
|
||||
Reference in New Issue
Block a user