@xiwebdesign/xicms-core 7.2.0 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/dist/XiCMSProvider.d.ts +2 -8
  2. package/dist/XiCMSProvider.js +1 -8
  3. package/dist/XiCMSProvider.js.map +1 -1
  4. package/dist/admin/AdminApp.js +7 -12
  5. package/dist/admin/AdminApp.js.map +1 -1
  6. package/dist/admin/NewsEditor.d.ts +8 -1
  7. package/dist/admin/NewsEditor.js +19 -18
  8. package/dist/admin/NewsEditor.js.map +1 -1
  9. package/dist/admin/SuperadminPanel.js +6 -7
  10. package/dist/admin/SuperadminPanel.js.map +1 -1
  11. package/dist/admin/customBlocks/CustomBlocksPanel.js +3 -4
  12. package/dist/admin/customBlocks/CustomBlocksPanel.js.map +1 -1
  13. package/dist/admin/lib/pagesClient.js +3 -4
  14. package/dist/admin/lib/pagesClient.js.map +1 -1
  15. package/dist/admin/lib/symbolsClient.js +3 -4
  16. package/dist/admin/lib/symbolsClient.js.map +1 -1
  17. package/dist/admin/pages/PagesPanel.js +5 -2
  18. package/dist/admin/pages/PagesPanel.js.map +1 -1
  19. package/dist/admin/settings/MailSettings.js +2 -3
  20. package/dist/admin/settings/MailSettings.js.map +1 -1
  21. package/dist/admin/settings/MailTemplates.js +2 -3
  22. package/dist/admin/settings/MailTemplates.js.map +1 -1
  23. package/dist/admin/settings/SettingsPanel.js +250 -225
  24. package/dist/admin/settings/SettingsPanel.js.map +1 -1
  25. package/dist/admin/settings/SnapshotsCard.js +3 -4
  26. package/dist/admin/settings/SnapshotsCard.js.map +1 -1
  27. package/dist/admin/shop/lib.js +2 -3
  28. package/dist/admin/shop/lib.js.map +1 -1
  29. package/dist/admin/visual/VisualEditor.js +239 -103
  30. package/dist/admin/visual/VisualEditor.js.map +1 -1
  31. package/dist/admin.css +1 -1
  32. package/dist/blocks/builtins/Agenda.js +6 -6
  33. package/dist/blocks/builtins/Agenda.js.map +1 -1
  34. package/dist/blocks/builtins/Banner.js +1 -1
  35. package/dist/blocks/builtins/Banner.js.map +1 -1
  36. package/dist/blocks/builtins/Breadcrumbs.js +5 -2
  37. package/dist/blocks/builtins/Breadcrumbs.js.map +1 -1
  38. package/dist/blocks/builtins/Cards.js +2 -2
  39. package/dist/blocks/builtins/Cards.js.map +1 -1
  40. package/dist/blocks/builtins/Contact.js +3 -3
  41. package/dist/blocks/builtins/Contact.js.map +1 -1
  42. package/dist/blocks/builtins/Cta.js +3 -3
  43. package/dist/blocks/builtins/Cta.js.map +1 -1
  44. package/dist/blocks/builtins/Downloads.js +5 -5
  45. package/dist/blocks/builtins/Downloads.js.map +1 -1
  46. package/dist/blocks/builtins/Elements.js +8 -5
  47. package/dist/blocks/builtins/Elements.js.map +1 -1
  48. package/dist/blocks/builtins/Hero.js +1 -1
  49. package/dist/blocks/builtins/Hero.js.map +1 -1
  50. package/dist/blocks/builtins/Jobs.js +4 -1
  51. package/dist/blocks/builtins/Jobs.js.map +1 -1
  52. package/dist/blocks/builtins/MapBlock.js +11 -11
  53. package/dist/blocks/builtins/MapBlock.js.map +1 -1
  54. package/dist/blocks/builtins/Newsletter.js +3 -2
  55. package/dist/blocks/builtins/Newsletter.js.map +1 -1
  56. package/dist/blocks/builtins/OpeningHours.js +2 -2
  57. package/dist/blocks/builtins/OpeningHours.js.map +1 -1
  58. package/dist/blocks/builtins/PdfBlock.js +2 -2
  59. package/dist/blocks/builtins/PdfBlock.js.map +1 -1
  60. package/dist/blocks/builtins/Portfolio.js +4 -4
  61. package/dist/blocks/builtins/Portfolio.js.map +1 -1
  62. package/dist/blocks/builtins/Pricing.js +3 -3
  63. package/dist/blocks/builtins/Pricing.js.map +1 -1
  64. package/dist/blocks/builtins/Sections.js +7 -7
  65. package/dist/blocks/builtins/Sections.js.map +1 -1
  66. package/dist/blocks/builtins/Team.js +3 -3
  67. package/dist/blocks/builtins/Team.js.map +1 -1
  68. package/dist/blocks/builtins/Widgets.js +28 -28
  69. package/dist/blocks/builtins/Widgets.js.map +1 -1
  70. package/dist/blocks/builtins/lib/submitForm.js +3 -4
  71. package/dist/blocks/builtins/lib/submitForm.js.map +1 -1
  72. package/dist/blocks/ui/index.d.ts +8 -1
  73. package/dist/blocks/ui/index.js +3 -2
  74. package/dist/blocks/ui/index.js.map +1 -1
  75. package/dist/components/EditBar.d.ts +9 -1
  76. package/dist/components/EditBar.js +6 -5
  77. package/dist/components/EditBar.js.map +1 -1
  78. package/dist/components/PageView.js +3 -5
  79. package/dist/components/PageView.js.map +1 -1
  80. package/dist/firebase/admin.js +4 -0
  81. package/dist/firebase/admin.js.map +1 -1
  82. package/dist/firebase/client.js +23 -5
  83. package/dist/firebase/client.js.map +1 -1
  84. package/dist/firebase/emulators.d.ts +9 -0
  85. package/dist/firebase/emulators.js +24 -0
  86. package/dist/firebase/emulators.js.map +1 -0
  87. package/dist/firebase/functionsClient.d.ts +18 -0
  88. package/dist/firebase/functionsClient.js +17 -0
  89. package/dist/firebase/functionsClient.js.map +1 -0
  90. package/dist/lock/DemoLock.js +19 -2
  91. package/dist/lock/DemoLock.js.map +1 -1
  92. package/dist/modules/shop/cartStore.js +2 -1
  93. package/dist/modules/shop/cartStore.js.map +1 -1
  94. package/dist/modules/shop/lib.js +9 -10
  95. package/dist/modules/shop/lib.js.map +1 -1
  96. package/dist/server/index.d.ts +1 -1
  97. package/dist/server/index.js +2 -0
  98. package/dist/server/index.js.map +1 -1
  99. package/dist/server/pages.d.ts +11 -0
  100. package/dist/server/pages.js +47 -0
  101. package/dist/server/pages.js.map +1 -1
  102. package/dist/styles.css +130 -29
  103. package/dist/theme/color.d.ts +17 -0
  104. package/dist/theme/color.js +12 -0
  105. package/dist/theme/color.js.map +1 -0
  106. package/dist/version.js +1 -1
  107. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/builtins/Team.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport { TeamBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { VStack, HStack, Grid, Card, Heading, Text, Avatar } from \"../ui\";\nimport { jsonLdHtml } from \"./jsonld\";\n\ntype Team = z.infer<typeof TeamBlockSchema>;\n\nfunction personJsonLd(members: Team[\"members\"]): Record<string, unknown> {\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"ItemList\",\n itemListElement: members\n .filter((m) => m.name)\n .map((m, i) => ({\n \"@type\": \"ListItem\",\n position: i + 1,\n item: {\n \"@type\": \"Person\",\n name: m.name,\n ...(m.role ? { jobTitle: m.role } : {}),\n ...(m.email ? { email: m.email } : {}),\n ...(m.phone ? { telephone: m.phone } : {}),\n ...(m.photoUrl ? { image: m.photoUrl } : {}),\n ...(m.social?.length ? { sameAs: m.social.map((s) => s.href) } : {}),\n },\n })),\n };\n}\n\n/** Team-/medewerkersoverzicht als kaarten (Astryx), optioneel gegroepeerd per afdeling. */\nfunction TeamRender({ block }: BlockRenderProps<Team>) {\n // _i = index in de OORSPRONKELIJKE array — nodig voor de inline-edit-paden bij groepering.\n const members = (block.members ?? []).map((m, i) => ({ ...m, _i: i })).filter((m) => m.name);\n if (members.length === 0) return null;\n\n // Groepen in volgorde van eerste voorkomen; leden zonder afdeling achteraan onder één kop.\n const groups = block.groupByDepartment\n ? [...new Set(members.map((m) => m.department ?? \"\"))]\n .sort((a, b) => (a === \"\" ? 1 : b === \"\" ? -1 : 0))\n .map((dep) => ({ dep, members: members.filter((m) => (m.department ?? \"\") === dep) }))\n : [{ dep: \"\", members }];\n\n const grid = (list: typeof members) => (\n <Grid columns={{ minWidth: 220, max: 4 }} gap={4}>\n {list.map((m) => {\n const i = m._i;\n return (\n <Card key={i} padding={4} height=\"100%\">\n <VStack gap={1} hAlign=\"center\" style={{ textAlign: \"center\", height: \"100%\" }}>\n <Avatar src={m.photoUrl} name={m.name} size={96} />\n <Heading level={3} data-xicms-edit={`members.${i}.name`}>{m.name}</Heading>\n {m.role && <Text type=\"label\" data-xicms-edit={`members.${i}.role`} style={{ color: \"var(--color-accent)\" }}>{m.role}</Text>}\n {m.bio && <Text color=\"secondary\" data-xicms-edit={`members.${i}.bio`}>{m.bio}</Text>}\n {m.email && (\n <a href={`mailto:${m.email}`} style={{ color: \"var(--color-accent)\" }}>\n <Text type=\"supporting\">{m.email}</Text>\n </a>\n )}\n {m.phone && <Text type=\"supporting\" color=\"secondary\">{m.phone}</Text>}\n {m.social && m.social.length > 0 && (\n <HStack gap={2} hAlign=\"center\" as=\"ul\" style={{ listStyle: \"none\", margin: 0, padding: 0, flexWrap: \"wrap\" }}>\n {m.social.map((s, j) => (\n <li key={j}>\n <a href={s.href} rel=\"noopener noreferrer\" target=\"_blank\" style={{ color: \"var(--color-accent)\" }}>\n <Text type=\"supporting\">{s.platform}</Text>\n </a>\n </li>\n ))}\n </HStack>\n )}\n </VStack>\n </Card>\n );\n })}\n </Grid>\n );\n\n return (\n <VStack gap={4} as=\"section\" className=\"xicms-team\">\n {block.heading && (\n <Heading level={2} justify=\"center\" data-xicms-edit=\"heading\" style={{ textAlign: \"center\" }}>{block.heading}</Heading>\n )}\n {groups.map(({ dep, members: list }) => (\n <VStack key={dep || \"_overig\"} gap={3}>\n {block.groupByDepartment && groups.length > 1 && (\n <Heading level={3} justify=\"center\" style={{ textAlign: \"center\" }}>\n {dep || \"Overig\"}\n </Heading>\n )}\n {grid(list)}\n </VStack>\n ))}\n {block.jsonLd && (\n <script\n type=\"application/ld+json\"\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{ __html: jsonLdHtml(personJsonLd(members)) }}\n />\n )}\n </VStack>\n );\n}\n\nexport const teamBlock = defineBlock({\n type: \"team\",\n schema: TeamBlockSchema,\n Render: TeamRender,\n label: \"Team\",\n icon: \"👥\",\n defaults: () => ({\n heading: \"Ons team\",\n members: [{ name: \"Naam Medewerker\", role: \"Functie\" }],\n }),\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/blocks/builtins/Team.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport { TeamBlockSchema } from \"../../schema/blocks\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { VStack, HStack, Grid, Card, Heading, Text, Avatar } from \"../ui\";\nimport { jsonLdHtml } from \"./jsonld\";\n\ntype Team = z.infer<typeof TeamBlockSchema>;\n\nfunction personJsonLd(members: Team[\"members\"]): Record<string, unknown> {\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"ItemList\",\n itemListElement: members\n .filter((m) => m.name)\n .map((m, i) => ({\n \"@type\": \"ListItem\",\n position: i + 1,\n item: {\n \"@type\": \"Person\",\n name: m.name,\n ...(m.role ? { jobTitle: m.role } : {}),\n ...(m.email ? { email: m.email } : {}),\n ...(m.phone ? { telephone: m.phone } : {}),\n ...(m.photoUrl ? { image: m.photoUrl } : {}),\n ...(m.social?.length ? { sameAs: m.social.map((s) => s.href) } : {}),\n },\n })),\n };\n}\n\n/** Team-/medewerkersoverzicht als kaarten (Astryx), optioneel gegroepeerd per afdeling. */\nfunction TeamRender({ block }: BlockRenderProps<Team>) {\n // _i = index in de OORSPRONKELIJKE array — nodig voor de inline-edit-paden bij groepering.\n const members = (block.members ?? []).map((m, i) => ({ ...m, _i: i })).filter((m) => m.name);\n if (members.length === 0) return null;\n\n // Groepen in volgorde van eerste voorkomen; leden zonder afdeling achteraan onder één kop.\n const groups = block.groupByDepartment\n ? [...new Set(members.map((m) => m.department ?? \"\"))]\n .sort((a, b) => (a === \"\" ? 1 : b === \"\" ? -1 : 0))\n .map((dep) => ({ dep, members: members.filter((m) => (m.department ?? \"\") === dep) }))\n : [{ dep: \"\", members }];\n\n const grid = (list: typeof members) => (\n <Grid columns={{ minWidth: 220, max: 4 }} gap={4}>\n {list.map((m) => {\n const i = m._i;\n return (\n <Card key={i} padding={4} height=\"100%\">\n <VStack gap={1} hAlign=\"center\" style={{ textAlign: \"center\", height: \"100%\" }}>\n <Avatar src={m.photoUrl} name={m.name} size={96} />\n <Heading level={3} data-xicms-edit={`members.${i}.name`}>{m.name}</Heading>\n {m.role && <Text type=\"label\" data-xicms-edit={`members.${i}.role`} style={{ color: \"var(--color-accent)\" }}>{m.role}</Text>}\n {m.bio && <Text color=\"secondary\" data-xicms-edit={`members.${i}.bio`}>{m.bio}</Text>}\n {m.email && (\n <a href={`mailto:${m.email}`} style={{ color: \"var(--color-accent)\" }}>\n <Text type=\"supporting\" data-xicms-edit={`members.${i}.email`}>{m.email}</Text>\n </a>\n )}\n {m.phone && <Text type=\"supporting\" color=\"secondary\" data-xicms-edit={`members.${i}.phone`}>{m.phone}</Text>}\n {m.social && m.social.length > 0 && (\n <HStack gap={2} hAlign=\"center\" as=\"ul\" style={{ listStyle: \"none\", margin: 0, padding: 0, flexWrap: \"wrap\" }}>\n {m.social.map((s, j) => (\n <li key={j}>\n <a href={s.href} rel=\"noopener noreferrer\" target=\"_blank\" style={{ color: \"var(--color-accent)\" }}>\n <Text type=\"supporting\" data-xicms-edit={`members.${i}.social.${j}.platform`}>{s.platform}</Text>\n </a>\n </li>\n ))}\n </HStack>\n )}\n </VStack>\n </Card>\n );\n })}\n </Grid>\n );\n\n return (\n <VStack gap={4} as=\"section\" className=\"xicms-team\">\n {block.heading && (\n <Heading level={2} justify=\"center\" data-xicms-edit=\"heading\" style={{ textAlign: \"center\" }}>{block.heading}</Heading>\n )}\n {groups.map(({ dep, members: list }) => (\n <VStack key={dep || \"_overig\"} gap={3}>\n {block.groupByDepartment && groups.length > 1 && (\n <Heading level={3} justify=\"center\" style={{ textAlign: \"center\" }}>\n {dep || \"Overig\"}\n </Heading>\n )}\n {grid(list)}\n </VStack>\n ))}\n {block.jsonLd && (\n <script\n type=\"application/ld+json\"\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{ __html: jsonLdHtml(personJsonLd(members)) }}\n />\n )}\n </VStack>\n );\n}\n\nexport const teamBlock = defineBlock({\n type: \"team\",\n schema: TeamBlockSchema,\n Render: TeamRender,\n label: \"Team\",\n icon: \"👥\",\n defaults: () => ({\n heading: \"Ons team\",\n members: [{ name: \"Naam Medewerker\", role: \"Functie\" }],\n }),\n});\n"],"mappings":"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","names":[]}
