@xiwebdesign/xicms-core 7.14.0 → 7.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/dist/admin/AdminApp.js +4 -3
  2. package/dist/admin/AdminApp.js.map +1 -1
  3. package/dist/admin/dashboard/DashboardPanel.d.ts +3 -0
  4. package/dist/admin/dashboard/DashboardPanel.js +316 -0
  5. package/dist/admin/dashboard/DashboardPanel.js.map +1 -0
  6. package/dist/admin/navContext.d.ts +14 -0
  7. package/dist/admin/navContext.js +12 -0
  8. package/dist/admin/navContext.js.map +1 -0
  9. package/dist/admin/pages/PagesPanel.js +38 -12
  10. package/dist/admin/pages/PagesPanel.js.map +1 -1
  11. package/dist/admin/panelRegistry.js +4 -0
  12. package/dist/admin/panelRegistry.js.map +1 -1
  13. package/dist/admin/ui/PanelIcon.js +5 -0
  14. package/dist/admin/ui/PanelIcon.js.map +1 -1
  15. package/dist/admin/visual/VisualEditor.js +56 -20
  16. package/dist/admin/visual/VisualEditor.js.map +1 -1
  17. package/dist/admin.css +1 -1
  18. package/dist/auth/AuthProvider.js +8 -1
  19. package/dist/auth/AuthProvider.js.map +1 -1
  20. package/dist/blocks/builtins/Accordion.d.ts +1 -2
  21. package/dist/blocks/builtins/Accordion.js +2 -39
  22. package/dist/blocks/builtins/Accordion.js.map +1 -1
  23. package/dist/blocks/builtins/AccordionRender.d.ts +7 -0
  24. package/dist/blocks/builtins/AccordionRender.js +42 -0
  25. package/dist/blocks/builtins/AccordionRender.js.map +1 -0
  26. package/dist/blocks/builtins/Agenda.d.ts +1 -29
  27. package/dist/blocks/builtins/Agenda.js +3 -94
  28. package/dist/blocks/builtins/Agenda.js.map +1 -1
  29. package/dist/blocks/builtins/AgendaRender.d.ts +34 -0
  30. package/dist/blocks/builtins/AgendaRender.js +96 -0
  31. package/dist/blocks/builtins/AgendaRender.js.map +1 -0
  32. package/dist/blocks/builtins/Banner.d.ts +1 -2
  33. package/dist/blocks/builtins/Banner.js +2 -32
  34. package/dist/blocks/builtins/Banner.js.map +1 -1
  35. package/dist/blocks/builtins/BannerRender.d.ts +11 -0
  36. package/dist/blocks/builtins/BannerRender.js +35 -0
  37. package/dist/blocks/builtins/BannerRender.js.map +1 -0
  38. package/dist/blocks/builtins/BeforeAfter.d.ts +1 -2
  39. package/dist/blocks/builtins/BeforeAfter.js +2 -31
  40. package/dist/blocks/builtins/BeforeAfter.js.map +1 -1
  41. package/dist/blocks/builtins/BeforeAfterRender.d.ts +11 -0
  42. package/dist/blocks/builtins/BeforeAfterRender.js +34 -0
  43. package/dist/blocks/builtins/BeforeAfterRender.js.map +1 -0
  44. package/dist/blocks/builtins/Booking.d.ts +1 -2
  45. package/dist/blocks/builtins/Booking.js +2 -14
  46. package/dist/blocks/builtins/Booking.js.map +1 -1
  47. package/dist/blocks/builtins/BookingRender.d.ts +8 -0
  48. package/dist/blocks/builtins/BookingRender.js +17 -0
  49. package/dist/blocks/builtins/BookingRender.js.map +1 -0
  50. package/dist/blocks/builtins/Breadcrumbs.d.ts +1 -10
  51. package/dist/blocks/builtins/Breadcrumbs.js +3 -69
  52. package/dist/blocks/builtins/Breadcrumbs.js.map +1 -1
  53. package/dist/blocks/builtins/BreadcrumbsRender.d.ts +18 -0
  54. package/dist/blocks/builtins/BreadcrumbsRender.js +71 -0
  55. package/dist/blocks/builtins/BreadcrumbsRender.js.map +1 -0
  56. package/dist/blocks/builtins/Cards.d.ts +1 -2
  57. package/dist/blocks/builtins/Cards.js +2 -74
  58. package/dist/blocks/builtins/Cards.js.map +1 -1
  59. package/dist/blocks/builtins/CardsRender.d.ts +7 -0
  60. package/dist/blocks/builtins/CardsRender.js +77 -0
  61. package/dist/blocks/builtins/CardsRender.js.map +1 -0
  62. package/dist/blocks/builtins/Columns.d.ts +1 -2
  63. package/dist/blocks/builtins/Columns.js +2 -9
  64. package/dist/blocks/builtins/Columns.js.map +1 -1
  65. package/dist/blocks/builtins/ColumnsRender.d.ts +6 -0
  66. package/dist/blocks/builtins/ColumnsRender.js +12 -0
  67. package/dist/blocks/builtins/ColumnsRender.js.map +1 -0
  68. package/dist/blocks/builtins/Contact.d.ts +2 -7
  69. package/dist/blocks/builtins/Contact.js +3 -102
  70. package/dist/blocks/builtins/Contact.js.map +1 -1
  71. package/dist/blocks/builtins/ContactRender.d.ts +9 -0
  72. package/dist/blocks/builtins/ContactRender.js +105 -0
  73. package/dist/blocks/builtins/ContactRender.js.map +1 -0
  74. package/dist/blocks/builtins/Countdown.d.ts +1 -18
  75. package/dist/blocks/builtins/Countdown.js +3 -53
  76. package/dist/blocks/builtins/Countdown.js.map +1 -1
  77. package/dist/blocks/builtins/CountdownRender.d.ts +22 -0
  78. package/dist/blocks/builtins/CountdownRender.js +61 -0
  79. package/dist/blocks/builtins/CountdownRender.js.map +1 -0
  80. package/dist/blocks/builtins/Cta.d.ts +1 -2
  81. package/dist/blocks/builtins/Cta.js +2 -39
  82. package/dist/blocks/builtins/Cta.js.map +1 -1
  83. package/dist/blocks/builtins/CtaRender.d.ts +6 -0
  84. package/dist/blocks/builtins/CtaRender.js +42 -0
  85. package/dist/blocks/builtins/CtaRender.js.map +1 -0
  86. package/dist/blocks/builtins/Downloads.d.ts +1 -2
  87. package/dist/blocks/builtins/Downloads.js +2 -16
  88. package/dist/blocks/builtins/Downloads.js.map +1 -1
  89. package/dist/blocks/builtins/DownloadsRender.d.ts +7 -0
  90. package/dist/blocks/builtins/DownloadsRender.js +19 -0
  91. package/dist/blocks/builtins/DownloadsRender.js.map +1 -0
  92. package/dist/blocks/builtins/Elements.d.ts +3 -4
  93. package/dist/blocks/builtins/Elements.js +4 -38
  94. package/dist/blocks/builtins/Elements.js.map +1 -1
  95. package/dist/blocks/builtins/ElementsRender.d.ts +10 -0
  96. package/dist/blocks/builtins/ElementsRender.js +41 -0
  97. package/dist/blocks/builtins/ElementsRender.js.map +1 -0
  98. package/dist/blocks/builtins/Embed.d.ts +1 -2
  99. package/dist/blocks/builtins/Embed.js +2 -19
  100. package/dist/blocks/builtins/Embed.js.map +1 -1
  101. package/dist/blocks/builtins/EmbedRender.d.ts +7 -0
  102. package/dist/blocks/builtins/EmbedRender.js +22 -0
  103. package/dist/blocks/builtins/EmbedRender.js.map +1 -0
  104. package/dist/blocks/builtins/Faq.d.ts +1 -6
  105. package/dist/blocks/builtins/Faq.js +3 -103
  106. package/dist/blocks/builtins/Faq.js.map +1 -1
  107. package/dist/blocks/builtins/FaqRender.d.ts +10 -0
  108. package/dist/blocks/builtins/FaqRender.js +105 -0
  109. package/dist/blocks/builtins/FaqRender.js.map +1 -0
  110. package/dist/blocks/builtins/FormBlock.d.ts +1 -2
  111. package/dist/blocks/builtins/FormBlock.js +2 -222
  112. package/dist/blocks/builtins/FormBlock.js.map +1 -1
  113. package/dist/blocks/builtins/FormBlockRender.d.ts +6 -0
  114. package/dist/blocks/builtins/FormBlockRender.js +225 -0
  115. package/dist/blocks/builtins/FormBlockRender.js.map +1 -0
  116. package/dist/blocks/builtins/Gallery.d.ts +1 -23
  117. package/dist/blocks/builtins/Gallery.js +2 -164
  118. package/dist/blocks/builtins/Gallery.js.map +1 -1
  119. package/dist/blocks/builtins/GalleryRender.d.ts +25 -0
  120. package/dist/blocks/builtins/GalleryRender.js +167 -0
  121. package/dist/blocks/builtins/GalleryRender.js.map +1 -0
  122. package/dist/blocks/builtins/Hero.d.ts +1 -2
  123. package/dist/blocks/builtins/Hero.js +2 -73
  124. package/dist/blocks/builtins/Hero.js.map +1 -1
  125. package/dist/blocks/builtins/HeroRender.d.ts +6 -0
  126. package/dist/blocks/builtins/HeroRender.js +76 -0
  127. package/dist/blocks/builtins/HeroRender.js.map +1 -0
  128. package/dist/blocks/builtins/ImageBlock.d.ts +1 -2
  129. package/dist/blocks/builtins/ImageBlock.js +2 -22
  130. package/dist/blocks/builtins/ImageBlock.js.map +1 -1
  131. package/dist/blocks/builtins/ImageBlockRender.d.ts +6 -0
  132. package/dist/blocks/builtins/ImageBlockRender.js +25 -0
  133. package/dist/blocks/builtins/ImageBlockRender.js.map +1 -0
  134. package/dist/blocks/builtins/Jobs.d.ts +1 -15
  135. package/dist/blocks/builtins/Jobs.js +3 -69
  136. package/dist/blocks/builtins/Jobs.js.map +1 -1
  137. package/dist/blocks/builtins/JobsRender.d.ts +17 -0
  138. package/dist/blocks/builtins/JobsRender.js +71 -0
  139. package/dist/blocks/builtins/JobsRender.js.map +1 -0
  140. package/dist/blocks/builtins/Layout.d.ts +2 -3
  141. package/dist/blocks/builtins/Layout.js +3 -39
  142. package/dist/blocks/builtins/Layout.js.map +1 -1
  143. package/dist/blocks/builtins/LayoutRender.d.ts +8 -0
  144. package/dist/blocks/builtins/LayoutRender.js +42 -0
  145. package/dist/blocks/builtins/LayoutRender.js.map +1 -0
  146. package/dist/blocks/builtins/MapBlock.d.ts +1 -2
  147. package/dist/blocks/builtins/MapBlock.js +2 -45
  148. package/dist/blocks/builtins/MapBlock.js.map +1 -1
  149. package/dist/blocks/builtins/MapBlockRender.d.ts +6 -0
  150. package/dist/blocks/builtins/MapBlockRender.js +48 -0
  151. package/dist/blocks/builtins/MapBlockRender.js.map +1 -0
  152. package/dist/blocks/builtins/NewsListBlock.d.ts +1 -2
  153. package/dist/blocks/builtins/NewsListBlock.js +2 -11
  154. package/dist/blocks/builtins/NewsListBlock.js.map +1 -1
  155. package/dist/blocks/builtins/NewsListBlockRender.d.ts +6 -0
  156. package/dist/blocks/builtins/NewsListBlockRender.js +14 -0
  157. package/dist/blocks/builtins/NewsListBlockRender.js.map +1 -0
  158. package/dist/blocks/builtins/Newsletter.d.ts +1 -2
  159. package/dist/blocks/builtins/Newsletter.js +2 -89
  160. package/dist/blocks/builtins/Newsletter.js.map +1 -1
  161. package/dist/blocks/builtins/NewsletterRender.d.ts +13 -0
  162. package/dist/blocks/builtins/NewsletterRender.js +92 -0
  163. package/dist/blocks/builtins/NewsletterRender.js.map +1 -0
  164. package/dist/blocks/builtins/OpeningHours.d.ts +1 -2
  165. package/dist/blocks/builtins/OpeningHours.js +2 -28
  166. package/dist/blocks/builtins/OpeningHours.js.map +1 -1
  167. package/dist/blocks/builtins/OpeningHoursRender.d.ts +7 -0
  168. package/dist/blocks/builtins/OpeningHoursRender.js +31 -0
  169. package/dist/blocks/builtins/OpeningHoursRender.js.map +1 -0
  170. package/dist/blocks/builtins/PdfBlock.d.ts +1 -2
  171. package/dist/blocks/builtins/PdfBlock.js +2 -76
  172. package/dist/blocks/builtins/PdfBlock.js.map +1 -1
  173. package/dist/blocks/builtins/PdfBlockRender.d.ts +11 -0
  174. package/dist/blocks/builtins/PdfBlockRender.js +79 -0
  175. package/dist/blocks/builtins/PdfBlockRender.js.map +1 -0
  176. package/dist/blocks/builtins/Portfolio.d.ts +1 -2
  177. package/dist/blocks/builtins/Portfolio.js +2 -75
  178. package/dist/blocks/builtins/Portfolio.js.map +1 -1
  179. package/dist/blocks/builtins/PortfolioRender.d.ts +7 -0
  180. package/dist/blocks/builtins/PortfolioRender.js +78 -0
  181. package/dist/blocks/builtins/PortfolioRender.js.map +1 -0
  182. package/dist/blocks/builtins/Pricing.d.ts +1 -8
  183. package/dist/blocks/builtins/Pricing.js +3 -73
  184. package/dist/blocks/builtins/Pricing.js.map +1 -1
  185. package/dist/blocks/builtins/PricingRender.d.ts +10 -0
  186. package/dist/blocks/builtins/PricingRender.js +75 -0
  187. package/dist/blocks/builtins/PricingRender.js.map +1 -0
  188. package/dist/blocks/builtins/RichTextBlock.d.ts +1 -2
  189. package/dist/blocks/builtins/RichTextBlock.js +2 -5
  190. package/dist/blocks/builtins/RichTextBlock.js.map +1 -1
  191. package/dist/blocks/builtins/RichTextBlockRender.d.ts +6 -0
  192. package/dist/blocks/builtins/RichTextBlockRender.js +8 -0
  193. package/dist/blocks/builtins/RichTextBlockRender.js.map +1 -0
  194. package/dist/blocks/builtins/Search.d.ts +1 -2
  195. package/dist/blocks/builtins/Search.js +2 -80
  196. package/dist/blocks/builtins/Search.js.map +1 -1
  197. package/dist/blocks/builtins/SearchRender.d.ts +7 -0
  198. package/dist/blocks/builtins/SearchRender.js +83 -0
  199. package/dist/blocks/builtins/SearchRender.js.map +1 -0
  200. package/dist/blocks/builtins/Sections.d.ts +4 -5
  201. package/dist/blocks/builtins/Sections.js +5 -142
  202. package/dist/blocks/builtins/Sections.js.map +1 -1
  203. package/dist/blocks/builtins/SectionsRender.d.ts +12 -0
  204. package/dist/blocks/builtins/SectionsRender.js +145 -0
  205. package/dist/blocks/builtins/SectionsRender.js.map +1 -0
  206. package/dist/blocks/builtins/Slider.d.ts +1 -2
  207. package/dist/blocks/builtins/Slider.js +2 -134
  208. package/dist/blocks/builtins/Slider.js.map +1 -1
  209. package/dist/blocks/builtins/SliderRender.d.ts +7 -0
  210. package/dist/blocks/builtins/SliderRender.js +137 -0
  211. package/dist/blocks/builtins/SliderRender.js.map +1 -0
  212. package/dist/blocks/builtins/Spacer.d.ts +1 -2
  213. package/dist/blocks/builtins/Spacer.js +2 -6
  214. package/dist/blocks/builtins/Spacer.js.map +1 -1
  215. package/dist/blocks/builtins/SpacerRender.d.ts +6 -0
  216. package/dist/blocks/builtins/SpacerRender.js +9 -0
  217. package/dist/blocks/builtins/SpacerRender.js.map +1 -0
  218. package/dist/blocks/builtins/SymbolRef.d.ts +1 -2
  219. package/dist/blocks/builtins/SymbolRef.js +2 -76
  220. package/dist/blocks/builtins/SymbolRef.js.map +1 -1
  221. package/dist/blocks/builtins/SymbolRefRender.d.ts +13 -0
  222. package/dist/blocks/builtins/SymbolRefRender.js +79 -0
  223. package/dist/blocks/builtins/SymbolRefRender.js.map +1 -0
  224. package/dist/blocks/builtins/Team.d.ts +1 -2
  225. package/dist/blocks/builtins/Team.js +2 -55
  226. package/dist/blocks/builtins/Team.js.map +1 -1
  227. package/dist/blocks/builtins/TeamRender.d.ts +7 -0
  228. package/dist/blocks/builtins/TeamRender.js +58 -0
  229. package/dist/blocks/builtins/TeamRender.js.map +1 -0
  230. package/dist/blocks/builtins/Testimonials.d.ts +1 -8
  231. package/dist/blocks/builtins/Testimonials.js +2 -69
  232. package/dist/blocks/builtins/Testimonials.js.map +1 -1
  233. package/dist/blocks/builtins/TestimonialsRender.d.ts +10 -0
  234. package/dist/blocks/builtins/TestimonialsRender.js +72 -0
  235. package/dist/blocks/builtins/TestimonialsRender.js.map +1 -0
  236. package/dist/blocks/builtins/Video.d.ts +1 -9
  237. package/dist/blocks/builtins/Video.js +2 -64
  238. package/dist/blocks/builtins/Video.js.map +1 -1
  239. package/dist/blocks/builtins/VideoRender.d.ts +10 -0
  240. package/dist/blocks/builtins/VideoRender.js +67 -0
  241. package/dist/blocks/builtins/VideoRender.js.map +1 -0
  242. package/dist/blocks/builtins/WhatsappChat.d.ts +1 -8
  243. package/dist/blocks/builtins/WhatsappChat.js +2 -37
  244. package/dist/blocks/builtins/WhatsappChat.js.map +1 -1
  245. package/dist/blocks/builtins/WhatsappChatRender.d.ts +17 -0
  246. package/dist/blocks/builtins/WhatsappChatRender.js +40 -0
  247. package/dist/blocks/builtins/WhatsappChatRender.js.map +1 -0
  248. package/dist/blocks/builtins/Widgets.d.ts +12 -13
  249. package/dist/blocks/builtins/Widgets.js +13 -175
  250. package/dist/blocks/builtins/Widgets.js.map +1 -1
  251. package/dist/blocks/builtins/WidgetsRender.d.ts +34 -0
  252. package/dist/blocks/builtins/WidgetsRender.js +178 -0
  253. package/dist/blocks/builtins/WidgetsRender.js.map +1 -0
  254. package/dist/components/barOffset.js +1 -1
  255. package/dist/components/barOffset.js.map +1 -1
  256. package/dist/modules/contract.js +2 -1
  257. package/dist/modules/contract.js.map +1 -1
  258. package/dist/schema/settings.d.ts +4 -0
  259. package/dist/schema/settings.js +10 -1
  260. package/dist/schema/settings.js.map +1 -1
  261. package/dist/styles.css +93 -19
  262. package/dist/version.js +1 -1
  263. package/package.json +1 -1
