@xiwebdesign/xicms-core 8.15.0 → 8.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/XiCMSProvider.js +1 -0
  2. package/dist/XiCMSProvider.js.map +1 -1
  3. package/dist/admin/lib/veldTaal.js +1 -0
  4. package/dist/admin/lib/veldTaal.js.map +1 -1
  5. package/dist/admin/settings/BedrijfInstellingen.js +17 -2
  6. package/dist/admin/settings/BedrijfInstellingen.js.map +1 -1
  7. package/dist/admin/shop/ShopSettingsTab.js +29 -16
  8. package/dist/admin/shop/ShopSettingsTab.js.map +1 -1
  9. package/dist/auth/AuthProvider.js +1 -0
  10. package/dist/auth/AuthProvider.js.map +1 -1
  11. package/dist/bedrijf/bedrijf.d.ts +8 -0
  12. package/dist/bedrijf/bedrijf.js +16 -1
  13. package/dist/bedrijf/bedrijf.js.map +1 -1
  14. package/dist/blocks/builtins/ContactRender.js +8 -0
  15. package/dist/blocks/builtins/ContactRender.js.map +1 -1
  16. package/dist/blocks/builtins/WhatsappChatRender.js +2 -0
  17. package/dist/blocks/builtins/WhatsappChatRender.js.map +1 -1
  18. package/dist/blocks/builtins/consentEmbed.js +26 -9
  19. package/dist/blocks/builtins/consentEmbed.js.map +1 -1
  20. package/dist/components/onderOffset.d.ts +13 -0
  21. package/dist/components/onderOffset.js +74 -0
  22. package/dist/components/onderOffset.js.map +1 -0
  23. package/dist/components/site/Bedrijfsnummers.d.ts +9 -0
  24. package/dist/components/site/Bedrijfsnummers.js +12 -0
  25. package/dist/components/site/Bedrijfsnummers.js.map +1 -0
  26. package/dist/components/site/SiteFooter.js +2 -1
  27. package/dist/components/site/SiteFooter.js.map +1 -1
  28. package/dist/firebase/functionsClient.js +5 -1
  29. package/dist/firebase/functionsClient.js.map +1 -1
  30. package/dist/index.d.ts +2 -1
  31. package/dist/index.js +5 -1
  32. package/dist/index.js.map +1 -1
  33. package/dist/modules/builtins.js +6 -6
  34. package/dist/modules/builtins.js.map +1 -1
  35. package/dist/modules/consent/ConsentBanner.d.ts +5 -0
  36. package/dist/modules/consent/ConsentBanner.js +8 -7
  37. package/dist/modules/consent/ConsentBanner.js.map +1 -1
  38. package/dist/modules/consent/standaard.d.ts +12 -0
  39. package/dist/modules/consent/standaard.js +10 -0
  40. package/dist/modules/consent/standaard.js.map +1 -0
  41. package/dist/modules/consent/useConsent.d.ts +4 -0
  42. package/dist/modules/consent/useConsent.js +30 -1
  43. package/dist/modules/consent/useConsent.js.map +1 -1
  44. package/dist/releaseNotes.js +8 -0
  45. package/dist/releaseNotes.js.map +1 -1
  46. package/dist/schema/blocks.d.ts +3 -0
  47. package/dist/schema/blocks.js +3 -1
  48. package/dist/schema/blocks.js.map +1 -1
  49. package/dist/schema/business.d.ts +1 -0
  50. package/dist/schema/business.js +2 -0
  51. package/dist/schema/business.js.map +1 -1
  52. package/dist/schema/settings.d.ts +2 -0
  53. package/dist/schema/siteConfig.d.ts +1 -0
  54. package/dist/styles.css +32 -4
  55. package/dist/version.js +1 -1
  56. package/package.json +1 -1
