"use strict"; /** * Herbruikbare helpers en UI-componenten. Alles wordt onder de globale * CL-namespace gehangen zodat router en pagina's het kunnen gebruiken. */ (function () { const CL = (window.CL = window.CL || {}); // ---- Opmaak-helpers ------------------------------------------------------- const formatPrice = (value) => "\u20AC" + Number(value).toFixed(2).replace(".", ","); const escapeHtml = (str) => String(str).replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c])); const stars = (rating) => "\u2605".repeat(rating) + "\u2606".repeat(5 - rating); // ---- Navigatiestructuur --------------------------------------------------- // Eén bron voor de hoofdnavigatie; de footer vult dit aan met extra links. const NAV = [ { path: "/producten", label: "Producten" }, { path: "/catalogus", label: "Catalogus" }, { path: "/specificaties", label: "Specificaties" }, { path: "/aanbiedingen", label: "Aanbiedingen" }, { path: "/bedrijf", label: "Bedrijf" }, { path: "/contact", label: "Contact" }, ]; const FOOTER_LINKS = { Producten: [ { path: "/producten", label: "Producten" }, { path: "/catalogus", label: "Catalogus" }, { path: "/specificaties", label: "Specificaties" }, { path: "/aanbiedingen", label: "Aanbiedingen" }, ], Bedrijf: [ { path: "/bedrijf", label: "Bedrijf" }, { path: "/over-ons", label: "Over ons" }, { path: "/vacatures", label: "Vacatures" }, { path: "/contact", label: "Contact" }, ], Juridisch: [ { path: "/voorwaarden", label: "Voorwaarden" }, { path: "/privacy", label: "Privacy" }, { path: "/disclaimer", label: "Disclaimer" }, ], }; // Bouwt een interne hash-link op die door de router wordt afgevangen. const href = (path) => "#" + path; // ---- Product-thumbnail ---------------------------------------------------- // Toont de foto als die er is, valt anders terug op de connector-tegel. function productThumb(p) { const fallback = `${escapeHtml(p.from)}` + `` + `${escapeHtml(p.to)}`; if (p.image) { return `${escapeHtml(p.name)}`; } return fallback; } // ---- Productkaart (volledig klikbaar) ------------------------------------ function productCard(p) { const fallback = `${escapeHtml(p.from)}` + `` + `${escapeHtml(p.to)}`; return `
${productThumb(p)}
${escapeHtml(p.id)} ${stars(p.rating)}(${p.reviews})

${escapeHtml(p.name)}

${escapeHtml(p.desc)}

${formatPrice(p.price)}${formatPrice(p.old)}
`; } function productGrid(list) { if (!list.length) { return `
Geen producten gevonden.
`; } return `
${list.map(productCard).join("")}
`; } // ---- Paginakop ------------------------------------------------------------ function pageHead({ eyebrow, title, intro, crumb }) { return `
${crumb ? `` : ""} ${eyebrow ? `${escapeHtml(eyebrow)}` : ""}

${escapeHtml(title)}

${intro ? `

${escapeHtml(intro)}

` : ""}
`; } function crumb(parts) { // parts: [{label, path?}] — laatste item is de huidige pagina. return parts .map((part, i) => { const last = i === parts.length - 1; const sep = last ? "" : `/`; if (last || !part.path) return `${escapeHtml(part.label)}${sep}`; return `${escapeHtml(part.label)}${sep}`; }) .join(""); } // ---- Header --------------------------------------------------------------- function header(activePath) { const isActive = (path) => path === activePath || (path !== "/" && activePath.startsWith(path + "/")) ? " active" : ""; const links = NAV.map( (item) => `${escapeHtml(item.label)}` ).join(""); return `
`; } // ---- Footer --------------------------------------------------------------- function footer() { const column = (heading, items) => `

${escapeHtml(heading)}

`; return ` `; } CL.fmt = { formatPrice, escapeHtml, stars }; CL.nav = { NAV, FOOTER_LINKS, href }; CL.components = { productThumb, productCard, productGrid, pageHead, crumb, header, footer }; })();