@@ -1,82 +1,8 @@
1
- "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import { useEffect, useState } from "react";
1
+ import dynamic from "next/dynamic";
4
2
  import { defineBlock } from "../registry.js";
5
- import { BlockRenderer } from "../BlockRenderer.js";
6
- import { useRegistry } from "../context.js";
7
- import { useEditor } from "../../editor/EditorProvider.js";
8
- function SymbolRefRender({ block, siteId, mode }) {
9
- const registry = useRegistry();
10
- const bewerken = useEditor().open || mode === "preview";
11
- const [symbol, setSymbol] = useState(void 0);
12
- useEffect(() => {
13
- if (!block.symbolId) {
14
- setSymbol(null);
15
- return;
16
- }
17
- let unsub;
18
- let afgebroken = false;
19
- void (async () => {
20
- const [{ getDb }, { doc, onSnapshot }] = await Promise.all([
21
- import("../../firebase/client.js"),
22
- import("firebase/firestore")
23
- ]);
24
- const db = getDb();
25
- if (!db || afgebroken) {
26
- setSymbol(null);
27
- return;
28
- }
29
- const ref = doc(db, "sites", siteId, "symbols", block.symbolId);
30
- const zet = (data, bestaat) => {
31
- const d = bestaat && data && typeof data === "object" ? data : null;
32
- const geldig = d && typeof d.name === "string" && Array.isArray(d.blocks);
33
- setSymbol(geldig ? d : null);
34
- };
35
- if (bewerken) {
36
- unsub = onSnapshot(
37
- ref,
38
- (snap) => zet(snap.data(), snap.exists()),
39
- () => setSymbol(null)
40
- );
41
- } else {
42
- const { getDoc } = await import("firebase/firestore");
43
- try {
44
- const snap = await getDoc(ref);
45
- if (!afgebroken) zet(snap.data(), snap.exists());
46
- } catch {
47
- if (!afgebroken) setSymbol(null);
48
- }
49
- }
50
- })();
51
- return () => {
52
- afgebroken = true;
53
- unsub?.();
54
- };
55
- }, [siteId, block.symbolId, bewerken]);
56
- if (symbol === void 0) return null;
57
- if (symbol === null) {
58
- return mode === "preview" ? /* @__PURE__ */ jsxs("p", { className: "xicms-ve__hint", children: [
59
- "\u{1F9E9} Symbool niet gevonden (",
60
- block.symbolId,
61
- ") \u2014 kies een ander symbool of verwijder dit blok."
62
- ] }) : null;
63
- }
64
- const inner = /* @__PURE__ */ jsx(BlockRenderer, { blocks: symbol.blocks, registry, siteId, mode });
65
- if (mode === "preview") {
66
- return /* @__PURE__ */ jsxs("div", { className: "xicms-symbol", "data-symbol": block.symbolId, children: [
67
- /* @__PURE__ */ jsxs("div", { className: "xicms-symbol__badge", children: [
68
- "\u{1F9E9} ",
69
- symbol.name,
70
- " \u2014 gedeeld symbool (wijzigingen gelden op \xE9lke pagina)"
71
- ] }),
72
- inner
73
- ] });
74
- }
75
- return inner;
76
- }
77
3
  const symbolRefBlock = defineBlock({
78
4
  type: "symbolRef",
79
- Render: SymbolRefRender,
5
+ Render: dynamic(() => import("./SymbolRefRender.js").then((m) => m.SymbolRefRender)),
80
6
  label: "Symbool (gedeelde sectie)",
81
7
  icon: "\u{1F9E9}",
82
8
  defaults: () => ({ symbolId: "" })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/builtins/SymbolRef.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport type { z } from \"zod\";\nimport type { SymbolRefBlockSchema } from \"../../schema/blocks\";\nimport type { SymbolDefinition } from \"../../schema/symbols\";\nimport { defineBlock, type BlockRenderProps } from \"../registry\";\nimport { BlockRenderer } from \"../BlockRenderer\";\nimport { useRegistry } from \"../context\";\nimport { useEditor } from \"../../editor/EditorProvider\";\n\ntype SymbolRef = z.infer<typeof SymbolRefBlockSchema>;\n\n/**\n * Verwijzing naar een gedeeld symbool. Op de LIVE site wordt een symbolRef normaliter al\n * server-side vervangen door de symbool-blokken (server/pages.ts `expandSymbols`) — dan komt\n * deze Render niet eens aan bod. In de editor/preview (en als client-fallback) rendert hij het\n * symbool live vanuit Firestore, met een subtiel kader zodat de editor ziet dat dit gedeelde\n * inhoud is die op meerdere pagina's meebeweegt.\n */\nfunction SymbolRefRender({ block, siteId, mode }: BlockRenderProps<SymbolRef>) {\n const registry = useRegistry();\n // Live meebewegen is alleen nuttig terwijl er BEWERKT wordt. Voor een gewone bezoeker was de\n // onSnapshot hieronder het duurste patroon van het systeem: een read plus een blijvend open\n // verbinding, per bezoeker — voor content die toch pas verandert als iemand publiceert.\n const bewerken = useEditor().open || mode === \"preview\";\n const [symbol, setSymbol] = useState<SymbolDefinition | null | undefined>(undefined);\n useEffect(() => {\n if (!block.symbolId) {\n setSymbol(null);\n return;\n }\n // Firestore dynamisch laden: een pagina zonder symbolen haalt de SDK zo nooit binnen, en een\n // pagina mét symbolen pas op het moment dat er echt iets op te halen valt.\n let unsub: (() => void) | undefined;\n let afgebroken = false;\n void (async () => {\n const [{ getDb }, { doc, onSnapshot }] = await Promise.all([\n import(\"../../firebase/client\"),\n import(\"firebase/firestore\"),\n ]);\n const db = getDb();\n if (!db || afgebroken) {\n setSymbol(null);\n return;\n }\n const ref = doc(db, \"sites\", siteId, \"symbols\", block.symbolId!);\n const zet = (data: unknown, bestaat: boolean) => {\n // Lichte vormcheck i.p.v. zod (7.13): dit is een publiek renderpad en de enige plek die\n // anders het hele symbols-schema (en daarmee de zod-runtime) in de bezoekersbundel trok.\n // De BlockRenderer eronder valideert de blokken zelf al per type.\n const d = bestaat && data && typeof data === \"object\" ? (data as { name?: unknown; blocks?: unknown }) : null;\n const geldig = d && typeof d.name === \"string\" && Array.isArray(d.blocks);\n setSymbol(geldig ? (d as unknown as SymbolDefinition) : null);\n };\n if (bewerken) {\n unsub = onSnapshot(\n ref,\n (snap) => zet(snap.data(), snap.exists()),\n () => setSymbol(null),\n );\n } else {\n // Publieke fallback (zeldzaam: normaal is de ref al server-side geëxpandeerd): één read,\n // geen listener.\n const { getDoc } = await import(\"firebase/firestore\");\n try {\n const snap = await getDoc(ref);\n if (!afgebroken) zet(snap.data(), snap.exists());\n } catch {\n if (!afgebroken) setSymbol(null);\n }\n }\n })();\n return () => {\n afgebroken = true;\n unsub?.();\n };\n }, [siteId, block.symbolId, bewerken]);\n\n if (symbol === undefined) return null; // laden — geen flits\n if (symbol === null) {\n // Verweesde referentie: nooit de pagina breken; in preview uitleggen, live niets tonen.\n return mode === \"preview\" ? (\n <p className=\"xicms-ve__hint\">🧩 Symbool niet gevonden ({block.symbolId}) — kies een ander symbool of verwijder dit blok.</p>\n ) : null;\n }\n const inner = <BlockRenderer blocks={symbol.blocks} registry={registry} siteId={siteId} mode={mode} />;\n if (mode === \"preview\") {\n return (\n <div className=\"xicms-symbol\" data-symbol={block.symbolId}>\n <div className=\"xicms-symbol__badge\">🧩 {symbol.name} — gedeeld symbool (wijzigingen gelden op élke pagina)</div>\n {inner}\n </div>\n );\n }\n return inner;\n}\n\nexport const symbolRefBlock = defineBlock({\n type: \"symbolRef\",\n Render: SymbolRefRender,\n label: \"Symbool (gedeelde sectie)\",\n icon: \"🧩\",\n defaults: () => ({ symbolId: \"\" }),\n});\n"],"mappings":";AAmFM,SAGU,KAHV;AAjFN,SAAS,WAAW,gBAAgB;AAIpC,SAAS,mBAA0C;AACnD,SAAS,qBAAqB;AAC9B,SAAS,mBAAmB;AAC5B,SAAS,iBAAiB;AAW1B,SAAS,gBAAgB,EAAE,OAAO,QAAQ,KAAK,GAAgC;AAC7E,QAAM,WAAW,YAAY;AAI7B,QAAM,WAAW,UAAU,EAAE,QAAQ,SAAS;AAC9C,QAAM,CAAC,QAAQ,SAAS,IAAI,SAA8C,MAAS;AACnF,YAAU,MAAM;AACd,QAAI,CAAC,MAAM,UAAU;AACnB,gBAAU,IAAI;AACd;AAAA,IACF;AAGA,QAAI;AACJ,QAAI,aAAa;AACjB,UAAM,YAAY;AAChB,YAAM,CAAC,EAAE,MAAM,GAAG,EAAE,KAAK,WAAW,CAAC,IAAI,MAAM,QAAQ,IAAI;AAAA,QACzD,OAAO,uBAAuB;AAAA,QAC9B,OAAO,oBAAoB;AAAA,MAC7B,CAAC;AACD,YAAM,KAAK,MAAM;AACjB,UAAI,CAAC,MAAM,YAAY;AACrB,kBAAU,IAAI;AACd;AAAA,MACF;AACA,YAAM,MAAM,IAAI,IAAI,SAAS,QAAQ,WAAW,MAAM,QAAS;AAC/D,YAAM,MAAM,CAAC,MAAe,YAAqB;AAI/C,cAAM,IAAI,WAAW,QAAQ,OAAO,SAAS,WAAY,OAAgD;AACzG,cAAM,SAAS,KAAK,OAAO,EAAE,SAAS,YAAY,MAAM,QAAQ,EAAE,MAAM;AACxE,kBAAU,SAAU,IAAoC,IAAI;AAAA,MAC9D;AACA,UAAI,UAAU;AACZ,gBAAQ;AAAA,UACN;AAAA,UACA,CAAC,SAAS,IAAI,KAAK,KAAK,GAAG,KAAK,OAAO,CAAC;AAAA,UACxC,MAAM,UAAU,IAAI;AAAA,QACtB;AAAA,MACF,OAAO;AAGL,cAAM,EAAE,OAAO,IAAI,MAAM,OAAO,oBAAoB;AACpD,YAAI;AACF,gBAAM,OAAO,MAAM,OAAO,GAAG;AAC7B,cAAI,CAAC,WAAY,KAAI,KAAK,KAAK,GAAG,KAAK,OAAO,CAAC;AAAA,QACjD,QAAQ;AACN,cAAI,CAAC,WAAY,WAAU,IAAI;AAAA,QACjC;AAAA,MACF;AAAA,IACF,GAAG;AACH,WAAO,MAAM;AACX,mBAAa;AACb,cAAQ;AAAA,IACV;AAAA,EACF,GAAG,CAAC,QAAQ,MAAM,UAAU,QAAQ,CAAC;AAErC,MAAI,WAAW,OAAW,QAAO;AACjC,MAAI,WAAW,MAAM;AAEnB,WAAO,SAAS,YACd,qBAAC,OAAE,WAAU,kBAAiB;AAAA;AAAA,MAA2B,MAAM;AAAA,MAAS;AAAA,OAAiD,IACvH;AAAA,EACN;AACA,QAAM,QAAQ,oBAAC,iBAAc,QAAQ,OAAO,QAAQ,UAAoB,QAAgB,MAAY;AACpG,MAAI,SAAS,WAAW;AACtB,WACE,qBAAC,SAAI,WAAU,gBAAe,eAAa,MAAM,UAC/C;AAAA,2BAAC,SAAI,WAAU,uBAAsB;AAAA;AAAA,QAAI,OAAO;AAAA,QAAK;AAAA,SAAsD;AAAA,MAC1G;AAAA,OACH;AAAA,EAEJ;AACA,SAAO;AACT;AAEO,MAAM,iBAAiB,YAAY;AAAA,EACxC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,UAAU,GAAG;AAClC,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../../src/blocks/builtins/SymbolRef.tsx"],"sourcesContent":["import dynamic from \"next/dynamic\";\nimport { defineBlock } from \"../registry\";\n\nexport const symbolRefBlock = defineBlock({\n type: \"symbolRef\",\n Render: dynamic(() => import(\"./SymbolRefRender\").then((m) => m.SymbolRefRender)),\n label: \"Symbool (gedeelde sectie)\",\n icon: \"🧩\",\n defaults: () => ({ symbolId: \"\" }),\n});\n"],"mappings":"AAAA,OAAO,aAAa;AACpB,SAAS,mBAAmB;AAErB,MAAM,iBAAiB,YAAY;AAAA,EACxC,MAAM;AAAA,EACN,QAAQ,QAAQ,MAAM,OAAO,mBAAmB,EAAE,KAAK,CAAC,MAAM,EAAE,eAAe,CAAC;AAAA,EAChF,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,UAAU,GAAG;AAClC,CAAC;","names":[]}
