@xiwebdesign/xicms-core 7.9.0 → 7.10.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.
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
- import { useState } from "react";
3
+ import { useEffect, useState } from "react";
4
4
  import { NewsletterBlockSchema } from "../../schema/blocks.js";
5
5
  import { defineBlock } from "../registry.js";
6
6
  import { Button } from "@astryxdesign/core/Button";
@@ -8,16 +8,20 @@ import { TextInput } from "@astryxdesign/core/TextInput";
8
8
  import { CheckboxInput } from "@astryxdesign/core/CheckboxInput";
9
9
  import { VStack, Card, Heading, Text } from "../ui/index.js";
10
10
  import { isDemoActive } from "../../demo/demoStore.js";
11
+ import { Onvoltooid } from "./lib/Onvoltooid.js";
11
12
  import { isFirebaseConfigured } from "../../firebase/config.js";
12
13
  import { submitFormValues } from "./lib/submitForm.js";
13
14
  function NewsletterRender({ block, siteId, mode }) {
14
15
  const [email, setEmail] = useState("");
15
16
  const [agreed, setAgreed] = useState(false);
16
17
  const [status, setStatus] = useState("idle");
17
- const useXicmsForm = !block.actionUrl && Boolean(block.formId);
18
+ const [demo, setDemo] = useState(false);
19
+ useEffect(() => setDemo(isDemoActive()), []);
20
+ const useXicmsForm = !block.actionUrl && (Boolean(block.formId) || demo);
18
21
  async function submitViaXicms(e) {
19
22
  e.preventDefault();
20
- if (mode === "preview" || !block.formId) return;
23
+ if (mode === "preview") return;
24
+ if (!block.formId && !demo) return;
21
25
  if (isDemoActive() || !isFirebaseConfigured()) {
22
26
  setStatus("ok");
23
27
  return;
@@ -81,7 +85,7 @@ function NewsletterRender({ block, siteId, mode }) {
81
85
  }
82
86
  ),
83
87
  status === "error" && /* @__PURE__ */ jsx(Text, { role: "alert", type: "supporting", style: { color: "var(--color-error, #c0392b)" }, children: "Aanmelden mislukt. Probeer het later opnieuw." })
84
- ] }) : /* @__PURE__ */ jsx(Text, { type: "supporting", color: "secondary", children: "Configureer een aanmeld-URL of formulier in de editor." })
88
+ ] }) : /* @__PURE__ */ jsx(Onvoltooid, { children: "Dit nieuwsbrief-blok is nog leeg: kies een aanmeld-URL of een formulier via het tandwiel. Bezoekers zien dit blok niet." })
85
89
  ] }) });
86
90
  }
87
91
  const newsletterBlock = defineBlock({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/builtins/Newsletter.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, type FormEvent } from \"react\";\nimport type { z } from \"zod\";\nimport { NewsletterBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { Button } from \"@astryxdesign/core/Button\";\nimport { TextInput } from \"@astryxdesign/core/TextInput\";\nimport { CheckboxInput } from \"@astryxdesign/core/CheckboxInput\";\nimport { VStack, Card, Heading, Text } from \"../ui\";\nimport { isDemoActive } from \"../../demo/demoStore\";\nimport { isFirebaseConfigured } from \"../../firebase/config\";\nimport { submitFormValues } from \"./lib/submitForm\";\n\ntype Newsletter = z.infer<typeof NewsletterBlockSchema>;\n\n/**\n * Nieuwsbrief-aanmelding. Twee modi:\n * - `actionUrl` (bv. de embed-action van Mailchimp/Brevo): native form-POST naar de provider.\n * - `formId` (zonder actionUrl): opslag via het XiCMS-formulier (submitForm-callable) — inzendingen\n * verschijnen in /beheer → Formulieren, met dezelfde rate-limiting/validatie als het formulier-blok.\n * Optionele AVG-checkbox via `consentText`.\n */\nfunction NewsletterRender({ block, siteId, mode }: BlockRenderProps<Newsletter>) {\n const [email, setEmail] = useState(\"\");\n const [agreed, setAgreed] = useState(false);\n const [status, setStatus] = useState<\"idle\" | \"busy\" | \"ok\" | \"error\">(\"idle\");\n const useXicmsForm = !block.actionUrl && Boolean(block.formId);\n\n async function submitViaXicms(e: FormEvent) {\n e.preventDefault();\n if (mode === \"preview\" || !block.formId) return;\n // Zelfde vangnet als het formulier-blok: in demo of zonder Firebase-backend lokaal \"slagen\"\n // i.p.v. een foutmelding tonen op een statische (referentie)site.\n if (isDemoActive() || !isFirebaseConfigured()) {\n setStatus(\"ok\");\n return;\n }\n setStatus(\"busy\");\n try {\n await submitFormValues(siteId, block.formId, { email });\n setStatus(\"ok\");\n setEmail(\"\");\n } catch {\n setStatus(\"error\");\n }\n }\n\n const consentBox = block.consentText ? (\n <div style={{ textAlign: \"left\", maxWidth: 440, width: \"100%\" }}>\n <CheckboxInput label={block.consentText} isRequired value={agreed} onChange={setAgreed} />\n </div>\n ) : null;\n\n const emailInput = (\n <div style={{ flex: 1, minWidth: 200, textAlign: \"left\" }}>\n <TextInput\n label=\"E-mailadres\"\n isLabelHidden\n type=\"email\"\n htmlName=\"EMAIL\"\n isRequired\n placeholder=\"je@email.nl\"\n value={email}\n onChange={setEmail}\n />\n </div>\n );\n const rowStyle = { display: \"flex\", gap: \"0.75rem\", flexWrap: \"wrap\", alignItems: \"end\", justifyContent: \"center\", maxWidth: 440, width: \"100%\" } as const;\n\n return (\n <Card padding={5} variant=\"muted\">\n <VStack gap={2} hAlign=\"center\" style={{ textAlign: \"center\" }}>\n {block.heading && <Heading level={2} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n {block.text && <Text color=\"secondary\" data-xicms-edit=\"text\">{block.text}</Text>}\n {status === \"ok\" ? (\n <Text role=\"status\">Bedankt voor je aanmelding!</Text>\n ) : block.actionUrl ? (\n <form\n action={block.actionUrl}\n method=\"post\"\n target=\"_blank\"\n style={rowStyle}\n // AVG: zonder deze guard kon de native POST doorgaan zonder aangevinkte toestemming\n // (Astryx CheckboxInput heeft geen htmlName, dus de browser hield 'm niet tegen).\n onSubmit={(e) => {\n if (block.consentText && !agreed) e.preventDefault();\n }}\n >\n {emailInput}\n {consentBox}\n {/* De toestemmingswaarde ook daadwerkelijk meesturen naar de provider. */}\n {block.consentText && <input type=\"hidden\" name=\"CONSENT\" value={agreed ? \"yes\" : \"\"} />}\n <Button label={block.buttonLabel} variant=\"primary\" size=\"lg\" type=\"submit\">\n <span data-xicms-edit=\"buttonLabel\">{block.buttonLabel}</span>\n </Button>\n </form>\n ) : useXicmsForm ? (\n <form onSubmit={submitViaXicms} style={rowStyle}>\n {emailInput}\n {consentBox}\n <Button\n label={status === \"busy\" ? \"Aanmelden…\" : block.buttonLabel}\n variant=\"primary\"\n size=\"lg\"\n type=\"submit\"\n isLoading={status === \"busy\"}\n >\n {/* Tijdens versturen wint het wachtlabel: `undefined` laat Astryx op `label` terugvallen. */}\n {status === \"busy\" ? undefined : <span data-xicms-edit=\"buttonLabel\">{block.buttonLabel}</span>}\n </Button>\n {status === \"error\" && (\n <Text role=\"alert\" type=\"supporting\" style={{ color: \"var(--color-error, #c0392b)\" }}>\n Aanmelden mislukt. Probeer het later opnieuw.\n </Text>\n )}\n </form>\n ) : (\n <Text type=\"supporting\" color=\"secondary\">Configureer een aanmeld-URL of formulier in de editor.</Text>\n )}\n </VStack>\n </Card>\n );\n}\n\nexport const newsletterBlock = defineBlock({\n type: \"newsletter\",\n schema: NewsletterBlockSchema,\n Render: NewsletterRender,\n label: \"Nieuwsbrief\",\n icon: \"✉️\",\n defaults: () => ({ heading: \"Blijf op de hoogte\", buttonLabel: \"Aanmelden\" }),\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/blocks/builtins/Newsletter.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState, type FormEvent } from \"react\";\nimport type { z } from \"zod\";\nimport { NewsletterBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { Button } from \"@astryxdesign/core/Button\";\nimport { TextInput } from \"@astryxdesign/core/TextInput\";\nimport { CheckboxInput } from \"@astryxdesign/core/CheckboxInput\";\nimport { VStack, Card, Heading, Text } from \"../ui\";\nimport { isDemoActive } from \"../../demo/demoStore\";\nimport { Onvoltooid } from \"./lib/Onvoltooid\";\nimport { isFirebaseConfigured } from \"../../firebase/config\";\nimport { submitFormValues } from \"./lib/submitForm\";\n\ntype Newsletter = z.infer<typeof NewsletterBlockSchema>;\n\n/**\n * Nieuwsbrief-aanmelding. Twee modi:\n * - `actionUrl` (bv. de embed-action van Mailchimp/Brevo): native form-POST naar de provider.\n * - `formId` (zonder actionUrl): opslag via het XiCMS-formulier (submitForm-callable) — inzendingen\n * verschijnen in /beheer → Formulieren, met dezelfde rate-limiting/validatie als het formulier-blok.\n * Optionele AVG-checkbox via `consentText`.\n */\nfunction NewsletterRender({ block, siteId, mode }: BlockRenderProps<Newsletter>) {\n const [email, setEmail] = useState(\"\");\n const [agreed, setAgreed] = useState(false);\n const [status, setStatus] = useState<\"idle\" | \"busy\" | \"ok\" | \"error\">(\"idle\");\n /**\n * In een demo is er altijd een werkend formulier: het slaat lokaal \"op\" (zie submitViaXicms),\n * precies zoals het formulier-blok. Een demo die om configuratie vraagt verkoopt niets.\n *\n * Via state + effect en niet rechtstreeks in de render: `setDemoActive` draait in een effect van\n * de provider, dus tijdens de eerste render is `isDemoActive()` nog false en zou dit blok zich\n * één keer verkeerd aankleden — en zonder eigen re-render zo blijven staan. FormBlock leert\n * dezelfde les op dezelfde manier.\n */\n const [demo, setDemo] = useState(false);\n useEffect(() => setDemo(isDemoActive()), []);\n const useXicmsForm = !block.actionUrl && (Boolean(block.formId) || demo);\n\n async function submitViaXicms(e: FormEvent) {\n e.preventDefault();\n if (mode === \"preview\") return;\n // Zonder formId kan er alleen in demo iets \"verzonden\" worden — de guard hieronder vangt dat af\n // met een lokaal succes vóór submitFormValues ooit wordt bereikt.\n if (!block.formId && !demo) return;\n // Zelfde vangnet als het formulier-blok: in demo of zonder Firebase-backend lokaal \"slagen\"\n // i.p.v. een foutmelding tonen op een statische (referentie)site.\n if (isDemoActive() || !isFirebaseConfigured()) {\n setStatus(\"ok\");\n return;\n }\n setStatus(\"busy\");\n try {\n // Niet-demo-pad; hierboven afgevangen als formId ontbreekt, dus hier bestaat hij.\n await submitFormValues(siteId, block.formId as string, { email });\n setStatus(\"ok\");\n setEmail(\"\");\n } catch {\n setStatus(\"error\");\n }\n }\n\n const consentBox = block.consentText ? (\n <div style={{ textAlign: \"left\", maxWidth: 440, width: \"100%\" }}>\n <CheckboxInput label={block.consentText} isRequired value={agreed} onChange={setAgreed} />\n </div>\n ) : null;\n\n const emailInput = (\n <div style={{ flex: 1, minWidth: 200, textAlign: \"left\" }}>\n <TextInput\n label=\"E-mailadres\"\n isLabelHidden\n type=\"email\"\n htmlName=\"EMAIL\"\n isRequired\n placeholder=\"je@email.nl\"\n value={email}\n onChange={setEmail}\n />\n </div>\n );\n const rowStyle = { display: \"flex\", gap: \"0.75rem\", flexWrap: \"wrap\", alignItems: \"end\", justifyContent: \"center\", maxWidth: 440, width: \"100%\" } as const;\n\n return (\n <Card padding={5} variant=\"muted\">\n <VStack gap={2} hAlign=\"center\" style={{ textAlign: \"center\" }}>\n {block.heading && <Heading level={2} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n {block.text && <Text color=\"secondary\" data-xicms-edit=\"text\">{block.text}</Text>}\n {status === \"ok\" ? (\n <Text role=\"status\">Bedankt voor je aanmelding!</Text>\n ) : block.actionUrl ? (\n <form\n action={block.actionUrl}\n method=\"post\"\n target=\"_blank\"\n style={rowStyle}\n // AVG: zonder deze guard kon de native POST doorgaan zonder aangevinkte toestemming\n // (Astryx CheckboxInput heeft geen htmlName, dus de browser hield 'm niet tegen).\n onSubmit={(e) => {\n if (block.consentText && !agreed) e.preventDefault();\n }}\n >\n {emailInput}\n {consentBox}\n {/* De toestemmingswaarde ook daadwerkelijk meesturen naar de provider. */}\n {block.consentText && <input type=\"hidden\" name=\"CONSENT\" value={agreed ? \"yes\" : \"\"} />}\n <Button label={block.buttonLabel} variant=\"primary\" size=\"lg\" type=\"submit\">\n <span data-xicms-edit=\"buttonLabel\">{block.buttonLabel}</span>\n </Button>\n </form>\n ) : useXicmsForm ? (\n <form onSubmit={submitViaXicms} style={rowStyle}>\n {emailInput}\n {consentBox}\n <Button\n label={status === \"busy\" ? \"Aanmelden…\" : block.buttonLabel}\n variant=\"primary\"\n size=\"lg\"\n type=\"submit\"\n isLoading={status === \"busy\"}\n >\n {/* Tijdens versturen wint het wachtlabel: `undefined` laat Astryx op `label` terugvallen. */}\n {status === \"busy\" ? undefined : <span data-xicms-edit=\"buttonLabel\">{block.buttonLabel}</span>}\n </Button>\n {status === \"error\" && (\n <Text role=\"alert\" type=\"supporting\" style={{ color: \"var(--color-error, #c0392b)\" }}>\n Aanmelden mislukt. Probeer het later opnieuw.\n </Text>\n )}\n </form>\n ) : (\n <Onvoltooid>Dit nieuwsbrief-blok is nog leeg: kies een aanmeld-URL of een formulier via het tandwiel. Bezoekers zien dit blok niet.</Onvoltooid>\n )}\n </VStack>\n </Card>\n );\n}\n\nexport const newsletterBlock = defineBlock({\n type: \"newsletter\",\n schema: NewsletterBlockSchema,\n Render: NewsletterRender,\n label: \"Nieuwsbrief\",\n icon: \"✉️\",\n defaults: () => ({ heading: \"Blijf op de hoogte\", buttonLabel: \"Aanmelden\" }),\n});\n"],"mappings":"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","names":[]}
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useState } from "react";
4
+ import { Onvoltooid } from "./lib/Onvoltooid.js";
4
5
  import { PdfBlockSchema } from "../../schema/blocks.js";