@@ -48,14 +48,14 @@ const newsWidget = defineBlock({
48
48
  defaults: () => ({ heading: "Laatste nieuws", limit: 5, basePath: "/nieuws", showImages: false })
49
49
  });
50
50
  function AgendaWidgetRender({ block }) {
51
- const events = selectAgendaEvents(block.events, { hidePast: block.hidePast, limit: block.limit });
51
+ const events = selectAgendaEvents((block.events ?? []).map((e, i) => ({ ...e, _i: i })), { hidePast: block.hidePast, limit: block.limit });
52
52
  return /* @__PURE__ */ jsxs("div", { className: "xicms-widget xicms-widget--agenda", children: [
53
53
  /* @__PURE__ */ jsx("h3", { className: "xicms-widget__title", "data-xicms-edit": "heading", children: block.heading ?? "Komende evenementen" }),
54
- events.length === 0 ? /* @__PURE__ */ jsx("p", { className: "xicms-widget__empty", children: "Geen geplande evenementen." }) : /* @__PURE__ */ jsx("ul", { className: "xicms-widget__list", children: events.map((e, i) => /* @__PURE__ */ jsxs("li", { className: "xicms-widget__item xicms-widget__item--event", children: [
54
+ events.length === 0 ? /* @__PURE__ */ jsx("p", { className: "xicms-widget__empty", children: "Geen geplande evenementen." }) : /* @__PURE__ */ jsx("ul", { className: "xicms-widget__list", children: events.map((e) => /* @__PURE__ */ jsxs("li", { className: "xicms-widget__item xicms-widget__item--event", children: [
55
55
  /* @__PURE__ */ jsx("time", { className: "xicms-widget__meta", dateTime: e.start, children: formatEventDate(e.start) }),
56
- /* @__PURE__ */ jsx("span", { className: "xicms-widget__link", children: e.url ? /* @__PURE__ */ jsx("a", { href: e.url, children: e.title }) : e.title }),
57
- e.location && /* @__PURE__ */ jsx("span", { className: "xicms-widget__sub", children: e.location })
58
- ] }, i)) })
56
+ /* @__PURE__ */ jsx("span", { className: "xicms-widget__link", children: e.url ? /* @__PURE__ */ jsx("a", { href: e.url, "data-xicms-edit": `events.${e._i}.title`, children: e.title }) : /* @__PURE__ */ jsx("span", { "data-xicms-edit": `events.${e._i}.title`, children: e.title }) }),
57
+ e.location && /* @__PURE__ */ jsx("span", { className: "xicms-widget__sub", "data-xicms-edit": `events.${e._i}.location`, children: e.location })
58
+ ] }, e._i)) })
59
59
  ] });
60
60
  }