@@ -0,0 +1,13 @@
1
+ import type { z } from "zod";
2
+ import type { SymbolRefBlockSchema } from "../../schema/blocks.js";
3
+ import type { BlockRenderProps } from "../registry.js";
4
+ type SymbolRef = z.infer<typeof SymbolRefBlockSchema>;
5
+ /**
6
+ * Verwijzing naar een gedeeld symbool. Op de LIVE site wordt een symbolRef normaliter al
7
+ * server-side vervangen door de symbool-blokken (server/pages.ts `expandSymbols`) — dan komt
8
+ * deze Render niet eens aan bod. In de editor/preview (en als client-fallback) rendert hij het
9
+ * symbool live vanuit Firestore, met een subtiel kader zodat de editor ziet dat dit gedeelde
10
+ * inhoud is die op meerdere pagina's meebeweegt.
11
+ */
12
+ export declare function SymbolRefRender({ block, siteId, mode }: BlockRenderProps<SymbolRef>): import("react").JSX.Element | null;
13
+ export {};
@@ -0,0 +1,79 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useState } from "react";
4
+ import { BlockRenderer } from "../BlockRenderer.js";
5
+ import { useRegistry } from "../context.js";
6
+ import { useEditor } from "../../editor/EditorProvider.js";
7
+ function SymbolRefRender({ block, siteId, mode }) {
8
+ const registry = useRegistry();
9
+ const bewerken = useEditor().open || mode === "preview";
10
+ const [symbol, setSymbol] = useState(void 0);
11
+ useEffect(() => {
12
+ if (!block.symbolId) {
13
+ setSymbol(null);
14
+ return;
15
+ }
16
+ let unsub;
17
+ let afgebroken = false;
18
+ void (async () => {
19
+ const [{ getDb }, { doc, onSnapshot }] = await Promise.all([
20
+ import("../../firebase/client.js"),
21
+ import("firebase/firestore")
22
+ ]);
23
+ const db = getDb();
24
+ if (!db || afgebroken) {
25
+ setSymbol(null);
26
+ return;
27
+ }
28
+ const ref = doc(db, "sites", siteId, "symbols", block.symbolId);
29
+ const zet = (data, bestaat) => {
30
+ const d = bestaat && data && typeof data === "object" ? data : null;
31
+ const geldig = d && typeof d.name === "string" && Array.isArray(d.blocks);
32
+ setSymbol(geldig ? d : null);
33
+ };
34
+ if (bewerken) {
35
+ unsub = onSnapshot(
36
+ ref,
37
+ (snap) => zet(snap.data(), snap.exists()),
38
+ () => setSymbol(null)
39
+ );
40
+ } else {
41
+ const { getDoc } = await import("firebase/firestore");
42
+ try {
43
+ const snap = await getDoc(ref);
44
+ if (!afgebroken) zet(snap.data(), snap.exists());
45
+ } catch {
46
+ if (!afgebroken) setSymbol(null);
47
+ }
48
+ }
49
+ })();
50
+ return () => {
51
+ afgebroken = true;
52
+ unsub?.();
53
+ };
54
+ }, [siteId, block.symbolId, bewerken]);
55
+ if (symbol === void 0) return null;
56
+ if (symbol === null) {
57
+ return mode === "preview" ? /* @__PURE__ */ jsxs("p", { className: "xicms-ve__hint", children: [
58
+ "\u{1F9E9} Symbool niet gevonden (",
59
+ block.symbolId,
60
+ ") \u2014 kies een ander symbool of verwijder dit blok."
61
+ ] }) : null;
62
+ }
63
+ const inner = /* @__PURE__ */ jsx(BlockRenderer, { blocks: symbol.blocks, registry, siteId, mode });
64
+ if (mode === "preview") {
65
+ return /* @__PURE__ */ jsxs("div", { className: "xicms-symbol", "data-symbol": block.symbolId, children: [
66
+ /* @__PURE__ */ jsxs("div", { className: "xicms-symbol__badge", children: [
67
+ "\u{1F9E9} ",
68
+ symbol.name,
69
+ " \u2014 gedeeld symbool (wijzigingen gelden op \xE9lke pagina)"
70
+ ] }),
71
+ inner
72
+ ] });
73
+ }
74
+ return inner;
75
+ }
76
+ export {
77
+ SymbolRefRender
78
+ };
79
+ //# sourceMappingURL=SymbolRefRender.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/blocks/builtins/SymbolRefRender.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport type { z } from \"zod\";\nimport type { SymbolRefBlockSchema } from \"../../schema/blocks\";\nimport type { SymbolDefinition } from \"../../schema/symbols\";\nimport type { BlockRenderProps } from \"../registry\";\nimport { BlockRenderer } from \"../BlockRenderer\";\nimport { useRegistry } from \"../context\";\nimport { useEditor } from \"../../editor/EditorProvider\";\n\ntype SymbolRef = z.infer<typeof SymbolRefBlockSchema>;\n\n/**\n * Verwijzing naar een gedeeld symbool. Op de LIVE site wordt een symbolRef normaliter al\n * server-side vervangen door de symbool-blokken (server/pages.ts `expandSymbols`) — dan komt\n * deze Render niet eens aan bod. In de editor/preview (en als client-fallback) rendert hij het\n * symbool live vanuit Firestore, met een subtiel kader zodat de editor ziet dat dit gedeelde\n * inhoud is die op meerdere pagina's meebeweegt.\n */\nexport function SymbolRefRender({ block, siteId, mode }: BlockRenderProps<SymbolRef>) {\n const registry = useRegistry();\n // Live meebewegen is alleen nuttig terwijl er BEWERKT wordt. Voor een gewone bezoeker was de\n // onSnapshot hieronder het duurste patroon van het systeem: een read plus een blijvend open\n // verbinding, per bezoeker — voor content die toch pas verandert als iemand publiceert.\n const bewerken = useEditor().open || mode === \"preview\";\n const [symbol, setSymbol] = useState<SymbolDefinition | null | undefined>(undefined);\n useEffect(() => {\n if (!block.symbolId) {\n setSymbol(null);\n return;\n }\n // Firestore dynamisch laden: een pagina zonder symbolen haalt de SDK zo nooit binnen, en een\n // pagina mét symbolen pas op het moment dat er echt iets op te halen valt.\n let unsub: (() => void) | undefined;\n let afgebroken = false;\n void (async () => {\n const [{ getDb }, { doc, onSnapshot }] = await Promise.all([\n import(\"../../firebase/client\"),\n import(\"firebase/firestore\"),\n ]);\n const db = getDb();\n if (!db || afgebroken) {\n setSymbol(null);\n return;\n }\n const ref = doc(db, \"sites\", siteId, \"symbols\", block.symbolId!);\n const zet = (data: unknown, bestaat: boolean) => {\n // Lichte vormcheck i.p.v. zod (7.13): dit is een publiek renderpad en de enige plek die\n // anders het hele symbols-schema (en daarmee de zod-runtime) in de bezoekersbundel trok.\n // De BlockRenderer eronder valideert de blokken zelf al per type.\n const d = bestaat && data && typeof data === \"object\" ? (data as { name?: unknown; blocks?: unknown }) : null;\n const geldig = d && typeof d.name === \"string\" && Array.isArray(d.blocks);\n setSymbol(geldig ? (d as unknown as SymbolDefinition) : null);\n };\n if (bewerken) {\n unsub = onSnapshot(\n ref,\n (snap) => zet(snap.data(), snap.exists()),\n () => setSymbol(null),\n );\n } else {\n // Publieke fallback (zeldzaam: normaal is de ref al server-side geëxpandeerd): één read,\n // geen listener.\n const { getDoc } = await import(\"firebase/firestore\");\n try {\n const snap = await getDoc(ref);\n if (!afgebroken) zet(snap.data(), snap.exists());\n } catch {\n if (!afgebroken) setSymbol(null);\n }\n }\n })();\n return () => {\n afgebroken = true;\n unsub?.();\n };\n }, [siteId, block.symbolId, bewerken]);\n\n if (symbol === undefined) return null; // laden — geen flits\n if (symbol === null) {\n // Verweesde referentie: nooit de pagina breken; in preview uitleggen, live niets tonen.\n return mode === \"preview\" ? (\n <p className=\"xicms-ve__hint\">🧩 Symbool niet gevonden ({block.symbolId}) — kies een ander symbool of verwijder dit blok.</p>\n ) : null;\n }\n const inner = <BlockRenderer blocks={symbol.blocks} registry={registry} siteId={siteId} mode={mode} />;\n if (mode === \"preview\") {\n return (\n <div className=\"xicms-symbol\" data-symbol={block.symbolId}>\n <div className=\"xicms-symbol__badge\">🧩 {symbol.name} — gedeeld symbool (wijzigingen gelden op élke pagina)</div>\n {inner}\n </div>\n );\n }\n return inner;\n}\n"],"mappings":";AAmFM,SAGU,KAHV;AAjFN,SAAS,WAAW,gBAAgB;AAKpC,SAAS,qBAAqB;AAC9B,SAAS,mBAAmB;AAC5B,SAAS,iBAAiB;AAWnB,SAAS,gBAAgB,EAAE,OAAO,QAAQ,KAAK,GAAgC;AACpF,QAAM,WAAW,YAAY;AAI7B,QAAM,WAAW,UAAU,EAAE,QAAQ,SAAS;AAC9C,QAAM,CAAC,QAAQ,SAAS,IAAI,SAA8C,MAAS;AACnF,YAAU,MAAM;AACd,QAAI,CAAC,MAAM,UAAU;AACnB,gBAAU,IAAI;AACd;AAAA,IACF;AAGA,QAAI;AACJ,QAAI,aAAa;AACjB,UAAM,YAAY;AAChB,YAAM,CAAC,EAAE,MAAM,GAAG,EAAE,KAAK,WAAW,CAAC,IAAI,MAAM,QAAQ,IAAI;AAAA,QACzD,OAAO,uBAAuB;AAAA,QAC9B,OAAO,oBAAoB;AAAA,MAC7B,CAAC;AACD,YAAM,KAAK,MAAM;AACjB,UAAI,CAAC,MAAM,YAAY;AACrB,kBAAU,IAAI;AACd;AAAA,MACF;AACA,YAAM,MAAM,IAAI,IAAI,SAAS,QAAQ,WAAW,MAAM,QAAS;AAC/D,YAAM,MAAM,CAAC,MAAe,YAAqB;AAI/C,cAAM,IAAI,WAAW,QAAQ,OAAO,SAAS,WAAY,OAAgD;AACzG,cAAM,SAAS,KAAK,OAAO,EAAE,SAAS,YAAY,MAAM,QAAQ,EAAE,MAAM;AACxE,kBAAU,SAAU,IAAoC,IAAI;AAAA,MAC9D;AACA,UAAI,UAAU;AACZ,gBAAQ;AAAA,UACN;AAAA,UACA,CAAC,SAAS,IAAI,KAAK,KAAK,GAAG,KAAK,OAAO,CAAC;AAAA,UACxC,MAAM,UAAU,IAAI;AAAA,QACtB;AAAA,MACF,OAAO;AAGL,cAAM,EAAE,OAAO,IAAI,MAAM,OAAO,oBAAoB;AACpD,YAAI;AACF,gBAAM,OAAO,MAAM,OAAO,GAAG;AAC7B,cAAI,CAAC,WAAY,KAAI,KAAK,KAAK,GAAG,KAAK,OAAO,CAAC;AAAA,QACjD,QAAQ;AACN,cAAI,CAAC,WAAY,WAAU,IAAI;AAAA,QACjC;AAAA,MACF;AAAA,IACF,GAAG;AACH,WAAO,MAAM;AACX,mBAAa;AACb,cAAQ;AAAA,IACV;AAAA,EACF,GAAG,CAAC,QAAQ,MAAM,UAAU,QAAQ,CAAC;AAErC,MAAI,WAAW,OAAW,QAAO;AACjC,MAAI,WAAW,MAAM;AAEnB,WAAO,SAAS,YACd,qBAAC,OAAE,WAAU,kBAAiB;AAAA;AAAA,MAA2B,MAAM;AAAA,MAAS;AAAA,OAAiD,IACvH;AAAA,EACN;AACA,QAAM,QAAQ,oBAAC,iBAAc,QAAQ,OAAO,QAAQ,UAAoB,QAAgB,MAAY;AACpG,MAAI,SAAS,WAAW;AACtB,WACE,qBAAC,SAAI,WAAU,gBAAe,eAAa,MAAM,UAC/C;AAAA,2BAAC,SAAI,WAAU,uBAAsB;AAAA;AAAA,QAAI,OAAO;AAAA,QAAK;AAAA,SAAsD;AAAA,MAC1G;AAAA,OACH;AAAA,EAEJ;AACA,SAAO;AACT;","names":[]}
@@ -1,2 +1 @@
1
- import type { z } from "zod";
2
- export declare const teamBlock: import("../index.js").BlockDefinition<z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
1
+ export declare const teamBlock: import("../index.js").BlockDefinition<import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>>;
@@ -1,61 +1,8 @@
1
- "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
1
+ import dynamic from "next/dynamic";
3
2
  import { defineBlock } from "../registry.js";