5
6
  import { defineBlock } from "../registry.js";
6
7
  import { VStack, HStack, Heading, Text } from "../ui/index.js";
@@ -66,7 +67,7 @@ function PdfRender({ block, mode }) {
66
67
  )
67
68
  )
68
69
  }
69
- ) : /* @__PURE__ */ jsx(Text, { color: "secondary", children: "Voeg een PDF toe in de editor." }),
70
+ ) : /* @__PURE__ */ jsx(Onvoltooid, { children: "Dit PDF-blok is nog leeg: kies een document via het tandwiel. Bezoekers zien dit blok niet." }),
70
71
  block.showDownload && current && /* @__PURE__ */ jsx("a", { href: current.url, target: "_blank", rel: "noopener noreferrer", style: { color: "var(--color-accent)" }, children: /* @__PURE__ */ jsxs(Text, { type: "label", children: [
71
72
  "\u2197 Open \u201C",
72
73
  current.label || "PDF",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/builtins/PdfBlock.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport type { z } from \"zod\";\nimport { PdfBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { VStack, HStack, Heading, Text } from \"../ui\";\n\ntype Pdf = z.infer<typeof PdfBlockSchema>;\n\n/**\n * Inline PDF-lezer voor bv. menukaarten. Eén of meer PDF's; bij meerdere verschijnen tabs\n * (lunchkaart/dinerkaart/wijnkaart…). De klant vervangt de PDF's zelf in de editor (URL of\n * media-upload). In de editor (mode=\"preview\") tonen we een lichte placeholder i.p.v. de iframe.\n */\nfunction PdfRender({ block, mode }: BlockRenderProps<Pdf>) {\n // _i = index in de OORSPRONKELIJKE array — de lijst wordt gefilterd op url.\n const docs = (block.documents ?? []).map((d, i) => ({ ...d, _i: i })).filter((d) => d.url);\n const [active, setActive] = useState(0);\n if (docs.length === 0 && !block.heading) return null;\n const current = docs[Math.min(active, docs.length - 1)];\n\n return (\n <VStack gap={3} as=\"section\">\n {block.heading && <Heading level={2} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n\n {/* Gewone toggle-knoppen: een echt tabs-patroon vereist tabpanel-koppeling + pijltjesnavigatie. */}\n {docs.length > 1 && (\n <HStack gap={1} style={{ flexWrap: \"wrap\" }} role=\"group\" aria-label=\"Kies document\">\n {docs.map((d, i) => (\n <button\n key={i}\n type=\"button\"\n aria-pressed={i === active}\n onClick={() => setActive(i)}\n style={{\n padding: \"0.4rem 0.9rem\",\n borderRadius: \"var(--radius-full, 999px)\",\n border: \"1px solid var(--color-border)\",\n cursor: \"pointer\",\n fontWeight: 600,\n fontSize: \"0.9rem\",\n background: i === active ? \"var(--color-accent)\" : \"transparent\",\n color: i === active ? \"var(--color-on-accent)\" : \"var(--color-text-primary)\",\n }}\n >\n <span data-xicms-edit={`documents.${d._i}.label`}>{d.label || `Document ${i + 1}`}</span>\n </button>\n ))}\n </HStack>\n )}\n\n {current ? (\n <div\n style={{\n borderRadius: \"var(--radius-container)\",\n overflow: \"hidden\",\n border: \"1px solid var(--color-border)\",\n background: \"var(--color-background-muted, rgba(0,0,0,0.03))\",\n }}\n >\n {mode === \"preview\" ? (\n <div className=\"xicms-embed-consent xicms-embed-preview\" role=\"note\" style={{ height: Math.min(block.height, 360) }}>\n <p>📄 PDF “{current.label || \"document\"}” — wordt op de live site geladen (niet in de editor).</p>\n </div>\n ) : (\n // <object> i.p.v. <iframe>: browsers zonder inline PDF-viewer (veel mobiel) tonen\n // dan de fallback-inhoud met een open/download-knop i.p.v. een leeg vlak.\n <object\n data={`${current.url}#view=FitH`}\n type=\"application/pdf\"\n aria-label={current.label || block.heading || \"PDF\"}\n style={{ border: 0, width: \"100%\", height: block.height, display: \"block\" }}\n >\n <div style={{ display: \"grid\", placeItems: \"center\", gap: \"0.6rem\", padding: \"2.5rem 1rem\", textAlign: \"center\" }}>\n <Text color=\"secondary\">Je browser kan deze PDF niet inline tonen.</Text>\n <a className=\"xicms-btn\" href={current.url} target=\"_blank\" rel=\"noopener noreferrer\">\n 📄 Open “{current.label || \"PDF\"}”\n </a>\n </div>\n </object>\n )}\n </div>\n ) : (\n <Text color=\"secondary\">Voeg een PDF toe in de editor.</Text>\n )}\n\n {block.showDownload && current && (\n <a href={current.url} target=\"_blank\" rel=\"noopener noreferrer\" style={{ color: \"var(--color-accent)\" }}>\n <Text type=\"label\">↗ Open “{current.label || \"PDF\"}” in een nieuw tabblad</Text>\n </a>\n )}\n </VStack>\n );\n}\n\nexport const pdfBlock = defineBlock({\n type: \"pdf\",\n schema: PdfBlockSchema,\n Render: PdfRender,\n label: \"PDF-lezer (menu/document)\",\n icon: \"📄\",\n defaults: () => ({\n heading: \"Onze kaart\",\n documents: [\n { label: \"Lunchkaart\", url: \"\" },\n { label: \"Dinerkaart\", url: \"\" },\n ],\n height: 820,\n showDownload: true,\n }),\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/blocks/builtins/PdfBlock.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport type { z } from \"zod\";\nimport { Onvoltooid } from \"./lib/Onvoltooid\";\nimport { PdfBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { VStack, HStack, Heading, Text } from \"../ui\";\n\ntype Pdf = z.infer<typeof PdfBlockSchema>;\n\n/**\n * Inline PDF-lezer voor bv. menukaarten. Eén of meer PDF's; bij meerdere verschijnen tabs\n * (lunchkaart/dinerkaart/wijnkaart…). De klant vervangt de PDF's zelf in de editor (URL of\n * media-upload). In de editor (mode=\"preview\") tonen we een lichte placeholder i.p.v. de iframe.\n */\nfunction PdfRender({ block, mode }: BlockRenderProps<Pdf>) {\n // _i = index in de OORSPRONKELIJKE array — de lijst wordt gefilterd op url.\n const docs = (block.documents ?? []).map((d, i) => ({ ...d, _i: i })).filter((d) => d.url);\n const [active, setActive] = useState(0);\n if (docs.length === 0 && !block.heading) return null;\n const current = docs[Math.min(active, docs.length - 1)];\n\n return (\n <VStack gap={3} as=\"section\">\n {block.heading && <Heading level={2} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n\n {/* Gewone toggle-knoppen: een echt tabs-patroon vereist tabpanel-koppeling + pijltjesnavigatie. */}\n {docs.length > 1 && (\n <HStack gap={1} style={{ flexWrap: \"wrap\" }} role=\"group\" aria-label=\"Kies document\">\n {docs.map((d, i) => (\n <button\n key={i}\n type=\"button\"\n aria-pressed={i === active}\n onClick={() => setActive(i)}\n style={{\n padding: \"0.4rem 0.9rem\",\n borderRadius: \"var(--radius-full, 999px)\",\n border: \"1px solid var(--color-border)\",\n cursor: \"pointer\",\n fontWeight: 600,\n fontSize: \"0.9rem\",\n background: i === active ? \"var(--color-accent)\" : \"transparent\",\n color: i === active ? \"var(--color-on-accent)\" : \"var(--color-text-primary)\",\n }}\n >\n <span data-xicms-edit={`documents.${d._i}.label`}>{d.label || `Document ${i + 1}`}</span>\n </button>\n ))}\n </HStack>\n )}\n\n {current ? (\n <div\n style={{\n borderRadius: \"var(--radius-container)\",\n overflow: \"hidden\",\n border: \"1px solid var(--color-border)\",\n background: \"var(--color-background-muted, rgba(0,0,0,0.03))\",\n }}\n >\n {mode === \"preview\" ? (\n <div className=\"xicms-embed-consent xicms-embed-preview\" role=\"note\" style={{ height: Math.min(block.height, 360) }}>\n <p>📄 PDF “{current.label || \"document\"}” — wordt op de live site geladen (niet in de editor).</p>\n </div>\n ) : (\n // <object> i.p.v. <iframe>: browsers zonder inline PDF-viewer (veel mobiel) tonen\n // dan de fallback-inhoud met een open/download-knop i.p.v. een leeg vlak.\n <object\n data={`${current.url}#view=FitH`}\n type=\"application/pdf\"\n aria-label={current.label || block.heading || \"PDF\"}\n style={{ border: 0, width: \"100%\", height: block.height, display: \"block\" }}\n >\n <div style={{ display: \"grid\", placeItems: \"center\", gap: \"0.6rem\", padding: \"2.5rem 1rem\", textAlign: \"center\" }}>\n <Text color=\"secondary\">Je browser kan deze PDF niet inline tonen.</Text>\n <a className=\"xicms-btn\" href={current.url} target=\"_blank\" rel=\"noopener noreferrer\">\n 📄 Open “{current.label || \"PDF\"}”\n </a>\n </div>\n </object>\n )}\n </div>\n ) : (\n <Onvoltooid>Dit PDF-blok is nog leeg: kies een document via het tandwiel. Bezoekers zien dit blok niet.</Onvoltooid>\n )}\n\n {block.showDownload && current && (\n <a href={current.url} target=\"_blank\" rel=\"noopener noreferrer\" style={{ color: \"var(--color-accent)\" }}>\n <Text type=\"label\">↗ Open “{current.label || \"PDF\"}” in een nieuw tabblad</Text>\n </a>\n )}\n </VStack>\n );\n}\n\nexport const pdfBlock = defineBlock({\n type: \"pdf\",\n schema: PdfBlockSchema,\n Render: PdfRender,\n label: \"PDF-lezer (menu/document)\",\n icon: \"📄\",\n defaults: () => ({\n heading: \"Onze kaart\",\n documents: [\n { label: \"Lunchkaart\", url: \"\" },\n { label: \"Dinerkaart\", url: \"\" },\n ],\n height: 820,\n showDownload: true,\n }),\n});\n"],"mappings":"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","names":[]}
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useState } from "react";
4
+ import { Onvoltooid } from "./lib/Onvoltooid.js";
4
5
  import {
5
6
  NewsWidgetSchema,
6
7
  AgendaWidgetSchema,
@@ -144,7 +145,7 @@ function NewsletterWidgetRender({ block }) {
144
145
  block.actionUrl ? /* @__PURE__ */ jsxs("form", { className: "xicms-widget__form", action: block.actionUrl, method: "post", target: "_blank", style: { display: "grid", gap: "0.6rem" }, children: [
145
146
  /* @__PURE__ */ jsx(TextInput, { label: "E-mailadres", isLabelHidden: true, type: "email", htmlName: "EMAIL", isRequired: true, placeholder: "je@email.nl", value: email, onChange: setEmail }),
146
147
  /* @__PURE__ */ jsx(Button, { label: block.buttonLabel, variant: "primary", type: "submit", children: /* @__PURE__ */ jsx("span", { "data-xicms-edit": "buttonLabel", children: block.buttonLabel }) })
147
- ] }) : /* @__PURE__ */ jsx("p", { className: "xicms-widget__empty", children: "Stel een aanmeld-URL in." })
148
+ ] }) : /* @__PURE__ */ jsx(Onvoltooid, { children: "Deze aanmeldwidget mist nog een aanmeld-URL (tandwiel). Bezoekers zien dit blok niet." })
148
149
  ] });
149
150
  }