61
61
  const agendaWidget = defineBlock({
@@ -76,8 +76,8 @@ function OpeningHoursWidgetRender({ block }) {
76
76
  /* @__PURE__ */ jsx("table", { className: "xicms-widget__hours", children: /* @__PURE__ */ jsx("tbody", { children: rows.map((r, i) => {
77
77
  const isToday = block.highlightToday && todayIdx !== null && parseDays(r.day).includes(todayIdx);
78
78
  return /* @__PURE__ */ jsxs("tr", { className: isToday ? "xicms-widget__hours-today" : void 0, children: [
79
- /* @__PURE__ */ jsx("th", { scope: "row", children: r.day }),
80
- /* @__PURE__ */ jsx("td", { children: r.hours })
79
+ /* @__PURE__ */ jsx("th", { scope: "row", "data-xicms-edit": `rows.${i}.day`, children: r.day }),
80
+ /* @__PURE__ */ jsx("td", { "data-xicms-edit": `rows.${i}.hours`, children: r.hours })
81
81
  ] }, i);
82
82
  }) }) })
83
83
  ] });
@@ -104,9 +104,9 @@ function ContactWidgetRender({ block }) {
104
104
  return /* @__PURE__ */ jsxs("div", { className: "xicms-widget xicms-widget--contact", children: [
105
105
  /* @__PURE__ */ jsx("h3", { className: "xicms-widget__title", "data-xicms-edit": "heading", children: block.heading ?? "Contact" }),
106
106
  /* @__PURE__ */ jsxs("ul", { className: "xicms-widget__list", children: [
107
- block.address && /* @__PURE__ */ jsx("li", { className: "xicms-widget__item", children: block.address }),
108
- block.phone && /* @__PURE__ */ jsx("li", { className: "xicms-widget__item", children: /* @__PURE__ */ jsx("a", { href: `tel:${block.phone.replace(/\s+/g, "")}`, children: block.phone }) }),
109
- block.email && /* @__PURE__ */ jsx("li", { className: "xicms-widget__item", children: /* @__PURE__ */ jsx("a", { href: `mailto:${block.email}`, children: block.email }) })
107
+ block.address && /* @__PURE__ */ jsx("li", { className: "xicms-widget__item", "data-xicms-edit": "address", children: block.address }),
108
+ block.phone && /* @__PURE__ */ jsx("li", { className: "xicms-widget__item", children: /* @__PURE__ */ jsx("a", { href: `tel:${block.phone.replace(/\s+/g, "")}`, "data-xicms-edit": "phone", children: block.phone }) }),
109
+ block.email && /* @__PURE__ */ jsx("li", { className: "xicms-widget__item", children: /* @__PURE__ */ jsx("a", { href: `mailto:${block.email}`, "data-xicms-edit": "email", children: block.email }) })
110
110
  ] })
111
111
  ] });
112
112
  }
@@ -120,11 +120,11 @@ const contactWidget = defineBlock({
120
120
  defaults: () => ({ heading: "Contact" })
121
121
  });
