${escapeHtml(p.name)}
+${escapeHtml(p.desc)}
+diff --git a/domme-converters/assets/js/components.js b/domme-converters/assets/js/components.js
new file mode 100644
index 0000000..a3be363
--- /dev/null
+++ b/domme-converters/assets/js/components.js
@@ -0,0 +1,187 @@
+"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.desc)}`;
+ }
+ return fallback;
+ }
+
+ // ---- Productkaart (volledig klikbaar) ------------------------------------
+ function productCard(p) {
+ const fallback =
+ `${escapeHtml(p.from)}` +
+ `→` +
+ `${escapeHtml(p.to)}`;
+ return `
+
${escapeHtml(p.name)}
+
${escapeHtml(intro)}
` : ""} +