150
151
  const newsletterWidget = defineBlock({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/builtins/Widgets.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport type { z } from \"zod\";\nimport {\n NewsWidgetSchema,\n AgendaWidgetSchema,\n OpeningHoursWidgetSchema,\n ContactWidgetSchema,\n SocialWidgetSchema,\n NewsletterWidgetSchema,\n CtaWidgetSchema,\n GalleryWidgetSchema,\n TestimonialsWidgetSchema,\n CardsWidgetSchema,\n DownloadsWidgetSchema,\n CountdownWidgetSchema,\n} from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { Btn } from \"../ui\";\nimport { useNews } from \"../../components/News\";\nimport { selectAgendaEvents, formatEventDate } from \"./Agenda\";\nimport { parseDays } from \"./lib/openingHours\";\nimport { useCountdown, CountdownDigits } from \"./Countdown\";\nimport { TextInput } from \"@astryxdesign/core/TextInput\";\nimport { Button } from \"@astryxdesign/core/Button\";\n\n/**\n * Widgets = compacte zijbalk-varianten van de modules. Elke widget hergebruikt de gegevens en\n * logica van de volwaardige versie (zelfde nieuws-collectie, zelfde agenda-selectie, zelfde\n * countdown-hook) en rendert die alleen compacter. Plaats ze in het \"Met zijbalk\"-blok of in een\n * smalle kolom naast je hoofdinhoud.\n */\n\n/* ── Laatste nieuws ────────────────────────────────────────────────────────── */\ntype NewsW = z.infer<typeof NewsWidgetSchema>;\nfunction NewsWidgetRender({ block }: BlockRenderProps<NewsW>) {\n const { articles, loading } = useNews({ max: block.limit });\n const shown = articles.slice(0, block.limit);\n return (\n <div className=\"xicms-widget xicms-widget--news\">\n <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading ?? \"Laatste nieuws\"}</h3>\n {loading ? (\n <p className=\"xicms-widget__empty\">Nieuws laden…</p>\n ) : shown.length === 0 ? (\n <p className=\"xicms-widget__empty\">Nog geen nieuws.</p>\n ) : (\n <ul className=\"xicms-widget__list\">\n {shown.map((a) => (\n <li key={a.id} className=\"xicms-widget__item\">\n {block.showImages && a.coverUrl && (\n // eslint-disable-next-line @next/next/no-img-element\n <img className=\"xicms-widget__thumb\" src={a.coverUrl} alt=\"\" loading=\"lazy\" />\n )}\n <div>\n <a className=\"xicms-widget__link\" href={`${block.basePath}/${a.slug}`}>{a.title}</a>\n <span className=\"xicms-widget__meta\">{a.date}</span>\n </div>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\nexport const newsWidget = defineBlock({\n type: \"newsWidget\",\n schema: NewsWidgetSchema,\n Render: NewsWidgetRender,\n label: \"Laatste nieuws\",\n icon: \"🗞️\",\n category: \"widget\",\n defaults: () => ({ heading: \"Laatste nieuws\", limit: 5, basePath: \"/nieuws\", showImages: false }),\n});\n\n/* ── Komende agenda ────────────────────────────────────────────────────────── */\ntype AgendaW = z.infer<typeof AgendaWidgetSchema>;\nfunction AgendaWidgetRender({ block }: BlockRenderProps<AgendaW>) {\n const events = selectAgendaEvents((block.events ?? []).map((e, i) => ({ ...e, _i: i })), { hidePast: block.hidePast, limit: block.limit });\n return (\n <div className=\"xicms-widget xicms-widget--agenda\">\n <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading ?? \"Komende evenementen\"}</h3>\n {events.length === 0 ? (\n <p className=\"xicms-widget__empty\">Geen geplande evenementen.</p>\n ) : (\n <ul className=\"xicms-widget__list\">\n {events.map((e) => (\n <li key={e._i} className=\"xicms-widget__item xicms-widget__item--event\">\n <time className=\"xicms-widget__meta\" dateTime={e.start}>{formatEventDate(e.start)}</time>\n <span className=\"xicms-widget__link\">\n {e.url\n ? <a href={e.url} data-xicms-edit={`events.${e._i}.title`}>{e.title}</a>\n : <span data-xicms-edit={`events.${e._i}.title`}>{e.title}</span>}\n </span>\n {e.location && <span className=\"xicms-widget__sub\" data-xicms-edit={`events.${e._i}.location`}>{e.location}</span>}\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\nexport const agendaWidget = defineBlock({\n type: \"agendaWidget\",\n schema: AgendaWidgetSchema,\n Render: AgendaWidgetRender,\n label: \"Komende agenda\",\n icon: \"📅\",\n category: \"widget\",\n defaults: () => ({ heading: \"Komende evenementen\", limit: 5, events: [], hidePast: true }),\n});\n\n/* ── Openingstijden (vandaag gemarkeerd) ───────────────────────────────────── */\ntype OpeningW = z.infer<typeof OpeningHoursWidgetSchema>;\nfunction OpeningHoursWidgetRender({ block }: BlockRenderProps<OpeningW>) {\n // \"Vandaag\" client-side bepalen (voorkomt hydration-mismatch t.o.v. de servertijd).\n const [todayIdx, setTodayIdx] = useState<number | null>(null);\n useEffect(() => setTodayIdx(new Date().getDay()), []);\n const rows = block.rows ?? [];\n return (\n <div className=\"xicms-widget xicms-widget--hours\">\n <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading ?? \"Openingstijden\"}</h3>\n <table className=\"xicms-widget__hours\">\n <tbody>\n {rows.map((r, i) => {\n // parseDays begrijpt ook bereiken (\"Ma-vr\", \"Maandag t/m vrijdag\") - een woensdag\n // hoort dan net zo goed gemarkeerd als de letterlijk genoemde dagen.\n const isToday =\n block.highlightToday && todayIdx !== null && parseDays(r.day).includes(todayIdx);\n return (\n <tr key={i} className={isToday ? \"xicms-widget__hours-today\" : undefined}>\n <th scope=\"row\" data-xicms-edit={`rows.${i}.day`}>{r.day}</th>\n <td data-xicms-edit={`rows.${i}.hours`}>{r.hours}</td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n );\n}\nexport const openingHoursWidget = defineBlock({\n type: \"openingHoursWidget\",\n schema: OpeningHoursWidgetSchema,\n Render: OpeningHoursWidgetRender,\n label: \"Openingstijden (compact)\",\n icon: \"🕒\",\n category: \"widget\",\n defaults: () => ({\n heading: \"Openingstijden\",\n highlightToday: true,\n rows: [\n { day: \"Maandag t/m vrijdag\", hours: \"09:00 – 17:00\" },\n { day: \"Zaterdag\", hours: \"10:00 – 16:00\" },\n { day: \"Zondag\", hours: \"Gesloten\" },\n ],\n }),\n});\n\n/* ── Contact (compact) ─────────────────────────────────────────────────────── */\ntype ContactW = z.infer<typeof ContactWidgetSchema>;\nfunction ContactWidgetRender({ block }: BlockRenderProps<ContactW>) {\n if (!block.address && !block.phone && !block.email) return null;\n return (\n <div className=\"xicms-widget xicms-widget--contact\">\n <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading ?? \"Contact\"}</h3>\n <ul className=\"xicms-widget__list\">\n {block.address && <li className=\"xicms-widget__item\" data-xicms-edit=\"address\">{block.address}</li>}\n {block.phone && (\n <li className=\"xicms-widget__item\"><a href={`tel:${block.phone.replace(/\\s+/g, \"\")}`} data-xicms-edit=\"phone\">{block.phone}</a></li>\n )}\n {block.email && (\n <li className=\"xicms-widget__item\"><a href={`mailto:${block.email}`} data-xicms-edit=\"email\">{block.email}</a></li>\n )}\n </ul>\n </div>\n );\n}\nexport const contactWidget = defineBlock({\n type: \"contactWidget\",\n schema: ContactWidgetSchema,\n Render: ContactWidgetRender,\n label: \"Contact (compact)\",\n icon: \"📇\",\n category: \"widget\",\n defaults: () => ({ heading: \"Contact\" }),\n});\n\n/* ── Social (compact) ──────────────────────────────────────────────────────── */\ntype SocialW = z.infer<typeof SocialWidgetSchema>;\nfunction SocialWidgetRender({ block }: BlockRenderProps<SocialW>) {\n // _i = index in de OORSPRONKELIJKE array — de lijst wordt gefilterd op href && platform.\n const items = (block.items ?? []).map((it, i) => ({ ...it, _i: i })).filter((i) => i.href && i.platform);\n if (items.length === 0) return null;\n return (\n <div className=\"xicms-widget xicms-widget--social\">\n {block.heading && <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading}</h3>}\n <ul className=\"xicms-widget__social\">\n {items.map((it) => (\n <li key={it._i}><a href={it.href} rel=\"noopener noreferrer\" target=\"_blank\" data-xicms-edit={`items.${it._i}.platform`}>{it.platform}</a></li>\n ))}\n </ul>\n </div>\n );\n}\nexport const socialWidget = defineBlock({\n type: \"socialWidget\",\n schema: SocialWidgetSchema,\n Render: SocialWidgetRender,\n label: \"Social (compact)\",\n icon: \"🔗\",\n category: \"widget\",\n defaults: () => ({ heading: \"Volg ons\", items: [{ platform: \"Instagram\", href: \"\" }] }),\n});\n\n/* ── Nieuwsbrief (compact) ─────────────────────────────────────────────────── */\ntype NewsletterW = z.infer<typeof NewsletterWidgetSchema>;\nfunction NewsletterWidgetRender({ block }: BlockRenderProps<NewsletterW>) {\n const [email, setEmail] = useState(\"\");\n return (\n <div className=\"xicms-widget xicms-widget--newsletter\">\n <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading ?? \"Nieuwsbrief\"}</h3>\n {block.text && <p className=\"xicms-widget__sub\" data-xicms-edit=\"text\">{block.text}</p>}\n {block.actionUrl ? (\n <form className=\"xicms-widget__form\" action={block.actionUrl} method=\"post\" target=\"_blank\" style={{ display: \"grid\", gap: \"0.6rem\" }}>\n <TextInput label=\"E-mailadres\" isLabelHidden type=\"email\" htmlName=\"EMAIL\" isRequired placeholder=\"je@email.nl\" value={email} onChange={setEmail} />\n <Button label={block.buttonLabel} variant=\"primary\" type=\"submit\">\n <span data-xicms-edit=\"buttonLabel\">{block.buttonLabel}</span>\n </Button>\n </form>\n ) : (\n <p className=\"xicms-widget__empty\">Stel een aanmeld-URL in.</p>\n )}\n </div>\n );\n}\nexport const newsletterWidget = defineBlock({\n type: \"newsletterWidget\",\n schema: NewsletterWidgetSchema,\n Render: NewsletterWidgetRender,\n label: \"Nieuwsbrief (compact)\",\n icon: \"✉️\",\n category: \"widget\",\n defaults: () => ({ heading: \"Blijf op de hoogte\", buttonLabel: \"Aanmelden\" }),\n});\n\n/* ── CTA (compact) ─────────────────────────────────────────────────────────── */\ntype CtaW = z.infer<typeof CtaWidgetSchema>;\nfunction CtaWidgetRender({ block }: BlockRenderProps<CtaW>) {\n if (!block.title && !block.text) return null;\n return (\n <div className=\"xicms-widget xicms-widget--cta\" style={block.backgroundColor ? { background: block.backgroundColor } : undefined}>\n {block.title && <h3 className=\"xicms-widget__title\" data-xicms-edit=\"title\">{block.title}</h3>}\n {block.text && <p className=\"xicms-widget__sub\" data-xicms-edit=\"text\">{block.text}</p>}\n {block.buttonLabel && (\n <Btn label={block.buttonLabel} href={block.buttonHref} variant=\"primary\" size=\"md\" editField=\"buttonLabel\" />\n )}\n </div>\n );\n}\nexport const ctaWidget = defineBlock({\n type: \"ctaWidget\",\n schema: CtaWidgetSchema,\n Render: CtaWidgetRender,\n label: \"Call-to-action (compact)\",\n icon: \"👉\",\n category: \"widget\",\n defaults: () => ({ title: \"Vragen?\", text: \"Neem gerust contact op.\", buttonLabel: \"Contact\", buttonHref: \"#contact\" }),\n});\n\n/* ── Galerij (compacte strip) ──────────────────────────────────────────────── */\ntype GalleryW = z.infer<typeof GalleryWidgetSchema>;\nfunction GalleryWidgetRender({ block }: BlockRenderProps<GalleryW>) {\n const items = (block.items ?? []).filter((i) => i.url);\n if (items.length === 0) return null;\n return (\n <div className=\"xicms-widget xicms-widget--gallery\">\n {block.heading && <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading}</h3>}\n <div className=\"xicms-widget__grid\" data-cols={block.columns}>\n {items.map((it, i) => (\n // eslint-disable-next-line @next/next/no-img-element\n <img key={i} className=\"xicms-widget__photo\" src={it.url} alt={it.alt ?? \"\"} loading=\"lazy\" />\n ))}\n </div>\n </div>\n );\n}\nexport const galleryWidget = defineBlock({\n type: \"galleryWidget\",\n schema: GalleryWidgetSchema,\n Render: GalleryWidgetRender,\n label: \"Fotostrip (compact)\",\n icon: \"🖼️\",\n category: \"widget\",\n defaults: () => ({ heading: \"Foto's\", columns: 3, items: [] }),\n});\n\n/* ── Review (compact) ──────────────────────────────────────────────────────── */\ntype TestimonialsW = z.infer<typeof TestimonialsWidgetSchema>;\nfunction TestimonialsWidgetRender({ block }: BlockRenderProps<TestimonialsW>) {\n // _i = index in de OORSPRONKELIJKE array — de lijst wordt gefilterd op quote.\n const items = (block.items ?? []).map((t, i) => ({ ...t, _i: i })).filter((t) => t.quote);\n if (items.length === 0) return null;\n return (\n <div className=\"xicms-widget xicms-widget--testimonial\">\n {block.heading && <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading}</h3>}\n <ul className=\"xicms-widget__list\">\n {items.map((t) => (\n <li key={t._i} className=\"xicms-widget__quote\">\n {typeof t.rating === \"number\" && (\n <span className=\"xicms-widget__stars\" aria-label={`${t.rating} van 5`}>{\"★\".repeat(t.rating)}{\"☆\".repeat(5 - t.rating)}</span>\n )}\n <p>“<span data-xicms-edit={`items.${t._i}.quote`}>{t.quote}</span>”</p>\n {t.author && <span className=\"xicms-widget__meta\">— <span data-xicms-edit={`items.${t._i}.author`}>{t.author}</span></span>}\n </li>\n ))}\n </ul>\n </div>\n );\n}\nexport const testimonialsWidget = defineBlock({\n type: \"testimonialsWidget\",\n schema: TestimonialsWidgetSchema,\n Render: TestimonialsWidgetRender,\n label: \"Review (compact)\",\n icon: \"⭐\",\n category: \"widget\",\n defaults: () => ({ heading: \"Wat klanten zeggen\", items: [{ quote: \"Echt een aanrader!\", author: \"Tevreden klant\", rating: 5 }] }),\n});\n\n/* ── Diensten (compact) ────────────────────────────────────────────────────── */\ntype CardsW = z.infer<typeof CardsWidgetSchema>;\nfunction CardsWidgetRender({ block }: BlockRenderProps<CardsW>) {\n const items = (block.items ?? []).filter((c) => c.title);\n if (items.length === 0) return null;\n return (\n <div className=\"xicms-widget xicms-widget--cards\">\n {block.heading && <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading}</h3>}\n <ul className=\"xicms-widget__list\">\n {items.map((c, i) => {\n const inner = (\n <>\n {c.icon && <span className=\"xicms-widget__cardicon\" aria-hidden=\"true\">{c.icon}</span>}\n <span>\n <span className=\"xicms-widget__link\">{c.title}</span>\n {c.text && <span className=\"xicms-widget__sub\">{c.text}</span>}\n </span>\n </>\n );\n return (\n <li key={i} className=\"xicms-widget__item xicms-widget__item--card\">\n {c.href ? <a href={c.href} className=\"xicms-widget__cardlink\">{inner}</a> : inner}\n </li>\n );\n })}\n </ul>\n </div>\n );\n}\nexport const cardsWidget = defineBlock({\n type: \"cardsWidget\",\n schema: CardsWidgetSchema,\n Render: CardsWidgetRender,\n label: \"Diensten (compact)\",\n icon: \"🧩\",\n category: \"widget\",\n defaults: () => ({ heading: \"Uitgelicht\", items: [{ icon: \"⭐\", title: \"Dienst\", text: \"Korte omschrijving.\" }] }),\n});\n\n/* ── Downloads (compact) ───────────────────────────────────────────────────── */\ntype DownloadsW = z.infer<typeof DownloadsWidgetSchema>;\nfunction DownloadsWidgetRender({ block }: BlockRenderProps<DownloadsW>) {\n // _i = index in de OORSPRONKELIJKE array — de lijst wordt gefilterd én afgekapt op `limit`.\n const items = (block.items ?? []).map((d, i) => ({ ...d, _i: i })).filter((d) => d.label && d.href).slice(0, block.limit);\n if (items.length === 0) return null;\n return (\n <div className=\"xicms-widget xicms-widget--downloads\">\n <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading ?? \"Downloads\"}</h3>\n <ul className=\"xicms-widget__list\">\n {items.map((d) => (\n <li key={d._i} className=\"xicms-widget__item\">\n <a className=\"xicms-widget__link\" href={d.href} download>\n <span aria-hidden=\"true\">📄</span> <span data-xicms-edit={`items.${d._i}.label`}>{d.label}</span>\n </a>\n {d.meta && <span className=\"xicms-widget__meta\" data-xicms-edit={`items.${d._i}.meta`}>{d.meta}</span>}\n </li>\n ))}\n </ul>\n </div>\n );\n}\nexport const downloadsWidget = defineBlock({\n type: \"downloadsWidget\",\n schema: DownloadsWidgetSchema,\n Render: DownloadsWidgetRender,\n label: \"Downloads (compact)\",\n icon: \"📥\",\n category: \"widget\",\n defaults: () => ({ heading: \"Downloads\", limit: 5, items: [] }),\n});\n\n/* ── Aftelteller (compact) ─────────────────────────────────────────────────── */\ntype CountdownW = z.infer<typeof CountdownWidgetSchema>;\nfunction CountdownWidgetRender({ block }: BlockRenderProps<CountdownW>) {\n const r = useCountdown(block.target);\n if (!block.target) return null;\n return (\n <div className=\"xicms-widget xicms-widget--countdown\">\n {block.heading && <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading}</h3>}\n {r === null ? (\n <p className=\"xicms-widget__empty\" aria-hidden=\"true\">…</p>\n ) : r.done ? (\n <p className=\"xicms-countdown__expired\" data-xicms-edit=\"expiredText\">{block.expiredText}</p>\n ) : (\n <CountdownDigits r={r} showLabels />\n )}\n </div>\n );\n}\nexport const countdownWidget = defineBlock({\n type: \"countdownWidget\",\n schema: CountdownWidgetSchema,\n Render: CountdownWidgetRender,\n label: \"Aftelteller (compact)\",\n icon: \"⏳\",\n category: \"widget\",\n defaults: () => ({ heading: \"Aftellen\", target: \"\", expiredText: \"Het is zover!\" }),\n});\n\n// Let op: exporteer GEEN aggregaat-array vanuit dit \"use client\"-bestand. Een array die hier\n// wordt opgebouwd is niet server-importeerbaar (de individuele block-exports wél). De volledige\n// lijst staat in blocks/builtins/index.ts.\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/blocks/builtins/Widgets.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport type { z } from \"zod\";\nimport { Onvoltooid } from \"./lib/Onvoltooid\";\nimport {\n NewsWidgetSchema,\n AgendaWidgetSchema,\n OpeningHoursWidgetSchema,\n ContactWidgetSchema,\n SocialWidgetSchema,\n NewsletterWidgetSchema,\n CtaWidgetSchema,\n GalleryWidgetSchema,\n TestimonialsWidgetSchema,\n CardsWidgetSchema,\n DownloadsWidgetSchema,\n CountdownWidgetSchema,\n} from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { Btn } from \"../ui\";\nimport { useNews } from \"../../components/News\";\nimport { selectAgendaEvents, formatEventDate } from \"./Agenda\";\nimport { parseDays } from \"./lib/openingHours\";\nimport { useCountdown, CountdownDigits } from \"./Countdown\";\nimport { TextInput } from \"@astryxdesign/core/TextInput\";\nimport { Button } from \"@astryxdesign/core/Button\";\n\n/**\n * Widgets = compacte zijbalk-varianten van de modules. Elke widget hergebruikt de gegevens en\n * logica van de volwaardige versie (zelfde nieuws-collectie, zelfde agenda-selectie, zelfde\n * countdown-hook) en rendert die alleen compacter. Plaats ze in het \"Met zijbalk\"-blok of in een\n * smalle kolom naast je hoofdinhoud.\n */\n\n/* ── Laatste nieuws ────────────────────────────────────────────────────────── */\ntype NewsW = z.infer<typeof NewsWidgetSchema>;\nfunction NewsWidgetRender({ block }: BlockRenderProps<NewsW>) {\n const { articles, loading } = useNews({ max: block.limit });\n const shown = articles.slice(0, block.limit);\n return (\n <div className=\"xicms-widget xicms-widget--news\">\n <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading ?? \"Laatste nieuws\"}</h3>\n {loading ? (\n <p className=\"xicms-widget__empty\">Nieuws laden…</p>\n ) : shown.length === 0 ? (\n <p className=\"xicms-widget__empty\">Nog geen nieuws.</p>\n ) : (\n <ul className=\"xicms-widget__list\">\n {shown.map((a) => (\n <li key={a.id} className=\"xicms-widget__item\">\n {block.showImages && a.coverUrl && (\n // eslint-disable-next-line @next/next/no-img-element\n <img className=\"xicms-widget__thumb\" src={a.coverUrl} alt=\"\" loading=\"lazy\" />\n )}\n <div>\n <a className=\"xicms-widget__link\" href={`${block.basePath}/${a.slug}`}>{a.title}</a>\n <span className=\"xicms-widget__meta\">{a.date}</span>\n </div>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\nexport const newsWidget = defineBlock({\n type: \"newsWidget\",\n schema: NewsWidgetSchema,\n Render: NewsWidgetRender,\n label: \"Laatste nieuws\",\n icon: \"🗞️\",\n category: \"widget\",\n defaults: () => ({ heading: \"Laatste nieuws\", limit: 5, basePath: \"/nieuws\", showImages: false }),\n});\n\n/* ── Komende agenda ────────────────────────────────────────────────────────── */\ntype AgendaW = z.infer<typeof AgendaWidgetSchema>;\nfunction AgendaWidgetRender({ block }: BlockRenderProps<AgendaW>) {\n const events = selectAgendaEvents((block.events ?? []).map((e, i) => ({ ...e, _i: i })), { hidePast: block.hidePast, limit: block.limit });\n return (\n <div className=\"xicms-widget xicms-widget--agenda\">\n <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading ?? \"Komende evenementen\"}</h3>\n {events.length === 0 ? (\n <p className=\"xicms-widget__empty\">Geen geplande evenementen.</p>\n ) : (\n <ul className=\"xicms-widget__list\">\n {events.map((e) => (\n <li key={e._i} className=\"xicms-widget__item xicms-widget__item--event\">\n <time className=\"xicms-widget__meta\" dateTime={e.start}>{formatEventDate(e.start)}</time>\n <span className=\"xicms-widget__link\">\n {e.url\n ? <a href={e.url} data-xicms-edit={`events.${e._i}.title`}>{e.title}</a>\n : <span data-xicms-edit={`events.${e._i}.title`}>{e.title}</span>}\n </span>\n {e.location && <span className=\"xicms-widget__sub\" data-xicms-edit={`events.${e._i}.location`}>{e.location}</span>}\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\nexport const agendaWidget = defineBlock({\n type: \"agendaWidget\",\n schema: AgendaWidgetSchema,\n Render: AgendaWidgetRender,\n label: \"Komende agenda\",\n icon: \"📅\",\n category: \"widget\",\n defaults: () => ({ heading: \"Komende evenementen\", limit: 5, events: [], hidePast: true }),\n});\n\n/* ── Openingstijden (vandaag gemarkeerd) ───────────────────────────────────── */\ntype OpeningW = z.infer<typeof OpeningHoursWidgetSchema>;\nfunction OpeningHoursWidgetRender({ block }: BlockRenderProps<OpeningW>) {\n // \"Vandaag\" client-side bepalen (voorkomt hydration-mismatch t.o.v. de servertijd).\n const [todayIdx, setTodayIdx] = useState<number | null>(null);\n useEffect(() => setTodayIdx(new Date().getDay()), []);\n const rows = block.rows ?? [];\n return (\n <div className=\"xicms-widget xicms-widget--hours\">\n <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading ?? \"Openingstijden\"}</h3>\n <table className=\"xicms-widget__hours\">\n <tbody>\n {rows.map((r, i) => {\n // parseDays begrijpt ook bereiken (\"Ma-vr\", \"Maandag t/m vrijdag\") - een woensdag\n // hoort dan net zo goed gemarkeerd als de letterlijk genoemde dagen.\n const isToday =\n block.highlightToday && todayIdx !== null && parseDays(r.day).includes(todayIdx);\n return (\n <tr key={i} className={isToday ? \"xicms-widget__hours-today\" : undefined}>\n <th scope=\"row\" data-xicms-edit={`rows.${i}.day`}>{r.day}</th>\n <td data-xicms-edit={`rows.${i}.hours`}>{r.hours}</td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n );\n}\nexport const openingHoursWidget = defineBlock({\n type: \"openingHoursWidget\",\n schema: OpeningHoursWidgetSchema,\n Render: OpeningHoursWidgetRender,\n label: \"Openingstijden (compact)\",\n icon: \"🕒\",\n category: \"widget\",\n defaults: () => ({\n heading: \"Openingstijden\",\n highlightToday: true,\n rows: [\n { day: \"Maandag t/m vrijdag\", hours: \"09:00 – 17:00\" },\n { day: \"Zaterdag\", hours: \"10:00 – 16:00\" },\n { day: \"Zondag\", hours: \"Gesloten\" },\n ],\n }),\n});\n\n/* ── Contact (compact) ─────────────────────────────────────────────────────── */\ntype ContactW = z.infer<typeof ContactWidgetSchema>;\nfunction ContactWidgetRender({ block }: BlockRenderProps<ContactW>) {\n if (!block.address && !block.phone && !block.email) return null;\n return (\n <div className=\"xicms-widget xicms-widget--contact\">\n <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading ?? \"Contact\"}</h3>\n <ul className=\"xicms-widget__list\">\n {block.address && <li className=\"xicms-widget__item\" data-xicms-edit=\"address\">{block.address}</li>}\n {block.phone && (\n <li className=\"xicms-widget__item\"><a href={`tel:${block.phone.replace(/\\s+/g, \"\")}`} data-xicms-edit=\"phone\">{block.phone}</a></li>\n )}\n {block.email && (\n <li className=\"xicms-widget__item\"><a href={`mailto:${block.email}`} data-xicms-edit=\"email\">{block.email}</a></li>\n )}\n </ul>\n </div>\n );\n}\nexport const contactWidget = defineBlock({\n type: \"contactWidget\",\n schema: ContactWidgetSchema,\n Render: ContactWidgetRender,\n label: \"Contact (compact)\",\n icon: \"📇\",\n category: \"widget\",\n defaults: () => ({ heading: \"Contact\" }),\n});\n\n/* ── Social (compact) ──────────────────────────────────────────────────────── */\ntype SocialW = z.infer<typeof SocialWidgetSchema>;\nfunction SocialWidgetRender({ block }: BlockRenderProps<SocialW>) {\n // _i = index in de OORSPRONKELIJKE array — de lijst wordt gefilterd op href && platform.\n const items = (block.items ?? []).map((it, i) => ({ ...it, _i: i })).filter((i) => i.href && i.platform);\n if (items.length === 0) return null;\n return (\n <div className=\"xicms-widget xicms-widget--social\">\n {block.heading && <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading}</h3>}\n <ul className=\"xicms-widget__social\">\n {items.map((it) => (\n <li key={it._i}><a href={it.href} rel=\"noopener noreferrer\" target=\"_blank\" data-xicms-edit={`items.${it._i}.platform`}>{it.platform}</a></li>\n ))}\n </ul>\n </div>\n );\n}\nexport const socialWidget = defineBlock({\n type: \"socialWidget\",\n schema: SocialWidgetSchema,\n Render: SocialWidgetRender,\n label: \"Social (compact)\",\n icon: \"🔗\",\n category: \"widget\",\n defaults: () => ({ heading: \"Volg ons\", items: [{ platform: \"Instagram\", href: \"\" }] }),\n});\n\n/* ── Nieuwsbrief (compact) ─────────────────────────────────────────────────── */\ntype NewsletterW = z.infer<typeof NewsletterWidgetSchema>;\nfunction NewsletterWidgetRender({ block }: BlockRenderProps<NewsletterW>) {\n const [email, setEmail] = useState(\"\");\n return (\n <div className=\"xicms-widget xicms-widget--newsletter\">\n <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading ?? \"Nieuwsbrief\"}</h3>\n {block.text && <p className=\"xicms-widget__sub\" data-xicms-edit=\"text\">{block.text}</p>}\n {block.actionUrl ? (\n <form className=\"xicms-widget__form\" action={block.actionUrl} method=\"post\" target=\"_blank\" style={{ display: \"grid\", gap: \"0.6rem\" }}>\n <TextInput label=\"E-mailadres\" isLabelHidden type=\"email\" htmlName=\"EMAIL\" isRequired placeholder=\"je@email.nl\" value={email} onChange={setEmail} />\n <Button label={block.buttonLabel} variant=\"primary\" type=\"submit\">\n <span data-xicms-edit=\"buttonLabel\">{block.buttonLabel}</span>\n </Button>\n </form>\n ) : (\n <Onvoltooid>Deze aanmeldwidget mist nog een aanmeld-URL (tandwiel). Bezoekers zien dit blok niet.</Onvoltooid>\n )}\n </div>\n );\n}\nexport const newsletterWidget = defineBlock({\n type: \"newsletterWidget\",\n schema: NewsletterWidgetSchema,\n Render: NewsletterWidgetRender,\n label: \"Nieuwsbrief (compact)\",\n icon: \"✉️\",\n category: \"widget\",\n defaults: () => ({ heading: \"Blijf op de hoogte\", buttonLabel: \"Aanmelden\" }),\n});\n\n/* ── CTA (compact) ─────────────────────────────────────────────────────────── */\ntype CtaW = z.infer<typeof CtaWidgetSchema>;\nfunction CtaWidgetRender({ block }: BlockRenderProps<CtaW>) {\n if (!block.title && !block.text) return null;\n return (\n <div className=\"xicms-widget xicms-widget--cta\" style={block.backgroundColor ? { background: block.backgroundColor } : undefined}>\n {block.title && <h3 className=\"xicms-widget__title\" data-xicms-edit=\"title\">{block.title}</h3>}\n {block.text && <p className=\"xicms-widget__sub\" data-xicms-edit=\"text\">{block.text}</p>}\n {block.buttonLabel && (\n <Btn label={block.buttonLabel} href={block.buttonHref} variant=\"primary\" size=\"md\" editField=\"buttonLabel\" />\n )}\n </div>\n );\n}\nexport const ctaWidget = defineBlock({\n type: \"ctaWidget\",\n schema: CtaWidgetSchema,\n Render: CtaWidgetRender,\n label: \"Call-to-action (compact)\",\n icon: \"👉\",\n category: \"widget\",\n defaults: () => ({ title: \"Vragen?\", text: \"Neem gerust contact op.\", buttonLabel: \"Contact\", buttonHref: \"#contact\" }),\n});\n\n/* ── Galerij (compacte strip) ──────────────────────────────────────────────── */\ntype GalleryW = z.infer<typeof GalleryWidgetSchema>;\nfunction GalleryWidgetRender({ block }: BlockRenderProps<GalleryW>) {\n const items = (block.items ?? []).filter((i) => i.url);\n if (items.length === 0) return null;\n return (\n <div className=\"xicms-widget xicms-widget--gallery\">\n {block.heading && <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading}</h3>}\n <div className=\"xicms-widget__grid\" data-cols={block.columns}>\n {items.map((it, i) => (\n // eslint-disable-next-line @next/next/no-img-element\n <img key={i} className=\"xicms-widget__photo\" src={it.url} alt={it.alt ?? \"\"} loading=\"lazy\" />\n ))}\n </div>\n </div>\n );\n}\nexport const galleryWidget = defineBlock({\n type: \"galleryWidget\",\n schema: GalleryWidgetSchema,\n Render: GalleryWidgetRender,\n label: \"Fotostrip (compact)\",\n icon: \"🖼️\",\n category: \"widget\",\n defaults: () => ({ heading: \"Foto's\", columns: 3, items: [] }),\n});\n\n/* ── Review (compact) ──────────────────────────────────────────────────────── */\ntype TestimonialsW = z.infer<typeof TestimonialsWidgetSchema>;\nfunction TestimonialsWidgetRender({ block }: BlockRenderProps<TestimonialsW>) {\n // _i = index in de OORSPRONKELIJKE array — de lijst wordt gefilterd op quote.\n const items = (block.items ?? []).map((t, i) => ({ ...t, _i: i })).filter((t) => t.quote);\n if (items.length === 0) return null;\n return (\n <div className=\"xicms-widget xicms-widget--testimonial\">\n {block.heading && <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading}</h3>}\n <ul className=\"xicms-widget__list\">\n {items.map((t) => (\n <li key={t._i} className=\"xicms-widget__quote\">\n {typeof t.rating === \"number\" && (\n <span className=\"xicms-widget__stars\" aria-label={`${t.rating} van 5`}>{\"★\".repeat(t.rating)}{\"☆\".repeat(5 - t.rating)}</span>\n )}\n <p>“<span data-xicms-edit={`items.${t._i}.quote`}>{t.quote}</span>”</p>\n {t.author && <span className=\"xicms-widget__meta\">— <span data-xicms-edit={`items.${t._i}.author`}>{t.author}</span></span>}\n </li>\n ))}\n </ul>\n </div>\n );\n}\nexport const testimonialsWidget = defineBlock({\n type: \"testimonialsWidget\",\n schema: TestimonialsWidgetSchema,\n Render: TestimonialsWidgetRender,\n label: \"Review (compact)\",\n icon: \"⭐\",\n category: \"widget\",\n defaults: () => ({ heading: \"Wat klanten zeggen\", items: [{ quote: \"Echt een aanrader!\", author: \"Tevreden klant\", rating: 5 }] }),\n});\n\n/* ── Diensten (compact) ────────────────────────────────────────────────────── */\ntype CardsW = z.infer<typeof CardsWidgetSchema>;\nfunction CardsWidgetRender({ block }: BlockRenderProps<CardsW>) {\n const items = (block.items ?? []).filter((c) => c.title);\n if (items.length === 0) return null;\n return (\n <div className=\"xicms-widget xicms-widget--cards\">\n {block.heading && <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading}</h3>}\n <ul className=\"xicms-widget__list\">\n {items.map((c, i) => {\n const inner = (\n <>\n {c.icon && <span className=\"xicms-widget__cardicon\" aria-hidden=\"true\">{c.icon}</span>}\n <span>\n <span className=\"xicms-widget__link\">{c.title}</span>\n {c.text && <span className=\"xicms-widget__sub\">{c.text}</span>}\n </span>\n </>\n );\n return (\n <li key={i} className=\"xicms-widget__item xicms-widget__item--card\">\n {c.href ? <a href={c.href} className=\"xicms-widget__cardlink\">{inner}</a> : inner}\n </li>\n );\n })}\n </ul>\n </div>\n );\n}\nexport const cardsWidget = defineBlock({\n type: \"cardsWidget\",\n schema: CardsWidgetSchema,\n Render: CardsWidgetRender,\n label: \"Diensten (compact)\",\n icon: \"🧩\",\n category: \"widget\",\n defaults: () => ({ heading: \"Uitgelicht\", items: [{ icon: \"⭐\", title: \"Dienst\", text: \"Korte omschrijving.\" }] }),\n});\n\n/* ── Downloads (compact) ───────────────────────────────────────────────────── */\ntype DownloadsW = z.infer<typeof DownloadsWidgetSchema>;\nfunction DownloadsWidgetRender({ block }: BlockRenderProps<DownloadsW>) {\n // _i = index in de OORSPRONKELIJKE array — de lijst wordt gefilterd én afgekapt op `limit`.\n const items = (block.items ?? []).map((d, i) => ({ ...d, _i: i })).filter((d) => d.label && d.href).slice(0, block.limit);\n if (items.length === 0) return null;\n return (\n <div className=\"xicms-widget xicms-widget--downloads\">\n <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading ?? \"Downloads\"}</h3>\n <ul className=\"xicms-widget__list\">\n {items.map((d) => (\n <li key={d._i} className=\"xicms-widget__item\">\n <a className=\"xicms-widget__link\" href={d.href} download>\n <span aria-hidden=\"true\">📄</span> <span data-xicms-edit={`items.${d._i}.label`}>{d.label}</span>\n </a>\n {d.meta && <span className=\"xicms-widget__meta\" data-xicms-edit={`items.${d._i}.meta`}>{d.meta}</span>}\n </li>\n ))}\n </ul>\n </div>\n );\n}\nexport const downloadsWidget = defineBlock({\n type: \"downloadsWidget\",\n schema: DownloadsWidgetSchema,\n Render: DownloadsWidgetRender,\n label: \"Downloads (compact)\",\n icon: \"📥\",\n category: \"widget\",\n defaults: () => ({ heading: \"Downloads\", limit: 5, items: [] }),\n});\n\n/* ── Aftelteller (compact) ─────────────────────────────────────────────────── */\ntype CountdownW = z.infer<typeof CountdownWidgetSchema>;\nfunction CountdownWidgetRender({ block }: BlockRenderProps<CountdownW>) {\n const r = useCountdown(block.target);\n if (!block.target) return null;\n return (\n <div className=\"xicms-widget xicms-widget--countdown\">\n {block.heading && <h3 className=\"xicms-widget__title\" data-xicms-edit=\"heading\">{block.heading}</h3>}\n {r === null ? (\n <p className=\"xicms-widget__empty\" aria-hidden=\"true\">…</p>\n ) : r.done ? (\n <p className=\"xicms-countdown__expired\" data-xicms-edit=\"expiredText\">{block.expiredText}</p>\n ) : (\n <CountdownDigits r={r} showLabels />\n )}\n </div>\n );\n}\nexport const countdownWidget = defineBlock({\n type: \"countdownWidget\",\n schema: CountdownWidgetSchema,\n Render: CountdownWidgetRender,\n label: \"Aftelteller (compact)\",\n icon: \"⏳\",\n category: \"widget\",\n defaults: () => ({ heading: \"Aftellen\", target: \"\", expiredText: \"Het is zover!\" }),\n});\n\n// Let op: exporteer GEEN aggregaat-array vanuit dit \"use client\"-bestand. Een array die hier\n// wordt opgebouwd is niet server-importeerbaar (de individuele block-exports wél). De volledige\n// lijst staat in blocks/builtins/index.ts.\n"],"mappings":";AA0CM,SA4SM,UA5SN,KAaQ,YAbR;AAxCN,SAAS,WAAW,gBAAgB;AAEpC,SAAS,kBAAkB;AAC3B;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,OACK;AACP,SAAS,mBAA0C;AACnD,SAAS,WAAW;AACpB,SAAS,eAAe;AACxB,SAAS,oBAAoB,uBAAuB;AACpD,SAAS,iBAAiB;AAC1B,SAAS,cAAc,uBAAuB;AAC9C,SAAS,iBAAiB;AAC1B,SAAS,cAAc;AAWvB,SAAS,iBAAiB,EAAE,MAAM,GAA4B;AAC5D,QAAM,EAAE,UAAU,QAAQ,IAAI,QAAQ,EAAE,KAAK,MAAM,MAAM,CAAC;AAC1D,QAAM,QAAQ,SAAS,MAAM,GAAG,MAAM,KAAK;AAC3C,SACE,qBAAC,SAAI,WAAU,mCACb;AAAA,wBAAC,QAAG,WAAU,uBAAsB,mBAAgB,WAAW,gBAAM,WAAW,kBAAiB;AAAA,IAChG,UACC,oBAAC,OAAE,WAAU,uBAAsB,gCAAa,IAC9C,MAAM,WAAW,IACnB,oBAAC,OAAE,WAAU,uBAAsB,8BAAgB,IAEnD,oBAAC,QAAG,WAAU,sBACX,gBAAM,IAAI,CAAC,MACV,qBAAC,QAAc,WAAU,sBACtB;AAAA,YAAM,cAAc,EAAE;AAAA,MAErB,oBAAC,SAAI,WAAU,uBAAsB,KAAK,EAAE,UAAU,KAAI,IAAG,SAAQ,QAAO;AAAA,MAE9E,qBAAC,SACC;AAAA,4BAAC,OAAE,WAAU,sBAAqB,MAAM,GAAG,MAAM,QAAQ,IAAI,EAAE,IAAI,IAAK,YAAE,OAAM;AAAA,QAChF,oBAAC,UAAK,WAAU,sBAAsB,YAAE,MAAK;AAAA,SAC/C;AAAA,SARO,EAAE,EASX,CACD,GACH;AAAA,KAEJ;AAEJ;AACO,MAAM,aAAa,YAAY;AAAA,EACpC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU,OAAO,EAAE,SAAS,kBAAkB,OAAO,GAAG,UAAU,WAAW,YAAY,MAAM;AACjG,CAAC;AAID,SAAS,mBAAmB,EAAE,MAAM,GAA8B;AAChE,QAAM,SAAS,oBAAoB,MAAM,UAAU,CAAC,GAAG,IAAI,CAAC,GAAG,OAAO,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,UAAU,MAAM,UAAU,OAAO,MAAM,MAAM,CAAC;AACzI,SACE,qBAAC,SAAI,WAAU,qCACb;AAAA,wBAAC,QAAG,WAAU,uBAAsB,mBAAgB,WAAW,gBAAM,WAAW,uBAAsB;AAAA,IACrG,OAAO,WAAW,IACjB,oBAAC,OAAE,WAAU,uBAAsB,wCAA0B,IAE7D,oBAAC,QAAG,WAAU,sBACX,iBAAO,IAAI,CAAC,MACX,qBAAC,QAAc,WAAU,gDACvB;AAAA,0BAAC,UAAK,WAAU,sBAAqB,UAAU,EAAE,OAAQ,0BAAgB,EAAE,KAAK,GAAE;AAAA,MAClF,oBAAC,UAAK,WAAU,sBACb,YAAE,MACC,oBAAC,OAAE,MAAM,EAAE,KAAK,mBAAiB,UAAU,EAAE,EAAE,UAAW,YAAE,OAAM,IAClE,oBAAC,UAAK,mBAAiB,UAAU,EAAE,EAAE,UAAW,YAAE,OAAM,GAC9D;AAAA,MACC,EAAE,YAAY,oBAAC,UAAK,WAAU,qBAAoB,mBAAiB,UAAU,EAAE,EAAE,aAAc,YAAE,UAAS;AAAA,SAPpG,EAAE,EAQX,CACD,GACH;AAAA,KAEJ;AAEJ;AACO,MAAM,eAAe,YAAY;AAAA,EACtC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU,OAAO,EAAE,SAAS,uBAAuB,OAAO,GAAG,QAAQ,CAAC,GAAG,UAAU,KAAK;AAC1F,CAAC;AAID,SAAS,yBAAyB,EAAE,MAAM,GAA+B;AAEvE,QAAM,CAAC,UAAU,WAAW,IAAI,SAAwB,IAAI;AAC5D,YAAU,MAAM,aAAY,oBAAI,KAAK,GAAE,OAAO,CAAC,GAAG,CAAC,CAAC;AACpD,QAAM,OAAO,MAAM,QAAQ,CAAC;AAC5B,SACE,qBAAC,SAAI,WAAU,oCACb;AAAA,wBAAC,QAAG,WAAU,uBAAsB,mBAAgB,WAAW,gBAAM,WAAW,kBAAiB;AAAA,IACjG,oBAAC,WAAM,WAAU,uBACf,8BAAC,WACE,eAAK,IAAI,CAAC,GAAG,MAAM;AAGlB,YAAM,UACJ,MAAM,kBAAkB,aAAa,QAAQ,UAAU,EAAE,GAAG,EAAE,SAAS,QAAQ;AACjF,aACE,qBAAC,QAAW,WAAW,UAAU,8BAA8B,QAC7D;AAAA,4BAAC,QAAG,OAAM,OAAM,mBAAiB,QAAQ,CAAC,QAAS,YAAE,KAAI;AAAA,QACzD,oBAAC,QAAG,mBAAiB,QAAQ,CAAC,UAAW,YAAE,OAAM;AAAA,WAF1C,CAGT;AAAA,IAEJ,CAAC,GACH,GACF;AAAA,KACF;AAEJ;AACO,MAAM,qBAAqB,YAAY;AAAA,EAC5C,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU,OAAO;AAAA,IACf,SAAS;AAAA,IACT,gBAAgB;AAAA,IAChB,MAAM;AAAA,MACJ,EAAE,KAAK,uBAAuB,OAAO,qBAAgB;AAAA,MACrD,EAAE,KAAK,YAAY,OAAO,qBAAgB;AAAA,MAC1C,EAAE,KAAK,UAAU,OAAO,WAAW;AAAA,IACrC;AAAA,EACF;AACF,CAAC;AAID,SAAS,oBAAoB,EAAE,MAAM,GAA+B;AAClE,MAAI,CAAC,MAAM,WAAW,CAAC,MAAM,SAAS,CAAC,MAAM,MAAO,QAAO;AAC3D,SACE,qBAAC,SAAI,WAAU,sCACb;AAAA,wBAAC,QAAG,WAAU,uBAAsB,mBAAgB,WAAW,gBAAM,WAAW,WAAU;AAAA,IAC1F,qBAAC,QAAG,WAAU,sBACX;AAAA,YAAM,WAAW,oBAAC,QAAG,WAAU,sBAAqB,mBAAgB,WAAW,gBAAM,SAAQ;AAAA,MAC7F,MAAM,SACL,oBAAC,QAAG,WAAU,sBAAqB,8BAAC,OAAE,MAAM,OAAO,MAAM,MAAM,QAAQ,QAAQ,EAAE,CAAC,IAAI,mBAAgB,SAAS,gBAAM,OAAM,GAAI;AAAA,MAEhI,MAAM,SACL,oBAAC,QAAG,WAAU,sBAAqB,8BAAC,OAAE,MAAM,UAAU,MAAM,KAAK,IAAI,mBAAgB,SAAS,gBAAM,OAAM,GAAI;AAAA,OAElH;AAAA,KACF;AAEJ;AACO,MAAM,gBAAgB,YAAY;AAAA,EACvC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU,OAAO,EAAE,SAAS,UAAU;AACxC,CAAC;AAID,SAAS,mBAAmB,EAAE,MAAM,GAA8B;AAEhE,QAAM,SAAS,MAAM,SAAS,CAAC,GAAG,IAAI,CAAC,IAAI,OAAO,EAAE,GAAG,IAAI,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ;AACvG,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SACE,qBAAC,SAAI,WAAU,qCACZ;AAAA,UAAM,WAAW,oBAAC,QAAG,WAAU,uBAAsB,mBAAgB,WAAW,gBAAM,SAAQ;AAAA,IAC/F,oBAAC,QAAG,WAAU,wBACX,gBAAM,IAAI,CAAC,OACV,oBAAC,QAAe,8BAAC,OAAE,MAAM,GAAG,MAAM,KAAI,uBAAsB,QAAO,UAAS,mBAAiB,SAAS,GAAG,EAAE,aAAc,aAAG,UAAS,KAA5H,GAAG,EAA6H,CAC1I,GACH;AAAA,KACF;AAEJ;AACO,MAAM,eAAe,YAAY;AAAA,EACtC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU,OAAO,EAAE,SAAS,YAAY,OAAO,CAAC,EAAE,UAAU,aAAa,MAAM,GAAG,CAAC,EAAE;AACvF,CAAC;AAID,SAAS,uBAAuB,EAAE,MAAM,GAAkC;AACxE,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,SACE,qBAAC,SAAI,WAAU,yCACb;AAAA,wBAAC,QAAG,WAAU,uBAAsB,mBAAgB,WAAW,gBAAM,WAAW,eAAc;AAAA,IAC7F,MAAM,QAAQ,oBAAC,OAAE,WAAU,qBAAoB,mBAAgB,QAAQ,gBAAM,MAAK;AAAA,IAClF,MAAM,YACL,qBAAC,UAAK,WAAU,sBAAqB,QAAQ,MAAM,WAAW,QAAO,QAAO,QAAO,UAAS,OAAO,EAAE,SAAS,QAAQ,KAAK,SAAS,GAClI;AAAA,0BAAC,aAAU,OAAM,eAAc,eAAa,MAAC,MAAK,SAAQ,UAAS,SAAQ,YAAU,MAAC,aAAY,eAAc,OAAO,OAAO,UAAU,UAAU;AAAA,MAClJ,oBAAC,UAAO,OAAO,MAAM,aAAa,SAAQ,WAAU,MAAK,UACvD,8BAAC,UAAK,mBAAgB,eAAe,gBAAM,aAAY,GACzD;AAAA,OACF,IAEA,oBAAC,cAAW,mGAAqF;AAAA,KAErG;AAEJ;AACO,MAAM,mBAAmB,YAAY;AAAA,EAC1C,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU,OAAO,EAAE,SAAS,sBAAsB,aAAa,YAAY;AAC7E,CAAC;AAID,SAAS,gBAAgB,EAAE,MAAM,GAA2B;AAC1D,MAAI,CAAC,MAAM,SAAS,CAAC,MAAM,KAAM,QAAO;AACxC,SACE,qBAAC,SAAI,WAAU,kCAAiC,OAAO,MAAM,kBAAkB,EAAE,YAAY,MAAM,gBAAgB,IAAI,QACpH;AAAA,UAAM,SAAS,oBAAC,QAAG,WAAU,uBAAsB,mBAAgB,SAAS,gBAAM,OAAM;AAAA,IACxF,MAAM,QAAQ,oBAAC,OAAE,WAAU,qBAAoB,mBAAgB,QAAQ,gBAAM,MAAK;AAAA,IAClF,MAAM,eACL,oBAAC,OAAI,OAAO,MAAM,aAAa,MAAM,MAAM,YAAY,SAAQ,WAAU,MAAK,MAAK,WAAU,eAAc;AAAA,KAE/G;AAEJ;AACO,MAAM,YAAY,YAAY;AAAA,EACnC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU,OAAO,EAAE,OAAO,WAAW,MAAM,2BAA2B,aAAa,WAAW,YAAY,WAAW;AACvH,CAAC;AAID,SAAS,oBAAoB,EAAE,MAAM,GAA+B;AAClE,QAAM,SAAS,MAAM,SAAS,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG;AACrD,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SACE,qBAAC,SAAI,WAAU,sCACZ;AAAA,UAAM,WAAW,oBAAC,QAAG,WAAU,uBAAsB,mBAAgB,WAAW,gBAAM,SAAQ;AAAA,IAC/F,oBAAC,SAAI,WAAU,sBAAqB,aAAW,MAAM,SAClD,gBAAM,IAAI,CAAC,IAAI;AAAA;AAAA,MAEd,oBAAC,SAAY,WAAU,uBAAsB,KAAK,GAAG,KAAK,KAAK,GAAG,OAAO,IAAI,SAAQ,UAA3E,CAAkF;AAAA,KAC7F,GACH;AAAA,KACF;AAEJ;AACO,MAAM,gBAAgB,YAAY;AAAA,EACvC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU,OAAO,EAAE,SAAS,UAAU,SAAS,GAAG,OAAO,CAAC,EAAE;AAC9D,CAAC;AAID,SAAS,yBAAyB,EAAE,MAAM,GAAoC;AAE5E,QAAM,SAAS,MAAM,SAAS,CAAC,GAAG,IAAI,CAAC,GAAG,OAAO,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK;AACxF,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SACE,qBAAC,SAAI,WAAU,0CACZ;AAAA,UAAM,WAAW,oBAAC,QAAG,WAAU,uBAAsB,mBAAgB,WAAW,gBAAM,SAAQ;AAAA,IAC/F,oBAAC,QAAG,WAAU,sBACX,gBAAM,IAAI,CAAC,MACV,qBAAC,QAAc,WAAU,uBACtB;AAAA,aAAO,EAAE,WAAW,YACnB,qBAAC,UAAK,WAAU,uBAAsB,cAAY,GAAG,EAAE,MAAM,UAAW;AAAA,iBAAI,OAAO,EAAE,MAAM;AAAA,QAAG,SAAI,OAAO,IAAI,EAAE,MAAM;AAAA,SAAE;AAAA,MAEzH,qBAAC,OAAE;AAAA;AAAA,QAAC,oBAAC,UAAK,mBAAiB,SAAS,EAAE,EAAE,UAAW,YAAE,OAAM;AAAA,QAAO;AAAA,SAAC;AAAA,MAClE,EAAE,UAAU,qBAAC,UAAK,WAAU,sBAAqB;AAAA;AAAA,QAAE,oBAAC,UAAK,mBAAiB,SAAS,EAAE,EAAE,WAAY,YAAE,QAAO;AAAA,SAAO;AAAA,SAL7G,EAAE,EAMX,CACD,GACH;AAAA,KACF;AAEJ;AACO,MAAM,qBAAqB,YAAY;AAAA,EAC5C,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU,OAAO,EAAE,SAAS,sBAAsB,OAAO,CAAC,EAAE,OAAO,sBAAsB,QAAQ,kBAAkB,QAAQ,EAAE,CAAC,EAAE;AAClI,CAAC;AAID,SAAS,kBAAkB,EAAE,MAAM,GAA6B;AAC9D,QAAM,SAAS,MAAM,SAAS,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,KAAK;AACvD,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SACE,qBAAC,SAAI,WAAU,oCACZ;AAAA,UAAM,WAAW,oBAAC,QAAG,WAAU,uBAAsB,mBAAgB,WAAW,gBAAM,SAAQ;AAAA,IAC/F,oBAAC,QAAG,WAAU,sBACX,gBAAM,IAAI,CAAC,GAAG,MAAM;AACnB,YAAM,QACJ,iCACG;AAAA,UAAE,QAAQ,oBAAC,UAAK,WAAU,0BAAyB,eAAY,QAAQ,YAAE,MAAK;AAAA,QAC/E,qBAAC,UACC;AAAA,8BAAC,UAAK,WAAU,sBAAsB,YAAE,OAAM;AAAA,UAC7C,EAAE,QAAQ,oBAAC,UAAK,WAAU,qBAAqB,YAAE,MAAK;AAAA,WACzD;AAAA,SACF;AAEF,aACE,oBAAC,QAAW,WAAU,+CACnB,YAAE,OAAO,oBAAC,OAAE,MAAM,EAAE,MAAM,WAAU,0BAA0B,iBAAM,IAAO,SADrE,CAET;AAAA,IAEJ,CAAC,GACH;AAAA,KACF;AAEJ;AACO,MAAM,cAAc,YAAY;AAAA,EACrC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU,OAAO,EAAE,SAAS,cAAc,OAAO,CAAC,EAAE,MAAM,UAAK,OAAO,UAAU,MAAM,sBAAsB,CAAC,EAAE;AACjH,CAAC;AAID,SAAS,sBAAsB,EAAE,MAAM,GAAiC;AAEtE,QAAM,SAAS,MAAM,SAAS,CAAC,GAAG,IAAI,CAAC,GAAG,OAAO,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,KAAK;AACxH,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SACE,qBAAC,SAAI,WAAU,wCACb;AAAA,wBAAC,QAAG,WAAU,uBAAsB,mBAAgB,WAAW,gBAAM,WAAW,aAAY;AAAA,IAC5F,oBAAC,QAAG,WAAU,sBACX,gBAAM,IAAI,CAAC,MACV,qBAAC,QAAc,WAAU,sBACvB;AAAA,2BAAC,OAAE,WAAU,sBAAqB,MAAM,EAAE,MAAM,UAAQ,MACtD;AAAA,4BAAC,UAAK,eAAY,QAAO,uBAAE;AAAA,QAAO;AAAA,QAAC,oBAAC,UAAK,mBAAiB,SAAS,EAAE,EAAE,UAAW,YAAE,OAAM;AAAA,SAC5F;AAAA,MACC,EAAE,QAAQ,oBAAC,UAAK,WAAU,sBAAqB,mBAAiB,SAAS,EAAE,EAAE,SAAU,YAAE,MAAK;AAAA,SAJxF,EAAE,EAKX,CACD,GACH;AAAA,KACF;AAEJ;AACO,MAAM,kBAAkB,YAAY;AAAA,EACzC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU,OAAO,EAAE,SAAS,aAAa,OAAO,GAAG,OAAO,CAAC,EAAE;AAC/D,CAAC;AAID,SAAS,sBAAsB,EAAE,MAAM,GAAiC;AACtE,QAAM,IAAI,aAAa,MAAM,MAAM;AACnC,MAAI,CAAC,MAAM,OAAQ,QAAO;AAC1B,SACE,qBAAC,SAAI,WAAU,wCACZ;AAAA,UAAM,WAAW,oBAAC,QAAG,WAAU,uBAAsB,mBAAgB,WAAW,gBAAM,SAAQ;AAAA,IAC9F,MAAM,OACL,oBAAC,OAAE,WAAU,uBAAsB,eAAY,QAAO,oBAAC,IACrD,EAAE,OACJ,oBAAC,OAAE,WAAU,4BAA2B,mBAAgB,eAAe,gBAAM,aAAY,IAEzF,oBAAC,mBAAgB,GAAM,YAAU,MAAC;AAAA,KAEtC;AAEJ;AACO,MAAM,kBAAkB,YAAY;AAAA,EACzC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU,OAAO,EAAE,SAAS,YAAY,QAAQ,IAAI,aAAa,gBAAgB;AACnF,CAAC;","names":[]}