@@ -0,0 +1,74 @@
1
+ "use client";
2
+ import { useEffect } from "react";
3
+ const ZWEVERS = ".xicms-consent, .xicms-consent__reopen, .xicms-whatsapp, [data-xicms-tooling]";
4
+ function useOnderOffset(actief = true) {
5
+ useEffect(() => {
6
+ if (!actief || typeof document === "undefined") return;
7
+ if (gebruikers++ === 0) stoppen = start();
8
+ return () => {
9
+ if (--gebruikers === 0) stoppen?.();
10
+ };
11
+ }, [actief]);
12
+ }
13
+ let gebruikers = 0;
14
+ let stoppen;
15
+ function start() {
16
+ const root = document.documentElement;
17
+ let vorige = -1;
18
+ let kandidaten = [];
19
+ const zoek = () => {
20
+ kandidaten = Array.from(document.querySelectorAll("body *")).filter(
21
+ (el) => getComputedStyle(el).position === "fixed" && !el.closest(ZWEVERS)
22
+ );
23
+ };
24
+ const meet = () => {
25
+ const vh = window.innerHeight;
26
+ const vw = window.innerWidth;
27
+ let hoogte = 0;
28
+ for (const el of kandidaten) {
29
+ if (!el.isConnected) continue;
30
+ const r = el.getBoundingClientRect();
31
+ if (r.height === 0 || r.bottom < vh - 2 || r.top >= vh) continue;
32
+ if (r.width < vw * 0.6 || r.height > vh * 0.4) continue;
33
+ const cs = getComputedStyle(el);
34
+ if (cs.visibility === "hidden" || Number(cs.opacity) === 0) continue;
35
+ hoogte = Math.max(hoogte, Math.round(vh - r.top));
36
+ }
37
+ if (hoogte !== vorige) {
38
+ vorige = hoogte;
39
+ root.style.setProperty("--xicms-onder", `${hoogte}px`);
40
+ }
41
+ };
42
+ let frame = 0;
43
+ let opnieuwZoeken = false;
44
+ const plan = (zoeken) => {
45
+ opnieuwZoeken ||= zoeken;
46
+ cancelAnimationFrame(frame);
47
+ frame = requestAnimationFrame(() => {
48
+ if (opnieuwZoeken) zoek();
49
+ opnieuwZoeken = false;
50
+ meet();
51
+ });
52
+ };
53
+ const naMutatie = () => plan(true);
54
+ const naBeweging = () => plan(false);
55
+ zoek();
56
+ meet();
57
+ const obs = new MutationObserver(naMutatie);
58
+ obs.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["class", "style", "hidden"] });
59
+ window.addEventListener("resize", naBeweging);
60
+ document.addEventListener("transitionend", naBeweging, true);
61
+ window.addEventListener("scroll", naBeweging, { passive: true });
62
+ return () => {
63
+ obs.disconnect();
64
+ cancelAnimationFrame(frame);
65
+ window.removeEventListener("resize", naBeweging);
66
+ document.removeEventListener("transitionend", naBeweging, true);
67
+ window.removeEventListener("scroll", naBeweging);
68
+ root.style.removeProperty("--xicms-onder");
69
+ };
70
+ }
71
+ export {
72
+ useOnderOffset
73
+ };
74
+ //# sourceMappingURL=onderOffset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/onderOffset.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\n\n/** Wat zelf boven de balken hoort te zweven, en dus niet als \"balk\" mag tellen (anders een rondje). */\nconst ZWEVERS = \".xicms-consent, .xicms-consent__reopen, .xicms-whatsapp, [data-xicms-tooling]\";\n\n/**\n * Hoe hoog zijn de vaste balken onderaan het venster? → `--xicms-onder` op `:root` (8.16).\n *\n * De cookiebanner stond `bottom: 0`, en op een telefoon staat daar bijna altijd al iets: de\n * demobalk, de belbalk van SiteHeader, of een eigen \"Maak een afspraak\"-balk van de klantsite. Op\n * barbier lag de demobalk precies over de knoppen van de banner — de bezoeker kón geen keuze maken.\n *\n * Net als `useBalkOffset` (bovenkant) meten we in plaats van te gokken: elke klantsite noemt zijn\n * balk anders. Telt als balk: `position: fixed`, zichtbaar, raakt de onderrand, minstens 60% van de\n * breedte en niet hoger dan 40% van het venster (geen schermvullende overlay). Een balk die pas bij\n * het scrollen inschuift wordt opnieuw gemeten zodra zijn klasse/stijl verandert of de overgang klaar is.\n */\nexport function useOnderOffset(actief = true): void {\n useEffect(() => {\n if (!actief || typeof document === \"undefined\") return;\n // Banner, 🍪-knopje en WhatsApp-knop vragen dit allemaal; één meting is genoeg.\n if (gebruikers++ === 0) stoppen = start();\n return () => {\n if (--gebruikers === 0) stoppen?.();\n };\n }, [actief]);\n}\n\nlet gebruikers = 0;\nlet stoppen: (() => void) | undefined;\n\nfunction start(): () => void {\n const root = document.documentElement;\n let vorige = -1;\n\n // Zoeken (dure scan van de hele pagina) alleen als de DOM verandert; meten (alleen de gevonden\n // vaste elementen) ook bij scrollen en na een overgang — dat moet goedkoop blijven.\n let kandidaten: HTMLElement[] = [];\n const zoek = () => {\n kandidaten = Array.from(document.querySelectorAll<HTMLElement>(\"body *\")).filter(\n (el) => getComputedStyle(el).position === \"fixed\" && !el.closest(ZWEVERS),\n );\n };\n const meet = () => {\n const vh = window.innerHeight;\n const vw = window.innerWidth;\n let hoogte = 0;\n for (const el of kandidaten) {\n if (!el.isConnected) continue;\n const r = el.getBoundingClientRect();\n if (r.height === 0 || r.bottom < vh - 2 || r.top >= vh) continue;\n if (r.width < vw * 0.6 || r.height > vh * 0.4) continue;\n const cs = getComputedStyle(el);\n if (cs.visibility === \"hidden\" || Number(cs.opacity) === 0) continue;\n hoogte = Math.max(hoogte, Math.round(vh - r.top));\n }\n if (hoogte !== vorige) {\n vorige = hoogte;\n root.style.setProperty(\"--xicms-onder\", `${hoogte}px`);\n }\n };\n\n // Gebundeld per frame: de observer ziet salvo's mutaties (zie useBalkOffset).\n let frame = 0;\n let opnieuwZoeken = false;\n const plan = (zoeken: boolean) => {\n opnieuwZoeken ||= zoeken;\n cancelAnimationFrame(frame);\n frame = requestAnimationFrame(() => {\n if (opnieuwZoeken) zoek();\n opnieuwZoeken = false;\n meet();\n });\n };\n const naMutatie = () => plan(true);\n const naBeweging = () => plan(false);\n zoek();\n meet();\n const obs = new MutationObserver(naMutatie);\n obs.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: [\"class\", \"style\", \"hidden\"] });\n window.addEventListener(\"resize\", naBeweging);\n document.addEventListener(\"transitionend\", naBeweging, true);\n // Sommige balken schuiven pas in na een stukje scrollen, zonder dat er een klasse verandert.\n window.addEventListener(\"scroll\", naBeweging, { passive: true });\n\n return () => {\n obs.disconnect();\n cancelAnimationFrame(frame);\n window.removeEventListener(\"resize\", naBeweging);\n document.removeEventListener(\"transitionend\", naBeweging, true);\n window.removeEventListener(\"scroll\", naBeweging);\n root.style.removeProperty(\"--xicms-onder\");\n };\n}\n"],"mappings":";AAEA,SAAS,iBAAiB;AAG1B,MAAM,UAAU;AAcT,SAAS,eAAe,SAAS,MAAY;AAClD,YAAU,MAAM;AACd,QAAI,CAAC,UAAU,OAAO,aAAa,YAAa;AAEhD,QAAI,iBAAiB,EAAG,WAAU,MAAM;AACxC,WAAO,MAAM;AACX,UAAI,EAAE,eAAe,EAAG,WAAU;AAAA,IACpC;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AACb;AAEA,IAAI,aAAa;AACjB,IAAI;AAEJ,SAAS,QAAoB;AAC3B,QAAM,OAAO,SAAS;AACtB,MAAI,SAAS;AAIb,MAAI,aAA4B,CAAC;AACjC,QAAM,OAAO,MAAM;AACjB,iBAAa,MAAM,KAAK,SAAS,iBAA8B,QAAQ,CAAC,EAAE;AAAA,MACxE,CAAC,OAAO,iBAAiB,EAAE,EAAE,aAAa,WAAW,CAAC,GAAG,QAAQ,OAAO;AAAA,IAC1E;AAAA,EACF;AACA,QAAM,OAAO,MAAM;AACjB,UAAM,KAAK,OAAO;AAClB,UAAM,KAAK,OAAO;AAClB,QAAI,SAAS;AACb,eAAW,MAAM,YAAY;AAC3B,UAAI,CAAC,GAAG,YAAa;AACrB,YAAM,IAAI,GAAG,sBAAsB;AACnC,UAAI,EAAE,WAAW,KAAK,EAAE,SAAS,KAAK,KAAK,EAAE,OAAO,GAAI;AACxD,UAAI,EAAE,QAAQ,KAAK,OAAO,EAAE,SAAS,KAAK,IAAK;AAC/C,YAAM,KAAK,iBAAiB,EAAE;AAC9B,UAAI,GAAG,eAAe,YAAY,OAAO,GAAG,OAAO,MAAM,EAAG;AAC5D,eAAS,KAAK,IAAI,QAAQ,KAAK,MAAM,KAAK,EAAE,GAAG,CAAC;AAAA,IAClD;AACA,QAAI,WAAW,QAAQ;AACrB,eAAS;AACT,WAAK,MAAM,YAAY,iBAAiB,GAAG,MAAM,IAAI;AAAA,IACvD;AAAA,EACF;AAGA,MAAI,QAAQ;AACZ,MAAI,gBAAgB;AACpB,QAAM,OAAO,CAAC,WAAoB;AAChC,sBAAkB;AAClB,yBAAqB,KAAK;AAC1B,YAAQ,sBAAsB,MAAM;AAClC,UAAI,cAAe,MAAK;AACxB,sBAAgB;AAChB,WAAK;AAAA,IACP,CAAC;AAAA,EACH;AACA,QAAM,YAAY,MAAM,KAAK,IAAI;AACjC,QAAM,aAAa,MAAM,KAAK,KAAK;AACnC,OAAK;AACL,OAAK;AACL,QAAM,MAAM,IAAI,iBAAiB,SAAS;AAC1C,MAAI,QAAQ,SAAS,MAAM,EAAE,WAAW,MAAM,SAAS,MAAM,YAAY,MAAM,iBAAiB,CAAC,SAAS,SAAS,QAAQ,EAAE,CAAC;AAC9H,SAAO,iBAAiB,UAAU,UAAU;AAC5C,WAAS,iBAAiB,iBAAiB,YAAY,IAAI;AAE3D,SAAO,iBAAiB,UAAU,YAAY,EAAE,SAAS,KAAK,CAAC;AAE/D,SAAO,MAAM;AACX,QAAI,WAAW;AACf,yBAAqB,KAAK;AAC1B,WAAO,oBAAoB,UAAU,UAAU;AAC/C,aAAS,oBAAoB,iBAAiB,YAAY,IAAI;AAC9D,WAAO,oBAAoB,UAAU,UAAU;AAC/C,SAAK,MAAM,eAAe,eAAe;AAAA,EAC3C;AACF;","names":[]}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * "KvK 12345678 · Btw NL123456789B01" uit het bedrijfsprofiel (8.16), voor sites met een eigen
3
+ * footer. Een ondernemer moet zijn KvK-nummer op de website vermelden, en bij verkoop aan
4
+ * consumenten ook het btw-identificatienummer. Zet dit in je footer; de klant vult de nummers in
5
+ * via /beheer → Instellingen → Bedrijf. Leeg profiel = niets.
6
+ */
7
+ export declare function Bedrijfsnummers({ className }: {
8
+ className?: string;
9
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { useMergedSiteConfig } from "../../settings/useSiteSettings.js";
4
+ import { bedrijfsnummersTekst } from "../../bedrijf/bedrijf.js";
5
+ function Bedrijfsnummers({ className }) {
6
+ const tekst = bedrijfsnummersTekst(useMergedSiteConfig().business);
7
+ return tekst ? /* @__PURE__ */ jsx("span", { className: className ?? "xicms-bedrijfsnummers", children: tekst }) : null;
8
+ }
9
+ export {
10
+ Bedrijfsnummers
11
+ };
12
+ //# sourceMappingURL=Bedrijfsnummers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/site/Bedrijfsnummers.tsx"],"sourcesContent":["\"use client\";\n\nimport { useMergedSiteConfig } from \"../../settings/useSiteSettings\";\nimport { bedrijfsnummersTekst } from \"../../bedrijf/bedrijf\";\n\n/**\n * \"KvK 12345678 · Btw NL123456789B01\" uit het bedrijfsprofiel (8.16), voor sites met een eigen\n * footer. Een ondernemer moet zijn KvK-nummer op de website vermelden, en bij verkoop aan\n * consumenten ook het btw-identificatienummer. Zet dit in je footer; de klant vult de nummers in\n * via /beheer → Instellingen → Bedrijf. Leeg profiel = niets.\n */\nexport function Bedrijfsnummers({ className }: { className?: string }) {\n const tekst = bedrijfsnummersTekst(useMergedSiteConfig().business);\n return tekst ? <span className={className ?? \"xicms-bedrijfsnummers\"}>{tekst}</span> : null;\n}\n"],"mappings":";AAaiB;AAXjB,SAAS,2BAA2B;AACpC,SAAS,4BAA4B;AAQ9B,SAAS,gBAAgB,EAAE,UAAU,GAA2B;AACrE,QAAM,QAAQ,qBAAqB,oBAAoB,EAAE,QAAQ;AACjE,SAAO,QAAQ,oBAAC,UAAK,WAAW,aAAa,yBAA0B,iBAAM,IAAU;AACzF;","names":[]}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useMergedSiteConfig, useSiteSettings } from "../../settings/useSiteSettings.js";
4
- import { adresRegels, heeftProfiel, telLink } from "../../bedrijf/bedrijf.js";
4
+ import { adresRegels, bedrijfsnummersTekst, heeftProfiel, telLink } from "../../bedrijf/bedrijf.js";
5
5
  import { useSiteConfig } from "../../config.js";
6
6
  function SiteFooter({
7
7
  className,
@@ -46,6 +46,7 @@ function SiteFooter({
46
46
  social.length > 0 && /* @__PURE__ */ jsx("ul", { className: "xicms-footer__social", children: social.map((s, i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", { href: s.href, "aria-label": s.platform, rel: "noopener noreferrer", target: "_blank", children: s.platform }) }, i)) }),
47
47
  /* @__PURE__ */ jsxs("div", { className: "xicms-footer__bottom", children: [
48
48
  /* @__PURE__ */ jsx("span", { children: footer.copyright ?? `\xA9 ${year} ${name}` }),
49
+ bedrijfsnummersTekst(profiel) && /* @__PURE__ */ jsx("span", { className: "xicms-footer__nummers", children: bedrijfsnummersTekst(profiel) }),
49
50
  showAdminLink && /* @__PURE__ */ jsx("a", { href: "/beheer", children: "Beheer" })
50
51
  ] }),
51
52
  /* @__PURE__ */ jsxs("div", { className: "xicms-footer__credit", children: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/site/SiteFooter.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { useMergedSiteConfig, useSiteSettings } from \"../../settings/useSiteSettings\";\nimport { adresRegels, heeftProfiel, telLink } from \"../../bedrijf/bedrijf\";\nimport { useSiteConfig } from \"../../config\";\nimport type { FooterSettings } from \"../../schema/settings\";\n\n/**\n * Door de klant in /beheer bewerkbare footer. Unstyled-by-default: alle opmaak hangt aan\n * `xicms-footer*`-classNames + thema-CSS-variabelen, zodat een site hem volledig kan herstijlen\n * (of vervangen door een eigen footer). De inhoud komt live uit `settings/public.footer`.\n */\nexport function SiteFooter({\n className,\n renderColumn,\n bedrijf = false,\n}: {\n className?: string;\n /**\n * 8.13: een eerste kolom met adres, telefoon, e-mail en openingstijden uit het bedrijfsprofiel\n * (Instellingen → Bedrijf). Uit voor bestaande sites; de template zet hem aan.\n */\n bedrijf?: boolean;\n /** Override de opmaak van één kolom zonder de logica te forken. */\n renderColumn?: (column: NonNullable<FooterSettings[\"columns\"]>[number], index: number) => ReactNode;\n}) {\n const { settings } = useSiteSettings();\n const config = useSiteConfig();\n const footer = settings.footer ?? {};\n const name = settings.name ?? config.name;\n const columns = footer.columns ?? [];\n const social = footer.social ?? [];\n const showAdminLink = footer.showAdminLink !== false;\n const year = new Date().getFullYear();\n const profiel = useMergedSiteConfig().business;\n const toonProfiel = bedrijf && heeftProfiel(profiel);\n\n return (\n <footer className={className ?? \"xicms-footer\"}>\n {(columns.length > 0 || toonProfiel) && (\n <div className=\"xicms-footer__columns\">\n {toonProfiel && profiel && (\n <div className=\"xicms-footer__column xicms-footer__column--bedrijf\">\n <h3 className=\"xicms-footer__heading\">Contact</h3>\n <ul className=\"xicms-footer__links\">\n {adresRegels(profiel).map((r) => <li key={r}>{r}</li>)}\n {profiel.phone && <li><a href={telLink(profiel.phone)}>{profiel.phone}</a></li>}\n {profiel.email && <li><a href={`mailto:${profiel.email}`}>{profiel.email}</a></li>}\n </ul>\n {(profiel.hours?.length ?? 0) > 0 && (\n <>\n <h3 className=\"xicms-footer__heading\">Openingstijden</h3>\n <ul className=\"xicms-footer__links\">\n {profiel.hours!.map((r, i) => <li key={i}>{r.day} — {r.hours}</li>)}\n </ul>\n </>\n )}\n </div>\n )}\n {columns.map((col, i) =>\n renderColumn ? (\n <div key={i}>{renderColumn(col, i)}</div>\n ) : (\n <div key={i} className=\"xicms-footer__column\">\n {col.heading && <h3 className=\"xicms-footer__heading\">{col.heading}</h3>}\n <ul className=\"xicms-footer__links\">\n {(col.links ?? []).map((l, j) => (\n <li key={j}>\n <a href={l.href}>{l.label}</a>\n </li>\n ))}\n </ul>\n </div>\n ),\n )}\n </div>\n )}\n\n {social.length > 0 && (\n <ul className=\"xicms-footer__social\">\n {social.map((s, i) => (\n <li key={i}>\n <a href={s.href} aria-label={s.platform} rel=\"noopener noreferrer\" target=\"_blank\">\n {s.platform}\n </a>\n </li>\n ))}\n </ul>\n )}\n\n <div className=\"xicms-footer__bottom\">\n <span>{footer.copyright ?? `© ${year} ${name}`}</span>\n {showAdminLink && <a href=\"/beheer\">Beheer</a>}\n </div>\n\n <div className=\"xicms-footer__credit\">\n <a\n className=\"xicms-footer__credit-merk\"\n href=\"https://www.xiwebdesign.nl\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n <svg viewBox=\"0 0 64 64\" aria-hidden=\"true\" fill=\"currentColor\">\n <rect x=\"6\" y=\"10\" width=\"52\" height=\"11\" rx=\"3\" />\n <rect x=\"16\" y=\"27\" width=\"32\" height=\"11\" rx=\"3\" opacity=\"0.7\" />\n <rect x=\"6\" y=\"44\" width=\"52\" height=\"11\" rx=\"3\" />\n </svg>\n Website gemaakt door Xi Webdesign\n </a>\n <span aria-hidden>·</span>\n <a\n className=\"xicms-footer__credit-cta\"\n href=\"https://www.xiwebdesign.nl/#contact\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Ook zo&apos;n mooie website? Neem contact op →\n </a>\n </div>\n </footer>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/components/site/SiteFooter.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { useMergedSiteConfig, useSiteSettings } from \"../../settings/useSiteSettings\";\nimport { adresRegels, bedrijfsnummersTekst, heeftProfiel, telLink } from \"../../bedrijf/bedrijf\";\nimport { useSiteConfig } from \"../../config\";\nimport type { FooterSettings } from \"../../schema/settings\";\n\n/**\n * Door de klant in /beheer bewerkbare footer. Unstyled-by-default: alle opmaak hangt aan\n * `xicms-footer*`-classNames + thema-CSS-variabelen, zodat een site hem volledig kan herstijlen\n * (of vervangen door een eigen footer). De inhoud komt live uit `settings/public.footer`.\n */\nexport function SiteFooter({\n className,\n renderColumn,\n bedrijf = false,\n}: {\n className?: string;\n /**\n * 8.13: een eerste kolom met adres, telefoon, e-mail en openingstijden uit het bedrijfsprofiel\n * (Instellingen → Bedrijf). Uit voor bestaande sites; de template zet hem aan.\n */\n bedrijf?: boolean;\n /** Override de opmaak van één kolom zonder de logica te forken. */\n renderColumn?: (column: NonNullable<FooterSettings[\"columns\"]>[number], index: number) => ReactNode;\n}) {\n const { settings } = useSiteSettings();\n const config = useSiteConfig();\n const footer = settings.footer ?? {};\n const name = settings.name ?? config.name;\n const columns = footer.columns ?? [];\n const social = footer.social ?? [];\n const showAdminLink = footer.showAdminLink !== false;\n const year = new Date().getFullYear();\n const profiel = useMergedSiteConfig().business;\n const toonProfiel = bedrijf && heeftProfiel(profiel);\n\n return (\n <footer className={className ?? \"xicms-footer\"}>\n {(columns.length > 0 || toonProfiel) && (\n <div className=\"xicms-footer__columns\">\n {toonProfiel && profiel && (\n <div className=\"xicms-footer__column xicms-footer__column--bedrijf\">\n <h3 className=\"xicms-footer__heading\">Contact</h3>\n <ul className=\"xicms-footer__links\">\n {adresRegels(profiel).map((r) => <li key={r}>{r}</li>)}\n {profiel.phone && <li><a href={telLink(profiel.phone)}>{profiel.phone}</a></li>}\n {profiel.email && <li><a href={`mailto:${profiel.email}`}>{profiel.email}</a></li>}\n </ul>\n {(profiel.hours?.length ?? 0) > 0 && (\n <>\n <h3 className=\"xicms-footer__heading\">Openingstijden</h3>\n <ul className=\"xicms-footer__links\">\n {profiel.hours!.map((r, i) => <li key={i}>{r.day} — {r.hours}</li>)}\n </ul>\n </>\n )}\n </div>\n )}\n {columns.map((col, i) =>\n renderColumn ? (\n <div key={i}>{renderColumn(col, i)}</div>\n ) : (\n <div key={i} className=\"xicms-footer__column\">\n {col.heading && <h3 className=\"xicms-footer__heading\">{col.heading}</h3>}\n <ul className=\"xicms-footer__links\">\n {(col.links ?? []).map((l, j) => (\n <li key={j}>\n <a href={l.href}>{l.label}</a>\n </li>\n ))}\n </ul>\n </div>\n ),\n )}\n </div>\n )}\n\n {social.length > 0 && (\n <ul className=\"xicms-footer__social\">\n {social.map((s, i) => (\n <li key={i}>\n <a href={s.href} aria-label={s.platform} rel=\"noopener noreferrer\" target=\"_blank\">\n {s.platform}\n </a>\n </li>\n ))}\n </ul>\n )}\n\n <div className=\"xicms-footer__bottom\">\n <span>{footer.copyright ?? `© ${year} ${name}`}</span>\n {/* 8.16: KvK en btw-nummer — wettelijk verplicht op de site; altijd zodra ze in het profiel staan. */}\n {bedrijfsnummersTekst(profiel) && <span className=\"xicms-footer__nummers\">{bedrijfsnummersTekst(profiel)}</span>}\n {showAdminLink && <a href=\"/beheer\">Beheer</a>}\n </div>\n\n <div className=\"xicms-footer__credit\">\n <a\n className=\"xicms-footer__credit-merk\"\n href=\"https://www.xiwebdesign.nl\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n <svg viewBox=\"0 0 64 64\" aria-hidden=\"true\" fill=\"currentColor\">\n <rect x=\"6\" y=\"10\" width=\"52\" height=\"11\" rx=\"3\" />\n <rect x=\"16\" y=\"27\" width=\"32\" height=\"11\" rx=\"3\" opacity=\"0.7\" />\n <rect x=\"6\" y=\"44\" width=\"52\" height=\"11\" rx=\"3\" />\n </svg>\n Website gemaakt door Xi Webdesign\n </a>\n <span aria-hidden>·</span>\n <a\n className=\"xicms-footer__credit-cta\"\n href=\"https://www.xiwebdesign.nl/#contact\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Ook zo&apos;n mooie website? Neem contact op →\n </a>\n </div>\n </footer>\n );\n}\n"],"mappings":"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","names":[]}
@@ -5,6 +5,7 @@ const verbonden = /* @__PURE__ */ new WeakSet();
5
5
  function zonderUndefined(data) {
6
6
  return data === void 0 ? void 0 : JSON.parse(JSON.stringify(data));
7
7
  }
8
+ const ZONDER_APPCHECK = /* @__PURE__ */ new Set(["trackView", "reportClientError"]);
8
9
  function callable(app, naam) {
9
10
  const fns = getFunctions(app, functionsRegion());
10
11
  if (!verbonden.has(fns)) {
@@ -13,7 +14,10 @@ function callable(app, naam) {
13
14
  if (em) connectFunctionsEmulator(fns, em.host, em.functions);
14
15
  }
15
16
  const fn = httpsCallable(fns, naam);
16
- return ((data) => fn(zonderUndefined(data)));
17
+ return (async (data) => {
18
+ if (!ZONDER_APPCHECK.has(naam)) await (await import("./appcheck.js")).initAppCheck();
19
+ return fn(zonderUndefined(data));
20
+ });
17
21
  }
18
22
  export {
19
23
  callable
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/firebase/functionsClient.ts"],"sourcesContent":["/**\n * Eén plek waar een Cloud-Function-callable vandaan komt.\n *\n * Hiervoor stond op eenentwintig plekken hetzelfde regeltje\n * `httpsCallable(getFunctions(app, functionsRegion()), \"naam\")`. Dat was al duplicatie, maar het\n * werd een risico toen de emulators erbij kwamen: verbind je Firestore lokaal en laat je de\n * callables ongemoeid, dan lees je uit de emulator terwijl je SCHRIJFT naar het echte project —\n * en dat merk je pas als de productiedata al veranderd is. Door de callables hier te maken kan\n * die scheefstand niet ontstaan.\n *\n * Dit bestand importeert `firebase/functions` statisch, en wordt daarom zélf overal dynamisch\n * geïmporteerd waar het publieke pad langskomt (PageView, submitForm) — zo blijft de SDK uit de\n * bundel van een gewone bezoeker.\n */\nimport type { FirebaseApp } from \"firebase/app\";\nimport { getFunctions, httpsCallable, connectFunctionsEmulator, type HttpsCallable } from \"firebase/functions\";\nimport { functionsRegion } from \"./region\";\nimport { emulatorHosts } from \"./emulators\";\n\n// `getFunctions(app, regio)` geeft per app+regio dezelfde instantie terug, dus één verbinding volstaat.\nconst verbonden = new WeakSet<object>();\n\n/**\n * `undefined`-velden strippen vóór verzenden.\n *\n * De functions-SDK encodeert `undefined` als `null` over de draad, en de zod-schema's op de\n * server zeggen `.optional()` — dat accepteert een ONTBREKEND veld, maar geen `null`. Elke\n * payload met een `veld: kanLeegZijn ? waarde : undefined`-patroon werd daardoor server-side\n * geweigerd: zo faalde \"+ Nieuw product\" ALTIJD (\"Ongeldige productgegevens\" — `productId:\n * undefined` kwam als `null` aan, live bewezen op christelijkkraamcadeau met een handmatige\n * call: zónder het veld 200, mét `null` 400) en \"als verzonden markeren\" zonder tracking-URL\n * net zo. Eén JSON-roundtrip hier dicht die hele klasse voor álle callables: de payloads zijn\n * plain JSON (geen Timestamps of klasse-instanties), dus dit is verliesvrij.\n */\nfunction zonderUndefined(data: unknown): unknown {\n return data === undefined ? undefined : JSON.parse(JSON.stringify(data));\n}\n\n/** Een getypeerde callable voor `naam`, in de juiste regio en (lokaal) tegen de emulator. */\nexport function callable<Req = unknown, Res = unknown>(app: FirebaseApp, naam: string): HttpsCallable<Req, Res> {\n const fns = getFunctions(app, functionsRegion());\n if (!verbonden.has(fns)) {\n verbonden.add(fns);\n const em = emulatorHosts();\n if (em) connectFunctionsEmulator(fns, em.host, em.functions);\n }\n const fn = httpsCallable<Req, Res>(fns, naam);\n return ((data?: Req) => fn(zonderUndefined(data) as Req)) as HttpsCallable<Req, Res>;\n}\n"],"mappings":"AAeA,SAAS,cAAc,eAAe,gCAAoD;AAC1F,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAG9B,MAAM,YAAY,oBAAI,QAAgB;AActC,SAAS,gBAAgB,MAAwB;AAC/C,SAAO,SAAS,SAAY,SAAY,KAAK,MAAM,KAAK,UAAU,IAAI,CAAC;AACzE;AAGO,SAAS,SAAuC,KAAkB,MAAuC;AAC9G,QAAM,MAAM,aAAa,KAAK,gBAAgB,CAAC;AAC/C,MAAI,CAAC,UAAU,IAAI,GAAG,GAAG;AACvB,cAAU,IAAI,GAAG;AACjB,UAAM,KAAK,cAAc;AACzB,QAAI,GAAI,0BAAyB,KAAK,GAAG,MAAM,GAAG,SAAS;AAAA,EAC7D;AACA,QAAM,KAAK,cAAwB,KAAK,IAAI;AAC5C,UAAQ,CAAC,SAAe,GAAG,gBAAgB,IAAI,CAAQ;AACzD;","names":[]}
1
+ {"version":3,"sources":["../../src/firebase/functionsClient.ts"],"sourcesContent":["/**\n * Eén plek waar een Cloud-Function-callable vandaan komt.\n *\n * Hiervoor stond op eenentwintig plekken hetzelfde regeltje\n * `httpsCallable(getFunctions(app, functionsRegion()), \"naam\")`. Dat was al duplicatie, maar het\n * werd een risico toen de emulators erbij kwamen: verbind je Firestore lokaal en laat je de\n * callables ongemoeid, dan lees je uit de emulator terwijl je SCHRIJFT naar het echte project —\n * en dat merk je pas als de productiedata al veranderd is. Door de callables hier te maken kan\n * die scheefstand niet ontstaan.\n *\n * Dit bestand importeert `firebase/functions` statisch, en wordt daarom zélf overal dynamisch\n * geïmporteerd waar het publieke pad langskomt (PageView, submitForm) — zo blijft de SDK uit de\n * bundel van een gewone bezoeker.\n */\nimport type { FirebaseApp } from \"firebase/app\";\nimport { getFunctions, httpsCallable, connectFunctionsEmulator, type HttpsCallable } from \"firebase/functions\";\nimport { functionsRegion } from \"./region\";\nimport { emulatorHosts } from \"./emulators\";\n\n// `getFunctions(app, regio)` geeft per app+regio dezelfde instantie terug, dus één verbinding volstaat.\nconst verbonden = new WeakSet<object>();\n\n/**\n * `undefined`-velden strippen vóór verzenden.\n *\n * De functions-SDK encodeert `undefined` als `null` over de draad, en de zod-schema's op de\n * server zeggen `.optional()` — dat accepteert een ONTBREKEND veld, maar geen `null`. Elke\n * payload met een `veld: kanLeegZijn ? waarde : undefined`-patroon werd daardoor server-side\n * geweigerd: zo faalde \"+ Nieuw product\" ALTIJD (\"Ongeldige productgegevens\" — `productId:\n * undefined` kwam als `null` aan, live bewezen op christelijkkraamcadeau met een handmatige\n * call: zónder het veld 200, mét `null` 400) en \"als verzonden markeren\" zonder tracking-URL\n * net zo. Eén JSON-roundtrip hier dicht die hele klasse voor álle callables: de payloads zijn\n * plain JSON (geen Timestamps of klasse-instanties), dus dit is verliesvrij.\n */\nfunction zonderUndefined(data: unknown): unknown {\n return data === undefined ? undefined : JSON.parse(JSON.stringify(data));\n}\n\n/**\n * 8.16: callables die GEEN App Check nodig hebben. De bezoekersteller en de foutmelder draaien bij\n * gewone bezoekers; zij starten reCAPTCHA (en dus scripts van Google) niet. Ze zijn op de server\n * begrensd per IP en vragen ook daar geen App Check meer (functions 3.30).\n */\nconst ZONDER_APPCHECK = new Set([\"trackView\", \"reportClientError\"]);\n\n/** Een getypeerde callable voor `naam`, in de juiste regio en (lokaal) tegen de emulator. */\nexport function callable<Req = unknown, Res = unknown>(app: FirebaseApp, naam: string): HttpsCallable<Req, Res> {\n const fns = getFunctions(app, functionsRegion());\n if (!verbonden.has(fns)) {\n verbonden.add(fns);\n const em = emulatorHosts();\n if (em) connectFunctionsEmulator(fns, em.host, em.functions);\n }\n const fn = httpsCallable<Req, Res>(fns, naam);\n return (async (data?: Req) => {\n // App Check pas nu: vlak vóór een formulier, bestelling of inlogmail (no-op zonder sleutel of\n // als het al draait). De functions-SDK pikt het token daarna vanzelf op.\n if (!ZONDER_APPCHECK.has(naam)) await (await import(\"./appcheck\")).initAppCheck();\n return fn(zonderUndefined(data) as Req);\n }) as HttpsCallable<Req, Res>;\n}\n"],"mappings":"AAeA,SAAS,cAAc,eAAe,gCAAoD;AAC1F,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAG9B,MAAM,YAAY,oBAAI,QAAgB;AActC,SAAS,gBAAgB,MAAwB;AAC/C,SAAO,SAAS,SAAY,SAAY,KAAK,MAAM,KAAK,UAAU,IAAI,CAAC;AACzE;AAOA,MAAM,kBAAkB,oBAAI,IAAI,CAAC,aAAa,mBAAmB,CAAC;AAG3D,SAAS,SAAuC,KAAkB,MAAuC;AAC9G,QAAM,MAAM,aAAa,KAAK,gBAAgB,CAAC;AAC/C,MAAI,CAAC,UAAU,IAAI,GAAG,GAAG;AACvB,cAAU,IAAI,GAAG;AACjB,UAAM,KAAK,cAAc;AACzB,QAAI,GAAI,0BAAyB,KAAK,GAAG,MAAM,GAAG,SAAS;AAAA,EAC7D;AACA,QAAM,KAAK,cAAwB,KAAK,IAAI;AAC5C,UAAQ,OAAO,SAAe;AAG5B,QAAI,CAAC,gBAAgB,IAAI,IAAI,EAAG,QAAO,MAAM,OAAO,YAAY,GAAG,aAAa;AAChF,WAAO,GAAG,gBAAgB,IAAI,CAAQ;AAAA,EACxC;AACF;","names":[]}
package/dist/index.d.ts CHANGED
@@ -17,6 +17,7 @@ export { SiteSettingsProvider, useSiteSettings, useMergedSiteConfig, } from "./s
17
17
  export { SiteFooter } from "./components/site/SiteFooter.js";
18
18
  export { SiteNav } from "./components/site/SiteNav.js";
19
19
  export { SiteHeader } from "./components/site/SiteHeader.js";
20
+ export { Bedrijfsnummers } from "./components/site/Bedrijfsnummers.js";
20
21
  export { EditorProvider, useEditor } from "./editor/EditorProvider.js";
21
22
  export { definePattern, instantiatePattern, collectPatternTypes, builtinPatterns, type Pattern, type PatternBlock, } from "./patterns/index.js";
22
23
  export { builtinThemePresets, type ThemePreset } from "./theme/presets.js";
@@ -36,7 +37,7 @@ export type { ThemeTokens, NavItem, NavLeaf, Redirect, SiteSettings, PublicSiteS
36
37
  export { zoekRedirect, normaliseerPad, navHref, isExterneLink } from "./schema/settings.js";
37
38
  export type { Seo } from "./schema/seo.js";
38
39
  export { BusinessSchema, BEDRIJFSTYPES, type Business, type BusinessException } from "./schema/business.js";
39
- export { adresRegels, telLink, routeLink, afwijkingOp, komendeAfwijkingen, afwijkingDatumTekst, isOpenNuMetAfwijkingen, heeftProfiel } from "./bedrijf/bedrijf.js";
40
+ export { bedrijfsnummersTekst, bedrijfsnummerAdvies, adresRegels, telLink, routeLink, afwijkingOp, komendeAfwijkingen, afwijkingDatumTekst, isOpenNuMetAfwijkingen, heeftProfiel } from "./bedrijf/bedrijf.js";
40
41
  export type { Page, PageStatus } from "./schema/pages.js";
41
42
  export type { FormDefinition, FormField } from "./schema/forms.js";
42
43
  export { AuthProvider, useAuth } from "./auth/AuthProvider.js";
package/dist/index.js CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  import { SiteFooter } from "./components/site/SiteFooter.js";
13
13
  import { SiteNav } from "./components/site/SiteNav.js";
14
14
  import { SiteHeader } from "./components/site/SiteHeader.js";
15
+ import { Bedrijfsnummers } from "./components/site/Bedrijfsnummers.js";
15
16
  import { EditorProvider, useEditor } from "./editor/EditorProvider.js";
16
17
  import {
17
18
  definePattern,
@@ -37,7 +38,7 @@ import {
37
38
  } from "./i18n/overlay.js";
38
39
  import { zoekRedirect, normaliseerPad, navHref, isExterneLink } from "./schema/settings.js";
39
40
  import { BusinessSchema, BEDRIJFSTYPES } from "./schema/business.js";
40
- import { adresRegels, telLink, routeLink, afwijkingOp, komendeAfwijkingen, afwijkingDatumTekst, isOpenNuMetAfwijkingen, heeftProfiel } from "./bedrijf/bedrijf.js";
41
+ import { bedrijfsnummersTekst, bedrijfsnummerAdvies, adresRegels, telLink, routeLink, afwijkingOp, komendeAfwijkingen, afwijkingDatumTekst, isOpenNuMetAfwijkingen, heeftProfiel } from "./bedrijf/bedrijf.js";
41
42
  import { AuthProvider, useAuth } from "./auth/AuthProvider.js";
42
43
  import { LoginForm } from "./auth/LoginForm.js";
43
44
  import {
@@ -95,6 +96,7 @@ import { CORE_VERSION, CORE_PACKAGE, isNieuwer } from "./version.js";
95
96
  export {
96
97
  AuthProvider,
97
98
  BEDRIJFSTYPES,
99
+ Bedrijfsnummers,
98
100
  BlockDataProvider,
99
101
  BlockRenderer,
100
102
  BusinessSchema,
@@ -138,6 +140,8 @@ export {
138
140
  afwijkingOp,
139
141
  applyBlockOverrides,
140
142
  assertModuleContract,
143
+ bedrijfsnummerAdvies,
144
+ bedrijfsnummersTekst,
141
145
  buildBlockAddOptions,
142
146
  builtinBlocks,
143
147
  builtinModules,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Publieke runtime-API van @xiwebdesign/xicms-core (lichte client/runtime laag).\n * - Admin (TipTap/Radix) zit in \"@xiwebdesign/xicms-core/admin\".\n * - Server-only code (firebase-admin, sanitize, SEO) zit in \"@xiwebdesign/xicms-core/server\".\n * - Pure schema's in \"@xiwebdesign/xicms-core/schema\".\n */\n\n// Provider & config\nexport { XiCMSProvider } from \"./XiCMSProvider\";\nexport { useSiteConfig } from \"./config\";\n\n// Theming & design-primitieven (maatwerk zonder core te forken).\n// - `defineTheme` maakt een eigen Astryx-thema (tokens + component-overrides) → geef door als\n// XiCMSProvider `astryxTheme`-prop.\n// - De `ui`-primitieven (Card/Stack/Grid/Heading/Text/Btn…) zijn de bouwstenen waarop de ingebouwde\n// blokken draaien; gebruik ze in eigen blokken voor een consistent maar te herstijlen uiterlijk.\nexport { defineTheme, useTheme } from \"@astryxdesign/core/theme\";\nexport type { DefinedTheme } from \"@astryxdesign/core/theme\";\n// Framework-router-integratie: geef `next/link` door als XiCMSProvider `linkComponent`-prop\n// (soepele client-nav + prefetch op alle Astryx-knoppen/links). `useLinkComponent` voor eigen blokken.\nexport { LinkProvider, useLinkComponent } from \"@astryxdesign/core/Link\";\nexport type { LinkComponentType } from \"@astryxdesign/core/Link\";\n// Beeldoptimalisatie: geef `next/image` door als XiCMSProvider `imageComponent`-prop. `Img` is de\n// wrapper die de blokken gebruiken; `useImageComponent` voor eigen blokken.\nexport { Img, ImageProvider, useImageComponent, InlineImageEditProvider } from \"./media/ImageContext\";\nexport type { ImageComponentType, ImgProps } from \"./media/ImageContext\";\nexport * from \"./blocks/ui\";\nexport {\n SiteSettingsProvider,\n useSiteSettings,\n useMergedSiteConfig,\n} from \"./settings/useSiteSettings\";\nexport { SiteFooter } from \"./components/site/SiteFooter\";\n// 7.24: de beheerde hoofdnavigatie — de enige plek die `settings.nav` leest. Zie SiteNav.tsx.\nexport { SiteNav } from \"./components/site/SiteNav\";\n// 8.13: kop met logo, menu, actieknop, hamburgermenu en mobiele belbalk. Zie SiteHeader.tsx.\nexport { SiteHeader } from \"./components/site/SiteHeader\";\nexport { EditorProvider, useEditor } from \"./editor/EditorProvider\";\nexport {\n definePattern,\n instantiatePattern,\n collectPatternTypes,\n builtinPatterns,\n type Pattern,\n type PatternBlock,\n} from \"./patterns\";\nexport { builtinThemePresets, type ThemePreset } from \"./theme/presets\";\nexport { defineSiteConfig } from \"./schema/siteConfig\";\nexport type { SiteConfig, SiteMode } from \"./schema/siteConfig\";\n// 5.0: Field-IR (primo-port), symbolen en custom blocks.\nexport { FieldSchema, FieldsSchema, fieldsToZod, fieldsDefaults, isFieldVisible, isRichTextKey } from \"./schema/fields\";\nexport type { Field, FieldHints, ShowIf } from \"./schema/fields\";\nexport { SymbolSchema } from \"./schema/symbols\";\nexport type { SymbolDefinition, StoredSymbol } from \"./schema/symbols\";\nexport { CustomBlockSchema } from \"./schema/customBlocks\";\nexport type { CustomBlock, CustomBlock as CustomBlockData } from \"./schema/customBlocks\";\nexport { customBlockToDefinition } from \"./blocks/customTemplate/definition\";\nexport { interpretTemplate, scopeCss } from \"./blocks/customTemplate/interpret\";\n// 5.0: localisatie — overlay-model (primo's locale-per-waarde, additief vertaald).\nexport {\n siteLocales,\n parseLocaleSlugs,\n localizedPath,\n localizePage,\n localizeBlocks,\n pruneTranslations,\n TranslationsSchema,\n} from \"./i18n/overlay\";\nexport type { Translations, LocaleConfig } from \"./i18n/overlay\";\nexport type { ThemeTokens, NavItem, NavLeaf, Redirect, SiteSettings, PublicSiteSettings, FormsSender } from \"./schema/settings\";\nexport { zoekRedirect, normaliseerPad, navHref, isExterneLink } from \"./schema/settings\";\nexport type { Seo } from \"./schema/seo\";\n// 8.13: bedrijfsprofiel (adres, telefoon, openingstijden) + hulpjes voor eigen headers/footers.\nexport { BusinessSchema, BEDRIJFSTYPES, type Business, type BusinessException } from \"./schema/business\";\nexport { adresRegels, telLink, routeLink, afwijkingOp, komendeAfwijkingen, afwijkingDatumTekst, isOpenNuMetAfwijkingen, heeftProfiel } from \"./bedrijf/bedrijf\";\nexport type { Page, PageStatus } from \"./schema/pages\";\nexport type { FormDefinition, FormField } from \"./schema/forms\";\n\n// Auth\nexport { AuthProvider, useAuth } from \"./auth/AuthProvider\";\nexport { LoginForm } from \"./auth/LoginForm\";\nexport {\n roleForSite,\n canEdit,\n canManageSite,\n isSuperadmin,\n type Role,\n type XiClaims,\n} from \"./auth/roles\";\n\n// De legacy inline-laag (ContentProvider/useContent + EditableText/EditableRichText/EditableImage,\n// het v1 platte `cms/content`-model) is in 5.0 VERWIJDERD, zoals bij de deprecatie aangekondigd.\n// Inline bewerken loopt via het block-model: markeer tekstvelden met `data-xicms-edit` in de Render.\nexport type { NewsArticle, MediaItem, MediaVariant } from \"./content/types\";\n\nexport { EditBar } from \"./components/EditBar\";\nexport { ExternEmbed } from \"./components/ExternEmbed\";\nexport { ResponsiveImage } from \"./components/ResponsiveImage\";\nexport { PageView, NietGevondenMelder } from \"./components/PageView\";\nexport { NewsList, NewsArticleView, useNews } from \"./components/News\";\n\n// Block-systeem (runtime: registry + renderer; editors zitten in /admin)\nexport {\n defineBlock,\n createRegistry,\n mergeRegistry,\n validateBlocks,\n buildBlockAddOptions,\n type BlockDefinition,\n type BlockRegistry,\n type BlockRenderProps,\n type BlockEditorProps,\n type BlockCategory,\n} from \"./blocks/registry\";\nexport { BlockRenderer } from \"./blocks/BlockRenderer\";\nexport { RegistryProvider, useRegistry, BlockDataProvider, useBlockData } from \"./blocks/context\";\nexport { builtinBlocks, ConsentEmbed } from \"./blocks/builtins\";\nexport { PageRenderer } from \"./render/PageRenderer\";\nexport { PublishedPage } from \"./render/PublishedPage\";\n\n// Module-systeem (XiCMS 3.0): modules bundelen blocks + instellingen; per site aan/uit + te stylen.\nexport {\n defineModule,\n resolveModules,\n isModuleActive,\n ModulesProvider,\n useModules,\n useModuleActive,\n useModuleSettings,\n applyBlockOverrides,\n moduleIdForBlockType,\n builtinModules,\n validateModuleContract,\n assertModuleContract,\n useConsent,\n ConsentBanner,\n ConsentGate,\n ConsentReopenLink,\n type ConsentState,\n type ConsentSettings,\n type ConsentCategory,\n type ModuleDefinition,\n type ModuleSiteSetting,\n type ModulesSiteConfig,\n type Capability,\n type ResolvedModules,\n type BlockOverride,\n type BlockOverrides,\n} from \"./modules\";\n\n// Demo-lock\nexport { DemoLock } from \"./lock/DemoLock\";\n\n// Demo-bewerkmodus (lokaal-only) leeft op het subpad `@xiwebdesign/xicms-core/demo` — dit zijn\n// demo-store-internals die niet in de publieke runtime-API thuishoren (klantsites gebruiken ze nooit;\n// alleen de XiCMS.nl-showcase). DemoStudio wordt intern door XiCMSProvider gerenderd.\n\n// Firebase (client)\nexport {\n getFirebaseApp,\n getFirebaseAuth,\n getDb,\n getBucket,\n isFirebaseConfigured,\n} from \"./firebase/client\";\nexport { initAppCheck } from \"./firebase/appcheck\";\nexport { SiteChrome } from \"./SiteChrome\";\nexport { CORE_VERSION, CORE_PACKAGE, isNieuwer } from \"./version\";\n"],"mappings":"AAQA,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAO9B,SAAS,aAAa,gBAAgB;AAItC,SAAS,cAAc,wBAAwB;AAI/C,SAAS,KAAK,eAAe,mBAAmB,+BAA+B;AAE/E,cAAc;AACd;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAE3B,SAAS,eAAe;AAExB,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB,iBAAiB;AAC1C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP,SAAS,2BAA6C;AACtD,SAAS,wBAAwB;AAGjC,SAAS,aAAa,cAAc,aAAa,gBAAgB,gBAAgB,qBAAqB;AAEtG,SAAS,oBAAoB;AAE7B,SAAS,yBAAyB;AAElC,SAAS,+BAA+B;AACxC,SAAS,mBAAmB,gBAAgB;AAE5C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,cAAc,gBAAgB,SAAS,qBAAqB;AAGrE,SAAS,gBAAgB,qBAA4D;AACrF,SAAS,aAAa,SAAS,WAAW,aAAa,oBAAoB,qBAAqB,wBAAwB,oBAAoB;AAK5I,SAAS,cAAc,eAAe;AACtC,SAAS,iBAAiB;AAC1B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAOP,SAAS,eAAe;AACxB,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;AAChC,SAAS,UAAU,0BAA0B;AAC7C,SAAS,UAAU,iBAAiB,eAAe;AAGnD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAMK;AACP,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB,aAAa,mBAAmB,oBAAoB;AAC/E,SAAS,eAAe,oBAAoB;AAC5C,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAG9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAWK;AAGP,SAAS,gBAAgB;AAOzB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AAC3B,SAAS,cAAc,cAAc,iBAAiB;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Publieke runtime-API van @xiwebdesign/xicms-core (lichte client/runtime laag).\n * - Admin (TipTap/Radix) zit in \"@xiwebdesign/xicms-core/admin\".\n * - Server-only code (firebase-admin, sanitize, SEO) zit in \"@xiwebdesign/xicms-core/server\".\n * - Pure schema's in \"@xiwebdesign/xicms-core/schema\".\n */\n\n// Provider & config\nexport { XiCMSProvider } from \"./XiCMSProvider\";\nexport { useSiteConfig } from \"./config\";\n\n// Theming & design-primitieven (maatwerk zonder core te forken).\n// - `defineTheme` maakt een eigen Astryx-thema (tokens + component-overrides) → geef door als\n// XiCMSProvider `astryxTheme`-prop.\n// - De `ui`-primitieven (Card/Stack/Grid/Heading/Text/Btn…) zijn de bouwstenen waarop de ingebouwde\n// blokken draaien; gebruik ze in eigen blokken voor een consistent maar te herstijlen uiterlijk.\nexport { defineTheme, useTheme } from \"@astryxdesign/core/theme\";\nexport type { DefinedTheme } from \"@astryxdesign/core/theme\";\n// Framework-router-integratie: geef `next/link` door als XiCMSProvider `linkComponent`-prop\n// (soepele client-nav + prefetch op alle Astryx-knoppen/links). `useLinkComponent` voor eigen blokken.\nexport { LinkProvider, useLinkComponent } from \"@astryxdesign/core/Link\";\nexport type { LinkComponentType } from \"@astryxdesign/core/Link\";\n// Beeldoptimalisatie: geef `next/image` door als XiCMSProvider `imageComponent`-prop. `Img` is de\n// wrapper die de blokken gebruiken; `useImageComponent` voor eigen blokken.\nexport { Img, ImageProvider, useImageComponent, InlineImageEditProvider } from \"./media/ImageContext\";\nexport type { ImageComponentType, ImgProps } from \"./media/ImageContext\";\nexport * from \"./blocks/ui\";\nexport {\n SiteSettingsProvider,\n useSiteSettings,\n useMergedSiteConfig,\n} from \"./settings/useSiteSettings\";\nexport { SiteFooter } from \"./components/site/SiteFooter\";\n// 7.24: de beheerde hoofdnavigatie — de enige plek die `settings.nav` leest. Zie SiteNav.tsx.\nexport { SiteNav } from \"./components/site/SiteNav\";\n// 8.13: kop met logo, menu, actieknop, hamburgermenu en mobiele belbalk. Zie SiteHeader.tsx.\nexport { SiteHeader } from \"./components/site/SiteHeader\";\n// 8.16: KvK- en btw-nummer uit het bedrijfsprofiel, voor eigen footers.\nexport { Bedrijfsnummers } from \"./components/site/Bedrijfsnummers\";\nexport { EditorProvider, useEditor } from \"./editor/EditorProvider\";\nexport {\n definePattern,\n instantiatePattern,\n collectPatternTypes,\n builtinPatterns,\n type Pattern,\n type PatternBlock,\n} from \"./patterns\";\nexport { builtinThemePresets, type ThemePreset } from \"./theme/presets\";\nexport { defineSiteConfig } from \"./schema/siteConfig\";\nexport type { SiteConfig, SiteMode } from \"./schema/siteConfig\";\n// 5.0: Field-IR (primo-port), symbolen en custom blocks.\nexport { FieldSchema, FieldsSchema, fieldsToZod, fieldsDefaults, isFieldVisible, isRichTextKey } from \"./schema/fields\";\nexport type { Field, FieldHints, ShowIf } from \"./schema/fields\";\nexport { SymbolSchema } from \"./schema/symbols\";\nexport type { SymbolDefinition, StoredSymbol } from \"./schema/symbols\";\nexport { CustomBlockSchema } from \"./schema/customBlocks\";\nexport type { CustomBlock, CustomBlock as CustomBlockData } from \"./schema/customBlocks\";\nexport { customBlockToDefinition } from \"./blocks/customTemplate/definition\";\nexport { interpretTemplate, scopeCss } from \"./blocks/customTemplate/interpret\";\n// 5.0: localisatie — overlay-model (primo's locale-per-waarde, additief vertaald).\nexport {\n siteLocales,\n parseLocaleSlugs,\n localizedPath,\n localizePage,\n localizeBlocks,\n pruneTranslations,\n TranslationsSchema,\n} from \"./i18n/overlay\";\nexport type { Translations, LocaleConfig } from \"./i18n/overlay\";\nexport type { ThemeTokens, NavItem, NavLeaf, Redirect, SiteSettings, PublicSiteSettings, FormsSender } from \"./schema/settings\";\nexport { zoekRedirect, normaliseerPad, navHref, isExterneLink } from \"./schema/settings\";\nexport type { Seo } from \"./schema/seo\";\n// 8.13: bedrijfsprofiel (adres, telefoon, openingstijden) + hulpjes voor eigen headers/footers.\nexport { BusinessSchema, BEDRIJFSTYPES, type Business, type BusinessException } from \"./schema/business\";\nexport { bedrijfsnummersTekst, bedrijfsnummerAdvies, adresRegels, telLink, routeLink, afwijkingOp, komendeAfwijkingen, afwijkingDatumTekst, isOpenNuMetAfwijkingen, heeftProfiel } from \"./bedrijf/bedrijf\";\nexport type { Page, PageStatus } from \"./schema/pages\";\nexport type { FormDefinition, FormField } from \"./schema/forms\";\n\n// Auth\nexport { AuthProvider, useAuth } from \"./auth/AuthProvider\";\nexport { LoginForm } from \"./auth/LoginForm\";\nexport {\n roleForSite,\n canEdit,\n canManageSite,\n isSuperadmin,\n type Role,\n type XiClaims,\n} from \"./auth/roles\";\n\n// De legacy inline-laag (ContentProvider/useContent + EditableText/EditableRichText/EditableImage,\n// het v1 platte `cms/content`-model) is in 5.0 VERWIJDERD, zoals bij de deprecatie aangekondigd.\n// Inline bewerken loopt via het block-model: markeer tekstvelden met `data-xicms-edit` in de Render.\nexport type { NewsArticle, MediaItem, MediaVariant } from \"./content/types\";\n\nexport { EditBar } from \"./components/EditBar\";\nexport { ExternEmbed } from \"./components/ExternEmbed\";\nexport { ResponsiveImage } from \"./components/ResponsiveImage\";\nexport { PageView, NietGevondenMelder } from \"./components/PageView\";\nexport { NewsList, NewsArticleView, useNews } from \"./components/News\";\n\n// Block-systeem (runtime: registry + renderer; editors zitten in /admin)\nexport {\n defineBlock,\n createRegistry,\n mergeRegistry,\n validateBlocks,\n buildBlockAddOptions,\n type BlockDefinition,\n type BlockRegistry,\n type BlockRenderProps,\n type BlockEditorProps,\n type BlockCategory,\n} from \"./blocks/registry\";\nexport { BlockRenderer } from \"./blocks/BlockRenderer\";\nexport { RegistryProvider, useRegistry, BlockDataProvider, useBlockData } from \"./blocks/context\";\nexport { builtinBlocks, ConsentEmbed } from \"./blocks/builtins\";\nexport { PageRenderer } from \"./render/PageRenderer\";\nexport { PublishedPage } from \"./render/PublishedPage\";\n\n// Module-systeem (XiCMS 3.0): modules bundelen blocks + instellingen; per site aan/uit + te stylen.\nexport {\n defineModule,\n resolveModules,\n isModuleActive,\n ModulesProvider,\n useModules,\n useModuleActive,\n useModuleSettings,\n applyBlockOverrides,\n moduleIdForBlockType,\n builtinModules,\n validateModuleContract,\n assertModuleContract,\n useConsent,\n ConsentBanner,\n ConsentGate,\n ConsentReopenLink,\n type ConsentState,\n type ConsentSettings,\n type ConsentCategory,\n type ModuleDefinition,\n type ModuleSiteSetting,\n type ModulesSiteConfig,\n type Capability,\n type ResolvedModules,\n type BlockOverride,\n type BlockOverrides,\n} from \"./modules\";\n\n// Demo-lock\nexport { DemoLock } from \"./lock/DemoLock\";\n\n// Demo-bewerkmodus (lokaal-only) leeft op het subpad `@xiwebdesign/xicms-core/demo` — dit zijn\n// demo-store-internals die niet in de publieke runtime-API thuishoren (klantsites gebruiken ze nooit;\n// alleen de XiCMS.nl-showcase). DemoStudio wordt intern door XiCMSProvider gerenderd.\n\n// Firebase (client)\nexport {\n getFirebaseApp,\n getFirebaseAuth,\n getDb,\n getBucket,\n isFirebaseConfigured,\n} from \"./firebase/client\";\nexport { initAppCheck } from \"./firebase/appcheck\";\nexport { SiteChrome } from \"./SiteChrome\";\nexport { CORE_VERSION, CORE_PACKAGE, isNieuwer } from \"./version\";\n"],"mappings":"AAQA,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAO9B,SAAS,aAAa,gBAAgB;AAItC,SAAS,cAAc,wBAAwB;AAI/C,SAAS,KAAK,eAAe,mBAAmB,+BAA+B;AAE/E,cAAc;AACd;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAE3B,SAAS,eAAe;AAExB,SAAS,kBAAkB;AAE3B,SAAS,uBAAuB;AAChC,SAAS,gBAAgB,iBAAiB;AAC1C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP,SAAS,2BAA6C;AACtD,SAAS,wBAAwB;AAGjC,SAAS,aAAa,cAAc,aAAa,gBAAgB,gBAAgB,qBAAqB;AAEtG,SAAS,oBAAoB;AAE7B,SAAS,yBAAyB;AAElC,SAAS,+BAA+B;AACxC,SAAS,mBAAmB,gBAAgB;AAE5C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,SAAS,cAAc,gBAAgB,SAAS,qBAAqB;AAGrE,SAAS,gBAAgB,qBAA4D;AACrF,SAAS,sBAAsB,sBAAsB,aAAa,SAAS,WAAW,aAAa,oBAAoB,qBAAqB,wBAAwB,oBAAoB;AAKxL,SAAS,cAAc,eAAe;AACtC,SAAS,iBAAiB;AAC1B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAOP,SAAS,eAAe;AACxB,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;AAChC,SAAS,UAAU,0BAA0B;AAC7C,SAAS,UAAU,iBAAiB,eAAe;AAGnD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAMK;AACP,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB,aAAa,mBAAmB,oBAAoB;AAC/E,SAAS,eAAe,oBAAoB;AAC5C,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAG9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAWK;AAGP,SAAS,gBAAgB;AAOzB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AAC3B,SAAS,cAAc,cAAc,iBAAiB;","names":[]}
@@ -1,5 +1,6 @@
1
1
  import * as z from "zod/mini";
2
2
  import { defineModule } from "./defineModule.js";
3
+ import { DEFAULT_CATEGORIES, DEFAULT_MESSAGE } from "./consent/standaard.js";
3
4
  import { heroBlock } from "../blocks/builtins/Hero.js";
4
5
  import { richTextBlock } from "../blocks/builtins/RichTextBlock.js";
5
6
  import { imageBlock } from "../blocks/builtins/ImageBlock.js";
@@ -371,20 +372,19 @@ const consentModule = defineModule({
371
372
  description: "Toestemmingsbanner + consent-opslag; stelt niet-essenti\xEBle scripts uit.",
372
373
  defaultEnabled: false,
373
374
  settingsSchema: z.object({
374
- message: z._default(z.string(), "We gebruiken cookies om de site te verbeteren. Kies hieronder je voorkeuren.").register(z.globalRegistry, { description: "Bannertekst" }),
375
+ message: z._default(z.string(), DEFAULT_MESSAGE).register(z.globalRegistry, { description: "Bannertekst" }),
375
376
  privacyUrl: z.optional(z.string()).register(z.globalRegistry, { description: "Link naar privacyverklaring" }),
376
377
  version: z.optional(z.string()).register(z.globalRegistry, { description: "Beleidsversie (wijzig \u2192 banner opnieuw tonen)" }),
377
378
  showReopen: z._default(z.boolean(), true).register(z.globalRegistry, { description: "Zwevend cookie-knopje om keuze te wijzigen" }),
379
+ toon: z._default(z.enum(["automatisch", "altijd"]), "automatisch").register(z.globalRegistry, {
380
+ description: "Wanneer de banner verschijnt: automatisch = alleen op pagina's met een video, kaart of andere externe inhoud"
381
+ }),
378
382
  categories: z._default(z.array(z.object({
379
383
  id: z.string(),
380
384
  label: z.string(),
381
385
  description: z.optional(z.string()),
382
386
  required: z._default(z.boolean(), false)
383
- })), [
384
- { id: "necessary", label: "Noodzakelijk", description: "Nodig om de site te laten werken.", required: true },
385
- { id: "analytics", label: "Statistieken", description: "Anonieme statistieken om de site te verbeteren.", required: false },
386
- { id: "marketing", label: "Marketing", description: "Externe embeds zoals video's en kaarten.", required: false }
387
- ])
387
+ })), DEFAULT_CATEGORIES.map((c) => ({ ...c, required: Boolean(c.required) })))
388
388
  }),
389
389
  defaultSettings: {}
390
390
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/modules/builtins.ts"],"sourcesContent":["/**\n * Ingebouwde modules (XiCMS 3.0). Elke \"feature\" van 2.x is hier een first-class module geworden,\n * zodat hij per site aan/uit kan en los te verbeteren is. De bijbehorende admin-panelen staan in\n * `@xiwebdesign/xicms-core/admin` (paneel-registry), gekoppeld via dezelfde `id`/`featureKey`.\n *\n * Backward compatible: zonder `SiteConfig.modules`/`features` zijn alle modules actief — identiek\n * aan 2.x. De `content`-module is `core: true` en kan niet uitgezet worden (de basis-bouwstenen).\n */\nimport * as z from \"zod/mini\";\nimport { defineModule } from \"./defineModule\";\nimport type { ModuleDefinition } from \"./types\";\n\nimport { heroBlock } from \"../blocks/builtins/Hero\";\nimport { richTextBlock } from \"../blocks/builtins/RichTextBlock\";\nimport { imageBlock } from \"../blocks/builtins/ImageBlock\";\nimport { ctaBlock } from \"../blocks/builtins/Cta\";\nimport { columnsBlock } from \"../blocks/builtins/Columns\";\nimport { spacerBlock } from \"../blocks/builtins/Spacer\";\nimport { galleryBlock } from \"../blocks/builtins/Gallery\";\nimport { faqBlock } from \"../blocks/builtins/Faq\";\nimport { openingHoursBlock } from \"../blocks/builtins/OpeningHours\";\nimport { pricingBlock } from \"../blocks/builtins/Pricing\";\nimport { priceListBlock } from \"../blocks/builtins/PriceList\";\nimport { sectionHeadingBlock } from \"../blocks/builtins/SectionHeading\";\nimport { availabilityBlock } from \"../blocks/builtins/Availability\";\nimport { newsListBlock } from \"../blocks/builtins/NewsListBlock\";\nimport { formBlock } from \"../blocks/builtins/FormBlock\";\nimport { testimonialsBlock } from \"../blocks/builtins/Testimonials\";\nimport { teamBlock } from \"../blocks/builtins/Team\";\nimport { agendaBlock } from \"../blocks/builtins/Agenda\";\nimport { searchBlock } from \"../blocks/builtins/Search\";\nimport { featureBlock, countersBlock, logosBlock, timelineBlock } from \"../blocks/builtins/Sections\";\nimport { symbolRefBlock } from \"../blocks/builtins/SymbolRef\";\nimport { videoBlock } from \"../blocks/builtins/Video\";\nimport { bannerBlock } from \"../blocks/builtins/Banner\";\nimport { contactBlock, socialBlock } from \"../blocks/builtins/Contact\";\nimport { mapBlock } from \"../blocks/builtins/MapBlock\";\nimport { newsletterBlock } from \"../blocks/builtins/Newsletter\";\nimport { bookingBlock } from \"../blocks/builtins/Booking\";\nimport { buttonsBlock, quoteBlock, dividerBlock } from \"../blocks/builtins/Elements\";\nimport { accordionBlock } from \"../blocks/builtins/Accordion\";\nimport { embedBlock } from \"../blocks/builtins/Embed\";\nimport { withSidebarBlock, tabsBlock } from \"../blocks/builtins/Layout\";\nimport { cardsBlock } from \"../blocks/builtins/Cards\";\nimport { downloadsBlock } from \"../blocks/builtins/Downloads\";\nimport { pdfBlock } from \"../blocks/builtins/PdfBlock\";\nimport { countdownBlock } from \"../blocks/builtins/Countdown\";\nimport { sliderBlock } from \"../blocks/builtins/Slider\";\nimport { whatsappChatBlock } from \"../blocks/builtins/WhatsappChat\";\nimport { beforeAfterBlock } from \"../blocks/builtins/BeforeAfter\";\nimport { portfolioBlock } from \"../blocks/builtins/Portfolio\";\nimport { jobsBlock } from \"../blocks/builtins/Jobs\";\nimport { breadcrumbsBlock } from \"../blocks/builtins/Breadcrumbs\";\nimport {\n newsWidget,\n agendaWidget,\n openingHoursWidget,\n contactWidget,\n socialWidget as socialWidgetBlock,\n newsletterWidget,\n ctaWidget,\n galleryWidget,\n testimonialsWidget,\n cardsWidget,\n downloadsWidget,\n countdownWidget,\n} from \"../blocks/builtins/Widgets\";\n\nconst CORE_VERSION = \"5.0.0\";\n\n/**\n * Basis-bouwstenen — altijd aanwezig (niet uit te zetten). Bevat ook de indelingsblokken\n * (kolommen, \"Met zijbalk\") waarmee je widgets naast je hoofdinhoud plaatst, plus de\n * compacte CTA-widget.\n */\nexport const contentModule = defineModule({\n id: \"content\",\n version: CORE_VERSION,\n label: \"Basisinhoud\",\n description: \"Kern-bouwstenen: hero, tekst, afbeelding, CTA, kolommen, zijbalk, witruimte.\",\n core: true,\n blocks: [heroBlock, sectionHeadingBlock, richTextBlock, imageBlock, ctaBlock, columnsBlock, withSidebarBlock, spacerBlock, buttonsBlock, quoteBlock, dividerBlock, ctaWidget, symbolRefBlock],\n});\n\nexport const galleryModule = defineModule({\n id: \"gallery\",\n version: CORE_VERSION,\n label: \"Fotogalerij\",\n description: \"Galerij-block met grid en (optioneel) lightbox + compacte fotostrip-widget.\",\n blocks: [galleryBlock, galleryWidget],\n // Per-site instelbaar door de agent/klant (modules.gallery.config) zonder core te forken.\n // `.describe()` = het label dat de klant in /beheer ziet.\n settingsSchema: z.object({\n columns: z._default(z.int().check(z.minimum(1)).check(z.maximum(6)), 3).register(z.globalRegistry, { description: \"Kolommen\" }),\n lightbox: z._default(z.boolean(), true).register(z.globalRegistry, { description: \"Lightbox bij klikken\" }),\n }),\n defaultSettings: { columns: 3, lightbox: true },\n});\n\nexport const faqModule = defineModule({\n id: \"faq\",\n version: CORE_VERSION,\n label: \"FAQ\",\n description: \"Veelgestelde vragen (accordeon) met optionele zoek + FAQ-JSON-LD.\",\n blocks: [faqBlock],\n});\n\nexport const openingHoursModule = defineModule({\n id: \"openingHours\",\n version: CORE_VERSION,\n label: \"Openingstijden\",\n description: \"Openingstijden-tabel + compacte widget met 'vandaag' gemarkeerd.\",\n blocks: [openingHoursBlock, openingHoursWidget],\n});\n\nexport const pricingModule = defineModule({\n id: \"pricing\",\n version: CORE_VERSION,\n label: \"Prijzen\",\n blocks: [pricingBlock, priceListBlock],\n});\n\nexport const pagesModule = defineModule({\n id: \"pages\",\n version: CORE_VERSION,\n label: \"Pagina's\",\n featureKey: \"pages\",\n description: \"Paginabouwer (draft → publish + versiegeschiedenis).\",\n});\n\nexport const newsModule = defineModule({\n id: \"news\",\n version: CORE_VERSION,\n label: \"Nieuws\",\n featureKey: \"news\",\n description: \"Nieuwsartikelen + nieuwslijst-block + 'laatste nieuws'-widget voor de zijbalk.\",\n blocks: [newsListBlock, newsWidget],\n});\n\nexport const mediaModule = defineModule({\n id: \"media\",\n version: CORE_VERSION,\n label: \"Media\",\n featureKey: \"media\",\n description: \"Mediabeheer met compressie + webp/srcset-varianten.\",\n requires: [{ kind: \"function\", name: \"onMediaUpload\" }, { kind: \"storage\", prefix: \"sites/\" }],\n});\n\nexport const formsModule = defineModule({\n id: \"forms\",\n version: CORE_VERSION,\n label: \"Formulieren\",\n featureKey: \"forms\",\n description: \"Formulierbouwer + inzendingen + e-mailnotificatie.\",\n blocks: [formBlock],\n requires: [\n { kind: \"function\", name: \"submitForm\" },\n { kind: \"firestore\", collection: \"forms\" },\n ],\n});\n\nexport const statsModule = defineModule({\n id: \"stats\",\n version: CORE_VERSION,\n label: \"Statistieken\",\n featureKey: \"stats\",\n description: \"Privacy-vriendelijke bezoekersstatistieken (geen cookies).\",\n requires: [{ kind: \"function\", name: \"trackView\" }],\n});\n\nexport const settingsModule = defineModule({\n id: \"settings\",\n version: CORE_VERSION,\n label: \"Instellingen\",\n core: true,\n description: \"Site-instellingen (nav, thema, SEO, formulier-afzender) — alleen siteadmin.\",\n});\n\n// Opt-in modules (defaultEnabled: false): worden bij installatie of later aangezet via\n// `modules: { <id>: true }`. Geen extra backend nodig — data leeft in de page-blocks.\nexport const testimonialsModule = defineModule({\n id: \"testimonials\",\n version: CORE_VERSION,\n label: \"Reviews\",\n description: \"Klantquotes/reviews met sterren, optionele Review-JSON-LD + compacte review-widget.\",\n defaultEnabled: false,\n blocks: [testimonialsBlock, testimonialsWidget],\n});\n\nexport const teamModule = defineModule({\n id: \"team\",\n version: CORE_VERSION,\n label: \"Team\",\n description: \"Team-/medewerkersoverzicht met foto, functie en bio.\",\n defaultEnabled: false,\n blocks: [teamBlock],\n});\n\nexport const agendaModule = defineModule({\n id: \"agenda\",\n version: CORE_VERSION,\n label: \"Agenda\",\n description: \"Evenementen/agenda (chronologisch) met Event-JSON-LD + 'komende agenda'-widget.\",\n defaultEnabled: false,\n blocks: [agendaBlock, agendaWidget],\n});\n\nexport const searchModule = defineModule({\n id: \"search\",\n version: CORE_VERSION,\n label: \"Zoeken\",\n description: \"Site-zoekblok dat gepubliceerde pagina's (en nieuws) client-side doorzoekt.\",\n defaultEnabled: false,\n blocks: [searchBlock],\n});\n\nexport const featureModule = defineModule({\n id: \"feature\",\n version: CORE_VERSION,\n label: \"Beeld + tekst\",\n description: \"Feature-sectie met afbeelding links/rechts en tekst.\",\n defaultEnabled: false,\n blocks: [featureBlock],\n});\n\nexport const countersModule = defineModule({\n id: \"counters\",\n version: CORE_VERSION,\n label: \"Tellers\",\n description: \"Statistiek-tellers (bv. “100+ klanten”).\",\n defaultEnabled: false,\n blocks: [countersBlock],\n});\n\nexport const logosModule = defineModule({\n id: \"logos\",\n version: CORE_VERSION,\n label: \"Logo's\",\n description: \"Partner-/klantlogo-strip.\",\n defaultEnabled: false,\n blocks: [logosBlock],\n});\n\nexport const timelineModule = defineModule({\n id: \"timeline\",\n version: CORE_VERSION,\n label: \"Tijdlijn\",\n description: \"Stappen/proces als tijdlijn.\",\n defaultEnabled: false,\n blocks: [timelineBlock],\n});\n\nexport const videoModule = defineModule({\n id: \"video\",\n version: CORE_VERSION,\n label: \"Video\",\n description: \"YouTube/Vimeo/MP4-embed (consent-gated).\",\n defaultEnabled: false,\n blocks: [videoBlock],\n});\n\nexport const bannerModule = defineModule({\n id: \"banner\",\n version: CORE_VERSION,\n label: \"Aankondiging\",\n description: \"Aankondigingsbalk, optioneel sluitbaar.\",\n defaultEnabled: false,\n blocks: [bannerBlock],\n});\n\nexport const contactModule = defineModule({\n id: \"contact\",\n version: CORE_VERSION,\n label: \"Contact + kaart + social\",\n description: \"Contactgegevens (JSON-LD), kaart (consent-gated), social-links + compacte widgets.\",\n defaultEnabled: false,\n blocks: [contactBlock, mapBlock, socialBlock, contactWidget, socialWidgetBlock],\n});\n\nexport const newsletterModule = defineModule({\n id: \"newsletter\",\n version: CORE_VERSION,\n label: \"Nieuwsbrief\",\n description: \"Aanmeldformulier via een externe provider-URL + compacte nieuwsbrief-widget.\",\n defaultEnabled: false,\n blocks: [newsletterBlock, newsletterWidget],\n});\n\nexport const verhuurModule = defineModule({\n id: \"verhuur\",\n version: CORE_VERSION,\n label: \"Verhuur & beschikbaarheid\",\n description: \"Beschikbaarheidskalender uit de iCal-link van je boekingssysteem, met aanvragen voor een gekozen periode.\",\n defaultEnabled: false,\n blocks: [availabilityBlock],\n});\n\nexport const bookingModule = defineModule({\n id: \"booking\",\n version: CORE_VERSION,\n label: \"Afspraak maken\",\n description: \"Boekings-embed (bv. Calendly), consent-gated.\",\n defaultEnabled: false,\n blocks: [bookingBlock],\n});\n\nexport const accordionModule = defineModule({\n id: \"accordion\",\n version: CORE_VERSION,\n label: \"Accordeon\",\n description: \"Generieke in-/uitklapbare panelen.\",\n defaultEnabled: false,\n blocks: [accordionBlock],\n});\n\nexport const embedModule = defineModule({\n id: \"embed\",\n version: CORE_VERSION,\n label: \"Embed\",\n description: \"Generieke responsive iframe-embed (consent-gated).\",\n defaultEnabled: false,\n blocks: [embedBlock],\n});\n\n/* ── Nieuwe modules (3.1) — veelgebruikt op websites, volwaardig + widget waar zinvol ── */\n\nexport const cardsModule = defineModule({\n id: \"cards\",\n version: CORE_VERSION,\n label: \"Diensten / kaarten\",\n description: \"Diensten-/featurekaarten in een grid (icoon of beeld) + compacte 'uitgelicht'-widget.\",\n defaultEnabled: false,\n blocks: [cardsBlock, cardsWidget],\n});\n\nexport const tabsModule = defineModule({\n id: \"tabs\",\n version: CORE_VERSION,\n label: \"Tabbladen\",\n description: \"Tabblad-indeling: per tab een eigen set blokken (bv. beschrijving / specificaties).\",\n defaultEnabled: false,\n blocks: [tabsBlock],\n});\n\nexport const downloadsModule = defineModule({\n id: \"downloads\",\n version: CORE_VERSION,\n label: \"Downloads\",\n description: \"Lijst met downloadbare documenten (brochures, prijslijsten) + compacte widget.\",\n defaultEnabled: false,\n blocks: [downloadsBlock, downloadsWidget],\n});\n\nexport const pdfModule = defineModule({\n id: \"pdf\",\n version: CORE_VERSION,\n label: \"PDF-lezer\",\n description: \"Inline PDF-lezer voor menukaarten/documenten; meerdere PDF's met tabs, zelf te vervangen.\",\n defaultEnabled: false,\n blocks: [pdfBlock],\n});\n\nexport const countdownModule = defineModule({\n id: \"countdown\",\n version: CORE_VERSION,\n label: \"Aftelteller\",\n description: \"Tikkende countdown naar een datum (lancering, evenement, aanbieding) + widget.\",\n defaultEnabled: false,\n blocks: [countdownBlock, countdownWidget],\n});\n\nexport const sliderModule = defineModule({\n id: \"slider\",\n version: CORE_VERSION,\n label: \"Carrousel / slider\",\n description: \"Beeld-/contentcarrousel met dots, pijlen en optioneel autoplay (reduced-motion-veilig).\",\n defaultEnabled: false,\n blocks: [sliderBlock],\n});\n\n/* ── 4.16: nieuwe modules (allemaal opt-in) ──────────────────────────────── */\n\nexport const whatsappModule = defineModule({\n id: \"whatsapp\",\n version: CORE_VERSION,\n label: \"WhatsApp-knop\",\n description: \"Zwevende WhatsApp-/chatknop — laagdrempelig contact (wa.me-link, geen consent nodig).\",\n defaultEnabled: false,\n blocks: [whatsappChatBlock],\n});\n\nexport const beforeAfterModule = defineModule({\n id: \"beforeAfter\",\n version: CORE_VERSION,\n label: \"Voor / na\",\n description: \"Voor/na-vergelijker met sleepbare scheiding — sterk voor hoveniers, schilders, salons.\",\n defaultEnabled: false,\n blocks: [beforeAfterBlock],\n});\n\nexport const portfolioModule = defineModule({\n id: \"portfolio\",\n version: CORE_VERSION,\n label: \"Portfolio / projecten\",\n description: \"Projecten/cases-grid met categorie-filter en lightbox.\",\n defaultEnabled: false,\n blocks: [portfolioBlock],\n});\n\nexport const jobsModule = defineModule({\n id: \"jobs\",\n version: CORE_VERSION,\n label: \"Vacatures\",\n description: \"Vacature-overzicht met JobPosting-JSON-LD (vindbaar via Google Jobs).\",\n defaultEnabled: false,\n blocks: [jobsBlock],\n});\n\nexport const breadcrumbsModule = defineModule({\n id: \"breadcrumbs\",\n version: CORE_VERSION,\n label: \"Kruimelpad\",\n description: \"Kruimelpad afgeleid van de URL, met BreadcrumbList-JSON-LD (SEO).\",\n defaultEnabled: false,\n blocks: [breadcrumbsBlock],\n});\n\n/* ── 5.5: webwinkel + donaties ───────────────────────────────────────────────\n * 6.0: de shop-module zit NIET meer in de default-bundel. Hij is opt-in via de\n * subpath `@xiwebdesign/xicms-core/modules/shop` (+ `/admin/shop`, `/server/shop`),\n * of via de backward-compat-barrel `@xiwebdesign/xicms-core/all`. Zo landt shop-code\n * alleen in de build van sites die 'm daadwerkelijk aanzetten. */\n\nexport const consentModule = defineModule({\n id: \"consent\",\n version: CORE_VERSION,\n label: \"Cookie-consent (AVG)\",\n description: \"Toestemmingsbanner + consent-opslag; stelt niet-essentiële scripts uit.\",\n defaultEnabled: false,\n settingsSchema: z.object({\n message: z._default(z.string(), \"We gebruiken cookies om de site te verbeteren. Kies hieronder je voorkeuren.\").register(z.globalRegistry, { description: \"Bannertekst\" }),\n privacyUrl: z.optional(z.string()).register(z.globalRegistry, { description: \"Link naar privacyverklaring\" }),\n version: z.optional(z.string()).register(z.globalRegistry, { description: \"Beleidsversie (wijzig → banner opnieuw tonen)\" }),\n showReopen: z._default(z.boolean(), true).register(z.globalRegistry, { description: \"Zwevend cookie-knopje om keuze te wijzigen\" }),\n categories: z._default(z.array(z.object({\n id: z.string(),\n label: z.string(),\n description: z.optional(z.string()),\n required: z._default(z.boolean(), false),\n })), [\n { id: \"necessary\", label: \"Noodzakelijk\", description: \"Nodig om de site te laten werken.\", required: true },\n { id: \"analytics\", label: \"Statistieken\", description: \"Anonieme statistieken om de site te verbeteren.\", required: false },\n { id: \"marketing\", label: \"Marketing\", description: \"Externe embeds zoals video's en kaarten.\", required: false },\n ]),\n }),\n defaultSettings: {},\n});\n\n/** Alle ingebouwde modules (volgorde bepaalt block- en tab-volgorde). */\nexport const builtinModules: ModuleDefinition[] = [\n contentModule,\n pagesModule,\n newsModule,\n mediaModule,\n galleryModule,\n faqModule,\n openingHoursModule,\n pricingModule,\n formsModule,\n statsModule,\n settingsModule,\n testimonialsModule,\n teamModule,\n agendaModule,\n searchModule,\n featureModule,\n countersModule,\n logosModule,\n timelineModule,\n videoModule,\n bannerModule,\n contactModule,\n newsletterModule,\n bookingModule,\n verhuurModule,\n accordionModule,\n embedModule,\n cardsModule,\n tabsModule,\n downloadsModule,\n pdfModule,\n countdownModule,\n sliderModule,\n whatsappModule,\n beforeAfterModule,\n portfolioModule,\n jobsModule,\n breadcrumbsModule,\n consentModule,\n];\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/modules/builtins.ts"],"sourcesContent":["/**\n * Ingebouwde modules (XiCMS 3.0). Elke \"feature\" van 2.x is hier een first-class module geworden,\n * zodat hij per site aan/uit kan en los te verbeteren is. De bijbehorende admin-panelen staan in\n * `@xiwebdesign/xicms-core/admin` (paneel-registry), gekoppeld via dezelfde `id`/`featureKey`.\n *\n * Backward compatible: zonder `SiteConfig.modules`/`features` zijn alle modules actief — identiek\n * aan 2.x. De `content`-module is `core: true` en kan niet uitgezet worden (de basis-bouwstenen).\n */\nimport * as z from \"zod/mini\";\nimport { defineModule } from \"./defineModule\";\nimport { DEFAULT_CATEGORIES, DEFAULT_MESSAGE } from \"./consent/standaard\";\nimport type { ModuleDefinition } from \"./types\";\n\nimport { heroBlock } from \"../blocks/builtins/Hero\";\nimport { richTextBlock } from \"../blocks/builtins/RichTextBlock\";\nimport { imageBlock } from \"../blocks/builtins/ImageBlock\";\nimport { ctaBlock } from \"../blocks/builtins/Cta\";\nimport { columnsBlock } from \"../blocks/builtins/Columns\";\nimport { spacerBlock } from \"../blocks/builtins/Spacer\";\nimport { galleryBlock } from \"../blocks/builtins/Gallery\";\nimport { faqBlock } from \"../blocks/builtins/Faq\";\nimport { openingHoursBlock } from \"../blocks/builtins/OpeningHours\";\nimport { pricingBlock } from \"../blocks/builtins/Pricing\";\nimport { priceListBlock } from \"../blocks/builtins/PriceList\";\nimport { sectionHeadingBlock } from \"../blocks/builtins/SectionHeading\";\nimport { availabilityBlock } from \"../blocks/builtins/Availability\";\nimport { newsListBlock } from \"../blocks/builtins/NewsListBlock\";\nimport { formBlock } from \"../blocks/builtins/FormBlock\";\nimport { testimonialsBlock } from \"../blocks/builtins/Testimonials\";\nimport { teamBlock } from \"../blocks/builtins/Team\";\nimport { agendaBlock } from \"../blocks/builtins/Agenda\";\nimport { searchBlock } from \"../blocks/builtins/Search\";\nimport { featureBlock, countersBlock, logosBlock, timelineBlock } from \"../blocks/builtins/Sections\";\nimport { symbolRefBlock } from \"../blocks/builtins/SymbolRef\";\nimport { videoBlock } from \"../blocks/builtins/Video\";\nimport { bannerBlock } from \"../blocks/builtins/Banner\";\nimport { contactBlock, socialBlock } from \"../blocks/builtins/Contact\";\nimport { mapBlock } from \"../blocks/builtins/MapBlock\";\nimport { newsletterBlock } from \"../blocks/builtins/Newsletter\";\nimport { bookingBlock } from \"../blocks/builtins/Booking\";\nimport { buttonsBlock, quoteBlock, dividerBlock } from \"../blocks/builtins/Elements\";\nimport { accordionBlock } from \"../blocks/builtins/Accordion\";\nimport { embedBlock } from \"../blocks/builtins/Embed\";\nimport { withSidebarBlock, tabsBlock } from \"../blocks/builtins/Layout\";\nimport { cardsBlock } from \"../blocks/builtins/Cards\";\nimport { downloadsBlock } from \"../blocks/builtins/Downloads\";\nimport { pdfBlock } from \"../blocks/builtins/PdfBlock\";\nimport { countdownBlock } from \"../blocks/builtins/Countdown\";\nimport { sliderBlock } from \"../blocks/builtins/Slider\";\nimport { whatsappChatBlock } from \"../blocks/builtins/WhatsappChat\";\nimport { beforeAfterBlock } from \"../blocks/builtins/BeforeAfter\";\nimport { portfolioBlock } from \"../blocks/builtins/Portfolio\";\nimport { jobsBlock } from \"../blocks/builtins/Jobs\";\nimport { breadcrumbsBlock } from \"../blocks/builtins/Breadcrumbs\";\nimport {\n newsWidget,\n agendaWidget,\n openingHoursWidget,\n contactWidget,\n socialWidget as socialWidgetBlock,\n newsletterWidget,\n ctaWidget,\n galleryWidget,\n testimonialsWidget,\n cardsWidget,\n downloadsWidget,\n countdownWidget,\n} from \"../blocks/builtins/Widgets\";\n\nconst CORE_VERSION = \"5.0.0\";\n\n/**\n * Basis-bouwstenen — altijd aanwezig (niet uit te zetten). Bevat ook de indelingsblokken\n * (kolommen, \"Met zijbalk\") waarmee je widgets naast je hoofdinhoud plaatst, plus de\n * compacte CTA-widget.\n */\nexport const contentModule = defineModule({\n id: \"content\",\n version: CORE_VERSION,\n label: \"Basisinhoud\",\n description: \"Kern-bouwstenen: hero, tekst, afbeelding, CTA, kolommen, zijbalk, witruimte.\",\n core: true,\n blocks: [heroBlock, sectionHeadingBlock, richTextBlock, imageBlock, ctaBlock, columnsBlock, withSidebarBlock, spacerBlock, buttonsBlock, quoteBlock, dividerBlock, ctaWidget, symbolRefBlock],\n});\n\nexport const galleryModule = defineModule({\n id: \"gallery\",\n version: CORE_VERSION,\n label: \"Fotogalerij\",\n description: \"Galerij-block met grid en (optioneel) lightbox + compacte fotostrip-widget.\",\n blocks: [galleryBlock, galleryWidget],\n // Per-site instelbaar door de agent/klant (modules.gallery.config) zonder core te forken.\n // `.describe()` = het label dat de klant in /beheer ziet.\n settingsSchema: z.object({\n columns: z._default(z.int().check(z.minimum(1)).check(z.maximum(6)), 3).register(z.globalRegistry, { description: \"Kolommen\" }),\n lightbox: z._default(z.boolean(), true).register(z.globalRegistry, { description: \"Lightbox bij klikken\" }),\n }),\n defaultSettings: { columns: 3, lightbox: true },\n});\n\nexport const faqModule = defineModule({\n id: \"faq\",\n version: CORE_VERSION,\n label: \"FAQ\",\n description: \"Veelgestelde vragen (accordeon) met optionele zoek + FAQ-JSON-LD.\",\n blocks: [faqBlock],\n});\n\nexport const openingHoursModule = defineModule({\n id: \"openingHours\",\n version: CORE_VERSION,\n label: \"Openingstijden\",\n description: \"Openingstijden-tabel + compacte widget met 'vandaag' gemarkeerd.\",\n blocks: [openingHoursBlock, openingHoursWidget],\n});\n\nexport const pricingModule = defineModule({\n id: \"pricing\",\n version: CORE_VERSION,\n label: \"Prijzen\",\n blocks: [pricingBlock, priceListBlock],\n});\n\nexport const pagesModule = defineModule({\n id: \"pages\",\n version: CORE_VERSION,\n label: \"Pagina's\",\n featureKey: \"pages\",\n description: \"Paginabouwer (draft → publish + versiegeschiedenis).\",\n});\n\nexport const newsModule = defineModule({\n id: \"news\",\n version: CORE_VERSION,\n label: \"Nieuws\",\n featureKey: \"news\",\n description: \"Nieuwsartikelen + nieuwslijst-block + 'laatste nieuws'-widget voor de zijbalk.\",\n blocks: [newsListBlock, newsWidget],\n});\n\nexport const mediaModule = defineModule({\n id: \"media\",\n version: CORE_VERSION,\n label: \"Media\",\n featureKey: \"media\",\n description: \"Mediabeheer met compressie + webp/srcset-varianten.\",\n requires: [{ kind: \"function\", name: \"onMediaUpload\" }, { kind: \"storage\", prefix: \"sites/\" }],\n});\n\nexport const formsModule = defineModule({\n id: \"forms\",\n version: CORE_VERSION,\n label: \"Formulieren\",\n featureKey: \"forms\",\n description: \"Formulierbouwer + inzendingen + e-mailnotificatie.\",\n blocks: [formBlock],\n requires: [\n { kind: \"function\", name: \"submitForm\" },\n { kind: \"firestore\", collection: \"forms\" },\n ],\n});\n\nexport const statsModule = defineModule({\n id: \"stats\",\n version: CORE_VERSION,\n label: \"Statistieken\",\n featureKey: \"stats\",\n description: \"Privacy-vriendelijke bezoekersstatistieken (geen cookies).\",\n requires: [{ kind: \"function\", name: \"trackView\" }],\n});\n\nexport const settingsModule = defineModule({\n id: \"settings\",\n version: CORE_VERSION,\n label: \"Instellingen\",\n core: true,\n description: \"Site-instellingen (nav, thema, SEO, formulier-afzender) — alleen siteadmin.\",\n});\n\n// Opt-in modules (defaultEnabled: false): worden bij installatie of later aangezet via\n// `modules: { <id>: true }`. Geen extra backend nodig — data leeft in de page-blocks.\nexport const testimonialsModule = defineModule({\n id: \"testimonials\",\n version: CORE_VERSION,\n label: \"Reviews\",\n description: \"Klantquotes/reviews met sterren, optionele Review-JSON-LD + compacte review-widget.\",\n defaultEnabled: false,\n blocks: [testimonialsBlock, testimonialsWidget],\n});\n\nexport const teamModule = defineModule({\n id: \"team\",\n version: CORE_VERSION,\n label: \"Team\",\n description: \"Team-/medewerkersoverzicht met foto, functie en bio.\",\n defaultEnabled: false,\n blocks: [teamBlock],\n});\n\nexport const agendaModule = defineModule({\n id: \"agenda\",\n version: CORE_VERSION,\n label: \"Agenda\",\n description: \"Evenementen/agenda (chronologisch) met Event-JSON-LD + 'komende agenda'-widget.\",\n defaultEnabled: false,\n blocks: [agendaBlock, agendaWidget],\n});\n\nexport const searchModule = defineModule({\n id: \"search\",\n version: CORE_VERSION,\n label: \"Zoeken\",\n description: \"Site-zoekblok dat gepubliceerde pagina's (en nieuws) client-side doorzoekt.\",\n defaultEnabled: false,\n blocks: [searchBlock],\n});\n\nexport const featureModule = defineModule({\n id: \"feature\",\n version: CORE_VERSION,\n label: \"Beeld + tekst\",\n description: \"Feature-sectie met afbeelding links/rechts en tekst.\",\n defaultEnabled: false,\n blocks: [featureBlock],\n});\n\nexport const countersModule = defineModule({\n id: \"counters\",\n version: CORE_VERSION,\n label: \"Tellers\",\n description: \"Statistiek-tellers (bv. “100+ klanten”).\",\n defaultEnabled: false,\n blocks: [countersBlock],\n});\n\nexport const logosModule = defineModule({\n id: \"logos\",\n version: CORE_VERSION,\n label: \"Logo's\",\n description: \"Partner-/klantlogo-strip.\",\n defaultEnabled: false,\n blocks: [logosBlock],\n});\n\nexport const timelineModule = defineModule({\n id: \"timeline\",\n version: CORE_VERSION,\n label: \"Tijdlijn\",\n description: \"Stappen/proces als tijdlijn.\",\n defaultEnabled: false,\n blocks: [timelineBlock],\n});\n\nexport const videoModule = defineModule({\n id: \"video\",\n version: CORE_VERSION,\n label: \"Video\",\n description: \"YouTube/Vimeo/MP4-embed (consent-gated).\",\n defaultEnabled: false,\n blocks: [videoBlock],\n});\n\nexport const bannerModule = defineModule({\n id: \"banner\",\n version: CORE_VERSION,\n label: \"Aankondiging\",\n description: \"Aankondigingsbalk, optioneel sluitbaar.\",\n defaultEnabled: false,\n blocks: [bannerBlock],\n});\n\nexport const contactModule = defineModule({\n id: \"contact\",\n version: CORE_VERSION,\n label: \"Contact + kaart + social\",\n description: \"Contactgegevens (JSON-LD), kaart (consent-gated), social-links + compacte widgets.\",\n defaultEnabled: false,\n blocks: [contactBlock, mapBlock, socialBlock, contactWidget, socialWidgetBlock],\n});\n\nexport const newsletterModule = defineModule({\n id: \"newsletter\",\n version: CORE_VERSION,\n label: \"Nieuwsbrief\",\n description: \"Aanmeldformulier via een externe provider-URL + compacte nieuwsbrief-widget.\",\n defaultEnabled: false,\n blocks: [newsletterBlock, newsletterWidget],\n});\n\nexport const verhuurModule = defineModule({\n id: \"verhuur\",\n version: CORE_VERSION,\n label: \"Verhuur & beschikbaarheid\",\n description: \"Beschikbaarheidskalender uit de iCal-link van je boekingssysteem, met aanvragen voor een gekozen periode.\",\n defaultEnabled: false,\n blocks: [availabilityBlock],\n});\n\nexport const bookingModule = defineModule({\n id: \"booking\",\n version: CORE_VERSION,\n label: \"Afspraak maken\",\n description: \"Boekings-embed (bv. Calendly), consent-gated.\",\n defaultEnabled: false,\n blocks: [bookingBlock],\n});\n\nexport const accordionModule = defineModule({\n id: \"accordion\",\n version: CORE_VERSION,\n label: \"Accordeon\",\n description: \"Generieke in-/uitklapbare panelen.\",\n defaultEnabled: false,\n blocks: [accordionBlock],\n});\n\nexport const embedModule = defineModule({\n id: \"embed\",\n version: CORE_VERSION,\n label: \"Embed\",\n description: \"Generieke responsive iframe-embed (consent-gated).\",\n defaultEnabled: false,\n blocks: [embedBlock],\n});\n\n/* ── Nieuwe modules (3.1) — veelgebruikt op websites, volwaardig + widget waar zinvol ── */\n\nexport const cardsModule = defineModule({\n id: \"cards\",\n version: CORE_VERSION,\n label: \"Diensten / kaarten\",\n description: \"Diensten-/featurekaarten in een grid (icoon of beeld) + compacte 'uitgelicht'-widget.\",\n defaultEnabled: false,\n blocks: [cardsBlock, cardsWidget],\n});\n\nexport const tabsModule = defineModule({\n id: \"tabs\",\n version: CORE_VERSION,\n label: \"Tabbladen\",\n description: \"Tabblad-indeling: per tab een eigen set blokken (bv. beschrijving / specificaties).\",\n defaultEnabled: false,\n blocks: [tabsBlock],\n});\n\nexport const downloadsModule = defineModule({\n id: \"downloads\",\n version: CORE_VERSION,\n label: \"Downloads\",\n description: \"Lijst met downloadbare documenten (brochures, prijslijsten) + compacte widget.\",\n defaultEnabled: false,\n blocks: [downloadsBlock, downloadsWidget],\n});\n\nexport const pdfModule = defineModule({\n id: \"pdf\",\n version: CORE_VERSION,\n label: \"PDF-lezer\",\n description: \"Inline PDF-lezer voor menukaarten/documenten; meerdere PDF's met tabs, zelf te vervangen.\",\n defaultEnabled: false,\n blocks: [pdfBlock],\n});\n\nexport const countdownModule = defineModule({\n id: \"countdown\",\n version: CORE_VERSION,\n label: \"Aftelteller\",\n description: \"Tikkende countdown naar een datum (lancering, evenement, aanbieding) + widget.\",\n defaultEnabled: false,\n blocks: [countdownBlock, countdownWidget],\n});\n\nexport const sliderModule = defineModule({\n id: \"slider\",\n version: CORE_VERSION,\n label: \"Carrousel / slider\",\n description: \"Beeld-/contentcarrousel met dots, pijlen en optioneel autoplay (reduced-motion-veilig).\",\n defaultEnabled: false,\n blocks: [sliderBlock],\n});\n\n/* ── 4.16: nieuwe modules (allemaal opt-in) ──────────────────────────────── */\n\nexport const whatsappModule = defineModule({\n id: \"whatsapp\",\n version: CORE_VERSION,\n label: \"WhatsApp-knop\",\n description: \"Zwevende WhatsApp-/chatknop — laagdrempelig contact (wa.me-link, geen consent nodig).\",\n defaultEnabled: false,\n blocks: [whatsappChatBlock],\n});\n\nexport const beforeAfterModule = defineModule({\n id: \"beforeAfter\",\n version: CORE_VERSION,\n label: \"Voor / na\",\n description: \"Voor/na-vergelijker met sleepbare scheiding — sterk voor hoveniers, schilders, salons.\",\n defaultEnabled: false,\n blocks: [beforeAfterBlock],\n});\n\nexport const portfolioModule = defineModule({\n id: \"portfolio\",\n version: CORE_VERSION,\n label: \"Portfolio / projecten\",\n description: \"Projecten/cases-grid met categorie-filter en lightbox.\",\n defaultEnabled: false,\n blocks: [portfolioBlock],\n});\n\nexport const jobsModule = defineModule({\n id: \"jobs\",\n version: CORE_VERSION,\n label: \"Vacatures\",\n description: \"Vacature-overzicht met JobPosting-JSON-LD (vindbaar via Google Jobs).\",\n defaultEnabled: false,\n blocks: [jobsBlock],\n});\n\nexport const breadcrumbsModule = defineModule({\n id: \"breadcrumbs\",\n version: CORE_VERSION,\n label: \"Kruimelpad\",\n description: \"Kruimelpad afgeleid van de URL, met BreadcrumbList-JSON-LD (SEO).\",\n defaultEnabled: false,\n blocks: [breadcrumbsBlock],\n});\n\n/* ── 5.5: webwinkel + donaties ───────────────────────────────────────────────\n * 6.0: de shop-module zit NIET meer in de default-bundel. Hij is opt-in via de\n * subpath `@xiwebdesign/xicms-core/modules/shop` (+ `/admin/shop`, `/server/shop`),\n * of via de backward-compat-barrel `@xiwebdesign/xicms-core/all`. Zo landt shop-code\n * alleen in de build van sites die 'm daadwerkelijk aanzetten. */\n\nexport const consentModule = defineModule({\n id: \"consent\",\n version: CORE_VERSION,\n label: \"Cookie-consent (AVG)\",\n description: \"Toestemmingsbanner + consent-opslag; stelt niet-essentiële scripts uit.\",\n defaultEnabled: false,\n settingsSchema: z.object({\n message: z._default(z.string(), DEFAULT_MESSAGE).register(z.globalRegistry, { description: \"Bannertekst\" }),\n privacyUrl: z.optional(z.string()).register(z.globalRegistry, { description: \"Link naar privacyverklaring\" }),\n version: z.optional(z.string()).register(z.globalRegistry, { description: \"Beleidsversie (wijzig → banner opnieuw tonen)\" }),\n showReopen: z._default(z.boolean(), true).register(z.globalRegistry, { description: \"Zwevend cookie-knopje om keuze te wijzigen\" }),\n toon: z._default(z.enum([\"automatisch\", \"altijd\"]), \"automatisch\").register(z.globalRegistry, {\n description: \"Wanneer de banner verschijnt: automatisch = alleen op pagina's met een video, kaart of andere externe inhoud\",\n }),\n categories: z._default(z.array(z.object({\n id: z.string(),\n label: z.string(),\n description: z.optional(z.string()),\n required: z._default(z.boolean(), false),\n })), DEFAULT_CATEGORIES.map((c) => ({ ...c, required: Boolean(c.required) }))),\n }),\n defaultSettings: {},\n});\n\n/** Alle ingebouwde modules (volgorde bepaalt block- en tab-volgorde). */\nexport const builtinModules: ModuleDefinition[] = [\n contentModule,\n pagesModule,\n newsModule,\n mediaModule,\n galleryModule,\n faqModule,\n openingHoursModule,\n pricingModule,\n formsModule,\n statsModule,\n settingsModule,\n testimonialsModule,\n teamModule,\n agendaModule,\n searchModule,\n featureModule,\n countersModule,\n logosModule,\n timelineModule,\n videoModule,\n bannerModule,\n contactModule,\n newsletterModule,\n bookingModule,\n verhuurModule,\n accordionModule,\n embedModule,\n cardsModule,\n tabsModule,\n downloadsModule,\n pdfModule,\n countdownModule,\n sliderModule,\n whatsappModule,\n beforeAfterModule,\n portfolioModule,\n jobsModule,\n breadcrumbsModule,\n consentModule,\n];\n"],"mappings":"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","names":[]}
@@ -14,6 +14,11 @@ export interface ConsentSettings {
14
14
  version?: string;
15
15
  /** Zwevend 🍪-knopje tonen om de keuze later te wijzigen (AVG). Standaard aan. */
16
16
  showReopen?: boolean;
17
+ /**
18
+ * 8.16: "automatisch" (standaard) = de banner verschijnt alleen op een pagina waar iets op
19
+ * toestemming wacht (video, kaart, boekingswidget, ConsentGate). "altijd" = het oude gedrag.
20
+ */
21
+ toon?: "automatisch" | "altijd";
17
22
  }
18
23
  /**
19
24
  * AVG-toestemmingsbanner met twee-staps-UX: compact (accepteren / weigeren / voorkeuren), en een
@@ -1,12 +1,9 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useRef, useState } from "react";
4
- import { consentDecided, useConsent } from "./useConsent.js";
5
- const DEFAULT_CATEGORIES = [
6
- { id: "necessary", label: "Noodzakelijk", required: true, description: "Nodig om de site te laten werken. Altijd actief." },
7
- { id: "analytics", label: "Statistieken", description: "Anonieme bezoekersstatistieken om de site te verbeteren." },
8
- { id: "marketing", label: "Marketing", description: "Voor gepersonaliseerde content en advertenties." }
9
- ];
4
+ import { consentDecided, useConsent, useConsentNodig, useMeldConsentNodig } from "./useConsent.js";
5
+ import { useOnderOffset } from "../../components/onderOffset.js";
6
+ import { DEFAULT_CATEGORIES, DEFAULT_MESSAGE } from "./standaard.js";
10
7
  function ConsentBanner({ settings }) {
11
8
  const { state, save } = useConsent();
12
9
  const categories = settings?.categories?.length ? settings.categories : DEFAULT_CATEGORIES;
@@ -20,6 +17,8 @@ function ConsentBanner({ settings }) {
20
17
  if (reopened) bannerRef.current?.querySelector(".xicms-consent__btn--primary")?.focus();
21
18
  }, [reopened]);
22
19
  const decided = consentDecided(state, settings?.version);
20
+ const nodig = useConsentNodig();
21
+ useOnderOffset();
23
22
  const openBanner = () => {
24
23
  setChoices((prev) => ({ ...prev, ...state.categories }));
25
24
  setShowPrefs(true);
@@ -30,6 +29,7 @@ function ConsentBanner({ settings }) {
30
29
  window.addEventListener("xicms:consent:open", onOpen);
31
30
  return () => window.removeEventListener("xicms:consent:open", onOpen);
32
31
  }, [state.categories]);
32
+ if (!decided && !reopened && settings?.toon !== "altijd" && !nodig) return null;
33
33
  if (decided && !reopened) {
34
34
  if (settings?.showReopen === false) return null;
35
35
  return /* @__PURE__ */ jsx(
@@ -55,7 +55,7 @@ function ConsentBanner({ settings }) {
55
55
  /* @__PURE__ */ jsxs("div", { className: "xicms-consent__head", children: [
56
56
  /* @__PURE__ */ jsx("p", { className: "xicms-consent__title", children: settings?.title ?? "\u{1F36A} Cookievoorkeuren" }),
57
57
  /* @__PURE__ */ jsxs("p", { className: "xicms-consent__message", children: [
58
- settings?.message ?? "We gebruiken cookies om de site te laten werken en te verbeteren. Kies hieronder wat je toestaat.",
58
+ settings?.message ?? DEFAULT_MESSAGE,
59
59
  settings?.privacyUrl && /* @__PURE__ */ jsxs(Fragment, { children: [
60
60
  " ",
61
61
  /* @__PURE__ */ jsx("a", { className: "xicms-consent__link", href: settings.privacyUrl, children: "Privacyverklaring" })
@@ -98,6 +98,7 @@ function ConsentBanner({ settings }) {
98
98
  }
99
99
  function ConsentGate({ category, children }) {
100
100
  const { has } = useConsent();
101
+ useMeldConsentNodig(category, !has(category));
101
102
  return has(category) ? /* @__PURE__ */ jsx(Fragment, { children }) : null;
102
103
  }
103
104
  function ConsentReopenLink({ children, className }) {