"use strict";
/**
* Pagina-views. Elke view geeft een object terug:
* { title, html, onMount? }
* - title : documenttitel.
* - html : markup voor de #app-container.
* - onMount: optionele functie die na rendering events koppelt.
*
* Alle inhoud komt uit de centrale databronnen (PRODUCTS, CATEGORIES, CONTENT).
*/
(function () {
const CL = (window.CL = window.CL || {});
const { formatPrice, escapeHtml, stars } = CL.fmt;
const { productGrid, pageHead, crumb, productThumb } = CL.components;
const { href } = CL.nav;
const PRODUCTS = window.PRODUCTS || [];
const CATEGORIES = window.CATEGORIES || [{ key: "all", label: "Alles" }];
const CONTENT = window.CONTENT || {};
const bySlug = (slug) => PRODUCTS.find((p) => p.slug === slug);
const categoryLabel = (key) => (CATEGORIES.find((c) => c.key === key) || { label: key }).label;
const discount = (p) => Math.round((1 - p.price / p.old) * 100);
// ---- Home -----------------------------------------------------------------
function home() {
const featured = PRODUCTS.slice(0, 4);
return {
title: "Converterland — Adapters en signaalconverters",
html: `
Universele signaalconversie
Elk signaal naar elk medium. Theoretisch.
Converterland levert adapters voor verbindingen die niet bestaan en
problemen die u niet heeft. Een complete catalogus aan fictieve
converters, professioneel gepresenteerd en volledig onbruikbaar.
Ondersteunde signalen ∞
Gemiddelde latency 3 werkdagen
Compatibiliteit 0 / 0
Garantie geen
Retourtermijn n.v.t.
Niet op voorraad
Elk product, altijd.
Geen verzendkosten
Want geen verzending.
Veilig afrekenen
Er gebeurt niets.
Support 0/7
Wij nemen niet op.
${productGrid(featured)}
`,
};
}
// ---- Producten ------------------------------------------------------------
function producten() {
return {
title: "Producten — Converterland",
html: `
${pageHead({
eyebrow: "Assortiment",
title: "Producten",
intro: "Het volledige assortiment fictieve signaalconverters, overzichtelijk gepresenteerd.",
crumb: crumb([{ label: "Home", path: "/" }, { label: "Producten" }]),
})}
Alle converters ${PRODUCTS.length} producten
${productGrid(PRODUCTS)}
`,
};
}
// ---- Catalogus (zoeken / sorteren / filteren) -----------------------------
function catalogus() {
const filterButtons = CATEGORIES.map(
(c) => `${escapeHtml(c.label)} `
).join("");
const maxPrice = Math.ceil(Math.max(...PRODUCTS.map((p) => p.price)));
return {
title: "Catalogus — Converterland",
html: `
${pageHead({
eyebrow: "Catalogus",
title: "Catalogus",
intro: "Doorzoek, sorteer en filter het volledige assortiment.",
crumb: crumb([{ label: "Home", path: "/" }, { label: "Catalogus" }]),
})}
${productGrid(PRODUCTS)}
`,
onMount() {
const state = { q: "", sort: "featured", category: "all", maxPrice };
const gridEl = document.getElementById("catalogGrid");
const countEl = document.getElementById("resultCount");
const searchEl = document.getElementById("searchInput");
const sortEl = document.getElementById("sortSelect");
const rangeEl = document.getElementById("priceRange");
const priceOut = document.getElementById("priceOut");
const filtersEl = document.getElementById("filters");
function apply() {
let list = PRODUCTS.filter((p) => {
if (state.category !== "all" && p.category !== state.category) return false;
if (p.price > state.maxPrice) return false;
if (state.q) {
const hay = (p.name + " " + p.from + " " + p.to + " " + p.desc).toLowerCase();
if (!hay.includes(state.q)) return false;
}
return true;
});
switch (state.sort) {
case "price-asc": list.sort((a, b) => a.price - b.price); break;
case "price-desc": list.sort((a, b) => b.price - a.price); break;
case "rating": list.sort((a, b) => b.rating - a.rating || b.reviews - a.reviews); break;
case "name": list.sort((a, b) => a.name.localeCompare(b.name, "nl")); break;
}
gridEl.innerHTML = productGrid(list);
countEl.textContent = list.length + " van " + PRODUCTS.length + " producten";
}
searchEl.addEventListener("input", () => { state.q = searchEl.value.trim().toLowerCase(); apply(); });
sortEl.addEventListener("change", () => { state.sort = sortEl.value; apply(); });
rangeEl.addEventListener("input", () => {
state.maxPrice = Number(rangeEl.value);
priceOut.textContent = formatPrice(state.maxPrice);
apply();
});
filtersEl.addEventListener("click", (e) => {
const btn = e.target.closest("[data-filter]");
if (!btn) return;
state.category = btn.dataset.filter;
filtersEl.querySelectorAll(".filter").forEach((b) => b.classList.toggle("active", b === btn));
apply();
});
apply();
},
};
}
// ---- Specificaties --------------------------------------------------------
function specificaties() {
const rows = PRODUCTS.map(
(p) => `
${escapeHtml(p.name)} ${escapeHtml(p.id)}
${escapeHtml(p.from)} → ${escapeHtml(p.to)}
${escapeHtml(categoryLabel(p.category))}
${escapeHtml(p.stock.label)}
${formatPrice(p.price)}
`
).join("");
return {
title: "Specificaties — Converterland",
html: `
${pageHead({
eyebrow: "Technische gegevens",
title: "Specificaties",
intro: "Een vergelijkend overzicht van het volledige assortiment. Alle waarden zijn fictief.",
crumb: crumb([{ label: "Home", path: "/" }, { label: "Specificaties" }]),
})}
Product Conversie Categorie Beschikbaarheid Prijs
${rows}
Algemene kenmerken
Ondersteunde signalen ∞
Gemiddelde latency 3 werkdagen
Compatibiliteit 0 / 0
Garantie geen
Retourtermijn n.v.t.
Certificering zelfverklaard
`,
};
}
// ---- Aanbiedingen ---------------------------------------------------------
function aanbiedingen() {
const list = [...PRODUCTS].sort((a, b) => discount(b) - discount(a));
const cards = list
.map((p) => {
const fallback =
`${escapeHtml(p.from)} → ${escapeHtml(p.to)} `;
return `
-${discount(p)}%
${productThumb(p)}
${escapeHtml(p.id)} ${stars(p.rating)}(${p.reviews})
${escapeHtml(p.name)}
${escapeHtml(p.desc)}
`;
})
.join("");
return {
title: "Aanbiedingen — Converterland",
html: `
${pageHead({
eyebrow: "Tijdelijk voordeel",
title: "Aanbiedingen",
intro: "Alle converters zijn afgeprijsd, want niets is iets waard. Gesorteerd op korting.",
crumb: crumb([{ label: "Home", path: "/" }, { label: "Aanbiedingen" }]),
})}
${cards}
`,
};
}
// ---- Bedrijf --------------------------------------------------------------
function bedrijf() {
const c = CONTENT.company;
const values = c.values
.map((v) => `${escapeHtml(v.title)} ${escapeHtml(v.text)}
`)
.join("");
return {
title: "Bedrijf — Converterland",
html: `
${pageHead({
eyebrow: "Over de onderneming",
title: "Bedrijf",
intro: c.intro,
crumb: crumb([{ label: "Home", path: "/" }, { label: "Bedrijf" }]),
})}
${escapeHtml(c.founded)} Opgericht
${escapeHtml(c.employees)} Medewerkers
${PRODUCTS.length} Producten
0 Leveringen
${values}
`,
};
}
// ---- Over ons -------------------------------------------------------------
function overOns() {
const c = CONTENT.company;
const timeline = c.history
.map((h) => `${escapeHtml(h.year)} ${escapeHtml(h.text)} `)
.join("");
return {
title: "Over ons — Converterland",
html: `
${pageHead({
eyebrow: "Onze geschiedenis",
title: "Over ons",
intro: c.intro,
crumb: crumb([{ label: "Home", path: "/" }, { label: "Bedrijf", path: "/bedrijf" }, { label: "Over ons" }]),
})}
Hoofdkantoor
${escapeHtml(c.headquarters)}
Tijdlijn
${timeline}
`,
};
}
// ---- Contact --------------------------------------------------------------
function contact() {
const c = CONTENT.contact;
return {
title: "Contact — Converterland",
html: `
${pageHead({
eyebrow: "Neem contact op",
title: "Contact",
intro: "Stuur ons een bericht. Het formulier verwerkt geen gegevens en verstuurt niets.",
crumb: crumb([{ label: "Home", path: "/" }, { label: "Contact" }]),
})}
`,
onMount() {
const form = document.getElementById("contactForm");
const note = document.getElementById("contactNote");
form.addEventListener("submit", (e) => {
e.preventDefault();
if (!form.checkValidity()) { form.reportValidity(); return; }
form.reset();
note.textContent = "Bericht ontvangen in deze demonstratie. Er is niets verzonden of opgeslagen.";
});
},
};
}
// ---- Vacatures ------------------------------------------------------------
function vacatures() {
const items = CONTENT.jobs
.map(
(j) => `
${escapeHtml(j.title)}
${escapeHtml(j.type)} · ${escapeHtml(j.location)}
+
${escapeHtml(j.summary)}
${escapeHtml(j.details)}
Wat wij vragen
${j.requirements.map((r) => `${escapeHtml(r)} `).join("")}
Solliciteer (gaat naar contact)
`
)
.join("");
return {
title: "Vacatures — Converterland",
html: `
${pageHead({
eyebrow: "Werken bij",
title: "Vacatures",
intro: "Wij groeien al jaren niet, maar er is altijd plek voor talent dat van niets houdt.",
crumb: crumb([{ label: "Home", path: "/" }, { label: "Bedrijf", path: "/bedrijf" }, { label: "Vacatures" }]),
})}
${items}
`,
onMount() {
const jobs = document.querySelector(".jobs");
jobs.addEventListener("click", (e) => {
const head = e.target.closest("[data-job]");
if (!head) return;
const body = head.nextElementSibling;
const open = head.getAttribute("aria-expanded") === "true";
head.setAttribute("aria-expanded", String(!open));
head.querySelector(".job-toggle").textContent = open ? "+" : "\u2212";
body.hidden = open;
});
},
};
}
// ---- Juridische pagina's --------------------------------------------------
function legalPage(key) {
const data = CONTENT.legal[key];
const sections = data.sections
.map((s) => `${escapeHtml(s.h)} ${escapeHtml(s.p)}
`)
.join("");
return {
title: data.title + " — Converterland",
html: `
${pageHead({
eyebrow: "Juridisch",
title: data.title,
intro: data.intro,
crumb: crumb([{ label: "Home", path: "/" }, { label: data.title }]),
})}
${sections}
`,
};
}
// ---- Productdetail --------------------------------------------------------
function productDetail(slug) {
const p = bySlug(slug);
if (!p) return notFound();
const specRows = Object.entries(p.specs)
.map(([k, v]) => `${escapeHtml(k)} ${escapeHtml(v)}
`)
.join("");
const features = p.features.map((f) => `${escapeHtml(f)} `).join("");
const fallback =
`${escapeHtml(p.from)} → ${escapeHtml(p.to)} `;
const related = PRODUCTS.filter((x) => x.category === p.category && x.id !== p.id).slice(0, 3);
const relatedHtml = related.length ? `${CL.components.productGrid(related)}` : "";
return {
title: p.name + " — Converterland",
html: `
${pageHead({
crumb: crumb([
{ label: "Home", path: "/" },
{ label: "Producten", path: "/producten" },
{ label: p.name },
]),
title: p.name,
})}
${escapeHtml(p.id)}
${stars(p.rating)}(${p.reviews} beoordelingen)
${formatPrice(p.price)}${formatPrice(p.old)}
U bespaart ${formatPrice(p.old - p.price)}
${escapeHtml(p.stock.label)}
${escapeHtml(p.long)}
Technische specificaties
${specRows}
${
related.length
? ``
: ""
}
`,
};
}
// ---- 404 ------------------------------------------------------------------
function notFound() {
return {
title: "Niet gevonden — Converterland",
html: `
${pageHead({ eyebrow: "Fout 404", title: "Pagina niet gevonden", intro: "Deze pagina bestaat net zomin als onze producten." })}
Terug naar de startpagina
`,
};
}
CL.pages = {
home,
producten,
catalogus,
specificaties,
aanbiedingen,
bedrijf,
overOns,
contact,
vacatures,
voorwaarden: () => legalPage("voorwaarden"),
privacy: () => legalPage("privacy"),
disclaimer: () => legalPage("disclaimer"),
productDetail,
notFound,
};
})();