@@ -0,0 +1,19 @@
1
+ import type { ReactNode } from "react";
2
+ /**
3
+ * Een blok dat nog niet is ingericht (geen PDF gekozen, geen aanmeld-URL, geen formulier).
4
+ *
5
+ * Zulke blokken toonden hun hulptekst aan IEDEREEN: "Configureer een aanmeld-URL of formulier in
6
+ * de editor" stond gewoon op de publieke pagina — en op de verkoopdemo. Dat is een boodschap voor
7
+ * de beheerder, gelekt naar de bezoeker; die kan er niets mee en het oogt als een kapotte site.
8
+ *
9
+ * De regel is nu overal dezelfde:
10
+ * - Staat de BEWERKMODUS open, dan is de hint zichtbaar — daar is hij voor, en de beheerder moet
11
+ * het blok kunnen terugvinden om het af te maken (een onzichtbaar blok is onvindbaar).
12
+ * - Voor een bezoeker rendert het blok NIETS. Een half ingericht blok is geen inhoud.
13
+ *
14
+ * FormBlock had dit gedrag al (demo-fallback + "niet beschikbaar" alleen waar het hoort); dit
15
+ * maakt de rest van de familie even netjes.
16
+ */
17
+ export declare function Onvoltooid({ children }: {
18
+ children: ReactNode;
19
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { useEditor } from "../../../editor/EditorProvider.js";
4
+ import { Text } from "../../ui/index.js";
5
+ function Onvoltooid({ children }) {
6
+ const { open } = useEditor();
7
+ if (!open) return null;
8
+ return /* @__PURE__ */ jsx(Text, { type: "supporting", color: "secondary", children });
9
+ }
10
+ export {
11
+ Onvoltooid
12
+ };
13
+ //# sourceMappingURL=Onvoltooid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/blocks/builtins/lib/Onvoltooid.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { useEditor } from \"../../../editor/EditorProvider\";\nimport { Text } from \"../../ui\";\n\n/**\n * Een blok dat nog niet is ingericht (geen PDF gekozen, geen aanmeld-URL, geen formulier).\n *\n * Zulke blokken toonden hun hulptekst aan IEDEREEN: \"Configureer een aanmeld-URL of formulier in\n * de editor\" stond gewoon op de publieke pagina — en op de verkoopdemo. Dat is een boodschap voor\n * de beheerder, gelekt naar de bezoeker; die kan er niets mee en het oogt als een kapotte site.\n *\n * De regel is nu overal dezelfde:\n * - Staat de BEWERKMODUS open, dan is de hint zichtbaar — daar is hij voor, en de beheerder moet\n * het blok kunnen terugvinden om het af te maken (een onzichtbaar blok is onvindbaar).\n * - Voor een bezoeker rendert het blok NIETS. Een half ingericht blok is geen inhoud.\n *\n * FormBlock had dit gedrag al (demo-fallback + \"niet beschikbaar\" alleen waar het hoort); dit\n * maakt de rest van de familie even netjes.\n */\nexport function Onvoltooid({ children }: { children: ReactNode }) {\n const { open } = useEditor();\n if (!open) return null;\n return (\n <Text type=\"supporting\" color=\"secondary\">\n {children}\n </Text>\n );\n}\n"],"mappings":";AAyBI;AAtBJ,SAAS,iBAAiB;AAC1B,SAAS,YAAY;AAiBd,SAAS,WAAW,EAAE,SAAS,GAA4B;AAChE,QAAM,EAAE,KAAK,IAAI,UAAU;AAC3B,MAAI,CAAC,KAAM,QAAO;AAClB,SACE,oBAAC,QAAK,MAAK,cAAa,OAAM,aAC3B,UACH;AAEJ;","names":[]}
@@ -6,6 +6,8 @@ import { useRegistry, BlockDataProvider } from "../blocks/context.js";
6
6
  import { useEditor } from "../editor/EditorProvider.js";
7
7
  import { isDemoActive, registerSeed } from "../demo/demoStore.js";
8
8
  import { InlineImageEditProvider } from "../media/ImageContext.js";
9
+ import { useSiteConfig } from "../config.js";
10
+ import { parseLocaleSlugs, siteLocales } from "../i18n/overlay.js";
9
11
  function PublishedPage({
10
12
  page,
11
13
  siteId,
@@ -13,6 +15,7 @@ function PublishedPage({
13
15
  blockData
14
16
  }) {
15
17
  const registry = useRegistry();
18
+ const config = useSiteConfig();
16
19
  const { draftBlocks, editPath, fotoVervanger } = useEditor();
17
20
  useEffect(() => {
18
21
  if (!isDemoActive()) return;
@@ -25,7 +28,13 @@ function PublishedPage({
25
28
  path: pad
26
29
  });
27
30
  }, [siteId, page]);
28
- const opDezePagina = draftBlocks !== null && typeof window !== "undefined" && huidigPad(window.location.pathname) === editPath;
31
+ const opDezePagina = draftBlocks !== null && typeof window !== "undefined" && (() => {
32
+ const { slugs } = parseLocaleSlugs(
33
+ window.location.pathname.split("/").filter(Boolean),
34
+ siteLocales(config)
35
+ );
36
+ return huidigPad("/" + slugs.join("/")) === editPath;
37
+ })();
29
38
  const teTonen = opDezePagina ? { ...page, blocks: draftBlocks } : page;
30
39
  return /* @__PURE__ */ jsx(BlockDataProvider, { data: blockData, children: /* @__PURE__ */ jsx(InlineImageEditProvider, { onReplace: opDezePagina ? fotoVervanger : null, children: /* @__PURE__ */ jsx(PageRenderer, { page: teTonen, registry, siteId, mode }) }) });
31
40
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/render/PublishedPage.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\nimport { PageRenderer } from \"./PageRenderer\";\nimport { useRegistry, BlockDataProvider } from \"../blocks/context\";\nimport { useEditor } from \"../editor/EditorProvider\";\nimport { isDemoActive, registerSeed } from \"../demo/demoStore\";\nimport { InlineImageEditProvider } from \"../media/ImageContext\";\nimport type { Page } from \"../schema/pages\";\n\n/**\n * Rendert een (gepubliceerde) pagina via de **context-registry** (module-resolved, opgebouwd in\n * XiCMSProvider). Gebruik dit i.p.v. zelf `createRegistry([...builtinBlocks])` server-side te bouwen:\n * sinds de blokken op Astryx draaien zijn de meeste `\"use client\"`, en een server-opgebouwde registry\n * krijgt daar alleen opake client-referenties van → die blokken worden stil overgeslagen. Deze client-\n * component zit binnen de provider en heeft dus de volledige registry.\n *\n * `blockData` (5.6, optioneel): server-gefetchte startdata per domein (bv. `{ shop: … }` uit\n * `getShopPageData`). Data-blokken renderen dan direct met inhoud (SSR/ISR) i.p.v. eerst\n * client-side te fetchen. Moet serialiseerbare plain data zijn (server → client-prop).\n */\nexport function PublishedPage({\n page,\n siteId,\n mode = \"view\",\n blockData,\n}: {\n page: Pick<Page, \"blocks\">;\n siteId: string;\n mode?: \"view\" | \"preview\";\n blockData?: Record<string, unknown>;\n}) {\n const registry = useRegistry();\n const { draftBlocks, editPath, fotoVervanger } = useEditor();\n\n /**\n * In een DEMO is deze pagina zijn eigen uitgangspunt.\n *\n * De demo-bewerkmodus bewaart wijzigingen in de browser en legt die over een \"seed\": de\n * oorspronkelijke pagina waar de bezoeker op verder bewerkt. Zonder geregistreerde seed geeft\n * `resolveDemoPage` niets terug, meldt de editor \"Nog geen werkversie\", en loopt de enige knop\n * die dan overblijft (\"+ Pagina aanmaken\") tegen de échte database aan.\n *\n * Dat overkwam elke demo-site behalve xicms.nl zelf, want daar stond de registratie met de hand\n * in een eigen catch-all route. Een klantsite heeft die route niet en had dus wél een\n * demo-bewerkmodus in de balk, maar geen enkele pagina om te bewerken — op sites die bestaan om\n * te laten zien hoe prettig het bewerken werkt.\n *\n * Hier hoort het thuis: dit component wéét welke pagina er op dit pad staat. Buiten de demo doet\n * het niets, en in de demo is de seed per definitie gelijk aan wat de bezoeker ziet.\n */\n useEffect(() => {\n if (!isDemoActive()) return;\n const pad = huidigPad(window.location.pathname);\n // Titel en slug horen erbij: de editor toont ze in zijn balk en in de pagina-instellingen.\n // `page` levert in de praktijk het hele pagina-object; deze twee zijn de terugval voor een site\n // die alleen blokken doorgeeft — het type belooft immers niet meer dan `blocks`.\n const volledig = page as Partial<Page> & Pick<Page, \"blocks\">;\n registerSeed(siteId, pad, {\n ...volledig,\n title: volledig.title || document.title,\n slug: volledig.slug || (pad.split(\"/\").filter(Boolean).pop() ?? \"\"),\n path: pad,\n } as Page);\n // Alleen op het pad en de inhoud: opnieuw registreren bij elke render zou de seed tijdens het\n // bewerken vervangen door de zojuist bewerkte tekst, en dan is er geen origineel meer om op\n // terug te vallen.\n }, [siteId, page]);\n\n /**\n * Staat de editor open op DEZE pagina, dan tonen we de werkversie in plaats van het\n * gepubliceerde. Zo blijft de site zijn eigen layout en huisstijl tekenen, en is wat je ziet\n * precies wat je bewerkt — in plaats van een nabootsing in een apart editorvenster.\n *\n * De padvergelijking is niet overdreven voorzichtig: een pagina kan meerdere gerenderde pagina's\n * in beeld hebben (een preview, een ingekaderde pagina). Zonder die controle zou de werkversie\n * van de ene pagina in de andere opduiken.\n */\n const opDezePagina =\n draftBlocks !== null &&\n typeof window !== \"undefined\" &&\n huidigPad(window.location.pathname) === editPath;\n\n const teTonen = opDezePagina ? { ...page, blocks: draftBlocks } : page;\n\n return (\n <BlockDataProvider data={blockData}>\n {/* Alleen op de pagina die de editor open heeft: anders krijgt een preview of ingekaderde\n pagina óók 📷-knopjes, terwijl een klik daar in het verkeerde draft zou landen. */}\n <InlineImageEditProvider onReplace={opDezePagina ? fotoVervanger : null}>\n <PageRenderer page={teTonen} registry={registry} siteId={siteId} mode={mode} />\n </InlineImageEditProvider>\n </BlockDataProvider>\n );\n}\n\n/** Normaliseert een pad zoals de editor het bijhoudt: geen trailing slash, root blijft \"/\". */\nfunction huidigPad(p: string): string {\n const schoon = p.replace(/\\/+$/, \"\");\n return schoon === \"\" ? \"/\" : schoon;\n}\n"],"mappings":";AA0FQ;AAxFR,SAAS,iBAAiB;AAC1B,SAAS,oBAAoB;AAC7B,SAAS,aAAa,yBAAyB;AAC/C,SAAS,iBAAiB;AAC1B,SAAS,cAAc,oBAAoB;AAC3C,SAAS,+BAA+B;AAcjC,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AACF,GAKG;AACD,QAAM,WAAW,YAAY;AAC7B,QAAM,EAAE,aAAa,UAAU,cAAc,IAAI,UAAU;AAkB3D,YAAU,MAAM;AACd,QAAI,CAAC,aAAa,EAAG;AACrB,UAAM,MAAM,UAAU,OAAO,SAAS,QAAQ;AAI9C,UAAM,WAAW;AACjB,iBAAa,QAAQ,KAAK;AAAA,MACxB,GAAG;AAAA,MACH,OAAO,SAAS,SAAS,SAAS;AAAA,MAClC,MAAM,SAAS,SAAS,IAAI,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,IAAI,KAAK;AAAA,MAChE,MAAM;AAAA,IACR,CAAS;AAAA,EAIX,GAAG,CAAC,QAAQ,IAAI,CAAC;AAWjB,QAAM,eACJ,gBAAgB,QAChB,OAAO,WAAW,eAClB,UAAU,OAAO,SAAS,QAAQ,MAAM;AAE1C,QAAM,UAAU,eAAe,EAAE,GAAG,MAAM,QAAQ,YAAY,IAAI;AAElE,SACE,oBAAC,qBAAkB,MAAM,WAGvB,8BAAC,2BAAwB,WAAW,eAAe,gBAAgB,MACjE,8BAAC,gBAAa,MAAM,SAAS,UAAoB,QAAgB,MAAY,GAC/E,GACF;AAEJ;AAGA,SAAS,UAAU,GAAmB;AACpC,QAAM,SAAS,EAAE,QAAQ,QAAQ,EAAE;AACnC,SAAO,WAAW,KAAK,MAAM;AAC/B;","names":[]}
1
+ {"version":3,"sources":["../../src/render/PublishedPage.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\nimport { PageRenderer } from \"./PageRenderer\";\nimport { useRegistry, BlockDataProvider } from \"../blocks/context\";\nimport { useEditor } from \"../editor/EditorProvider\";\nimport { isDemoActive, registerSeed } from \"../demo/demoStore\";\nimport { InlineImageEditProvider } from \"../media/ImageContext\";\nimport { useSiteConfig } from \"../config\";\nimport { parseLocaleSlugs, siteLocales } from \"../i18n/overlay\";\nimport type { Page } from \"../schema/pages\";\n\n/**\n * Rendert een (gepubliceerde) pagina via de **context-registry** (module-resolved, opgebouwd in\n * XiCMSProvider). Gebruik dit i.p.v. zelf `createRegistry([...builtinBlocks])` server-side te bouwen:\n * sinds de blokken op Astryx draaien zijn de meeste `\"use client\"`, en een server-opgebouwde registry\n * krijgt daar alleen opake client-referenties van → die blokken worden stil overgeslagen. Deze client-\n * component zit binnen de provider en heeft dus de volledige registry.\n *\n * `blockData` (5.6, optioneel): server-gefetchte startdata per domein (bv. `{ shop: … }` uit\n * `getShopPageData`). Data-blokken renderen dan direct met inhoud (SSR/ISR) i.p.v. eerst\n * client-side te fetchen. Moet serialiseerbare plain data zijn (server → client-prop).\n */\nexport function PublishedPage({\n page,\n siteId,\n mode = \"view\",\n blockData,\n}: {\n page: Pick<Page, \"blocks\">;\n siteId: string;\n mode?: \"view\" | \"preview\";\n blockData?: Record<string, unknown>;\n}) {\n const registry = useRegistry();\n const config = useSiteConfig();\n const { draftBlocks, editPath, fotoVervanger } = useEditor();\n\n /**\n * In een DEMO is deze pagina zijn eigen uitgangspunt.\n *\n * De demo-bewerkmodus bewaart wijzigingen in de browser en legt die over een \"seed\": de\n * oorspronkelijke pagina waar de bezoeker op verder bewerkt. Zonder geregistreerde seed geeft\n * `resolveDemoPage` niets terug, meldt de editor \"Nog geen werkversie\", en loopt de enige knop\n * die dan overblijft (\"+ Pagina aanmaken\") tegen de échte database aan.\n *\n * Dat overkwam elke demo-site behalve xicms.nl zelf, want daar stond de registratie met de hand\n * in een eigen catch-all route. Een klantsite heeft die route niet en had dus wél een\n * demo-bewerkmodus in de balk, maar geen enkele pagina om te bewerken — op sites die bestaan om\n * te laten zien hoe prettig het bewerken werkt.\n *\n * Hier hoort het thuis: dit component wéét welke pagina er op dit pad staat. Buiten de demo doet\n * het niets, en in de demo is de seed per definitie gelijk aan wat de bezoeker ziet.\n */\n useEffect(() => {\n if (!isDemoActive()) return;\n const pad = huidigPad(window.location.pathname);\n // Titel en slug horen erbij: de editor toont ze in zijn balk en in de pagina-instellingen.\n // `page` levert in de praktijk het hele pagina-object; deze twee zijn de terugval voor een site\n // die alleen blokken doorgeeft — het type belooft immers niet meer dan `blocks`.\n const volledig = page as Partial<Page> & Pick<Page, \"blocks\">;\n registerSeed(siteId, pad, {\n ...volledig,\n title: volledig.title || document.title,\n slug: volledig.slug || (pad.split(\"/\").filter(Boolean).pop() ?? \"\"),\n path: pad,\n } as Page);\n // Alleen op het pad en de inhoud: opnieuw registreren bij elke render zou de seed tijdens het\n // bewerken vervangen door de zojuist bewerkte tekst, en dan is er geen origineel meer om op\n // terug te vallen.\n }, [siteId, page]);\n\n /**\n * Staat de editor open op DEZE pagina, dan tonen we de werkversie in plaats van het\n * gepubliceerde. Zo blijft de site zijn eigen layout en huisstijl tekenen, en is wat je ziet\n * precies wat je bewerkt — in plaats van een nabootsing in een apart editorvenster.\n *\n * De padvergelijking is niet overdreven voorzichtig: een pagina kan meerdere gerenderde pagina's\n * in beeld hebben (een preview, een ingekaderde pagina). Zonder die controle zou de werkversie\n * van de ene pagina in de andere opduiken.\n */\n /**\n * `editPath` is het CANONIEKE pad — zonder taalprefix, want zo houdt de editor zijn werkversie\n * bij. De URL-balk heeft die prefix wél (`/de/over-ons`). Vergeleken zonder die prefix eraf te\n * halen was de werkversie op elke vertaalde pagina onzichtbaar: de editor stond open, je typte,\n * en de pagina bleef stug het gepubliceerde tonen. Eéntalige sites merkten hier niets van —\n * precies waarom dit zo lang kon blijven staan.\n */\n const opDezePagina =\n draftBlocks !== null &&\n typeof window !== \"undefined\" &&\n (() => {\n const { slugs } = parseLocaleSlugs(\n window.location.pathname.split(\"/\").filter(Boolean),\n siteLocales(config),\n );\n return huidigPad(\"/\" + slugs.join(\"/\")) === editPath;\n })();\n\n const teTonen = opDezePagina ? { ...page, blocks: draftBlocks } : page;\n\n return (\n <BlockDataProvider data={blockData}>\n {/* Alleen op de pagina die de editor open heeft: anders krijgt een preview of ingekaderde\n pagina óók 📷-knopjes, terwijl een klik daar in het verkeerde draft zou landen. */}\n <InlineImageEditProvider onReplace={opDezePagina ? fotoVervanger : null}>\n <PageRenderer page={teTonen} registry={registry} siteId={siteId} mode={mode} />\n </InlineImageEditProvider>\n </BlockDataProvider>\n );\n}\n\n/** Normaliseert een pad zoals de editor het bijhoudt: geen trailing slash, root blijft \"/\". */\nfunction huidigPad(p: string): string {\n const schoon = p.replace(/\\/+$/, \"\");\n return schoon === \"\" ? \"/\" : schoon;\n}\n"],"mappings":";AA0GQ;AAxGR,SAAS,iBAAiB;AAC1B,SAAS,oBAAoB;AAC7B,SAAS,aAAa,yBAAyB;AAC/C,SAAS,iBAAiB;AAC1B,SAAS,cAAc,oBAAoB;AAC3C,SAAS,+BAA+B;AACxC,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB,mBAAmB;AAcvC,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AACF,GAKG;AACD,QAAM,WAAW,YAAY;AAC7B,QAAM,SAAS,cAAc;AAC7B,QAAM,EAAE,aAAa,UAAU,cAAc,IAAI,UAAU;AAkB3D,YAAU,MAAM;AACd,QAAI,CAAC,aAAa,EAAG;AACrB,UAAM,MAAM,UAAU,OAAO,SAAS,QAAQ;AAI9C,UAAM,WAAW;AACjB,iBAAa,QAAQ,KAAK;AAAA,MACxB,GAAG;AAAA,MACH,OAAO,SAAS,SAAS,SAAS;AAAA,MAClC,MAAM,SAAS,SAAS,IAAI,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,IAAI,KAAK;AAAA,MAChE,MAAM;AAAA,IACR,CAAS;AAAA,EAIX,GAAG,CAAC,QAAQ,IAAI,CAAC;AAkBjB,QAAM,eACJ,gBAAgB,QAChB,OAAO,WAAW,gBACjB,MAAM;AACL,UAAM,EAAE,MAAM,IAAI;AAAA,MAChB,OAAO,SAAS,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AAAA,MAClD,YAAY,MAAM;AAAA,IACpB;AACA,WAAO,UAAU,MAAM,MAAM,KAAK,GAAG,CAAC,MAAM;AAAA,EAC9C,GAAG;AAEL,QAAM,UAAU,eAAe,EAAE,GAAG,MAAM,QAAQ,YAAY,IAAI;AAElE,SACE,oBAAC,qBAAkB,MAAM,WAGvB,8BAAC,2BAAwB,WAAW,eAAe,gBAAgB,MACjE,8BAAC,gBAAa,MAAM,SAAS,UAAoB,QAAgB,MAAY,GAC/E,GACF;AAEJ;AAGA,SAAS,UAAU,GAAmB;AACpC,QAAM,SAAS,EAAE,QAAQ,QAAQ,EAAE;AACnC,SAAO,WAAW,KAAK,MAAM;AAC/B;","names":[]}
package/dist/styles.css CHANGED
@@ -333,7 +333,11 @@
333
333
  min-height: 0;
334
334
  }
335
335
  .xicms-ve__body.is-panel-open {
336
- grid-template-columns: 1fr 360px;
336
+ /* 360px was gekozen voor blok-instellingen (een handvol velden). Sinds het productformulier in
337
+ ditzelfde paneel opent (7.8) is dat te smal: twee kolommen velden, varianten-tabellen en
338
+ foto-rijen vouwden zich dubbel. clamp: nooit smaller dan de oude 360, nooit meer dan 480, en
339
+ op een gewoon scherm ± een kwart — de pagina blijft de hoofdzaak. */
340
+ grid-template-columns: 1fr clamp(360px, 28vw, 480px);
337
341
  }
338
342
  .xicms-ve__canvas {
339
343
  overflow: auto;
@@ -782,6 +786,29 @@
782
786
  :root:has(.xicms-ve__bar) {
783
787
  padding-top: 2.6rem;
784
788
  }
789
+ /* Smalle schermen: de balk hield alles en werd twee regels hoog — en de pagina-offset (2.6rem,
790
+ vast) rekent op één regel, dus de site schoof onder de balk. Het pad en de statustekst zijn op
791
+ een telefoon ballast; de vier moduskoppen en het gereedschap zijn de balk. */
792
+ @media (max-width: 720px) {
793
+ .xicms-ve__path,
794
+ .xicms-ve__status,
795
+ .xicms-ve__locale {
796
+ display: none;
797
+ }
798
+ .xicms-editbar,
799
+ .xicms-ve__bar {
800
+ gap: 0.15rem;
801
+ padding: 0.4rem 0.5rem;
802
+ overflow-x: auto;
803
+ /* Eén regel afdwingen: krimpen mag, breken niet. */
804
+ flex-wrap: nowrap;
805
+ white-space: nowrap;
806
+ }
807
+ .xicms-editbar__btn {
808
+ padding: 0.42rem 0.55rem;
809
+ }
810
+ }
811
+
785
812
  .xicms-ve__sep {
786
813
  width: 1px;
787
814
  align-self: stretch;
@@ -3112,21 +3139,29 @@
3112
3139
  outline: 2px solid #a5b4fc;
3113
3140
  outline-offset: 1px;
3114
3141
  }
3115
- /* De rest van het gereedschap (verplaatsen, dupliceren, verwijderen) klapt uit bij aanwijzen of
3116
- toetsenbordfocus. Dicht in rust: zes permanente knoppen naast elk blok zijn geen gereedschap
3117
- maar een hek om de site heen. */
3118
- .xicms-ve-blokknoppen__meer {
3119
- display: flex;
3120
- max-width: 0;
3121
- overflow: hidden;
3122
- opacity: 0;
3123
- transition: max-width 0.18s ease, opacity 0.15s ease;
3124
- gap: 2px;
3142
+ /* De rest van het gereedschap (verplaatsen, dupliceren, verwijderen) toont zich bij aanwijzen,
3143
+ toetsenbordfocus of een geselecteerd blok (`is-open` — op een telefoon bestaat aanwijzen niet).
3144
+ Dicht in rust: zes permanente knoppen naast elk blok zijn geen gereedschap maar een hek om de
3145
+ site heen.
3146
+
3147
+ Een kale display-toggle, bewust zonder uitklap-animatie. Hier hebben twee animatietrucs
3148
+ (max-width en 0fr→1fr) allebei stilletjes gefaald in de fixed+flex-context van dit cluster —
3149
+ dicht terwijl de selector aantoonbaar matchte. Een knoppenrij die er ALTIJD is wanneer hij er
3150
+ hoort te zijn is meer waard dan een die er mooi in schuift maar soms niet komt. */
3151
+ .xicms-ve-blokknoppen__meer,
3152
+ .xicms-ve-blokknoppen__meer-in {
3153
+ display: none;
3125
3154
  }
3126
3155
  .xicms-ve-blokknoppen:hover .xicms-ve-blokknoppen__meer,
3127
- .xicms-ve-blokknoppen:focus-within .xicms-ve-blokknoppen__meer {
3128
- max-width: 12rem;
3129
- opacity: 1;
3156
+ .xicms-ve-blokknoppen:focus-within .xicms-ve-blokknoppen__meer,
3157
+ .xicms-ve-blokknoppen.is-open .xicms-ve-blokknoppen__meer {
3158
+ display: contents;
3159
+ }
3160
+ .xicms-ve-blokknoppen:hover .xicms-ve-blokknoppen__meer-in,
3161
+ .xicms-ve-blokknoppen:focus-within .xicms-ve-blokknoppen__meer-in,
3162
+ .xicms-ve-blokknoppen.is-open .xicms-ve-blokknoppen__meer-in {
3163
+ display: flex;
3164
+ gap: 2px;
3130
3165
  }
3131
3166
  .xicms-ve-blokknop:disabled {
3132
3167
  opacity: 0.35;
package/dist/version.js CHANGED
@@ -1,4 +1,4 @@
1
- const CORE_VERSION = true ? "7.9.0" : "0.0.0-dev";
1
+ const CORE_VERSION = true ? "7.10.0" : "0.0.0-dev";
2
2
  const CORE_PACKAGE = "@xiwebdesign/xicms-core";
3
3
  function isNieuwer(beschikbaar, huidig) {
4
4
  const delen = (v) => v.split("-")[0].split(".").map((n) => Number.parseInt(n, 10) || 0);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/version.ts"],"sourcesContent":["/**\n * De versie van de engine waarop deze site draait.\n *\n * De waarde wordt bij het bouwen ingevuld (tsup `define`), niet uit package.json geïmporteerd: met\n * `bundle: false` zou zo'n import als losse JSON-module in `dist` belanden en bij de consumer niet\n * bestaan. In de monorepo (tests, dev) is de define er niet — vandaar de terugval, die meteen\n * zichtbaar maakt dát je naar een ongebouwde core kijkt.\n */\ndeclare const __XICMS_CORE_VERSION__: string | undefined;\n\nexport const CORE_VERSION: string =\n typeof __XICMS_CORE_VERSION__ === \"string\" ? __XICMS_CORE_VERSION__ : \"0.0.0-dev\";\n\n/** De npm-registry, waar `npm run check:core-update` en het beheer de laatste versie ophalen. */\nexport const CORE_PACKAGE = \"@xiwebdesign/xicms-core\";\n\n/**\n * Vergelijkt twee semver-strings zonder dependency. Geeft true als `beschikbaar` nieuwer is.\n * Pre-release-suffixen tellen niet mee — voor \"is er een update?\" volstaat major.minor.patch.\n */\nexport function isNieuwer(beschikbaar: string, huidig: string): boolean {\n const delen = (v: string) => v.split(\"-\")[0].split(\".\").map((n) => Number.parseInt(n, 10) || 0);\n const [aM, aN, aP] = delen(beschikbaar);\n const [bM, bN, bP] = delen(huidig);\n if (aM !== bM) return aM > bM;\n if (aN !== bN) return aN > bN;\n return aP > bP;\n}\n"],"mappings":"AAUO,MAAM,eACX,OAA6C,UAAyB;AAGjE,MAAM,eAAe;AAMrB,SAAS,UAAU,aAAqB,QAAyB;AACtE,QAAM,QAAQ,CAAC,MAAc,EAAE,MAAM,GAAG,EAAE,CAAC,EAAE,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,OAAO,SAAS,GAAG,EAAE,KAAK,CAAC;AAC9F,QAAM,CAAC,IAAI,IAAI,EAAE,IAAI,MAAM,WAAW;AACtC,QAAM,CAAC,IAAI,IAAI,EAAE,IAAI,MAAM,MAAM;AACjC,MAAI,OAAO,GAAI,QAAO,KAAK;AAC3B,MAAI,OAAO,GAAI,QAAO,KAAK;AAC3B,SAAO,KAAK;AACd;","names":[]}
1
+ {"version":3,"sources":["../src/version.ts"],"sourcesContent":["/**\n * De versie van de engine waarop deze site draait.\n *\n * De waarde wordt bij het bouwen ingevuld (tsup `define`), niet uit package.json geïmporteerd: met\n * `bundle: false` zou zo'n import als losse JSON-module in `dist` belanden en bij de consumer niet\n * bestaan. In de monorepo (tests, dev) is de define er niet — vandaar de terugval, die meteen\n * zichtbaar maakt dát je naar een ongebouwde core kijkt.\n */\ndeclare const __XICMS_CORE_VERSION__: string | undefined;\n\nexport const CORE_VERSION: string =\n typeof __XICMS_CORE_VERSION__ === \"string\" ? __XICMS_CORE_VERSION__ : \"0.0.0-dev\";\n\n/** De npm-registry, waar `npm run check:core-update` en het beheer de laatste versie ophalen. */\nexport const CORE_PACKAGE = \"@xiwebdesign/xicms-core\";\n\n/**\n * Vergelijkt twee semver-strings zonder dependency. Geeft true als `beschikbaar` nieuwer is.\n * Pre-release-suffixen tellen niet mee — voor \"is er een update?\" volstaat major.minor.patch.\n */\nexport function isNieuwer(beschikbaar: string, huidig: string): boolean {\n const delen = (v: string) => v.split(\"-\")[0].split(\".\").map((n) => Number.parseInt(n, 10) || 0);\n const [aM, aN, aP] = delen(beschikbaar);\n const [bM, bN, bP] = delen(huidig);\n if (aM !== bM) return aM > bM;\n if (aN !== bN) return aN > bN;\n return aP > bP;\n}\n"],"mappings":"AAUO,MAAM,eACX,OAA6C,WAAyB;AAGjE,MAAM,eAAe;AAMrB,SAAS,UAAU,aAAqB,QAAyB;AACtE,QAAM,QAAQ,CAAC,MAAc,EAAE,MAAM,GAAG,EAAE,CAAC,EAAE,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,OAAO,SAAS,GAAG,EAAE,KAAK,CAAC;AAC9F,QAAM,CAAC,IAAI,IAAI,EAAE,IAAI,MAAM,WAAW;AACtC,QAAM,CAAC,IAAI,IAAI,EAAE,IAAI,MAAM,MAAM;AACjC,MAAI,OAAO,GAAI,QAAO,KAAK;AAC3B,MAAI,OAAO,GAAI,QAAO,KAAK;AAC3B,SAAO,KAAK;AACd;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiwebdesign/xicms-core",
3
- "version": "7.9.0",
3
+ "version": "7.10.0",
4
4
  "description": "XiCMS engine: gestructureerde content, pagina's, draft/publish, admin (TipTap+Radix), SEO en beveiliging voor klantsites.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -102,8 +102,8 @@
102
102
  }
103
103
  },
104
104
  "dependencies": {
105
- "@astryxdesign/core": "^0.4.2",
106
- "@astryxdesign/theme-neutral": "^0.4.2",
105
+ "@astryxdesign/core": "^0.5.1",
106
+ "@astryxdesign/theme-neutral": "^0.5.1",
107
107
  "@radix-ui/react-tabs": "^1.1.21",
108
108
  "@tiptap/extension-image": "^3.30.1",
109
109
  "@tiptap/extension-link": "^3.30.1",
@@ -120,7 +120,7 @@
120
120
  "zod": "^4.4.3"
121
121
  },
122
122
  "devDependencies": {
123
- "@astryxdesign/cli": "^0.4.2",
123
+ "@astryxdesign/cli": "^0.5.1",
124
124
  "@tailwindcss/cli": "^4.3.3",
125
125
  "@testing-library/dom": "^10.4.1",
126
126
  "@testing-library/react": "^16.3.2",