4
- import { VStack, HStack, Grid, Card, Heading, Text, Avatar } from "../ui/index.js";
5
- import { jsonLdHtml } from "./jsonld.js";
6
- function personJsonLd(members) {
7
- return {
8
- "@context": "https://schema.org",
9
- "@type": "ItemList",
10
- itemListElement: members.filter((m) => m.name).map((m, i) => ({
11
- "@type": "ListItem",
12
- position: i + 1,
13
- item: {
14
- "@type": "Person",
15
- name: m.name,
16
- ...m.role ? { jobTitle: m.role } : {},
17
- ...m.email ? { email: m.email } : {},
18
- ...m.phone ? { telephone: m.phone } : {},
19
- ...m.photoUrl ? { image: m.photoUrl } : {},
20
- ...m.social?.length ? { sameAs: m.social.map((s) => s.href) } : {}
21
- }
22
- }))
23
- };
24
- }
25
- function TeamRender({ block }) {
26
- const members = (block.members ?? []).map((m, i) => ({ ...m, _i: i })).filter((m) => m.name);
27
- if (members.length === 0) return null;
28
- const groups = block.groupByDepartment ? [...new Set(members.map((m) => m.department ?? ""))].sort((a, b) => a === "" ? 1 : b === "" ? -1 : 0).map((dep) => ({ dep, members: members.filter((m) => (m.department ?? "") === dep) })) : [{ dep: "", members }];
29
- const grid = (list) => /* @__PURE__ */ jsx(Grid, { columns: { minWidth: 220, max: 4 }, gap: 4, children: list.map((m) => {
30
- const i = m._i;
31
- return /* @__PURE__ */ jsx(Card, { padding: 4, height: "100%", children: /* @__PURE__ */ jsxs(VStack, { gap: 1, hAlign: "center", style: { textAlign: "center", height: "100%" }, children: [
32
- /* @__PURE__ */ jsx(Avatar, { src: m.photoUrl, name: m.name, size: 96 }),
33
- /* @__PURE__ */ jsx(Heading, { level: 3, "data-xicms-edit": `members.${i}.name`, children: m.name }),
34
- m.role && /* @__PURE__ */ jsx(Text, { type: "label", "data-xicms-edit": `members.${i}.role`, style: { color: "var(--color-accent)" }, children: m.role }),
35
- m.bio && /* @__PURE__ */ jsx(Text, { color: "secondary", "data-xicms-edit": `members.${i}.bio`, children: m.bio }),
36
- m.email && /* @__PURE__ */ jsx("a", { href: `mailto:${m.email}`, style: { color: "var(--color-accent)" }, children: /* @__PURE__ */ jsx(Text, { type: "supporting", "data-xicms-edit": `members.${i}.email`, children: m.email }) }),
37
- m.phone && /* @__PURE__ */ jsx(Text, { type: "supporting", color: "secondary", "data-xicms-edit": `members.${i}.phone`, children: m.phone }),
38
- m.social && m.social.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: 2, hAlign: "center", as: "ul", style: { listStyle: "none", margin: 0, padding: 0, flexWrap: "wrap" }, children: m.social.map((s, j) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", { href: s.href, rel: "noopener noreferrer", target: "_blank", style: { color: "var(--color-accent)" }, children: /* @__PURE__ */ jsx(Text, { type: "supporting", "data-xicms-edit": `members.${i}.social.${j}.platform`, children: s.platform }) }) }, j)) })
39
- ] }) }, i);
40
- }) });
41
- return /* @__PURE__ */ jsxs(VStack, { gap: 4, as: "section", className: "xicms-team", children: [
42
- block.heading && /* @__PURE__ */ jsx(Heading, { level: 2, justify: "center", "data-xicms-edit": "heading", style: { textAlign: "center" }, children: block.heading }),
43
- groups.map(({ dep, members: list }) => /* @__PURE__ */ jsxs(VStack, { gap: 3, children: [
44
- block.groupByDepartment && groups.length > 1 && /* @__PURE__ */ jsx(Heading, { level: 3, justify: "center", style: { textAlign: "center" }, children: dep || "Overig" }),
45
- grid(list)
46
- ] }, dep || "_overig")),
47
- block.jsonLd && /* @__PURE__ */ jsx(
48
- "script",
49
- {
50
- type: "application/ld+json",
51
- dangerouslySetInnerHTML: { __html: jsonLdHtml(personJsonLd(members)) }
52
- }
53
- )
54
- ] });
55
- }
56
3
  const teamBlock = defineBlock({
57
4
  type: "team",
58
- Render: TeamRender,
5
+ Render: dynamic(() => import("./TeamRender.js").then((m) => m.TeamRender)),
59
6
  label: "Team",
60
7
  icon: "\u{1F465}",
61
8
  defaults: () => ({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/builtins/Team.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport type { 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 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":["import dynamic from \"next/dynamic\";\nimport { defineBlock } from \"../registry\";\n\nexport const teamBlock = defineBlock({\n type: \"team\",\n Render: dynamic(() => import(\"./TeamRender\").then((m) => m.TeamRender)),\n label: \"Team\",\n icon: \"👥\",\n defaults: () => ({\n heading: \"Ons team\",\n members: [{ name: \"Naam Medewerker\", role: \"Functie\" }],\n }),\n});\n"],"mappings":"AAAA,OAAO,aAAa;AACpB,SAAS,mBAAmB;AAErB,MAAM,YAAY,YAAY;AAAA,EACnC,MAAM;AAAA,EACN,QAAQ,QAAQ,MAAM,OAAO,cAAc,EAAE,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC;AAAA,EACtE,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO;AAAA,IACf,SAAS;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,mBAAmB,MAAM,UAAU,CAAC;AAAA,EACxD;AACF,CAAC;","names":[]}
@@ -0,0 +1,7 @@
1
+ import type { z } from "zod";
2
+ import type { TeamBlockSchema } from "../../schema/blocks.js";
3
+ import type { BlockRenderProps } from "../registry.js";
4
+ type Team = z.infer<typeof TeamBlockSchema>;
5
+ /** Team-/medewerkersoverzicht als kaarten (Astryx), optioneel gegroepeerd per afdeling. */
6
+ export declare function TeamRender({ block }: BlockRenderProps<Team>): import("react").JSX.Element | null;
7
+ export {};
@@ -0,0 +1,58 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { VStack, HStack, Grid, Card, Heading, Text, Avatar } from "../ui/index.js";
4
+ import { jsonLdHtml } from "./jsonld.js";
5
+ function personJsonLd(members) {
6
+ return {
7
+ "@context": "https://schema.org",
8
+ "@type": "ItemList",
9
+ itemListElement: members.filter((m) => m.name).map((m, i) => ({
10
+ "@type": "ListItem",
11
+ position: i + 1,
12
+ item: {
13
+ "@type": "Person",
14
+ name: m.name,
15
+ ...m.role ? { jobTitle: m.role } : {},
16
+ ...m.email ? { email: m.email } : {},
17
+ ...m.phone ? { telephone: m.phone } : {},
18
+ ...m.photoUrl ? { image: m.photoUrl } : {},
19
+ ...m.social?.length ? { sameAs: m.social.map((s) => s.href) } : {}
20
+ }
21
+ }))
22
+ };
23
+ }
24
+ function TeamRender({ block }) {
25
+ const members = (block.members ?? []).map((m, i) => ({ ...m, _i: i })).filter((m) => m.name);
26
+ if (members.length === 0) return null;
27
+ const groups = block.groupByDepartment ? [...new Set(members.map((m) => m.department ?? ""))].sort((a, b) => a === "" ? 1 : b === "" ? -1 : 0).map((dep) => ({ dep, members: members.filter((m) => (m.department ?? "") === dep) })) : [{ dep: "", members }];
28
+ const grid = (list) => /* @__PURE__ */ jsx(Grid, { columns: { minWidth: 220, max: 4 }, gap: 4, children: list.map((m) => {
29
+ const i = m._i;
30
+ return /* @__PURE__ */ jsx(Card, { padding: 4, height: "100%", children: /* @__PURE__ */ jsxs(VStack, { gap: 1, hAlign: "center", style: { textAlign: "center", height: "100%" }, children: [
31
+ /* @__PURE__ */ jsx(Avatar, { src: m.photoUrl, name: m.name, size: 96 }),
32
+ /* @__PURE__ */ jsx(Heading, { level: 3, "data-xicms-edit": `members.${i}.name`, children: m.name }),
33
+ m.role && /* @__PURE__ */ jsx(Text, { type: "label", "data-xicms-edit": `members.${i}.role`, style: { color: "var(--color-accent)" }, children: m.role }),
34
+ m.bio && /* @__PURE__ */ jsx(Text, { color: "secondary", "data-xicms-edit": `members.${i}.bio`, children: m.bio }),
35
+ m.email && /* @__PURE__ */ jsx("a", { href: `mailto:${m.email}`, style: { color: "var(--color-accent)" }, children: /* @__PURE__ */ jsx(Text, { type: "supporting", "data-xicms-edit": `members.${i}.email`, children: m.email }) }),
36
+ m.phone && /* @__PURE__ */ jsx(Text, { type: "supporting", color: "secondary", "data-xicms-edit": `members.${i}.phone`, children: m.phone }),
37
+ m.social && m.social.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: 2, hAlign: "center", as: "ul", style: { listStyle: "none", margin: 0, padding: 0, flexWrap: "wrap" }, children: m.social.map((s, j) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", { href: s.href, rel: "noopener noreferrer", target: "_blank", style: { color: "var(--color-accent)" }, children: /* @__PURE__ */ jsx(Text, { type: "supporting", "data-xicms-edit": `members.${i}.social.${j}.platform`, children: s.platform }) }) }, j)) })
38
+ ] }) }, i);
39
+ }) });
40
+ return /* @__PURE__ */ jsxs(VStack, { gap: 4, as: "section", className: "xicms-team", children: [
41
+ block.heading && /* @__PURE__ */ jsx(Heading, { level: 2, justify: "center", "data-xicms-edit": "heading", style: { textAlign: "center" }, children: block.heading }),
42
+ groups.map(({ dep, members: list }) => /* @__PURE__ */ jsxs(VStack, { gap: 3, children: [
43
+ block.groupByDepartment && groups.length > 1 && /* @__PURE__ */ jsx(Heading, { level: 3, justify: "center", style: { textAlign: "center" }, children: dep || "Overig" }),
44
+ grid(list)
45
+ ] }, dep || "_overig")),
46
+ block.jsonLd && /* @__PURE__ */ jsx(
47
+ "script",
48
+ {
49
+ type: "application/ld+json",
50
+ dangerouslySetInnerHTML: { __html: jsonLdHtml(personJsonLd(members)) }
51
+ }
52
+ )
53
+ ] });
54
+ }
55
+ export {
56
+ TeamRender
57
+ };
58
+ //# sourceMappingURL=TeamRender.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/blocks/builtins/TeamRender.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport type { TeamBlockSchema } from \"../../schema/blocks\";\nimport 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. */\nexport function 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"],"mappings":"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","names":[]}
@@ -1,8 +1 @@
1
- import type { z } from "zod";
2
- import type { TestimonialsBlockSchema } from "../../schema/blocks.js";
3
- type Testimonials = z.infer<typeof TestimonialsBlockSchema>;
4
- /** Gemiddelde beoordeling over de items met een rating — voor de sterren-snippet in Google. */
5
- export declare function aggregateRatingJsonLd(items: Testimonials["items"]): Record<string, unknown> | null;
6
- export declare function reviewJsonLd(items: Testimonials["items"]): Record<string, unknown>;
7
- export declare const testimonialsBlock: import("../index.js").BlockDefinition<z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
8
- export {};
1
+ export declare const testimonialsBlock: import("../index.js").BlockDefinition<import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>>;
@@ -1,73 +1,8 @@
1
- "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
1
+ import dynamic from "next/dynamic";
3
2
  import { defineBlock } from "../registry.js";
4
- import { VStack, HStack, Grid, Card, Heading, Text, Avatar } from "../ui/index.js";
5
- import { jsonLdHtml } from "./jsonld.js";
6
- function aggregateRatingJsonLd(items) {
7
- const rated = items.filter((it) => typeof it.rating === "number");
8
- if (rated.length === 0) return null;
9
- const avg = rated.reduce((sum, it) => sum + it.rating, 0) / rated.length;
10
- return {
11
- "@type": "AggregateRating",
12
- ratingValue: Math.round(avg * 10) / 10,
13
- reviewCount: rated.length,
14
- bestRating: 5
15
- };
16
- }
17
- function reviewJsonLd(items) {
18
- const aggregate = aggregateRatingJsonLd(items);
19
- return {
20
- "@context": "https://schema.org",
21
- "@type": "LocalBusiness",
22
- "@id": "#business",
23
- ...aggregate ? { aggregateRating: aggregate } : {},
24
- review: items.filter((it) => it.quote && it.author).map((it) => ({
25
- "@type": "Review",
26
- reviewBody: it.quote,
27
- author: { "@type": "Person", name: it.author },
28
- ...it.rating ? { reviewRating: { "@type": "Rating", ratingValue: it.rating, bestRating: 5 } } : {}
29
- }))
30
- };
31
- }
32
- function TestimonialsRender({ block }) {
33
- const items = (block.items ?? []).map((it, i) => ({ ...it, _i: i })).filter((i) => i.quote);
34
- if (items.length === 0) return null;
35
- const cols = block.layout === "list" ? { minWidth: 320, max: 1 } : { minWidth: 280, max: 3 };
36
- return /* @__PURE__ */ jsxs(VStack, { gap: 4, as: "section", className: "xicms-testimonials", children: [
37
- block.heading && /* @__PURE__ */ jsx(Heading, { level: 2, justify: "center", "data-xicms-edit": "heading", style: { textAlign: "center" }, children: block.heading }),
38
- /* @__PURE__ */ jsx(Grid, { columns: cols, gap: 4, children: items.map((it) => {
39
- const i = it._i;
40
- return /* @__PURE__ */ jsx(Card, { padding: 4, height: "100%", className: "xicms-testimonials__card", children: /* @__PURE__ */ jsxs(VStack, { gap: 2, style: { height: "100%" }, children: [
41
- typeof it.rating === "number" && /* @__PURE__ */ jsxs(Text, { className: "xicms-testimonials__rating", style: { color: "var(--xicms-star, #f59e0b)", letterSpacing: "0.1em" }, "aria-label": `${it.rating} van 5 sterren`, children: [
42
- "\u2605".repeat(it.rating),
43
- /* @__PURE__ */ jsx("span", { style: { opacity: 0.25 }, children: "\u2605".repeat(5 - it.rating) })
44
- ] }),
45
- /* @__PURE__ */ jsxs(Text, { type: "large", className: "xicms-testimonials__quote", style: { flex: 1 }, children: [
46
- "\u201C",
47
- /* @__PURE__ */ jsx("span", { "data-xicms-edit": `items.${i}.quote`, children: it.quote }),
48
- "\u201D"
49
- ] }),
50
- /* @__PURE__ */ jsxs(HStack, { gap: 1.5, vAlign: "center", children: [
51
- it.avatarUrl && /* @__PURE__ */ jsx(Avatar, { src: it.avatarUrl, name: it.author, size: 40 }),
52
- /* @__PURE__ */ jsxs(VStack, { gap: 0, children: [
53
- /* @__PURE__ */ jsx(Text, { weight: "bold", className: "xicms-testimonials__author", "data-xicms-edit": `items.${i}.author`, children: it.author }),
54
- it.role && /* @__PURE__ */ jsx(Text, { type: "supporting", color: "secondary", className: "xicms-testimonials__role", "data-xicms-edit": `items.${i}.role`, children: it.role })
55
- ] })
56
- ] })
57
- ] }) }, i);
58
- }) }),
59
- block.jsonLd && /* @__PURE__ */ jsx(
60
- "script",
61
- {
62
- type: "application/ld+json",
63
- dangerouslySetInnerHTML: { __html: jsonLdHtml(reviewJsonLd(items)) }
64
- }
65
- )
66
- ] });
67
- }
68
3
  const testimonialsBlock = defineBlock({
69
4
  type: "testimonials",
70
- Render: TestimonialsRender,
5
+ Render: dynamic(() => import("./TestimonialsRender.js").then((m) => m.TestimonialsRender)),
71
6
  label: "Reviews",
72
7
  icon: "\u2B50",
73
8
  defaults: () => ({
@@ -77,8 +12,6 @@ const testimonialsBlock = defineBlock({
77
12
  })
78
13
  });
79
14
  export {
80
- aggregateRatingJsonLd,
81
- reviewJsonLd,
82
15
  testimonialsBlock
83
16
  };
84
17
  //# sourceMappingURL=Testimonials.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/blocks/builtins/Testimonials.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport type { TestimonialsBlockSchema } 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 Testimonials = z.infer<typeof TestimonialsBlockSchema>;\n\n/** Gemiddelde beoordeling over de items met een rating — voor de sterren-snippet in Google. */\nexport function aggregateRatingJsonLd(items: Testimonials[\"items\"]): Record<string, unknown> | null {\n const rated = items.filter((it) => typeof it.rating === \"number\");\n if (rated.length === 0) return null;\n const avg = rated.reduce((sum, it) => sum + (it.rating as number), 0) / rated.length;\n return {\n \"@type\": \"AggregateRating\",\n ratingValue: Math.round(avg * 10) / 10,\n reviewCount: rated.length,\n bestRating: 5,\n };\n}\n\nexport function reviewJsonLd(items: Testimonials[\"items\"]): Record<string, unknown> {\n const aggregate = aggregateRatingJsonLd(items);\n // Reviews/AggregateRating zijn voor rich results alleen geldig aan een \"ding\" (bedrijf/product);\n // een losse ItemList negeert Google. We hangen ze aan dezelfde #business-entiteit als de\n // contact-/openingstijden-JSON-LD, zodat alles samenvloeit tot één LocalBusiness.\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"LocalBusiness\",\n \"@id\": \"#business\",\n ...(aggregate ? { aggregateRating: aggregate } : {}),\n review: items\n .filter((it) => it.quote && it.author)\n .map((it) => ({\n \"@type\": \"Review\",\n reviewBody: it.quote,\n author: { \"@type\": \"Person\", name: it.author },\n ...(it.rating\n ? { reviewRating: { \"@type\": \"Rating\", ratingValue: it.rating, bestRating: 5 } }\n : {}),\n })),\n };\n}\n\n/** Klant­quotes / reviews als kaarten (Astryx). */\nfunction TestimonialsRender({ block }: BlockRenderProps<Testimonials>) {\n // _i = index in de OORSPRONKELIJKE array — inline-edit-paden (items.N.quote) moeten daarheen wijzen.\n const items = (block.items ?? []).map((it, i) => ({ ...it, _i: i })).filter((i) => i.quote);\n if (items.length === 0) return null;\n const cols = block.layout === \"list\" ? { minWidth: 320, max: 1 as const } : { minWidth: 280, max: 3 as const };\n return (\n <VStack gap={4} as=\"section\" className=\"xicms-testimonials\">\n {block.heading && (\n <Heading level={2} justify=\"center\" data-xicms-edit=\"heading\" style={{ textAlign: \"center\" }}>{block.heading}</Heading>\n )}\n <Grid columns={cols} gap={4}>\n {items.map((it) => {\n const i = it._i;\n return (\n <Card key={i} padding={4} height=\"100%\" className=\"xicms-testimonials__card\">\n <VStack gap={2} style={{ height: \"100%\" }}>\n {typeof it.rating === \"number\" && (\n <Text className=\"xicms-testimonials__rating\" style={{ color: \"var(--xicms-star, #f59e0b)\", letterSpacing: \"0.1em\" }} aria-label={`${it.rating} van 5 sterren`}>\n {\"★\".repeat(it.rating)}\n <span style={{ opacity: 0.25 }}>{\"★\".repeat(5 - it.rating)}</span>\n </Text>\n )}\n <Text type=\"large\" className=\"xicms-testimonials__quote\" style={{ flex: 1 }}>“<span data-xicms-edit={`items.${i}.quote`}>{it.quote}</span>”</Text>\n <HStack gap={1.5} vAlign=\"center\">\n {it.avatarUrl && <Avatar src={it.avatarUrl} name={it.author} size={40} />}\n <VStack gap={0}>\n <Text weight=\"bold\" className=\"xicms-testimonials__author\" data-xicms-edit={`items.${i}.author`}>{it.author}</Text>\n {it.role && <Text type=\"supporting\" color=\"secondary\" className=\"xicms-testimonials__role\" data-xicms-edit={`items.${i}.role`}>{it.role}</Text>}\n </VStack>\n </HStack>\n </VStack>\n </Card>\n );\n })}\n </Grid>\n {block.jsonLd && (\n <script\n type=\"application/ld+json\"\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{ __html: jsonLdHtml(reviewJsonLd(items)) }}\n />\n )}\n </VStack>\n );\n}\n\nexport const testimonialsBlock = defineBlock({\n type: \"testimonials\",\n Render: TestimonialsRender,\n label: \"Reviews\",\n icon: \"⭐\",\n defaults: () => ({\n heading: \"Wat klanten zeggen\",\n items: [{ quote: \"Top geholpen!\", author: \"Tevreden klant\", rating: 5 }],\n jsonLd: true,\n }),\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/blocks/builtins/Testimonials.tsx"],"sourcesContent":["import dynamic from \"next/dynamic\";\nimport { defineBlock } from \"../registry\";\n\nexport const testimonialsBlock = defineBlock({\n type: \"testimonials\",\n Render: dynamic(() => import(\"./TestimonialsRender\").then((m) => m.TestimonialsRender)),\n label: \"Reviews\",\n icon: \"⭐\",\n defaults: () => ({\n heading: \"Wat klanten zeggen\",\n items: [{ quote: \"Top geholpen!\", author: \"Tevreden klant\", rating: 5 }],\n jsonLd: true,\n }),\n});\n"],"mappings":"AAAA,OAAO,aAAa;AACpB,SAAS,mBAAmB;AAErB,MAAM,oBAAoB,YAAY;AAAA,EAC3C,MAAM;AAAA,EACN,QAAQ,QAAQ,MAAM,OAAO,sBAAsB,EAAE,KAAK,CAAC,MAAM,EAAE,kBAAkB,CAAC;AAAA,EACtF,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO;AAAA,IACf,SAAS;AAAA,IACT,OAAO,CAAC,EAAE,OAAO,iBAAiB,QAAQ,kBAAkB,QAAQ,EAAE,CAAC;AAAA,IACvE,QAAQ;AAAA,EACV;AACF,CAAC;","names":[]}
@@ -0,0 +1,10 @@
1
+ import type { z } from "zod";
2
+ import type { TestimonialsBlockSchema } from "../../schema/blocks.js";
3
+ import type { BlockRenderProps } from "../registry.js";
4
+ type Testimonials = z.infer<typeof TestimonialsBlockSchema>;
5
+ /** Gemiddelde beoordeling over de items met een rating — voor de sterren-snippet in Google. */
6
+ export declare function aggregateRatingJsonLd(items: Testimonials["items"]): Record<string, unknown> | null;
7
+ export declare function reviewJsonLd(items: Testimonials["items"]): Record<string, unknown>;
8
+ /** Klant­quotes / reviews als kaarten (Astryx). */
9
+ export declare function TestimonialsRender({ block }: BlockRenderProps<Testimonials>): import("react").JSX.Element | null;
10
+ export {};
@@ -0,0 +1,72 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { VStack, HStack, Grid, Card, Heading, Text, Avatar } from "../ui/index.js";
4
+ import { jsonLdHtml } from "./jsonld.js";
5
+ function aggregateRatingJsonLd(items) {
6
+ const rated = items.filter((it) => typeof it.rating === "number");
7
+ if (rated.length === 0) return null;
8
+ const avg = rated.reduce((sum, it) => sum + it.rating, 0) / rated.length;
9
+ return {
10
+ "@type": "AggregateRating",
11
+ ratingValue: Math.round(avg * 10) / 10,
12
+ reviewCount: rated.length,
13
+ bestRating: 5
14
+ };
15
+ }
16
+ function reviewJsonLd(items) {
17
+ const aggregate = aggregateRatingJsonLd(items);
18
+ return {
19
+ "@context": "https://schema.org",
20
+ "@type": "LocalBusiness",
21
+ "@id": "#business",
22
+ ...aggregate ? { aggregateRating: aggregate } : {},
23
+ review: items.filter((it) => it.quote && it.author).map((it) => ({
24
+ "@type": "Review",
25
+ reviewBody: it.quote,
26
+ author: { "@type": "Person", name: it.author },
27
+ ...it.rating ? { reviewRating: { "@type": "Rating", ratingValue: it.rating, bestRating: 5 } } : {}
28
+ }))
29
+ };
30
+ }
31
+ function TestimonialsRender({ block }) {
32
+ const items = (block.items ?? []).map((it, i) => ({ ...it, _i: i })).filter((i) => i.quote);
33
+ if (items.length === 0) return null;
34
+ const cols = block.layout === "list" ? { minWidth: 320, max: 1 } : { minWidth: 280, max: 3 };
35
+ return /* @__PURE__ */ jsxs(VStack, { gap: 4, as: "section", className: "xicms-testimonials", children: [
36
+ block.heading && /* @__PURE__ */ jsx(Heading, { level: 2, justify: "center", "data-xicms-edit": "heading", style: { textAlign: "center" }, children: block.heading }),
37
+ /* @__PURE__ */ jsx(Grid, { columns: cols, gap: 4, children: items.map((it) => {
38
+ const i = it._i;
39
+ return /* @__PURE__ */ jsx(Card, { padding: 4, height: "100%", className: "xicms-testimonials__card", children: /* @__PURE__ */ jsxs(VStack, { gap: 2, style: { height: "100%" }, children: [
40
+ typeof it.rating === "number" && /* @__PURE__ */ jsxs(Text, { className: "xicms-testimonials__rating", style: { color: "var(--xicms-star, #f59e0b)", letterSpacing: "0.1em" }, "aria-label": `${it.rating} van 5 sterren`, children: [
41
+ "\u2605".repeat(it.rating),
42
+ /* @__PURE__ */ jsx("span", { style: { opacity: 0.25 }, children: "\u2605".repeat(5 - it.rating) })
43
+ ] }),
44
+ /* @__PURE__ */ jsxs(Text, { type: "large", className: "xicms-testimonials__quote", style: { flex: 1 }, children: [
45
+ "\u201C",
46
+ /* @__PURE__ */ jsx("span", { "data-xicms-edit": `items.${i}.quote`, children: it.quote }),
47
+ "\u201D"
48
+ ] }),
49
+ /* @__PURE__ */ jsxs(HStack, { gap: 1.5, vAlign: "center", children: [
50
+ it.avatarUrl && /* @__PURE__ */ jsx(Avatar, { src: it.avatarUrl, name: it.author, size: 40 }),
51
+ /* @__PURE__ */ jsxs(VStack, { gap: 0, children: [
52
+ /* @__PURE__ */ jsx(Text, { weight: "bold", className: "xicms-testimonials__author", "data-xicms-edit": `items.${i}.author`, children: it.author }),
53
+ it.role && /* @__PURE__ */ jsx(Text, { type: "supporting", color: "secondary", className: "xicms-testimonials__role", "data-xicms-edit": `items.${i}.role`, children: it.role })
54
+ ] })
55
+ ] })
56
+ ] }) }, i);
57
+ }) }),
58
+ block.jsonLd && /* @__PURE__ */ jsx(
59
+ "script",
60
+ {
61
+ type: "application/ld+json",
62
+ dangerouslySetInnerHTML: { __html: jsonLdHtml(reviewJsonLd(items)) }
63
+ }
64
+ )
65
+ ] });
66
+ }
67
+ export {
68
+ TestimonialsRender,
69
+ aggregateRatingJsonLd,
70
+ reviewJsonLd
71
+ };
72
+ //# sourceMappingURL=TestimonialsRender.js.map