// Kennisbank — SEO-blog: overzicht + artikelpagina's.
// Artikeldata komt uit public/kennisbank-data.js (window.KENNISBANK_ARTIKELEN),
// gedeeld met de server (src/lib/seo.js) voor meta-tags + sitemap.
function getArtikelen() {
return (typeof window !== "undefined" && window.KENNISBANK_ARTIKELEN) || [];
}
function getArtikel(slug) {
return getArtikelen().find(a => a.slug === slug) || null;
}
// Vaste beeldstandaard: echte werkplaatsfoto's, deterministisch per artikel verdeeld.
const BLOG_PHOTOS = [
"/photos/diagnose/IMG_4606.JPG", "/photos/diagnose/IMG_4607.JPG", "/photos/diagnose/IMG_4609.JPG",
"/photos/diagnose/IMG_4610.JPG", "/photos/diagnose/IMG_4611.JPG", "/photos/diagnose/IMG_4614.JPG",
"/photos/diagnose/IMG_4615.JPG", "/photos/diagnose/IMG_4616.JPG", "/photos/diagnose/IMG_4617.JPG",
"/photos/diagnose/IMG_4618.JPG", "/photos/diagnose/IMG_4624.JPG", "/photos/diagnose/IMG_4625.JPG",
"/photos/diagnose/IMG_4630.JPG", "/photos/diagnose/IMG_4632.JPG",
"/photos/diagnose/IMG_4626%20kopie%20klein.jpg", "/photos/diagnose/Foto%20Diagnose%20apparaat.JPG",
];
function photoFor(slug, offset) {
let h = 0;
for (let i = 0; i < (slug || "").length; i++) h = (h * 31 + slug.charCodeAt(i)) >>> 0;
return BLOG_PHOTOS[(h + (offset || 0)) % BLOG_PHOTOS.length];
}
// Herbruikbare afbeelding met vaste stijl (rond, 16:9, zachte schaduw)
function ArticleImage({ src, caption, style }) {
return (
{caption && {caption} }
);
}
// Icoon per categorie (val terug op boek)
const CAT_ICON = {
"APK": "Apk", "Onderhoud": "Wrench", "Banden & seizoen": "Tire",
"Airco": "Snow", "Diagnose": "Diag", "EV & hybride": "Bolt", "Kosten & tips": "Sparkle",
"Reparatie": "Cog", "Schade & ruit": "ShieldCheck",
};
function catIcon(cat) { return I[CAT_ICON[cat]] || I.Diag; }
// Interne link: categorie → relevante dienstpagina (SEO-structuur)
const CAT_SERVICE = {
"APK": { screen: "service-apk", label: "APK keuring" },
"Onderhoud": { screen: "service-onderhoud", label: "Onderhoudsbeurt" },
"Reparatie": { screen: "service-reparatie", label: "Auto reparatie" },
"Diagnose": { screen: "service-diagnose", label: "Diagnose" },
"Airco": { screen: "service-airco", label: "Airco service" },
"Banden & seizoen": { screen: "service-banden", label: "Banden & wielen" },
"Schade & ruit": { screen: "service-ruitschade", label: "Ruitschade" },
"EV & hybride": { screen: "service-onderhoud", label: "Onderhoud" },
"Kosten & tips": { screen: "diensten", label: "Alle diensten" },
};
// Platte-tekst body renderen: opeenvolgende "- "-regels worden een lijst,
// overige regels alinea's. Werkt ook als een inleidende regel + bullets in
// hetzelfde blok staan.
function ArticleBody({ text }) {
const lines = String(text || "").split("\n");
const out = [];
let para = [], bullets = [];
const flushPara = () => { if (para.length) { out.push({ t: "p", v: para.join(" ") }); para = []; } };
const flushBul = () => { if (bullets.length) { out.push({ t: "ul", v: bullets.slice() }); bullets = []; } };
for (const raw of lines) {
const l = raw.trim();
if (!l) { flushPara(); flushBul(); continue; }
if (l.startsWith("- ")) { flushPara(); bullets.push(l.replace(/^-\s+/, "")); }
else { flushBul(); para.push(l); }
}
flushPara(); flushBul();
return (
<>
{out.map((b, i) => b.t === "ul" ? (
{b.v.map((li, j) => (
{li}
))}
) : (
{b.v}
))}
>
);
}
// ─── OVERZICHT ──────────────────────────────────────────
function Kennisbank({ onNav }) {
const artikelen = getArtikelen();
const categories = ["Alle", ...Array.from(new Set(artikelen.map(a => a.category)))];
const [cat, setCat] = React.useState("Alle");
const list = cat === "Alle" ? artikelen : artikelen.filter(a => a.category === cat);
return (
{/* Hero */}
Kennisbank
Alles over autoonderhoud & APK
Praktische uitleg, tips en antwoorden op veelgestelde vragen — van APK en onderhoud
tot banden, airco en diagnose. Geschreven door de monteurs van Garage DéDé in Vijfhuizen.
{/* Categorie-filter */}
{categories.map(c => (
setCat(c)}
className={c === cat ? "pill accent" : "pill"}
style={{ cursor: "pointer", fontSize: 13, padding: "8px 14px" }}>
{c}
))}
{/* Artikel-grid */}
{list.length === 0 ? (
Binnenkort meer artikelen…
) : (
{list.map(a => {
const Icon = catIcon(a.category);
const excerpt = String(a.intro || "").split(/\n\n+/)[0].slice(0, 130);
return (
onNav("artikel-" + a.slug)}
className="card lift" style={{ padding: 0, textAlign: "left", cursor: "pointer", color: "var(--text)",
display: "flex", flexDirection: "column", overflow: "hidden" }}>
{a.category}
{a.title}
{excerpt}…
{a.readMin || 4} min lezen
Lees meer
);
})}
)}
);
}
// ─── ARTIKEL ────────────────────────────────────────────
function Artikel({ slug, onNav }) {
const a = getArtikel(slug);
React.useEffect(() => { window.scrollTo({ top: 0, behavior: "instant" }); }, [slug]);
if (!a) {
return (
Artikel niet gevonden
onNav("kennisbank")}>Terug naar de kennisbank
);
}
const related = (a.related || [])
.map(getArtikel).filter(Boolean).slice(0, 3);
// Fallback related: zelfde categorie
const relatedList = related.length ? related
: getArtikelen().filter(x => x.category === a.category && x.slug !== a.slug).slice(0, 3);
return (
{/* Header met hero-foto */}
onNav("kennisbank")} className="btn btn-ghost btn-sm" style={{ marginBottom: 24 }}>
Kennisbank
{a.category} · {a.readMin || 4} min lezen
{a.title}
{/* Intro + secties */}
{(a.sections || []).map((sec, i) => (
{(i === 1 || i === 3) && a.sections.length > i + 1 && (
)}
))}
{/* FAQ */}
{a.faq && a.faq.length > 0 && (
Veelgestelde vragen
{a.faq.map((qa, i) => )}
)}
{/* CTA */}
Hulp nodig met uw auto?
Garage DéDé in Vijfhuizen helpt u verder — APK, onderhoud, diagnose en meer. Plan online een afspraak of bel ons.
onNav("boeking")}>Afspraak maken
{CAT_SERVICE[a.category] && (
onNav(CAT_SERVICE[a.category].screen)}>
Meer over {CAT_SERVICE[a.category].label}
)}
023 - 545 1809
{/* Gerelateerd */}
{relatedList.length > 0 && (
Lees ook
{relatedList.map(r => (
onNav("artikel-" + r.slug)}
className="card lift" style={{ padding: 22, textAlign: "left", cursor: "pointer", color: "var(--text)" }}>
{r.category}
{r.title}
))}
)}
);
}
function FaqRow({ q, a }) {
const [open, setOpen] = React.useState(false);
return (
setOpen(o => !o)} style={{
width: "100%", textAlign: "left", padding: "18px 0", background: "transparent", border: 0,
display: "flex", justifyContent: "space-between", alignItems: "center", gap: 16, cursor: "pointer",
color: "var(--text)", fontFamily: "inherit",
}}>
{q}
{open &&
{a}
}
);
}
window.Kennisbank = Kennisbank;
window.Artikel = Artikel;