122
122
  function SocialWidgetRender({ block }) {
123
- const items = (block.items ?? []).filter((i) => i.href && i.platform);
123
+ const items = (block.items ?? []).map((it, i) => ({ ...it, _i: i })).filter((i) => i.href && i.platform);
124
124
  if (items.length === 0) return null;
125
125
  return /* @__PURE__ */ jsxs("div", { className: "xicms-widget xicms-widget--social", children: [
126
126
  block.heading && /* @__PURE__ */ jsx("h3", { className: "xicms-widget__title", "data-xicms-edit": "heading", children: block.heading }),
127
- /* @__PURE__ */ jsx("ul", { className: "xicms-widget__social", children: items.map((it, i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", { href: it.href, rel: "noopener noreferrer", target: "_blank", children: it.platform }) }, i)) })
127
+ /* @__PURE__ */ jsx("ul", { className: "xicms-widget__social", children: items.map((it) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", { href: it.href, rel: "noopener noreferrer", target: "_blank", "data-xicms-edit": `items.${it._i}.platform`, children: it.platform }) }, it._i)) })
128
128
  ] });
129
129
  }
130
130
  const socialWidget = defineBlock({
@@ -140,10 +140,10 @@ function NewsletterWidgetRender({ block }) {
140
140
  const [email, setEmail] = useState("");
141
141
  return /* @__PURE__ */ jsxs("div", { className: "xicms-widget xicms-widget--newsletter", children: [
142
142
  /* @__PURE__ */ jsx("h3", { className: "xicms-widget__title", "data-xicms-edit": "heading", children: block.heading ?? "Nieuwsbrief" }),
143
- block.text && /* @__PURE__ */ jsx("p", { className: "xicms-widget__sub", children: block.text }),
143
+ block.text && /* @__PURE__ */ jsx("p", { className: "xicms-widget__sub", "data-xicms-edit": "text", children: block.text }),
144
144
  block.actionUrl ? /* @__PURE__ */ jsxs("form", { className: "xicms-widget__form", action: block.actionUrl, method: "post", target: "_blank", style: { display: "grid", gap: "0.6rem" }, children: [
145
145
  /* @__PURE__ */ jsx(TextInput, { label: "E-mailadres", isLabelHidden: true, type: "email", htmlName: "EMAIL", isRequired: true, placeholder: "je@email.nl", value: email, onChange: setEmail }),
146
- /* @__PURE__ */ jsx(Button, { label: block.buttonLabel, variant: "primary", type: "submit" })
146
+ /* @__PURE__ */ jsx(Button, { label: block.buttonLabel, variant: "primary", type: "submit", children: /* @__PURE__ */ jsx("span", { "data-xicms-edit": "buttonLabel", children: block.buttonLabel }) })
147
147
  ] }) : /* @__PURE__ */ jsx("p", { className: "xicms-widget__empty", children: "Stel een aanmeld-URL in." })
148
148
  ] });
149
149
  }
@@ -159,9 +159,9 @@ const newsletterWidget = defineBlock({
159
159
  function CtaWidgetRender({ block }) {
160
160
  if (!block.title && !block.text) return null;
161
161
  return /* @__PURE__ */ jsxs("div", { className: "xicms-widget xicms-widget--cta", style: block.backgroundColor ? { background: block.backgroundColor } : void 0, children: [
162
- block.title && /* @__PURE__ */ jsx("h3", { className: "xicms-widget__title", "data-xicms-edit": "heading", children: block.title }),
163
- block.text && /* @__PURE__ */ jsx("p", { className: "xicms-widget__sub", children: block.text }),
164
- block.buttonLabel && /* @__PURE__ */ jsx(Btn, { label: block.buttonLabel, href: block.buttonHref, variant: "primary", size: "md" })
162
+ block.title && /* @__PURE__ */ jsx("h3", { className: "xicms-widget__title", "data-xicms-edit": "title", children: block.title }),
163
+ block.text && /* @__PURE__ */ jsx("p", { className: "xicms-widget__sub", "data-xicms-edit": "text", children: block.text }),
164
+ block.buttonLabel && /* @__PURE__ */ jsx(Btn, { label: block.buttonLabel, href: block.buttonHref, variant: "primary", size: "md", editField: "buttonLabel" })
165
165
  ] });
166
166
  }
167
167
  const ctaWidget = defineBlock({
@@ -194,25 +194,25 @@ const galleryWidget = defineBlock({
194
194
  defaults: () => ({ heading: "Foto's", columns: 3, items: [] })
195
195
  });
196
196
  function TestimonialsWidgetRender({ block }) {
197
- const items = (block.items ?? []).filter((t) => t.quote);
197
+ const items = (block.items ?? []).map((t, i) => ({ ...t, _i: i })).filter((t) => t.quote);
198
198
  if (items.length === 0) return null;
199
199
  return /* @__PURE__ */ jsxs("div", { className: "xicms-widget xicms-widget--testimonial", children: [
200
200
  block.heading && /* @__PURE__ */ jsx("h3", { className: "xicms-widget__title", "data-xicms-edit": "heading", children: block.heading }),
201
- /* @__PURE__ */ jsx("ul", { className: "xicms-widget__list", children: items.map((t, i) => /* @__PURE__ */ jsxs("li", { className: "xicms-widget__quote", children: [
201
+ /* @__PURE__ */ jsx("ul", { className: "xicms-widget__list", children: items.map((t) => /* @__PURE__ */ jsxs("li", { className: "xicms-widget__quote", children: [
202
202
  typeof t.rating === "number" && /* @__PURE__ */ jsxs("span", { className: "xicms-widget__stars", "aria-label": `${t.rating} van 5`, children: [
203
203
  "\u2605".repeat(t.rating),
204
204
  "\u2606".repeat(5 - t.rating)
205
205
  ] }),
206
206
  /* @__PURE__ */ jsxs("p", { children: [
207
207
  "\u201C",
208
- t.quote,
208
+ /* @__PURE__ */ jsx("span", { "data-xicms-edit": `items.${t._i}.quote`, children: t.quote }),
209
209
  "\u201D"
210
210
  ] }),
211
211
  t.author && /* @__PURE__ */ jsxs("span", { className: "xicms-widget__meta", children: [
212
212
  "\u2014 ",
213
- t.author
213
+ /* @__PURE__ */ jsx("span", { "data-xicms-edit": `items.${t._i}.author`, children: t.author })
214
214
  ] })
215
- ] }, i)) })
215
+ ] }, t._i)) })
216
216
  ] });
217
217
  }
218
218
  const testimonialsWidget = defineBlock({
@@ -251,18 +251,18 @@ const cardsWidget = defineBlock({
251
251
  defaults: () => ({ heading: "Uitgelicht", items: [{ icon: "\u2B50", title: "Dienst", text: "Korte omschrijving." }] })
252
252
  });
253
253
  function DownloadsWidgetRender({ block }) {
254
- const items = (block.items ?? []).filter((d) => d.label && d.href).slice(0, block.limit);
254
+ const items = (block.items ?? []).map((d, i) => ({ ...d, _i: i })).filter((d) => d.label && d.href).slice(0, block.limit);
255
255
  if (items.length === 0) return null;
256
256
  return /* @__PURE__ */ jsxs("div", { className: "xicms-widget xicms-widget--downloads", children: [
257
257
  /* @__PURE__ */ jsx("h3", { className: "xicms-widget__title", "data-xicms-edit": "heading", children: block.heading ?? "Downloads" }),
258
- /* @__PURE__ */ jsx("ul", { className: "xicms-widget__list", children: items.map((d, i) => /* @__PURE__ */ jsxs("li", { className: "xicms-widget__item", children: [
258
+ /* @__PURE__ */ jsx("ul", { className: "xicms-widget__list", children: items.map((d) => /* @__PURE__ */ jsxs("li", { className: "xicms-widget__item", children: [
259
259
  /* @__PURE__ */ jsxs("a", { className: "xicms-widget__link", href: d.href, download: true, children: [
260
260
  /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u{1F4C4}" }),
261
261
  " ",
262
- d.label
262
+ /* @__PURE__ */ jsx("span", { "data-xicms-edit": `items.${d._i}.label`, children: d.label })
263
263
  ] }),
264
- d.meta && /* @__PURE__ */ jsx("span", { className: "xicms-widget__meta", children: d.meta })
265
- ] }, i)) })
264
+ d.meta && /* @__PURE__ */ jsx("span", { className: "xicms-widget__meta", "data-xicms-edit": `items.${d._i}.meta`, children: d.meta })
265
+ ] }, d._i)) })
266
266
  ] });
267
267
  }
268
268
  const downloadsWidget = defineBlock({
@@ -279,7 +279,7 @@ function CountdownWidgetRender({ block }) {
279
279
  if (!block.target) return null;
280
280
  return /* @__PURE__ */ jsxs("div", { className: "xicms-widget xicms-widget--countdown", children: [
281
281
  block.heading && /* @__PURE__ */ jsx("h3", { className: "xicms-widget__title", "data-xicms-edit": "heading", children: block.heading }),
282
- r === null ? /* @__PURE__ */ jsx("p", { className: "xicms-widget__empty", "aria-hidden": "true", children: "\u2026" }) : r.done ? /* @__PURE__ */ jsx("p", { className: "xicms-countdown__expired", children: block.expiredText }) : /* @__PURE__ */ jsx(CountdownDigits, { r, showLabels: true })
282
+ r === null ? /* @__PURE__ */ jsx("p", { className: "xicms-widget__empty", "aria-hidden": "true", children: "\u2026" }) : r.done ? /* @__PURE__ */ jsx("p", { className: "xicms-countdown__expired", "data-xicms-edit": "expiredText", children: block.expiredText }) : /* @__PURE__ */ jsx(CountdownDigits, { r, showLabels: true })
283
283
  ] });
284
284
  }
285
285
  const countdownWidget = 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, { 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, i) => (\n <li key={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\">{e.url ? <a href={e.url}>{e.title}</a> : e.title}</span>\n {e.location && <span className=\"xicms-widget__sub\">{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\">{r.day}</th>\n <td>{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\">{block.address}</li>}\n {block.phone && (\n <li className=\"xicms-widget__item\"><a href={`tel:${block.phone.replace(/\\s+/g, \"\")}`}>{block.phone}</a></li>\n )}\n {block.email && (\n <li className=\"xicms-widget__item\"><a href={`mailto:${block.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 const items = (block.items ?? []).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, i) => (\n <li key={i}><a href={it.href} rel=\"noopener noreferrer\" target=\"_blank\">{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\">{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 </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=\"heading\">{block.title}</h3>}\n {block.text && <p className=\"xicms-widget__sub\">{block.text}</p>}\n {block.buttonLabel && (\n <Btn label={block.buttonLabel} href={block.buttonHref} variant=\"primary\" size=\"md\" />\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 const items = (block.items ?? []).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, i) => (\n <li key={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>“{t.quote}”</p>\n {t.author && <span className=\"xicms-widget__meta\">— {t.author}</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 const items = (block.items ?? []).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, i) => (\n <li key={i} className=\"xicms-widget__item\">\n <a className=\"xicms-widget__link\" href={d.href} download>\n <span aria-hidden=\"true\">📄</span> {d.label}\n </a>\n {d.meta && <span className=\"xicms-widget__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\">{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 {\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,13 +1,12 @@
1
1
  "use client";
2
- import { functionsRegion } from "../../../firebase/region.js";
3
2
  async function submitFormValues(siteId, formId, values, hp = "") {
4
- const [{ getFirebaseApp }, { getFunctions, httpsCallable }] = await Promise.all([
3
+ const [{ getFirebaseApp }, { callable }] = await Promise.all([
5
4
  import("../../../firebase/client.js"),
6
- import("firebase/functions")
5
+ import("../../../firebase/functionsClient.js")
7
6
  ]);
8
7
  const app = getFirebaseApp();
9
8
  if (!app) throw new Error("Niet beschikbaar.");
10
- const fn = httpsCallable(getFunctions(app, functionsRegion()), "submitForm");
9
+ const fn = callable(app, "submitForm");
11
10
  await fn({ siteId, formId, values, _hp: hp });
12
11
  }
13
12
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/blocks/builtins/lib/submitForm.ts"],"sourcesContent":["\"use client\";\n\nimport { functionsRegion } from \"../../../firebase/region\";\n\n/**\n * Verstuur een formulier-inzending via de `submitForm`-callable — gedeeld door het\n * formulier-blok en het nieuwsbrief-blok (formId-modus), zodat validatie/rate-limiting/\n * notificatie voor beide identiek server-side lopen.\n */\nexport async function submitFormValues(\n siteId: string,\n formId: string,\n values: Record<string, string | boolean>,\n hp = \"\",\n): Promise<void> {\n // Dynamisch: een bezoeker die nooit een formulier verstuurt, hoeft de SDK niet te downloaden.\n const [{ getFirebaseApp }, { getFunctions, httpsCallable }] = await Promise.all([\n import(\"../../../firebase/client\"),\n import(\"firebase/functions\"),\n ]);\n const app = getFirebaseApp();\n if (!app) throw new Error(\"Niet beschikbaar.\");\n const fn = httpsCallable(getFunctions(app, functionsRegion()), \"submitForm\");\n await fn({ siteId, formId, values, _hp: hp });\n}\n"],"mappings":";AAEA,SAAS,uBAAuB;AAOhC,eAAsB,iBACpB,QACA,QACA,QACA,KAAK,IACU;AAEf,QAAM,CAAC,EAAE,eAAe,GAAG,EAAE,cAAc,cAAc,CAAC,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC9E,OAAO,0BAA0B;AAAA,IACjC,OAAO,oBAAoB;AAAA,EAC7B,CAAC;AACD,QAAM,MAAM,eAAe;AAC3B,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,mBAAmB;AAC7C,QAAM,KAAK,cAAc,aAAa,KAAK,gBAAgB,CAAC,GAAG,YAAY;AAC3E,QAAM,GAAG,EAAE,QAAQ,QAAQ,QAAQ,KAAK,GAAG,CAAC;AAC9C;","names":[]}
1
+ {"version":3,"sources":["../../../../src/blocks/builtins/lib/submitForm.ts"],"sourcesContent":["\"use client\";\n\n/**\n * Verstuur een formulier-inzending via de `submitForm`-callable — gedeeld door het\n * formulier-blok en het nieuwsbrief-blok (formId-modus), zodat validatie/rate-limiting/\n * notificatie voor beide identiek server-side lopen.\n */\nexport async function submitFormValues(\n siteId: string,\n formId: string,\n values: Record<string, string | boolean>,\n hp = \"\",\n): Promise<void> {\n // Dynamisch: een bezoeker die nooit een formulier verstuurt, hoeft de SDK niet te downloaden.\n const [{ getFirebaseApp }, { callable }] = await Promise.all([\n import(\"../../../firebase/client\"),\n import(\"../../../firebase/functionsClient\"),\n ]);\n const app = getFirebaseApp();\n if (!app) throw new Error(\"Niet beschikbaar.\");\n const fn = callable(app, \"submitForm\");\n await fn({ siteId, formId, values, _hp: hp });\n}\n"],"mappings":";AAOA,eAAsB,iBACpB,QACA,QACA,QACA,KAAK,IACU;AAEf,QAAM,CAAC,EAAE,eAAe,GAAG,EAAE,SAAS,CAAC,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC3D,OAAO,0BAA0B;AAAA,IACjC,OAAO,mCAAmC;AAAA,EAC5C,CAAC;AACD,QAAM,MAAM,eAAe;AAC3B,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,mBAAmB;AAC7C,QAAM,KAAK,SAAS,KAAK,YAAY;AACrC,QAAM,GAAG,EAAE,QAAQ,QAAQ,QAAQ,KAAK,GAAG,CAAC;AAC9C;","names":[]}
@@ -27,9 +27,16 @@ export interface BtnProps {
27
27
  target?: string;
28
28
  onClick?: () => void;
29
29
  children?: ReactNode;
30
+ /**
31
+ * Veldpad voor inline bewerken, bv. `"buttonLabel"` of `` `items.${i}.ctaLabel` ``. Het label
32
+ * gaat dan door een eigen `<span>` met de `data-xicms-edit`-haak, zodat de knoptekst op het
33
+ * canvas te bewerken is i.p.v. alleen via het zijpaneel. Astryx houdt `label` als toegankelijke
34
+ * naam aan (het zet zelf `aria-label` zodra children afwijken), dus dit kost geen a11y.
35
+ */
36
+ editField?: string;
30
37
  }
31
38
  /**
32
39
  * Knop/CTA-helper bovenop Astryx `Button`. Rendert als link wanneer `href` gezet is. Houdt de
33
40
  * bestaande XiCMS-varianten (primary/secondary/outline) werkend via de mapping hierboven.
34
41
  */
35
- export declare function Btn({ label, href, variant, size, type, target, onClick }: BtnProps): import("react").JSX.Element;
42
+ export declare function Btn({ label, href, variant, size, type, target, onClick, editField }: BtnProps): import("react").JSX.Element;
@@ -17,7 +17,7 @@ const VARIANT_MAP = {
17
17
  outline: "ghost",
18
18
  ghost: "ghost"
19
19
  };
20
- function Btn({ label, href, variant = "primary", size = "lg", type, target, onClick }) {
20
+ function Btn({ label, href, variant = "primary", size = "lg", type, target, onClick, editField }) {
21
21
  return /* @__PURE__ */ jsx(
22
22
  Button,
23
23
  {
@@ -28,7 +28,8 @@ function Btn({ label, href, variant = "primary", size = "lg", type, target, onCl
28
28
  target: href && target ? target : void 0,
29
29
  rel: target === "_blank" ? "noopener noreferrer" : void 0,
30
30
  type: href ? void 0 : type ?? "button",
31
- clickAction: onClick
31
+ clickAction: onClick,
32
+ children: editField ? /* @__PURE__ */ jsx("span", { "data-xicms-edit": editField, children: label }) : void 0
32
33
  }
33
34
  );
34
35
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/ui/index.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * Gedeelde presentatie-primitieven voor de runtime-blokken — een dunne laag bovenop het Astryx\n * design system (Meta, StyleX). Blokken bouwen hierop i.p.v. losse `xicms-*`-classNames, zodat het\n * uiterlijk consistent is en we de onderlaag centraal kunnen wijzigen.\n *\n * De merk-look per site komt via de Astryx-token-mapping op `.xicms-root` (zie XiCMSProvider):\n * `--color-accent`, `--font-family-*`, `--radius-*` volgen de XiCMS-thema-tokens.\n */\n\nimport { type ReactNode } from \"react\";\nimport { Button, type ButtonVariant } from \"@astryxdesign/core/Button\";\n\nexport { VStack } from \"@astryxdesign/core/VStack\";\nexport { HStack } from \"@astryxdesign/core/HStack\";\nexport { Stack } from \"@astryxdesign/core/Stack\";\nexport { Grid } from \"@astryxdesign/core/Grid\";\nexport { Card } from \"@astryxdesign/core/Card\";\nexport { Heading } from \"@astryxdesign/core/Heading\";\nexport { Text } from \"@astryxdesign/core/Text\";\nexport { Divider } from \"@astryxdesign/core/Divider\";\nexport { Badge } from \"@astryxdesign/core/Badge\";\nexport { Avatar } from \"@astryxdesign/core/Avatar\";\n\n/** XiCMS-knopvarianten → Astryx-varianten (Astryx kent geen \"outline\" → ghost). */\nconst VARIANT_MAP: Record<string, ButtonVariant> = {\n primary: \"primary\",\n secondary: \"secondary\",\n outline: \"ghost\",\n ghost: \"ghost\",\n};\n\nexport interface BtnProps {\n label: string;\n href?: string;\n variant?: string;\n /** Marketing-knoppen zijn standaard wat groter dan de app-default. */\n size?: \"sm\" | \"md\" | \"lg\";\n type?: \"button\" | \"submit\" | \"reset\";\n target?: string;\n onClick?: () => void;\n children?: ReactNode;\n}\n\n/**\n * Knop/CTA-helper bovenop Astryx `Button`. Rendert als link wanneer `href` gezet is. Houdt de\n * bestaande XiCMS-varianten (primary/secondary/outline) werkend via de mapping hierboven.\n */\nexport function Btn({ label, href, variant = \"primary\", size = \"lg\", type, target, onClick }: BtnProps) {\n return (\n <Button\n label={label}\n variant={VARIANT_MAP[variant] ?? \"primary\"}\n size={size}\n href={href}\n target={href && target ? target : undefined}\n rel={target === \"_blank\" ? \"noopener noreferrer\" : undefined}\n type={href ? undefined : (type ?? \"button\")}\n clickAction={onClick}\n />\n );\n}\n"],"mappings":";AAmDI;AAvCJ,SAAS,cAAkC;AAE3C,SAAS,cAAc;AACvB,SAAS,cAAc;AACvB,SAAS,aAAa;AACtB,SAAS,YAAY;AACrB,SAAS,YAAY;AACrB,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,eAAe;AACxB,SAAS,aAAa;AACtB,SAAS,cAAc;AAGvB,MAAM,cAA6C;AAAA,EACjD,SAAS;AAAA,EACT,WAAW;AAAA,EACX,SAAS;AAAA,EACT,OAAO;AACT;AAkBO,SAAS,IAAI,EAAE,OAAO,MAAM,UAAU,WAAW,OAAO,MAAM,MAAM,QAAQ,QAAQ,GAAa;AACtG,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,SAAS,YAAY,OAAO,KAAK;AAAA,MACjC;AAAA,MACA;AAAA,MACA,QAAQ,QAAQ,SAAS,SAAS;AAAA,MAClC,KAAK,WAAW,WAAW,wBAAwB;AAAA,MACnD,MAAM,OAAO,SAAa,QAAQ;AAAA,MAClC,aAAa;AAAA;AAAA,EACf;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/blocks/ui/index.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * Gedeelde presentatie-primitieven voor de runtime-blokken — een dunne laag bovenop het Astryx\n * design system (Meta, StyleX). Blokken bouwen hierop i.p.v. losse `xicms-*`-classNames, zodat het\n * uiterlijk consistent is en we de onderlaag centraal kunnen wijzigen.\n *\n * De merk-look per site komt via de Astryx-token-mapping op `.xicms-root` (zie XiCMSProvider):\n * `--color-accent`, `--font-family-*`, `--radius-*` volgen de XiCMS-thema-tokens.\n */\n\nimport { type ReactNode } from \"react\";\nimport { Button, type ButtonVariant } from \"@astryxdesign/core/Button\";\n\nexport { VStack } from \"@astryxdesign/core/VStack\";\nexport { HStack } from \"@astryxdesign/core/HStack\";\nexport { Stack } from \"@astryxdesign/core/Stack\";\nexport { Grid } from \"@astryxdesign/core/Grid\";\nexport { Card } from \"@astryxdesign/core/Card\";\nexport { Heading } from \"@astryxdesign/core/Heading\";\nexport { Text } from \"@astryxdesign/core/Text\";\nexport { Divider } from \"@astryxdesign/core/Divider\";\nexport { Badge } from \"@astryxdesign/core/Badge\";\nexport { Avatar } from \"@astryxdesign/core/Avatar\";\n\n/** XiCMS-knopvarianten → Astryx-varianten (Astryx kent geen \"outline\" → ghost). */\nconst VARIANT_MAP: Record<string, ButtonVariant> = {\n primary: \"primary\",\n secondary: \"secondary\",\n outline: \"ghost\",\n ghost: \"ghost\",\n};\n\nexport interface BtnProps {\n label: string;\n href?: string;\n variant?: string;\n /** Marketing-knoppen zijn standaard wat groter dan de app-default. */\n size?: \"sm\" | \"md\" | \"lg\";\n type?: \"button\" | \"submit\" | \"reset\";\n target?: string;\n onClick?: () => void;\n children?: ReactNode;\n /**\n * Veldpad voor inline bewerken, bv. `\"buttonLabel\"` of `` `items.${i}.ctaLabel` ``. Het label\n * gaat dan door een eigen `<span>` met de `data-xicms-edit`-haak, zodat de knoptekst op het\n * canvas te bewerken is i.p.v. alleen via het zijpaneel. Astryx houdt `label` als toegankelijke\n * naam aan (het zet zelf `aria-label` zodra children afwijken), dus dit kost geen a11y.\n */\n editField?: string;\n}\n\n/**\n * Knop/CTA-helper bovenop Astryx `Button`. Rendert als link wanneer `href` gezet is. Houdt de\n * bestaande XiCMS-varianten (primary/secondary/outline) werkend via de mapping hierboven.\n */\nexport function Btn({ label, href, variant = \"primary\", size = \"lg\", type, target, onClick, editField }: BtnProps) {\n return (\n <Button\n label={label}\n variant={VARIANT_MAP[variant] ?? \"primary\"}\n size={size}\n href={href}\n target={href && target ? target : undefined}\n rel={target === \"_blank\" ? \"noopener noreferrer\" : undefined}\n type={href ? undefined : (type ?? \"button\")}\n clickAction={onClick}\n >\n {/* `undefined` laat Astryx op `label` terugvallen — alleen mét haak komt er een span omheen. */}\n {editField ? <span data-xicms-edit={editField}>{label}</span> : undefined}\n </Button>\n );\n}\n"],"mappings":";AAqEmB;AAzDnB,SAAS,cAAkC;AAE3C,SAAS,cAAc;AACvB,SAAS,cAAc;AACvB,SAAS,aAAa;AACtB,SAAS,YAAY;AACrB,SAAS,YAAY;AACrB,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,eAAe;AACxB,SAAS,aAAa;AACtB,SAAS,cAAc;AAGvB,MAAM,cAA6C;AAAA,EACjD,SAAS;AAAA,EACT,WAAW;AAAA,EACX,SAAS;AAAA,EACT,OAAO;AACT;AAyBO,SAAS,IAAI,EAAE,OAAO,MAAM,UAAU,WAAW,OAAO,MAAM,MAAM,QAAQ,SAAS,UAAU,GAAa;AACjH,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,SAAS,YAAY,OAAO,KAAK;AAAA,MACjC;AAAA,MACA;AAAA,MACA,QAAQ,QAAQ,SAAS,SAAS;AAAA,MAClC,KAAK,WAAW,WAAW,wBAAwB;AAAA,MACnD,MAAM,OAAO,SAAa,QAAQ;AAAA,MAClC,aAAa;AAAA,MAGZ,sBAAY,oBAAC,UAAK,mBAAiB,WAAY,iBAAM,IAAU;AAAA;AAAA,EAClE;AAEJ;","names":[]}
@@ -1,2 +1,10 @@
1
- /** Zwevende werkbalk voor ingelogde beheerders/editors. */
1
+ /**
2
+ * Zwevende werkbalk voor ingelogde beheerders/editors.
3
+ *
4
+ * Bewust met EIGEN klassen en eigen kleuren, niet met `.xicms-btn`. Die knop leest de
5
+ * `--xicms-*`-tokens van de klantsite, en dit balkje zweeft over die site heen: het nam daardoor
6
+ * half de huisstijl over (en op plekken waar de tokens niet in scope zijn, viel het terug op een
7
+ * indigo die bij niets hoorde). Gereedschap hoort er als gereedschap uit te zien — hetzelfde op
8
+ * elke site, herkenbaar los van de pagina eronder.
9
+ */
2
10
  export declare function EditBar(): import("react").JSX.Element | null;
@@ -7,11 +7,12 @@ function EditBar() {
7
7
  const { user, role, signOut, demo } = useAuth();
8
8
  const { open, openEditor } = useEditor();
9
9
  if (!canEdit(role) || !user || open) return null;
10
- return /* @__PURE__ */ jsxs("div", { className: "xicms-editbar", children: [
11
- /* @__PURE__ */ jsx("span", { style: { fontWeight: 600 }, children: demo ? "XiCMS \xB7 demo" : "XiCMS" }),
12
- /* @__PURE__ */ jsx("button", { type: "button", className: "xicms-btn", onClick: openEditor, children: "Bewerken" }),
13
- !demo && /* @__PURE__ */ jsx("a", { href: "/beheer", className: "xicms-btn xicms-btn--ghost", children: "Beheer" }),
14
- /* @__PURE__ */ jsx("button", { type: "button", className: "xicms-btn xicms-btn--ghost", onClick: () => void signOut(), children: "Uitloggen" })
10
+ return /* @__PURE__ */ jsxs("div", { className: "xicms-editbar", role: "toolbar", "aria-label": "Beheer", children: [
11
+ /* @__PURE__ */ jsx("span", { className: "xicms-editbar__brand", children: demo ? "XiCMS \xB7 demo" : "XiCMS" }),
12
+ /* @__PURE__ */ jsx("button", { type: "button", className: "xicms-editbar__btn xicms-editbar__btn--primary", onClick: openEditor, children: "Pagina bewerken" }),
13
+ /* @__PURE__ */ jsx("span", { className: "xicms-editbar__sep", "aria-hidden": "true" }),
14
+ !demo && /* @__PURE__ */ jsx("a", { href: "/beheer", className: "xicms-editbar__btn", children: "Beheer" }),
15
+ /* @__PURE__ */ jsx("button", { type: "button", className: "xicms-editbar__btn", onClick: () => void signOut(), children: "Uitloggen" })
15
16
  ] });
16
17
  }
17
18
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/EditBar.tsx"],"sourcesContent":["\"use client\";\n\nimport { useAuth } from \"../auth/AuthProvider\";\nimport { canEdit } from \"../auth/roles\";\nimport { useEditor } from \"../editor/EditorProvider\";\n\n/** Zwevende werkbalk voor ingelogde beheerders/editors. */\nexport function EditBar() {\n // Bewust via useAuth (niet via het deprecated ContentProvider-pad): de EditBar hoort bij het\n // block-model en mag niet aan het legacy inline-systeem hangen.\n const { user, role, signOut, demo } = useAuth();\n const { open, openEditor } = useEditor();\n\n if (!canEdit(role) || !user || open) return null;\n\n return (\n <div className=\"xicms-editbar\">\n <span style={{ fontWeight: 600 }}>{demo ? \"XiCMS · demo\" : \"XiCMS\"}</span>\n {/* Eén heldere bewerk-actie: opent de visuele editor waarin je tekst ter plekke (inline) bewerkt\n én structuur/blokken aanpast. Geen aparte (verwarrende) inline-toggle meer. */}\n <button type=\"button\" className=\"xicms-btn\" onClick={openEditor}>\n Bewerken\n </button>\n {/* In de demo bestaat er geen /beheer-route; daar bewerk je alleen op de pagina. */}\n {!demo && <a href=\"/beheer\" className=\"xicms-btn xicms-btn--ghost\">Beheer</a>}\n <button type=\"button\" className=\"xicms-btn xicms-btn--ghost\" onClick={() => void signOut()}>\n Uitloggen\n </button>\n </div>\n );\n}\n"],"mappings":";AAgBI,SACE,KADF;AAdJ,SAAS,eAAe;AACxB,SAAS,eAAe;AACxB,SAAS,iBAAiB;AAGnB,SAAS,UAAU;AAGxB,QAAM,EAAE,MAAM,MAAM,SAAS,KAAK,IAAI,QAAQ;AAC9C,QAAM,EAAE,MAAM,WAAW,IAAI,UAAU;AAEvC,MAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,KAAM,QAAO;AAE5C,SACE,qBAAC,SAAI,WAAU,iBACb;AAAA,wBAAC,UAAK,OAAO,EAAE,YAAY,IAAI,GAAI,iBAAO,oBAAiB,SAAQ;AAAA,IAGnE,oBAAC,YAAO,MAAK,UAAS,WAAU,aAAY,SAAS,YAAY,sBAEjE;AAAA,IAEC,CAAC,QAAQ,oBAAC,OAAE,MAAK,WAAU,WAAU,8BAA6B,oBAAM;AAAA,IACzE,oBAAC,YAAO,MAAK,UAAS,WAAU,8BAA6B,SAAS,MAAM,KAAK,QAAQ,GAAG,uBAE5F;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/components/EditBar.tsx"],"sourcesContent":["\"use client\";\n\nimport { useAuth } from \"../auth/AuthProvider\";\nimport { canEdit } from \"../auth/roles\";\nimport { useEditor } from \"../editor/EditorProvider\";\n\n/**\n * Zwevende werkbalk voor ingelogde beheerders/editors.\n *\n * Bewust met EIGEN klassen en eigen kleuren, niet met `.xicms-btn`. Die knop leest de\n * `--xicms-*`-tokens van de klantsite, en dit balkje zweeft over die site heen: het nam daardoor\n * half de huisstijl over (en op plekken waar de tokens niet in scope zijn, viel het terug op een\n * indigo die bij niets hoorde). Gereedschap hoort er als gereedschap uit te zien — hetzelfde op\n * elke site, herkenbaar los van de pagina eronder.\n */\nexport function EditBar() {\n // Bewust via useAuth (niet via het deprecated ContentProvider-pad): de EditBar hoort bij het\n // block-model en mag niet aan het legacy inline-systeem hangen.\n const { user, role, signOut, demo } = useAuth();\n const { open, openEditor } = useEditor();\n\n if (!canEdit(role) || !user || open) return null;\n\n return (\n <div className=\"xicms-editbar\" role=\"toolbar\" aria-label=\"Beheer\">\n <span className=\"xicms-editbar__brand\">{demo ? \"XiCMS · demo\" : \"XiCMS\"}</span>\n {/* Eén heldere hoofdactie: opent de visuele editor waarin je tekst ter plekke (inline)\n bewerkt én blokken aanpast. Woordelijk hetzelfde als waar de demo-balk naar verwijst. */}\n <button type=\"button\" className=\"xicms-editbar__btn xicms-editbar__btn--primary\" onClick={openEditor}>\n Pagina bewerken\n </button>\n <span className=\"xicms-editbar__sep\" aria-hidden=\"true\" />\n {/* In de demo bestaat er geen /beheer-route; daar bewerk je alleen op de pagina. */}\n {!demo && <a href=\"/beheer\" className=\"xicms-editbar__btn\">Beheer</a>}\n <button type=\"button\" className=\"xicms-editbar__btn\" onClick={() => void signOut()}>\n Uitloggen\n </button>\n </div>\n );\n}\n"],"mappings":";AAwBI,SACE,KADF;AAtBJ,SAAS,eAAe;AACxB,SAAS,eAAe;AACxB,SAAS,iBAAiB;AAWnB,SAAS,UAAU;AAGxB,QAAM,EAAE,MAAM,MAAM,SAAS,KAAK,IAAI,QAAQ;AAC9C,QAAM,EAAE,MAAM,WAAW,IAAI,UAAU;AAEvC,MAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,KAAM,QAAO;AAE5C,SACE,qBAAC,SAAI,WAAU,iBAAgB,MAAK,WAAU,cAAW,UACvD;AAAA,wBAAC,UAAK,WAAU,wBAAwB,iBAAO,oBAAiB,SAAQ;AAAA,IAGxE,oBAAC,YAAO,MAAK,UAAS,WAAU,kDAAiD,SAAS,YAAY,6BAEtG;AAAA,IACA,oBAAC,UAAK,WAAU,sBAAqB,eAAY,QAAO;AAAA,IAEvD,CAAC,QAAQ,oBAAC,OAAE,MAAK,WAAU,WAAU,sBAAqB,oBAAM;AAAA,IACjE,oBAAC,YAAO,MAAK,UAAS,WAAU,sBAAqB,SAAS,MAAM,KAAK,QAAQ,GAAG,uBAEpF;AAAA,KACF;AAEJ;","names":[]}
@@ -1,6 +1,5 @@
1
1
  "use client";
2
2
  import { useEffect } from "react";
3
- import { functionsRegion } from "../firebase/region.js";
4
3
  import { useSiteConfig } from "../config.js";
5
4
  function PageView({ path }) {
6
5
  const { siteId } = useSiteConfig();
@@ -13,14 +12,13 @@ function PageView({ path }) {
13
12
  } catch {
14
13
  }
15
14
  void (async () => {
16
- const [{ getFirebaseApp }, { getFunctions, httpsCallable }] = await Promise.all([
15
+ const [{ getFirebaseApp }, { callable }] = await Promise.all([
17
16
  import("../firebase/client.js"),
18
- import("firebase/functions")
17
+ import("../firebase/functionsClient.js")
19
18
  ]);
20
19
  const app = getFirebaseApp();
21
20
  if (!app) return;
22
- const fn = httpsCallable(getFunctions(app, functionsRegion()), "trackView");
23
- await fn({ siteId, path });
21
+ await callable(app, "trackView")({ siteId, path });
24
22
  })().catch(() => {
25
23
  });
26
24
  }, [siteId, path]);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/PageView.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\nimport { functionsRegion } from \"../firebase/region\";\nimport { useSiteConfig } from \"../config\";\n\n/**\n * Registreert één pageview voor de huidige site/pad — max. één keer per browsersessie per pad\n * (sessionStorage). Privacy-vriendelijk en goedkoop. No-op zonder Firebase. Plaats dit in de\n * publieke layout van een klantsite (binnen <XiCMSProvider>).\n */\nexport function PageView({ path }: { path: string }) {\n const { siteId } = useSiteConfig();\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const key = `xicms_view:${siteId}:${path}`;\n try {\n if (sessionStorage.getItem(key)) return;\n sessionStorage.setItem(key, \"1\");\n } catch {\n /* private mode e.d. — ga gewoon door */\n }\n // Firebase pas laden wanneer er écht getracked wordt: statisch importeren zette de hele SDK\n // in de bundel van elke publieke pagina, voor één fire-and-forget-call.\n void (async () => {\n const [{ getFirebaseApp }, { getFunctions, httpsCallable }] = await Promise.all([\n import(\"../firebase/client\"),\n import(\"firebase/functions\"),\n ]);\n const app = getFirebaseApp();\n if (!app) return;\n const fn = httpsCallable(getFunctions(app, functionsRegion()), \"trackView\");\n await fn({ siteId, path });\n })().catch(() => {\n /* stats mogen nooit de site breken */\n });\n }, [siteId, path]);\n\n return null;\n}\n"],"mappings":";AAEA,SAAS,iBAAiB;AAC1B,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAOvB,SAAS,SAAS,EAAE,KAAK,GAAqB;AACnD,QAAM,EAAE,OAAO,IAAI,cAAc;AAEjC,YAAU,MAAM;AACd,QAAI,OAAO,WAAW,YAAa;AACnC,UAAM,MAAM,cAAc,MAAM,IAAI,IAAI;AACxC,QAAI;AACF,UAAI,eAAe,QAAQ,GAAG,EAAG;AACjC,qBAAe,QAAQ,KAAK,GAAG;AAAA,IACjC,QAAQ;AAAA,IAER;AAGA,UAAM,YAAY;AAChB,YAAM,CAAC,EAAE,eAAe,GAAG,EAAE,cAAc,cAAc,CAAC,IAAI,MAAM,QAAQ,IAAI;AAAA,QAC9E,OAAO,oBAAoB;AAAA,QAC3B,OAAO,oBAAoB;AAAA,MAC7B,CAAC;AACD,YAAM,MAAM,eAAe;AAC3B,UAAI,CAAC,IAAK;AACV,YAAM,KAAK,cAAc,aAAa,KAAK,gBAAgB,CAAC,GAAG,WAAW;AAC1E,YAAM,GAAG,EAAE,QAAQ,KAAK,CAAC;AAAA,IAC3B,GAAG,EAAE,MAAM,MAAM;AAAA,IAEjB,CAAC;AAAA,EACH,GAAG,CAAC,QAAQ,IAAI,CAAC;AAEjB,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../src/components/PageView.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\nimport { useSiteConfig } from \"../config\";\n\n/**\n * Registreert één pageview voor de huidige site/pad — max. één keer per browsersessie per pad\n * (sessionStorage). Privacy-vriendelijk en goedkoop. No-op zonder Firebase. Plaats dit in de\n * publieke layout van een klantsite (binnen <XiCMSProvider>).\n */\nexport function PageView({ path }: { path: string }) {\n const { siteId } = useSiteConfig();\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const key = `xicms_view:${siteId}:${path}`;\n try {\n if (sessionStorage.getItem(key)) return;\n sessionStorage.setItem(key, \"1\");\n } catch {\n /* private mode e.d. — ga gewoon door */\n }\n // Firebase pas laden wanneer er écht getracked wordt: statisch importeren zette de hele SDK\n // in de bundel van elke publieke pagina, voor één fire-and-forget-call.\n void (async () => {\n const [{ getFirebaseApp }, { callable }] = await Promise.all([\n import(\"../firebase/client\"),\n import(\"../firebase/functionsClient\"),\n ]);\n const app = getFirebaseApp();\n if (!app) return;\n await callable(app, \"trackView\")({ siteId, path });\n })().catch(() => {\n /* stats mogen nooit de site breken */\n });\n }, [siteId, path]);\n\n return null;\n}\n"],"mappings":";AAEA,SAAS,iBAAiB;AAC1B,SAAS,qBAAqB;AAOvB,SAAS,SAAS,EAAE,KAAK,GAAqB;AACnD,QAAM,EAAE,OAAO,IAAI,cAAc;AAEjC,YAAU,MAAM;AACd,QAAI,OAAO,WAAW,YAAa;AACnC,UAAM,MAAM,cAAc,MAAM,IAAI,IAAI;AACxC,QAAI;AACF,UAAI,eAAe,QAAQ,GAAG,EAAG;AACjC,qBAAe,QAAQ,KAAK,GAAG;AAAA,IACjC,QAAQ;AAAA,IAER;AAGA,UAAM,YAAY;AAChB,YAAM,CAAC,EAAE,eAAe,GAAG,EAAE,SAAS,CAAC,IAAI,MAAM,QAAQ,IAAI;AAAA,QAC3D,OAAO,oBAAoB;AAAA,QAC3B,OAAO,6BAA6B;AAAA,MACtC,CAAC;AACD,YAAM,MAAM,eAAe;AAC3B,UAAI,CAAC,IAAK;AACV,YAAM,SAAS,KAAK,WAAW,EAAE,EAAE,QAAQ,KAAK,CAAC;AAAA,IACnD,GAAG,EAAE,MAAM,MAAM;AAAA,IAEjB,CAAC;AAAA,EACH,GAAG,CAAC,QAAQ,IAAI,CAAC;AAEjB,SAAO;AACT;","names":[]}
@@ -10,6 +10,10 @@ function readServiceAccount() {
10
10
  }
11
11
  function getAdminApp() {
12
12
  if (getApps().length) return getApp();
13
+ if (process.env.FIRESTORE_EMULATOR_HOST) {
14
+ const projectId = process.env.FIREBASE_PROJECT_ID ?? process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID;
15
+ if (projectId) return initializeApp({ projectId });
16
+ }
13
17
  const sa = readServiceAccount();
14
18
  if (!sa) return null;
15
19
  return initializeApp({ credential: cert(sa) });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/firebase/admin.ts"],"sourcesContent":["import \"server-only\";\n\nimport { cert, getApp, getApps, initializeApp, type App } from \"firebase-admin/app\";\nimport { getFirestore, type Firestore } from \"firebase-admin/firestore\";\n\n/**\n * Server-side Firebase Admin (alleen voor server actions / route handlers).\n * NOOIT importeren in client-componenten — importeer dit via \"@xiwebdesign/xicms-core/server\".\n *\n * BEWUST ZONDER `firebase-admin/auth` — die leeft in ./adminAuth.ts. Reden: `server/pages.ts`\n * importeert `getAdminDb` voor élke publieke pagina, en zolang auth in ditzelfde bestand stond\n * belandde de hele auth-tak in de route-bundel van iedere site. Dat is niet alleen ballast maar\n * FATAAL op Vercel: firebase-admin/auth trekt jwks-rsa aan, die `require(\"jose\")` doet terwijl\n * jose 6 puur ESM is. Turbopack laadt externals strikt als CJS, dus élke server-render van een\n * publieke pagina eindigde in ERR_REQUIRE_ESM → HTTP 500. Geprerenderde pagina's overleefden dat\n * (die draaien niet op de server), waardoor het pas opvalt zodra er echte CMS-content is.\n *\n * Credentials komen uit env:\n * FIREBASE_PROJECT_ID\n * FIREBASE_CLIENT_EMAIL\n * FIREBASE_PRIVATE_KEY (met letterlijke \\n; die vervangen we hieronder)\n */\nfunction readServiceAccount() {\n const projectId = process.env.FIREBASE_PROJECT_ID;\n const clientEmail = process.env.FIREBASE_CLIENT_EMAIL;\n const privateKey = process.env.FIREBASE_PRIVATE_KEY?.replace(/\\\\n/g, \"\\n\");\n if (!projectId || !clientEmail || !privateKey) return null;\n return { projectId, clientEmail, privateKey };\n}\n\nexport function getAdminApp(): App | null {\n if (getApps().length) return getApp();\n const sa = readServiceAccount();\n if (!sa) return null;\n return initializeApp({ credential: cert(sa) });\n}\n\nexport function getAdminDb(): Firestore | null {\n const app = getAdminApp();\n return app ? getFirestore(app) : null;\n}\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,MAAM,QAAQ,SAAS,qBAA+B;AAC/D,SAAS,oBAAoC;AAmB7C,SAAS,qBAAqB;AAC5B,QAAM,YAAY,QAAQ,IAAI;AAC9B,QAAM,cAAc,QAAQ,IAAI;AAChC,QAAM,aAAa,QAAQ,IAAI,sBAAsB,QAAQ,QAAQ,IAAI;AACzE,MAAI,CAAC,aAAa,CAAC,eAAe,CAAC,WAAY,QAAO;AACtD,SAAO,EAAE,WAAW,aAAa,WAAW;AAC9C;AAEO,SAAS,cAA0B;AACxC,MAAI,QAAQ,EAAE,OAAQ,QAAO,OAAO;AACpC,QAAM,KAAK,mBAAmB;AAC9B,MAAI,CAAC,GAAI,QAAO;AAChB,SAAO,cAAc,EAAE,YAAY,KAAK,EAAE,EAAE,CAAC;AAC/C;AAEO,SAAS,aAA+B;AAC7C,QAAM,MAAM,YAAY;AACxB,SAAO,MAAM,aAAa,GAAG,IAAI;AACnC;","names":[]}
1
+ {"version":3,"sources":["../../src/firebase/admin.ts"],"sourcesContent":["import \"server-only\";\n\nimport { cert, getApp, getApps, initializeApp, type App } from \"firebase-admin/app\";\nimport { getFirestore, type Firestore } from \"firebase-admin/firestore\";\n\n/**\n * Server-side Firebase Admin (alleen voor server actions / route handlers).\n * NOOIT importeren in client-componenten — importeer dit via \"@xiwebdesign/xicms-core/server\".\n *\n * BEWUST ZONDER `firebase-admin/auth` — die leeft in ./adminAuth.ts. Reden: `server/pages.ts`\n * importeert `getAdminDb` voor élke publieke pagina, en zolang auth in ditzelfde bestand stond\n * belandde de hele auth-tak in de route-bundel van iedere site. Dat is niet alleen ballast maar\n * FATAAL op Vercel: firebase-admin/auth trekt jwks-rsa aan, die `require(\"jose\")` doet terwijl\n * jose 6 puur ESM is. Turbopack laadt externals strikt als CJS, dus élke server-render van een\n * publieke pagina eindigde in ERR_REQUIRE_ESM → HTTP 500. Geprerenderde pagina's overleefden dat\n * (die draaien niet op de server), waardoor het pas opvalt zodra er echte CMS-content is.\n *\n * Credentials komen uit env:\n * FIREBASE_PROJECT_ID\n * FIREBASE_CLIENT_EMAIL\n * FIREBASE_PRIVATE_KEY (met letterlijke \\n; die vervangen we hieronder)\n */\nfunction readServiceAccount() {\n const projectId = process.env.FIREBASE_PROJECT_ID;\n const clientEmail = process.env.FIREBASE_CLIENT_EMAIL;\n const privateKey = process.env.FIREBASE_PRIVATE_KEY?.replace(/\\\\n/g, \"\\n\");\n if (!projectId || !clientEmail || !privateKey) return null;\n return { projectId, clientEmail, privateKey };\n}\n\nexport function getAdminApp(): App | null {\n if (getApps().length) return getApp();\n // Emulator-tak: firebase-admin praat vanzelf met `FIRESTORE_EMULATOR_HOST` zodra die gezet is en\n // heeft dan GEEN credentials nodig — alleen een projectId. Zonder deze tak gaf `getAdminDb()`\n // lokaal `null` (er is geen service-account op je machine) en viel de reader terug op het\n // keyless REST-pad, dat naar de ECHTE Firestore wijst. De emulator-ondersteuning van 7.3 dekte\n // daardoor alleen de browser; de SERVER-kant — en dus live-reads, het hele punt — was lokaal niet\n // te testen. De vlag is veilig als signaal: hij hoort alleen in een lokale shell te staan, en\n // firebase-admin zelf gebruikt precies dezelfde variabele.\n if (process.env.FIRESTORE_EMULATOR_HOST) {\n const projectId = process.env.FIREBASE_PROJECT_ID ?? process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID;\n if (projectId) return initializeApp({ projectId });\n }\n const sa = readServiceAccount();\n if (!sa) return null;\n return initializeApp({ credential: cert(sa) });\n}\n\nexport function getAdminDb(): Firestore | null {\n const app = getAdminApp();\n return app ? getFirestore(app) : null;\n}\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,MAAM,QAAQ,SAAS,qBAA+B;AAC/D,SAAS,oBAAoC;AAmB7C,SAAS,qBAAqB;AAC5B,QAAM,YAAY,QAAQ,IAAI;AAC9B,QAAM,cAAc,QAAQ,IAAI;AAChC,QAAM,aAAa,QAAQ,IAAI,sBAAsB,QAAQ,QAAQ,IAAI;AACzE,MAAI,CAAC,aAAa,CAAC,eAAe,CAAC,WAAY,QAAO;AACtD,SAAO,EAAE,WAAW,aAAa,WAAW;AAC9C;AAEO,SAAS,cAA0B;AACxC,MAAI,QAAQ,EAAE,OAAQ,QAAO,OAAO;AAQpC,MAAI,QAAQ,IAAI,yBAAyB;AACvC,UAAM,YAAY,QAAQ,IAAI,uBAAuB,QAAQ,IAAI;AACjE,QAAI,UAAW,QAAO,cAAc,EAAE,UAAU,CAAC;AAAA,EACnD;AACA,QAAM,KAAK,mBAAmB;AAC9B,MAAI,CAAC,GAAI,QAAO;AAChB,SAAO,cAAc,EAAE,YAAY,KAAK,EAAE,EAAE,CAAC;AAC/C;AAEO,SAAS,aAA+B;AAC7C,QAAM,MAAM,YAAY;AACxB,SAAO,MAAM,aAAa,GAAG,IAAI;AACnC;","names":[]}