@xiwebdesign/xicms-core 7.31.0 → 8.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (482) hide show
  1. package/dist/XiCMSProvider.js +23 -7
  2. package/dist/XiCMSProvider.js.map +1 -1
  3. package/dist/admin/AdminApp.js +175 -93
  4. package/dist/admin/AdminApp.js.map +1 -1
  5. package/dist/admin/AdminHelp.d.ts +1 -1
  6. package/dist/admin/AdminHelp.js +44 -36
  7. package/dist/admin/AdminHelp.js.map +1 -1
  8. package/dist/admin/CoreVersion.d.ts +6 -3
  9. package/dist/admin/CoreVersion.js +60 -24
  10. package/dist/admin/CoreVersion.js.map +1 -1
  11. package/dist/admin/NewsEditor.d.ts +7 -0
  12. package/dist/admin/NewsEditor.js +117 -75
  13. package/dist/admin/NewsEditor.js.map +1 -1
  14. package/dist/admin/SuperadminPanel.js +1 -1
  15. package/dist/admin/SuperadminPanel.js.map +1 -1
  16. package/dist/admin/ZoekPalet.d.ts +15 -0
  17. package/dist/admin/ZoekPalet.js +123 -0
  18. package/dist/admin/ZoekPalet.js.map +1 -0
  19. package/dist/admin/blockEditors/GenericEditor.js +36 -18
  20. package/dist/admin/blockEditors/GenericEditor.js.map +1 -1
  21. package/dist/admin/blockEditors/StyleEditor.js +37 -3
  22. package/dist/admin/blockEditors/StyleEditor.js.map +1 -1
  23. package/dist/admin/blockEditors/SymbolRefEditor.js +44 -2
  24. package/dist/admin/blockEditors/SymbolRefEditor.js.map +1 -1
  25. package/dist/admin/blockEditors/index.js +154 -73
  26. package/dist/admin/blockEditors/index.js.map +1 -1
  27. package/dist/admin/customBlocks/CustomBlocksPanel.js +18 -7
  28. package/dist/admin/customBlocks/CustomBlocksPanel.js.map +1 -1
  29. package/dist/admin/dashboard/DashboardPanel.js +26 -16
  30. package/dist/admin/dashboard/DashboardPanel.js.map +1 -1
  31. package/dist/admin/editors/RichTextEditor.d.ts +4 -3
  32. package/dist/admin/editors/RichTextEditor.js +19 -60
  33. package/dist/admin/editors/RichTextEditor.js.map +1 -1
  34. package/dist/admin/editors/fontSizeExtension.js +7 -1
  35. package/dist/admin/editors/fontSizeExtension.js.map +1 -1
  36. package/dist/admin/editors/slashMenu.d.ts +18 -0
  37. package/dist/admin/editors/slashMenu.js +34 -0
  38. package/dist/admin/editors/slashMenu.js.map +1 -0
  39. package/dist/admin/editors/useRijkeTekst.d.ts +48 -0
  40. package/dist/admin/editors/useRijkeTekst.js +310 -0
  41. package/dist/admin/editors/useRijkeTekst.js.map +1 -0
  42. package/dist/admin/forms/FormsPanel.d.ts +11 -2
  43. package/dist/admin/forms/FormsPanel.js +218 -65
  44. package/dist/admin/forms/FormsPanel.js.map +1 -1
  45. package/dist/admin/lib/blokInfo.d.ts +17 -0
  46. package/dist/admin/lib/blokInfo.js +80 -0
  47. package/dist/admin/lib/blokInfo.js.map +1 -0
  48. package/dist/admin/lib/foutNaarMens.d.ts +1 -0
  49. package/dist/admin/lib/foutNaarMens.js +22 -0
  50. package/dist/admin/lib/foutNaarMens.js.map +1 -0
  51. package/dist/admin/lib/gewisteVelden.d.ts +13 -0
  52. package/dist/admin/lib/gewisteVelden.js +31 -0
  53. package/dist/admin/lib/gewisteVelden.js.map +1 -0
  54. package/dist/admin/lib/heroHulp.d.ts +11 -0
  55. package/dist/admin/lib/heroHulp.js +18 -0
  56. package/dist/admin/lib/heroHulp.js.map +1 -0
  57. package/dist/admin/lib/kleur.js +2 -3
  58. package/dist/admin/lib/kleur.js.map +1 -1
  59. package/dist/admin/lib/leesbaarheid.d.ts +34 -0
  60. package/dist/admin/lib/leesbaarheid.js +82 -0
  61. package/dist/admin/lib/leesbaarheid.js.map +1 -0
  62. package/dist/admin/lib/lengteAdvies.d.ts +1 -0
  63. package/dist/admin/lib/lengteAdvies.js +16 -0
  64. package/dist/admin/lib/lengteAdvies.js.map +1 -0
  65. package/dist/admin/lib/mediaLijst.d.ts +26 -0
  66. package/dist/admin/lib/mediaLijst.js +42 -0
  67. package/dist/admin/lib/mediaLijst.js.map +1 -0
  68. package/dist/admin/lib/mediaUsage.d.ts +12 -1
  69. package/dist/admin/lib/mediaUsage.js +43 -33
  70. package/dist/admin/lib/mediaUsage.js.map +1 -1
  71. package/dist/admin/lib/menuHulp.d.ts +16 -0
  72. package/dist/admin/lib/menuHulp.js +41 -0
  73. package/dist/admin/lib/menuHulp.js.map +1 -0
  74. package/dist/admin/lib/onopgeslagen.d.ts +10 -0
  75. package/dist/admin/lib/onopgeslagen.js +35 -0
  76. package/dist/admin/lib/onopgeslagen.js.map +1 -0
  77. package/dist/admin/lib/pagesClient.d.ts +55 -2
  78. package/dist/admin/lib/pagesClient.js +126 -28
  79. package/dist/admin/lib/pagesClient.js.map +1 -1
  80. package/dist/admin/lib/paginaGebruik.d.ts +56 -0
  81. package/dist/admin/lib/paginaGebruik.js +109 -0
  82. package/dist/admin/lib/paginaGebruik.js.map +1 -0
  83. package/dist/admin/lib/publicatieCheck.d.ts +25 -0
  84. package/dist/admin/lib/publicatieCheck.js +114 -0
  85. package/dist/admin/lib/publicatieCheck.js.map +1 -0
  86. package/dist/admin/lib/scrollNaarDetail.d.ts +6 -0
  87. package/dist/admin/lib/scrollNaarDetail.js +20 -0
  88. package/dist/admin/lib/scrollNaarDetail.js.map +1 -0
  89. package/dist/admin/lib/symbolsClient.d.ts +10 -0
  90. package/dist/admin/lib/symbolsClient.js +14 -1
  91. package/dist/admin/lib/symbolsClient.js.map +1 -1
  92. package/dist/admin/lib/tekstVeld.d.ts +8 -0
  93. package/dist/admin/lib/tekstVeld.js +10 -0
  94. package/dist/admin/lib/tekstVeld.js.map +1 -0
  95. package/dist/admin/lib/useIsSuperadmin.d.ts +2 -0
  96. package/dist/admin/lib/useIsSuperadmin.js +13 -0
  97. package/dist/admin/lib/useIsSuperadmin.js.map +1 -0
  98. package/dist/admin/lib/veldTaal.d.ts +14 -0
  99. package/dist/admin/lib/veldTaal.js +248 -0
  100. package/dist/admin/lib/veldTaal.js.map +1 -0
  101. package/dist/admin/lib/versieVergelijk.d.ts +17 -0
  102. package/dist/admin/lib/versieVergelijk.js +24 -0
  103. package/dist/admin/lib/versieVergelijk.js.map +1 -0
  104. package/dist/admin/lib/zodFields.js +22 -4
  105. package/dist/admin/lib/zodFields.js.map +1 -1
  106. package/dist/admin/lib/zodFout.d.ts +9 -0
  107. package/dist/admin/lib/zodFout.js +63 -0
  108. package/dist/admin/lib/zodFout.js.map +1 -0
  109. package/dist/admin/media/MediaManager.js +162 -32
  110. package/dist/admin/media/MediaManager.js.map +1 -1
  111. package/dist/admin/media/MediaPicker.d.ts +3 -0
  112. package/dist/admin/media/MediaPicker.js +84 -31
  113. package/dist/admin/media/MediaPicker.js.map +1 -1
  114. package/dist/admin/menu/MenuPanel.js +144 -83
  115. package/dist/admin/menu/MenuPanel.js.map +1 -1
  116. package/dist/admin/navContext.d.ts +3 -0
  117. package/dist/admin/navContext.js +13 -1
  118. package/dist/admin/navContext.js.map +1 -1
  119. package/dist/admin/pages/PageEditor.js +146 -30
  120. package/dist/admin/pages/PageEditor.js.map +1 -1
  121. package/dist/admin/pages/PagesPanel.js +215 -61
  122. package/dist/admin/pages/PagesPanel.js.map +1 -1
  123. package/dist/admin/pages/StarterKiezer.d.ts +12 -0
  124. package/dist/admin/pages/StarterKiezer.js +113 -0
  125. package/dist/admin/pages/StarterKiezer.js.map +1 -0
  126. package/dist/admin/panelRegistry.d.ts +1 -1
  127. package/dist/admin/panelRegistry.js +2 -1
  128. package/dist/admin/panelRegistry.js.map +1 -1
  129. package/dist/admin/patterns/PatternInserter.js +1 -1
  130. package/dist/admin/patterns/PatternInserter.js.map +1 -1
  131. package/dist/admin/settings/BedrijfInstellingen.d.ts +20 -0
  132. package/dist/admin/settings/BedrijfInstellingen.js +159 -0
  133. package/dist/admin/settings/BedrijfInstellingen.js.map +1 -0
  134. package/dist/admin/settings/MailTemplates.js +5 -4
  135. package/dist/admin/settings/MailTemplates.js.map +1 -1
  136. package/dist/admin/settings/SettingsPanel.js +120 -78
  137. package/dist/admin/settings/SettingsPanel.js.map +1 -1
  138. package/dist/admin/settings/SnapshotsCard.js +4 -4
  139. package/dist/admin/settings/SnapshotsCard.js.map +1 -1
  140. package/dist/admin/settings/VorigeTerugzetten.d.ts +15 -0
  141. package/dist/admin/settings/VorigeTerugzetten.js +89 -0
  142. package/dist/admin/settings/VorigeTerugzetten.js.map +1 -0
  143. package/dist/admin/shop/CategoriesTab.js +6 -4
  144. package/dist/admin/shop/CategoriesTab.js.map +1 -1
  145. package/dist/admin/shop/DiscountsTab.js +4 -2
  146. package/dist/admin/shop/DiscountsTab.js.map +1 -1
  147. package/dist/admin/shop/OrdersTab.js +57 -19
  148. package/dist/admin/shop/OrdersTab.js.map +1 -1
  149. package/dist/admin/shop/ProductPaneel.js +2 -1
  150. package/dist/admin/shop/ProductPaneel.js.map +1 -1
  151. package/dist/admin/shop/ProductsTab.js +40 -19
  152. package/dist/admin/shop/ProductsTab.js.map +1 -1
  153. package/dist/admin/shop/ShopPanel.js +13 -1
  154. package/dist/admin/shop/ShopPanel.js.map +1 -1
  155. package/dist/admin/shop/ShopSettingsTab.js +56 -17
  156. package/dist/admin/shop/ShopSettingsTab.js.map +1 -1
  157. package/dist/admin/shop/productClient.js +7 -3
  158. package/dist/admin/shop/productClient.js.map +1 -1
  159. package/dist/admin/stats/NietGevonden.d.ts +10 -0
  160. package/dist/admin/stats/NietGevonden.js +78 -0
  161. package/dist/admin/stats/NietGevonden.js.map +1 -0
  162. package/dist/admin/stats/StatsPanel.js +6 -1
  163. package/dist/admin/stats/StatsPanel.js.map +1 -1
  164. package/dist/admin/stats/lib.d.ts +2 -0
  165. package/dist/admin/stats/lib.js.map +1 -1
  166. package/dist/admin/ui/ConfirmDialog.js +10 -1
  167. package/dist/admin/ui/ConfirmDialog.js.map +1 -1
  168. package/dist/admin/ui/Icon.d.ts +34 -0
  169. package/dist/admin/ui/Icon.js +44 -0
  170. package/dist/admin/ui/Icon.js.map +1 -0
  171. package/dist/admin/ui/ImageField.d.ts +15 -0
  172. package/dist/admin/ui/ImageField.js +67 -0
  173. package/dist/admin/ui/ImageField.js.map +1 -0
  174. package/dist/admin/ui/KleurVeld.d.ts +25 -0
  175. package/dist/admin/ui/KleurVeld.js +76 -0
  176. package/dist/admin/ui/KleurVeld.js.map +1 -0
  177. package/dist/admin/ui/LaadStaat.d.ts +21 -0
  178. package/dist/admin/ui/LaadStaat.js +43 -0
  179. package/dist/admin/ui/LaadStaat.js.map +1 -0
  180. package/dist/admin/ui/LeesbaarheidPaneel.d.ts +10 -0
  181. package/dist/admin/ui/LeesbaarheidPaneel.js +68 -0
  182. package/dist/admin/ui/LeesbaarheidPaneel.js.map +1 -0
  183. package/dist/admin/ui/LinkDialog.d.ts +22 -0
  184. package/dist/admin/ui/LinkDialog.js +131 -0
  185. package/dist/admin/ui/LinkDialog.js.map +1 -0
  186. package/dist/admin/ui/LinkVeld.d.ts +14 -0
  187. package/dist/admin/ui/LinkVeld.js +49 -0
  188. package/dist/admin/ui/LinkVeld.js.map +1 -0
  189. package/dist/admin/ui/PreviewLinkResultaat.d.ts +14 -0
  190. package/dist/admin/ui/PreviewLinkResultaat.js +52 -0
  191. package/dist/admin/ui/PreviewLinkResultaat.js.map +1 -0
  192. package/dist/admin/ui/charts.js +5 -5
  193. package/dist/admin/ui/charts.js.map +1 -1
  194. package/dist/admin/ui/primitives.d.ts +16 -6
  195. package/dist/admin/ui/primitives.js +98 -26
  196. package/dist/admin/ui/primitives.js.map +1 -1
  197. package/dist/admin/ui/select.js +5 -2
  198. package/dist/admin/ui/select.js.map +1 -1
  199. package/dist/admin/ui/switch.d.ts +3 -1
  200. package/dist/admin/ui/switch.js +6 -3
  201. package/dist/admin/ui/switch.js.map +1 -1
  202. package/dist/admin/ui/toast.d.ts +2 -1
  203. package/dist/admin/ui/toast.js +17 -11
  204. package/dist/admin/ui/toast.js.map +1 -1
  205. package/dist/admin/visual/BlokKiezer.d.ts +34 -0
  206. package/dist/admin/visual/BlokKiezer.js +225 -0
  207. package/dist/admin/visual/BlokKiezer.js.map +1 -0
  208. package/dist/admin/visual/InlineGereedschap.d.ts +52 -0
  209. package/dist/admin/visual/InlineGereedschap.js +356 -0
  210. package/dist/admin/visual/InlineGereedschap.js.map +1 -0
  211. package/dist/admin/visual/InlineRijkeTekst.d.ts +23 -0
  212. package/dist/admin/visual/InlineRijkeTekst.js +152 -0
  213. package/dist/admin/visual/InlineRijkeTekst.js.map +1 -0
  214. package/dist/admin/visual/VisualEditor.js +273 -125
  215. package/dist/admin/visual/VisualEditor.js.map +1 -1
  216. package/dist/admin.css +1 -1
  217. package/dist/auth/AuthProvider.js +1 -0
  218. package/dist/auth/AuthProvider.js.map +1 -1
  219. package/dist/bedrijf/bedrijf.d.ts +44 -0
  220. package/dist/bedrijf/bedrijf.js +125 -0
  221. package/dist/bedrijf/bedrijf.js.map +1 -0
  222. package/dist/blocks/BlockRenderer.js +11 -1
  223. package/dist/blocks/BlockRenderer.js.map +1 -1
  224. package/dist/blocks/blockStyle.d.ts +7 -0
  225. package/dist/blocks/blockStyle.js +16 -3
  226. package/dist/blocks/blockStyle.js.map +1 -1
  227. package/dist/blocks/builtinSchemas.js +6 -0
  228. package/dist/blocks/builtinSchemas.js.map +1 -1
  229. package/dist/blocks/builtins/AgendaRender.d.ts +22 -0
  230. package/dist/blocks/builtins/AgendaRender.js +69 -9
  231. package/dist/blocks/builtins/AgendaRender.js.map +1 -1
  232. package/dist/blocks/builtins/Availability.d.ts +1 -0
  233. package/dist/blocks/builtins/Availability.js +23 -0
  234. package/dist/blocks/builtins/Availability.js.map +1 -0
  235. package/dist/blocks/builtins/AvailabilityRender.d.ts +12 -0
  236. package/dist/blocks/builtins/AvailabilityRender.js +105 -0
  237. package/dist/blocks/builtins/AvailabilityRender.js.map +1 -0
  238. package/dist/blocks/builtins/BeforeAfterRender.js +4 -3
  239. package/dist/blocks/builtins/BeforeAfterRender.js.map +1 -1
  240. package/dist/blocks/builtins/Booking.js +1 -1
  241. package/dist/blocks/builtins/Booking.js.map +1 -1
  242. package/dist/blocks/builtins/BreadcrumbsRender.d.ts +4 -3
  243. package/dist/blocks/builtins/BreadcrumbsRender.js +14 -8
  244. package/dist/blocks/builtins/BreadcrumbsRender.js.map +1 -1
  245. package/dist/blocks/builtins/ColumnsRender.d.ts +1 -1
  246. package/dist/blocks/builtins/ColumnsRender.js +3 -1
  247. package/dist/blocks/builtins/ColumnsRender.js.map +1 -1
  248. package/dist/blocks/builtins/Contact.js +1 -1
  249. package/dist/blocks/builtins/Contact.js.map +1 -1
  250. package/dist/blocks/builtins/ContactRender.d.ts +1 -1
  251. package/dist/blocks/builtins/ContactRender.js +37 -8
  252. package/dist/blocks/builtins/ContactRender.js.map +1 -1
  253. package/dist/blocks/builtins/Cta.js +1 -1
  254. package/dist/blocks/builtins/Cta.js.map +1 -1
  255. package/dist/blocks/builtins/CtaRender.d.ts +1 -1
  256. package/dist/blocks/builtins/CtaRender.js +5 -4
  257. package/dist/blocks/builtins/CtaRender.js.map +1 -1
  258. package/dist/blocks/builtins/Embed.js +1 -1
  259. package/dist/blocks/builtins/Embed.js.map +1 -1
  260. package/dist/blocks/builtins/FormBlock.js +1 -0
  261. package/dist/blocks/builtins/FormBlock.js.map +1 -1
  262. package/dist/blocks/builtins/FormBlockRender.d.ts +6 -0
  263. package/dist/blocks/builtins/FormBlockRender.js +88 -16
  264. package/dist/blocks/builtins/FormBlockRender.js.map +1 -1
  265. package/dist/blocks/builtins/GalleryRender.js +3 -2
  266. package/dist/blocks/builtins/GalleryRender.js.map +1 -1
  267. package/dist/blocks/builtins/Hero.js +1 -1
  268. package/dist/blocks/builtins/Hero.js.map +1 -1
  269. package/dist/blocks/builtins/HeroRender.js +7 -3
  270. package/dist/blocks/builtins/HeroRender.js.map +1 -1
  271. package/dist/blocks/builtins/OpenNowBadge.d.ts +4 -2
  272. package/dist/blocks/builtins/OpenNowBadge.js +6 -6
  273. package/dist/blocks/builtins/OpenNowBadge.js.map +1 -1
  274. package/dist/blocks/builtins/OpeningHoursRender.d.ts +8 -2
  275. package/dist/blocks/builtins/OpeningHoursRender.js +27 -6
  276. package/dist/blocks/builtins/OpeningHoursRender.js.map +1 -1
  277. package/dist/blocks/builtins/PriceList.d.ts +1 -0
  278. package/dist/blocks/builtins/PriceList.js +25 -0
  279. package/dist/blocks/builtins/PriceList.js.map +1 -0
  280. package/dist/blocks/builtins/PriceListRender.d.ts +17 -0
  281. package/dist/blocks/builtins/PriceListRender.js +87 -0
  282. package/dist/blocks/builtins/PriceListRender.js.map +1 -0
  283. package/dist/blocks/builtins/RichTextBlockRender.js +6 -1
  284. package/dist/blocks/builtins/RichTextBlockRender.js.map +1 -1
  285. package/dist/blocks/builtins/SectionHeading.d.ts +1 -0
  286. package/dist/blocks/builtins/SectionHeading.js +14 -0
  287. package/dist/blocks/builtins/SectionHeading.js.map +1 -0
  288. package/dist/blocks/builtins/SectionHeadingRender.d.ts +7 -0
  289. package/dist/blocks/builtins/SectionHeadingRender.js +14 -0
  290. package/dist/blocks/builtins/SectionHeadingRender.js.map +1 -0
  291. package/dist/blocks/builtins/SliderRender.js +3 -2
  292. package/dist/blocks/builtins/SliderRender.js.map +1 -1
  293. package/dist/blocks/builtins/SymbolRef.js +1 -1
  294. package/dist/blocks/builtins/SymbolRef.js.map +1 -1
  295. package/dist/blocks/builtins/TeamRender.js +6 -1
  296. package/dist/blocks/builtins/TeamRender.js.map +1 -1
  297. package/dist/blocks/builtins/Testimonials.js +3 -1
  298. package/dist/blocks/builtins/Testimonials.js.map +1 -1
  299. package/dist/blocks/builtins/TestimonialsRender.js +4 -0
  300. package/dist/blocks/builtins/TestimonialsRender.js.map +1 -1
  301. package/dist/blocks/builtins/WhatsappChatRender.d.ts +1 -1
  302. package/dist/blocks/builtins/WhatsappChatRender.js +3 -1
  303. package/dist/blocks/builtins/WhatsappChatRender.js.map +1 -1
  304. package/dist/blocks/builtins/Widgets.js +2 -2
  305. package/dist/blocks/builtins/Widgets.js.map +1 -1
  306. package/dist/blocks/builtins/WidgetsRender.js +3 -1
  307. package/dist/blocks/builtins/WidgetsRender.js.map +1 -1
  308. package/dist/blocks/builtins/consentEmbed.js +26 -9
  309. package/dist/blocks/builtins/consentEmbed.js.map +1 -1
  310. package/dist/blocks/builtins/index.d.ts +3 -0
  311. package/dist/blocks/builtins/index.js +6 -0
  312. package/dist/blocks/builtins/index.js.map +1 -1
  313. package/dist/blocks/builtins/lib/autoComplete.d.ts +7 -0
  314. package/dist/blocks/builtins/lib/autoComplete.js +20 -0
  315. package/dist/blocks/builtins/lib/autoComplete.js.map +1 -0
  316. package/dist/blocks/builtins/lib/bookingUrl.d.ts +2 -2
  317. package/dist/blocks/builtins/lib/bookingUrl.js +1 -1
  318. package/dist/blocks/builtins/lib/bookingUrl.js.map +1 -1
  319. package/dist/blocks/builtins/lib/ical.d.ts +24 -0
  320. package/dist/blocks/builtins/lib/ical.js +82 -0
  321. package/dist/blocks/builtins/lib/ical.js.map +1 -0
  322. package/dist/blocks/builtins/lib/vandaag.d.ts +8 -0
  323. package/dist/blocks/builtins/lib/vandaag.js +22 -0
  324. package/dist/blocks/builtins/lib/vandaag.js.map +1 -0
  325. package/dist/blocks/registry.d.ts +6 -0
  326. package/dist/blocks/registry.js.map +1 -1
  327. package/dist/blocks/ui/index.js +1 -0
  328. package/dist/blocks/ui/index.js.map +1 -1
  329. package/dist/components/EditBar.js +2 -4
  330. package/dist/components/EditBar.js.map +1 -1
  331. package/dist/components/News.js +26 -18
  332. package/dist/components/News.js.map +1 -1
  333. package/dist/components/PageView.d.ts +7 -1
  334. package/dist/components/PageView.js +17 -0
  335. package/dist/components/PageView.js.map +1 -1
  336. package/dist/components/ResponsiveImage.js +18 -20
  337. package/dist/components/ResponsiveImage.js.map +1 -1
  338. package/dist/components/onderOffset.d.ts +13 -0
  339. package/dist/components/onderOffset.js +74 -0
  340. package/dist/components/onderOffset.js.map +1 -0
  341. package/dist/components/site/Bedrijfsnummers.d.ts +9 -0
  342. package/dist/components/site/Bedrijfsnummers.js +12 -0
  343. package/dist/components/site/Bedrijfsnummers.js.map +1 -0
  344. package/dist/components/site/SiteFooter.d.ts +6 -1
  345. package/dist/components/site/SiteFooter.js +62 -9
  346. package/dist/components/site/SiteFooter.js.map +1 -1
  347. package/dist/components/site/SiteHeader.d.ts +15 -0
  348. package/dist/components/site/SiteHeader.js +70 -0
  349. package/dist/components/site/SiteHeader.js.map +1 -0
  350. package/dist/components/site/SiteNav.d.ts +2 -0
  351. package/dist/components/site/SiteNav.js +29 -5
  352. package/dist/components/site/SiteNav.js.map +1 -1
  353. package/dist/demo/DemoStudio.js +2 -2
  354. package/dist/demo/DemoStudio.js.map +1 -1
  355. package/dist/demo/demoStore.d.ts +13 -0
  356. package/dist/demo/demoStore.js +36 -0
  357. package/dist/demo/demoStore.js.map +1 -1
  358. package/dist/editor/EditorProvider.js +15 -4
  359. package/dist/editor/EditorProvider.js.map +1 -1
  360. package/dist/firebase/functionsClient.js +5 -1
  361. package/dist/firebase/functionsClient.js.map +1 -1
  362. package/dist/index.d.ts +5 -1
  363. package/dist/index.js +20 -1
  364. package/dist/index.js.map +1 -1
  365. package/dist/media/ImageContext.d.ts +17 -0
  366. package/dist/media/ImageContext.js +65 -20
  367. package/dist/media/ImageContext.js.map +1 -1
  368. package/dist/media/altInHtml.d.ts +9 -0
  369. package/dist/media/altInHtml.js +17 -0
  370. package/dist/media/altInHtml.js.map +1 -0
  371. package/dist/media/srcset.d.ts +12 -0
  372. package/dist/media/srcset.js +13 -0
  373. package/dist/media/srcset.js.map +1 -0
  374. package/dist/modules/builtins.d.ts +1 -0
  375. package/dist/modules/builtins.js +22 -9
  376. package/dist/modules/builtins.js.map +1 -1
  377. package/dist/modules/consent/ConsentBanner.d.ts +5 -0
  378. package/dist/modules/consent/ConsentBanner.js +8 -7
  379. package/dist/modules/consent/ConsentBanner.js.map +1 -1
  380. package/dist/modules/consent/standaard.d.ts +12 -0
  381. package/dist/modules/consent/standaard.js +10 -0
  382. package/dist/modules/consent/standaard.js.map +1 -0
  383. package/dist/modules/consent/useConsent.d.ts +4 -0
  384. package/dist/modules/consent/useConsent.js +30 -1
  385. package/dist/modules/consent/useConsent.js.map +1 -1
  386. package/dist/modules/shop/blocks/Cart.js +5 -3
  387. package/dist/modules/shop/blocks/Cart.js.map +1 -1
  388. package/dist/modules/shop/blocks/Checkout.js +56 -35
  389. package/dist/modules/shop/blocks/Checkout.js.map +1 -1
  390. package/dist/modules/shop/blocks/Donation.js +4 -4
  391. package/dist/modules/shop/blocks/Donation.js.map +1 -1
  392. package/dist/modules/shop/blocks/ProductDetail.js +19 -3
  393. package/dist/modules/shop/blocks/ProductDetail.js.map +1 -1
  394. package/dist/modules/shop/blocks/ProductGrid.d.ts +3 -1
  395. package/dist/modules/shop/blocks/ProductGrid.js +8 -4
  396. package/dist/modules/shop/blocks/ProductGrid.js.map +1 -1
  397. package/dist/modules/shop/blocks/ShopCategories.js +4 -3
  398. package/dist/modules/shop/blocks/ShopCategories.js.map +1 -1
  399. package/dist/modules/shop/lib.d.ts +4 -0
  400. package/dist/modules/shop/lib.js +14 -0
  401. package/dist/modules/shop/lib.js.map +1 -1
  402. package/dist/modules/shop/settings.d.ts +3 -0
  403. package/dist/modules/shop/settings.js +14 -0
  404. package/dist/modules/shop/settings.js.map +1 -1
  405. package/dist/modules/shop/strings.d.ts +4 -0
  406. package/dist/modules/shop/strings.js +8 -0
  407. package/dist/modules/shop/strings.js.map +1 -1
  408. package/dist/next/envCheck.d.ts +42 -0
  409. package/dist/next/envCheck.js +106 -0
  410. package/dist/next/envCheck.js.map +1 -0
  411. package/dist/next/index.cjs +185 -2
  412. package/dist/next/index.d.ts +2 -0
  413. package/dist/next/index.js +8 -1
  414. package/dist/next/index.js.map +1 -1
  415. package/dist/next/securityHeaders.d.ts +36 -0
  416. package/dist/next/securityHeaders.js +74 -0
  417. package/dist/next/securityHeaders.js.map +1 -0
  418. package/dist/patterns/builtins.d.ts +7 -0
  419. package/dist/patterns/builtins.js +138 -3
  420. package/dist/patterns/builtins.js.map +1 -1
  421. package/dist/releaseNotes.js +148 -0
  422. package/dist/releaseNotes.js.map +1 -1
  423. package/dist/render/PublishedPage.d.ts +2 -1
  424. package/dist/render/PublishedPage.js +10 -4
  425. package/dist/render/PublishedPage.js.map +1 -1
  426. package/dist/schema/blocks.d.ts +473 -0
  427. package/dist/schema/blocks.js +105 -5
  428. package/dist/schema/blocks.js.map +1 -1
  429. package/dist/schema/business.d.ts +118 -0
  430. package/dist/schema/business.js +75 -0
  431. package/dist/schema/business.js.map +1 -0
  432. package/dist/schema/fields.d.ts +2 -1
  433. package/dist/schema/fields.js.map +1 -1
  434. package/dist/schema/forms.d.ts +18 -0
  435. package/dist/schema/forms.js +18 -3
  436. package/dist/schema/forms.js.map +1 -1
  437. package/dist/schema/mail.d.ts +10 -0
  438. package/dist/schema/mail.js +7 -0
  439. package/dist/schema/mail.js.map +1 -1
  440. package/dist/schema/settings.d.ts +103 -0
  441. package/dist/schema/settings.js +24 -3
  442. package/dist/schema/settings.js.map +1 -1
  443. package/dist/schema/shop.d.ts +2 -0
  444. package/dist/schema/shop.js +4 -0
  445. package/dist/schema/shop.js.map +1 -1
  446. package/dist/schema/shopGeld.d.ts +1 -0
  447. package/dist/schema/shopGeld.js +1 -0
  448. package/dist/schema/shopGeld.js.map +1 -1
  449. package/dist/schema/siteConfig.d.ts +69 -1
  450. package/dist/schema/siteConfig.js +7 -2
  451. package/dist/schema/siteConfig.js.map +1 -1
  452. package/dist/server/blockData.d.ts +1 -1
  453. package/dist/server/blockData.js +74 -18
  454. package/dist/server/blockData.js.map +1 -1
  455. package/dist/server/cspRapport.d.ts +20 -0
  456. package/dist/server/cspRapport.js +56 -0
  457. package/dist/server/cspRapport.js.map +1 -0
  458. package/dist/server/fonts.d.ts +3 -0
  459. package/dist/server/fonts.js +39 -0
  460. package/dist/server/fonts.js.map +1 -0
  461. package/dist/server/index.d.ts +3 -0
  462. package/dist/server/index.js +8 -0
  463. package/dist/server/index.js.map +1 -1
  464. package/dist/server/sanitize.js +2 -0
  465. package/dist/server/sanitize.js.map +1 -1
  466. package/dist/settings/useSiteSettings.js +4 -1
  467. package/dist/settings/useSiteSettings.js.map +1 -1
  468. package/dist/starters/starters.d.ts +69 -0
  469. package/dist/starters/starters.js +171 -0
  470. package/dist/starters/starters.js.map +1 -0
  471. package/dist/styles.css +1181 -212
  472. package/dist/theme/color.d.ts +10 -0
  473. package/dist/theme/color.js +17 -1
  474. package/dist/theme/color.js.map +1 -1
  475. package/dist/theme/fontFallback.d.ts +23 -0
  476. package/dist/theme/fontFallback.js +58 -0
  477. package/dist/theme/fontFallback.js.map +1 -0
  478. package/dist/theme/fonts.d.ts +11 -0
  479. package/dist/theme/fonts.js +16 -0
  480. package/dist/theme/fonts.js.map +1 -0
  481. package/dist/version.js +1 -1
  482. package/package.json +5 -4
@@ -5,8 +5,13 @@ import type { FooterSettings } from "../../schema/settings.js";
5
5
  * `xicms-footer*`-classNames + thema-CSS-variabelen, zodat een site hem volledig kan herstijlen
6
6
  * (of vervangen door een eigen footer). De inhoud komt live uit `settings/public.footer`.
7
7
  */
8
- export declare function SiteFooter({ className, renderColumn, }: {
8
+ export declare function SiteFooter({ className, renderColumn, bedrijf, }: {
9
9
  className?: string;
10
+ /**
11
+ * 8.13: een eerste kolom met adres, telefoon, e-mail en openingstijden uit het bedrijfsprofiel
12
+ * (Instellingen → Bedrijf). Uit voor bestaande sites; de template zet hem aan.
13
+ */
14
+ bedrijf?: boolean;
10
15
  /** Override de opmaak van één kolom zonder de logica te forken. */
11
16
  renderColumn?: (column: NonNullable<FooterSettings["columns"]>[number], index: number) => ReactNode;
12
17
  }): import("react").JSX.Element;
@@ -1,10 +1,12 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import { useSiteSettings } from "../../settings/useSiteSettings.js";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useMergedSiteConfig, useSiteSettings } from "../../settings/useSiteSettings.js";
4
+ import { adresRegels, bedrijfsnummersTekst, heeftProfiel, telLink } from "../../bedrijf/bedrijf.js";
4
5
  import { useSiteConfig } from "../../config.js";
5
6
  function SiteFooter({
6
7
  className,
7
- renderColumn
8
+ renderColumn,
9
+ bedrijf = false
8
10
  }) {
9
11
  const { settings } = useSiteSettings();
10
12
  const config = useSiteConfig();
@@ -14,17 +16,68 @@ function SiteFooter({
14
16
  const social = footer.social ?? [];
15
17
  const showAdminLink = footer.showAdminLink !== false;
16
18
  const year = (/* @__PURE__ */ new Date()).getFullYear();
19
+ const profiel = useMergedSiteConfig().business;
20
+ const toonProfiel = bedrijf && heeftProfiel(profiel);
17
21
  return /* @__PURE__ */ jsxs("footer", { className: className ?? "xicms-footer", children: [
18
- columns.length > 0 && /* @__PURE__ */ jsx("div", { className: "xicms-footer__columns", children: columns.map(
19
- (col, i) => renderColumn ? /* @__PURE__ */ jsx("div", { children: renderColumn(col, i) }, i) : /* @__PURE__ */ jsxs("div", { className: "xicms-footer__column", children: [
20
- col.heading && /* @__PURE__ */ jsx("h3", { className: "xicms-footer__heading", children: col.heading }),
21
- /* @__PURE__ */ jsx("ul", { className: "xicms-footer__links", children: (col.links ?? []).map((l, j) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", { href: l.href, children: l.label }) }, j)) })
22
- ] }, i)
23
- ) }),
22
+ (columns.length > 0 || toonProfiel) && /* @__PURE__ */ jsxs("div", { className: "xicms-footer__columns", children: [
23
+ toonProfiel && profiel && /* @__PURE__ */ jsxs("div", { className: "xicms-footer__column xicms-footer__column--bedrijf", children: [
24
+ /* @__PURE__ */ jsx("h3", { className: "xicms-footer__heading", children: "Contact" }),
25
+ /* @__PURE__ */ jsxs("ul", { className: "xicms-footer__links", children: [
26
+ adresRegels(profiel).map((r) => /* @__PURE__ */ jsx("li", { children: r }, r)),
27
+ profiel.phone && /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", { href: telLink(profiel.phone), children: profiel.phone }) }),
28
+ profiel.email && /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", { href: `mailto:${profiel.email}`, children: profiel.email }) })
29
+ ] }),
30
+ (profiel.hours?.length ?? 0) > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
31
+ /* @__PURE__ */ jsx("h3", { className: "xicms-footer__heading", children: "Openingstijden" }),
32
+ /* @__PURE__ */ jsx("ul", { className: "xicms-footer__links", children: profiel.hours.map((r, i) => /* @__PURE__ */ jsxs("li", { children: [
33
+ r.day,
34
+ " \u2014 ",
35
+ r.hours
36
+ ] }, i)) })
37
+ ] })
38
+ ] }),
39
+ columns.map(
40
+ (col, i) => renderColumn ? /* @__PURE__ */ jsx("div", { children: renderColumn(col, i) }, i) : /* @__PURE__ */ jsxs("div", { className: "xicms-footer__column", children: [
41
+ col.heading && /* @__PURE__ */ jsx("h3", { className: "xicms-footer__heading", children: col.heading }),
42
+ /* @__PURE__ */ jsx("ul", { className: "xicms-footer__links", children: (col.links ?? []).map((l, j) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", { href: l.href, children: l.label }) }, j)) })
43
+ ] }, i)
44
+ )
45
+ ] }),
24
46
  social.length > 0 && /* @__PURE__ */ jsx("ul", { className: "xicms-footer__social", children: social.map((s, i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", { href: s.href, "aria-label": s.platform, rel: "noopener noreferrer", target: "_blank", children: s.platform }) }, i)) }),
25
47
  /* @__PURE__ */ jsxs("div", { className: "xicms-footer__bottom", children: [
26
48
  /* @__PURE__ */ jsx("span", { children: footer.copyright ?? `\xA9 ${year} ${name}` }),
49
+ bedrijfsnummersTekst(profiel) && /* @__PURE__ */ jsx("span", { className: "xicms-footer__nummers", children: bedrijfsnummersTekst(profiel) }),
27
50
  showAdminLink && /* @__PURE__ */ jsx("a", { href: "/beheer", children: "Beheer" })
51
+ ] }),
52
+ /* @__PURE__ */ jsxs("div", { className: "xicms-footer__credit", children: [
53
+ /* @__PURE__ */ jsxs(
54
+ "a",
55
+ {
56
+ className: "xicms-footer__credit-merk",
57
+ href: "https://www.xiwebdesign.nl",
58
+ rel: "noopener noreferrer",
59
+ target: "_blank",
60
+ children: [
61
+ /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 64 64", "aria-hidden": "true", fill: "currentColor", children: [
62
+ /* @__PURE__ */ jsx("rect", { x: "6", y: "10", width: "52", height: "11", rx: "3" }),
63
+ /* @__PURE__ */ jsx("rect", { x: "16", y: "27", width: "32", height: "11", rx: "3", opacity: "0.7" }),
64
+ /* @__PURE__ */ jsx("rect", { x: "6", y: "44", width: "52", height: "11", rx: "3" })
65
+ ] }),
66
+ "Website gemaakt door Xi Webdesign"
67
+ ]
68
+ }
69
+ ),
70
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "\xB7" }),
71
+ /* @__PURE__ */ jsx(
72
+ "a",
73
+ {
74
+ className: "xicms-footer__credit-cta",
75
+ href: "https://www.xiwebdesign.nl/#contact",
76
+ rel: "noopener noreferrer",
77
+ target: "_blank",
78
+ children: "Ook zo'n mooie website? Neem contact op \u2192"
79
+ }
80
+ )
28
81
  ] })
29
82
  ] });
30
83
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/site/SiteFooter.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { useSiteSettings } from \"../../settings/useSiteSettings\";\nimport { useSiteConfig } from \"../../config\";\nimport type { FooterSettings } from \"../../schema/settings\";\n\n/**\n * Door de klant in /beheer bewerkbare footer. Unstyled-by-default: alle opmaak hangt aan\n * `xicms-footer*`-classNames + thema-CSS-variabelen, zodat een site hem volledig kan herstijlen\n * (of vervangen door een eigen footer). De inhoud komt live uit `settings/public.footer`.\n */\nexport function SiteFooter({\n className,\n renderColumn,\n}: {\n className?: string;\n /** Override de opmaak van één kolom zonder de logica te forken. */\n renderColumn?: (column: NonNullable<FooterSettings[\"columns\"]>[number], index: number) => ReactNode;\n}) {\n const { settings } = useSiteSettings();\n const config = useSiteConfig();\n const footer = settings.footer ?? {};\n const name = settings.name ?? config.name;\n const columns = footer.columns ?? [];\n const social = footer.social ?? [];\n const showAdminLink = footer.showAdminLink !== false;\n const year = new Date().getFullYear();\n\n return (\n <footer className={className ?? \"xicms-footer\"}>\n {columns.length > 0 && (\n <div className=\"xicms-footer__columns\">\n {columns.map((col, i) =>\n renderColumn ? (\n <div key={i}>{renderColumn(col, i)}</div>\n ) : (\n <div key={i} className=\"xicms-footer__column\">\n {col.heading && <h3 className=\"xicms-footer__heading\">{col.heading}</h3>}\n <ul className=\"xicms-footer__links\">\n {(col.links ?? []).map((l, j) => (\n <li key={j}>\n <a href={l.href}>{l.label}</a>\n </li>\n ))}\n </ul>\n </div>\n ),\n )}\n </div>\n )}\n\n {social.length > 0 && (\n <ul className=\"xicms-footer__social\">\n {social.map((s, i) => (\n <li key={i}>\n <a href={s.href} aria-label={s.platform} rel=\"noopener noreferrer\" target=\"_blank\">\n {s.platform}\n </a>\n </li>\n ))}\n </ul>\n )}\n\n <div className=\"xicms-footer__bottom\">\n <span>{footer.copyright ?? `© ${year} ${name}`}</span>\n {showAdminLink && <a href=\"/beheer\">Beheer</a>}\n </div>\n </footer>\n );\n}\n"],"mappings":";AAmCc,cAEA,YAFA;AAhCd,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAQvB,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AACF,GAIG;AACD,QAAM,EAAE,SAAS,IAAI,gBAAgB;AACrC,QAAM,SAAS,cAAc;AAC7B,QAAM,SAAS,SAAS,UAAU,CAAC;AACnC,QAAM,OAAO,SAAS,QAAQ,OAAO;AACrC,QAAM,UAAU,OAAO,WAAW,CAAC;AACnC,QAAM,SAAS,OAAO,UAAU,CAAC;AACjC,QAAM,gBAAgB,OAAO,kBAAkB;AAC/C,QAAM,QAAO,oBAAI,KAAK,GAAE,YAAY;AAEpC,SACE,qBAAC,YAAO,WAAW,aAAa,gBAC7B;AAAA,YAAQ,SAAS,KAChB,oBAAC,SAAI,WAAU,yBACZ,kBAAQ;AAAA,MAAI,CAAC,KAAK,MACjB,eACE,oBAAC,SAAa,uBAAa,KAAK,CAAC,KAAvB,CAAyB,IAEnC,qBAAC,SAAY,WAAU,wBACpB;AAAA,YAAI,WAAW,oBAAC,QAAG,WAAU,yBAAyB,cAAI,SAAQ;AAAA,QACnE,oBAAC,QAAG,WAAU,uBACV,eAAI,SAAS,CAAC,GAAG,IAAI,CAAC,GAAG,MACzB,oBAAC,QACC,8BAAC,OAAE,MAAM,EAAE,MAAO,YAAE,OAAM,KADnB,CAET,CACD,GACH;AAAA,WARQ,CASV;AAAA,IAEJ,GACF;AAAA,IAGD,OAAO,SAAS,KACf,oBAAC,QAAG,WAAU,wBACX,iBAAO,IAAI,CAAC,GAAG,MACd,oBAAC,QACC,8BAAC,OAAE,MAAM,EAAE,MAAM,cAAY,EAAE,UAAU,KAAI,uBAAsB,QAAO,UACvE,YAAE,UACL,KAHO,CAIT,CACD,GACH;AAAA,IAGF,qBAAC,SAAI,WAAU,wBACb;AAAA,0BAAC,UAAM,iBAAO,aAAa,QAAK,IAAI,IAAI,IAAI,IAAG;AAAA,MAC9C,iBAAiB,oBAAC,OAAE,MAAK,WAAU,oBAAM;AAAA,OAC5C;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/site/SiteFooter.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { useMergedSiteConfig, useSiteSettings } from \"../../settings/useSiteSettings\";\nimport { adresRegels, bedrijfsnummersTekst, heeftProfiel, telLink } from \"../../bedrijf/bedrijf\";\nimport { useSiteConfig } from \"../../config\";\nimport type { FooterSettings } from \"../../schema/settings\";\n\n/**\n * Door de klant in /beheer bewerkbare footer. Unstyled-by-default: alle opmaak hangt aan\n * `xicms-footer*`-classNames + thema-CSS-variabelen, zodat een site hem volledig kan herstijlen\n * (of vervangen door een eigen footer). De inhoud komt live uit `settings/public.footer`.\n */\nexport function SiteFooter({\n className,\n renderColumn,\n bedrijf = false,\n}: {\n className?: string;\n /**\n * 8.13: een eerste kolom met adres, telefoon, e-mail en openingstijden uit het bedrijfsprofiel\n * (Instellingen → Bedrijf). Uit voor bestaande sites; de template zet hem aan.\n */\n bedrijf?: boolean;\n /** Override de opmaak van één kolom zonder de logica te forken. */\n renderColumn?: (column: NonNullable<FooterSettings[\"columns\"]>[number], index: number) => ReactNode;\n}) {\n const { settings } = useSiteSettings();\n const config = useSiteConfig();\n const footer = settings.footer ?? {};\n const name = settings.name ?? config.name;\n const columns = footer.columns ?? [];\n const social = footer.social ?? [];\n const showAdminLink = footer.showAdminLink !== false;\n const year = new Date().getFullYear();\n const profiel = useMergedSiteConfig().business;\n const toonProfiel = bedrijf && heeftProfiel(profiel);\n\n return (\n <footer className={className ?? \"xicms-footer\"}>\n {(columns.length > 0 || toonProfiel) && (\n <div className=\"xicms-footer__columns\">\n {toonProfiel && profiel && (\n <div className=\"xicms-footer__column xicms-footer__column--bedrijf\">\n <h3 className=\"xicms-footer__heading\">Contact</h3>\n <ul className=\"xicms-footer__links\">\n {adresRegels(profiel).map((r) => <li key={r}>{r}</li>)}\n {profiel.phone && <li><a href={telLink(profiel.phone)}>{profiel.phone}</a></li>}\n {profiel.email && <li><a href={`mailto:${profiel.email}`}>{profiel.email}</a></li>}\n </ul>\n {(profiel.hours?.length ?? 0) > 0 && (\n <>\n <h3 className=\"xicms-footer__heading\">Openingstijden</h3>\n <ul className=\"xicms-footer__links\">\n {profiel.hours!.map((r, i) => <li key={i}>{r.day} — {r.hours}</li>)}\n </ul>\n </>\n )}\n </div>\n )}\n {columns.map((col, i) =>\n renderColumn ? (\n <div key={i}>{renderColumn(col, i)}</div>\n ) : (\n <div key={i} className=\"xicms-footer__column\">\n {col.heading && <h3 className=\"xicms-footer__heading\">{col.heading}</h3>}\n <ul className=\"xicms-footer__links\">\n {(col.links ?? []).map((l, j) => (\n <li key={j}>\n <a href={l.href}>{l.label}</a>\n </li>\n ))}\n </ul>\n </div>\n ),\n )}\n </div>\n )}\n\n {social.length > 0 && (\n <ul className=\"xicms-footer__social\">\n {social.map((s, i) => (\n <li key={i}>\n <a href={s.href} aria-label={s.platform} rel=\"noopener noreferrer\" target=\"_blank\">\n {s.platform}\n </a>\n </li>\n ))}\n </ul>\n )}\n\n <div className=\"xicms-footer__bottom\">\n <span>{footer.copyright ?? `© ${year} ${name}`}</span>\n {/* 8.16: KvK en btw-nummer — wettelijk verplicht op de site; altijd zodra ze in het profiel staan. */}\n {bedrijfsnummersTekst(profiel) && <span className=\"xicms-footer__nummers\">{bedrijfsnummersTekst(profiel)}</span>}\n {showAdminLink && <a href=\"/beheer\">Beheer</a>}\n </div>\n\n <div className=\"xicms-footer__credit\">\n <a\n className=\"xicms-footer__credit-merk\"\n href=\"https://www.xiwebdesign.nl\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n <svg viewBox=\"0 0 64 64\" aria-hidden=\"true\" fill=\"currentColor\">\n <rect x=\"6\" y=\"10\" width=\"52\" height=\"11\" rx=\"3\" />\n <rect x=\"16\" y=\"27\" width=\"32\" height=\"11\" rx=\"3\" opacity=\"0.7\" />\n <rect x=\"6\" y=\"44\" width=\"52\" height=\"11\" rx=\"3\" />\n </svg>\n Website gemaakt door Xi Webdesign\n </a>\n <span aria-hidden>·</span>\n <a\n className=\"xicms-footer__credit-cta\"\n href=\"https://www.xiwebdesign.nl/#contact\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Ook zo&apos;n mooie website? Neem contact op →\n </a>\n </div>\n </footer>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * De kop van de site (8.13): logo, het beheerde menu, één actieknop — en op een telefoon een
3
+ * hamburgermenu en (optioneel) een vaste balk onderaan met "Bel" en de actieknop.
4
+ *
5
+ * Alle drie de klantsites bouwden dit zelf (Header.tsx van 100+ regels, StickyCta.tsx), en de
6
+ * template had alleen `<strong>naam</strong>` plus het menu, zonder mobiel menu. Nu kan een
7
+ * nieuwe site starten met een kop die op elk scherm werkt, en past de klant logo en knop zelf aan
8
+ * in /beheer → Instellingen → Kop. Sites met een eigen header gebruiken dit gewoon niet.
9
+ *
10
+ * Unstyled-by-default zoals SiteNav en SiteFooter: alle opmaak hangt aan `.xicms-header*` en de
11
+ * thema-variabelen (styles.css), te overschrijven per site.
12
+ */
13
+ export declare function SiteHeader({ className }: {
14
+ className?: string;
15
+ }): import("react").JSX.Element;
@@ -0,0 +1,70 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useId, useState } from "react";
4
+ import { useLinkComponent } from "@astryxdesign/core/Link";
5
+ import { useMergedSiteConfig } from "../../settings/useSiteSettings.js";
6
+ import { telLink } from "../../bedrijf/bedrijf.js";
7
+ import { SiteNav } from "./SiteNav.js";
8
+ function SiteHeader({ className }) {
9
+ const cfg = useMergedSiteConfig();
10
+ const Link = useLinkComponent();
11
+ const header = cfg.header ?? {};
12
+ const [open, setOpen] = useState(false);
13
+ const menuId = useId();
14
+ useEffect(() => {
15
+ if (!open) return;
16
+ const sluit = () => setOpen(false);
17
+ const opToets = (e) => e.key === "Escape" && sluit();
18
+ window.addEventListener("popstate", sluit);
19
+ window.addEventListener("keydown", opToets);
20
+ const vorige = document.documentElement.style.overflow;
21
+ document.documentElement.style.overflow = "hidden";
22
+ return () => {
23
+ window.removeEventListener("popstate", sluit);
24
+ window.removeEventListener("keydown", opToets);
25
+ document.documentElement.style.overflow = vorige;
26
+ };
27
+ }, [open]);
28
+ const cta = header.cta?.label?.trim() && header.cta.href ? header.cta : null;
29
+ const bel = telLink(cfg.business?.phone);
30
+ const LinkEl = Link;
31
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
32
+ /* @__PURE__ */ jsx(
33
+ "header",
34
+ {
35
+ className: ["xicms-header", header.sticky === false ? "" : "is-sticky", open ? "is-open" : "", className].filter(Boolean).join(" "),
36
+ children: /* @__PURE__ */ jsxs("div", { className: "xicms-header__binnen", children: [
37
+ /* @__PURE__ */ jsx(LinkEl, { href: "/", className: "xicms-header__merk", children: header.logo ? (
38
+ // eslint-disable-next-line @next/next/no-img-element
39
+ /* @__PURE__ */ jsx("img", { src: header.logo, alt: cfg.name, style: { height: header.logoHoogte ?? 40 } })
40
+ ) : /* @__PURE__ */ jsx("span", { children: cfg.name }) }),
41
+ /* @__PURE__ */ jsxs("div", { className: "xicms-header__nav", id: menuId, children: [
42
+ /* @__PURE__ */ jsx("div", { onClick: (e) => e.target.closest("a") && setOpen(false), children: /* @__PURE__ */ jsx(SiteNav, { className: "xicms-nav xicms-header__menu" }) }),
43
+ cta && /* @__PURE__ */ jsx(LinkEl, { href: cta.href, className: "xicms-header__cta xicms-header__cta--in-menu", onClick: () => setOpen(false), children: cta.label })
44
+ ] }),
45
+ cta && /* @__PURE__ */ jsx(LinkEl, { href: cta.href, className: "xicms-header__cta", children: cta.label }),
46
+ /* @__PURE__ */ jsx(
47
+ "button",
48
+ {
49
+ type: "button",
50
+ className: "xicms-header__knop",
51
+ "aria-expanded": open,
52
+ "aria-controls": menuId,
53
+ "aria-label": open ? "Menu sluiten" : "Menu openen",
54
+ onClick: () => setOpen((v) => !v),
55
+ children: /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "xicms-header__streepjes" })
56
+ }
57
+ )
58
+ ] })
59
+ }
60
+ ),
61
+ header.mobielBalk && (bel || cta) && /* @__PURE__ */ jsxs("div", { className: "xicms-mobielbalk", role: "region", "aria-label": "Snel contact", children: [
62
+ bel && /* @__PURE__ */ jsx("a", { href: bel, className: "xicms-mobielbalk__bel", children: "Bel ons" }),
63
+ cta && /* @__PURE__ */ jsx(LinkEl, { href: cta.href, className: "xicms-mobielbalk__cta", children: cta.label })
64
+ ] })
65
+ ] });
66
+ }
67
+ export {
68
+ SiteHeader
69
+ };
70
+ //# sourceMappingURL=SiteHeader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/site/SiteHeader.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useId, useState } from \"react\";\nimport { useLinkComponent } from \"@astryxdesign/core/Link\";\nimport { useMergedSiteConfig } from \"../../settings/useSiteSettings\";\nimport { telLink } from \"../../bedrijf/bedrijf\";\nimport { SiteNav } from \"./SiteNav\";\n\n/**\n * De kop van de site (8.13): logo, het beheerde menu, één actieknop — en op een telefoon een\n * hamburgermenu en (optioneel) een vaste balk onderaan met \"Bel\" en de actieknop.\n *\n * Alle drie de klantsites bouwden dit zelf (Header.tsx van 100+ regels, StickyCta.tsx), en de\n * template had alleen `<strong>naam</strong>` plus het menu, zonder mobiel menu. Nu kan een\n * nieuwe site starten met een kop die op elk scherm werkt, en past de klant logo en knop zelf aan\n * in /beheer → Instellingen → Kop. Sites met een eigen header gebruiken dit gewoon niet.\n *\n * Unstyled-by-default zoals SiteNav en SiteFooter: alle opmaak hangt aan `.xicms-header*` en de\n * thema-variabelen (styles.css), te overschrijven per site.\n */\nexport function SiteHeader({ className }: { className?: string }) {\n const cfg = useMergedSiteConfig();\n const Link = useLinkComponent();\n const header = cfg.header ?? {};\n const [open, setOpen] = useState(false);\n const menuId = useId();\n\n // Menu dicht bij navigeren (Terug/Vooruit) en met Escape; scrollen blokkeren terwijl het open is.\n useEffect(() => {\n if (!open) return;\n const sluit = () => setOpen(false);\n const opToets = (e: KeyboardEvent) => e.key === \"Escape\" && sluit();\n window.addEventListener(\"popstate\", sluit);\n window.addEventListener(\"keydown\", opToets);\n const vorige = document.documentElement.style.overflow;\n document.documentElement.style.overflow = \"hidden\";\n return () => {\n window.removeEventListener(\"popstate\", sluit);\n window.removeEventListener(\"keydown\", opToets);\n document.documentElement.style.overflow = vorige;\n };\n }, [open]);\n\n const cta = header.cta?.label?.trim() && header.cta.href ? header.cta : null;\n const bel = telLink(cfg.business?.phone);\n const LinkEl = Link as unknown as React.ComponentType<{ href: string; className?: string; children: React.ReactNode; onClick?: () => void }>;\n\n return (\n <>\n <header\n className={[\"xicms-header\", header.sticky === false ? \"\" : \"is-sticky\", open ? \"is-open\" : \"\", className].filter(Boolean).join(\" \")}\n >\n <div className=\"xicms-header__binnen\">\n <LinkEl href=\"/\" className=\"xicms-header__merk\">\n {header.logo ? (\n // eslint-disable-next-line @next/next/no-img-element\n <img src={header.logo} alt={cfg.name} style={{ height: header.logoHoogte ?? 40 }} />\n ) : (\n <span>{cfg.name}</span>\n )}\n </LinkEl>\n <div className=\"xicms-header__nav\" id={menuId}>\n {/* Een klik op een link in het (mobiele) menu sluit het; de nav zelf is SiteNav. */}\n <div onClick={(e) => (e.target as HTMLElement).closest(\"a\") && setOpen(false)}>\n <SiteNav className=\"xicms-nav xicms-header__menu\" />\n </div>\n {cta && (\n <LinkEl href={cta.href} className=\"xicms-header__cta xicms-header__cta--in-menu\" onClick={() => setOpen(false)}>\n {cta.label}\n </LinkEl>\n )}\n </div>\n {cta && (\n <LinkEl href={cta.href} className=\"xicms-header__cta\">\n {cta.label}\n </LinkEl>\n )}\n <button\n type=\"button\"\n className=\"xicms-header__knop\"\n aria-expanded={open}\n aria-controls={menuId}\n aria-label={open ? \"Menu sluiten\" : \"Menu openen\"}\n onClick={() => setOpen((v) => !v)}\n >\n <span aria-hidden className=\"xicms-header__streepjes\" />\n </button>\n </div>\n </header>\n {header.mobielBalk && (bel || cta) && (\n <div className=\"xicms-mobielbalk\" role=\"region\" aria-label=\"Snel contact\">\n {bel && (\n <a href={bel} className=\"xicms-mobielbalk__bel\">\n Bel ons\n </a>\n )}\n {cta && (\n <LinkEl href={cta.href} className=\"xicms-mobielbalk__cta\">\n {cta.label}\n </LinkEl>\n )}\n </div>\n )}\n </>\n );\n}\n"],"mappings":";AAgDI,mBAQU,KAKJ,YAbN;AA9CJ,SAAS,WAAW,OAAO,gBAAgB;AAC3C,SAAS,wBAAwB;AACjC,SAAS,2BAA2B;AACpC,SAAS,eAAe;AACxB,SAAS,eAAe;AAcjB,SAAS,WAAW,EAAE,UAAU,GAA2B;AAChE,QAAM,MAAM,oBAAoB;AAChC,QAAM,OAAO,iBAAiB;AAC9B,QAAM,SAAS,IAAI,UAAU,CAAC;AAC9B,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,SAAS,MAAM;AAGrB,YAAU,MAAM;AACd,QAAI,CAAC,KAAM;AACX,UAAM,QAAQ,MAAM,QAAQ,KAAK;AACjC,UAAM,UAAU,CAAC,MAAqB,EAAE,QAAQ,YAAY,MAAM;AAClE,WAAO,iBAAiB,YAAY,KAAK;AACzC,WAAO,iBAAiB,WAAW,OAAO;AAC1C,UAAM,SAAS,SAAS,gBAAgB,MAAM;AAC9C,aAAS,gBAAgB,MAAM,WAAW;AAC1C,WAAO,MAAM;AACX,aAAO,oBAAoB,YAAY,KAAK;AAC5C,aAAO,oBAAoB,WAAW,OAAO;AAC7C,eAAS,gBAAgB,MAAM,WAAW;AAAA,IAC5C;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,MAAM,OAAO,KAAK,OAAO,KAAK,KAAK,OAAO,IAAI,OAAO,OAAO,MAAM;AACxE,QAAM,MAAM,QAAQ,IAAI,UAAU,KAAK;AACvC,QAAM,SAAS;AAEf,SACE,iCACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,CAAC,gBAAgB,OAAO,WAAW,QAAQ,KAAK,aAAa,OAAO,YAAY,IAAI,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,QAElI,+BAAC,SAAI,WAAU,wBACb;AAAA,8BAAC,UAAO,MAAK,KAAI,WAAU,sBACxB,iBAAO;AAAA;AAAA,YAEN,oBAAC,SAAI,KAAK,OAAO,MAAM,KAAK,IAAI,MAAM,OAAO,EAAE,QAAQ,OAAO,cAAc,GAAG,GAAG;AAAA,cAElF,oBAAC,UAAM,cAAI,MAAK,GAEpB;AAAA,UACA,qBAAC,SAAI,WAAU,qBAAoB,IAAI,QAErC;AAAA,gCAAC,SAAI,SAAS,CAAC,MAAO,EAAE,OAAuB,QAAQ,GAAG,KAAK,QAAQ,KAAK,GAC1E,8BAAC,WAAQ,WAAU,gCAA+B,GACpD;AAAA,YACC,OACC,oBAAC,UAAO,MAAM,IAAI,MAAM,WAAU,gDAA+C,SAAS,MAAM,QAAQ,KAAK,GAC1G,cAAI,OACP;AAAA,aAEJ;AAAA,UACC,OACC,oBAAC,UAAO,MAAM,IAAI,MAAM,WAAU,qBAC/B,cAAI,OACP;AAAA,UAEF;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,WAAU;AAAA,cACV,iBAAe;AAAA,cACf,iBAAe;AAAA,cACf,cAAY,OAAO,iBAAiB;AAAA,cACpC,SAAS,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;AAAA,cAEhC,8BAAC,UAAK,eAAW,MAAC,WAAU,2BAA0B;AAAA;AAAA,UACxD;AAAA,WACF;AAAA;AAAA,IACF;AAAA,IACC,OAAO,eAAe,OAAO,QAC5B,qBAAC,SAAI,WAAU,oBAAmB,MAAK,UAAS,cAAW,gBACxD;AAAA,aACC,oBAAC,OAAE,MAAM,KAAK,WAAU,yBAAwB,qBAEhD;AAAA,MAED,OACC,oBAAC,UAAO,MAAM,IAAI,MAAM,WAAU,yBAC/B,cAAI,OACP;AAAA,OAEJ;AAAA,KAEJ;AAEJ;","names":[]}
@@ -27,3 +27,5 @@ export declare function SiteNav({ className, ariaLabel, items, }: {
27
27
  /** Overschrijft de items (bv. voor een footer-menu); standaard de beheerde hoofdnavigatie. */
28
28
  items?: NavItem[];
29
29
  }): import("react").JSX.Element | null;
30
+ /** Is dit menu-item de huidige pagina (of, voor een item met submenu, een van zijn kinderen)? */
31
+ export declare function isHuidig(href: string, pad: string | null): boolean;
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
- import { useEffect, useId, useRef, useState } from "react";
3
+ import { useEffect, useId, useRef, useState, useSyncExternalStore } from "react";
4
4
  import { useLinkComponent } from "@astryxdesign/core/Link";
5
5
  import { useMergedSiteConfig } from "../../settings/useSiteSettings.js";
6
6
  import { isExterneLink, navHref } from "../../schema/settings.js";
@@ -14,7 +14,26 @@ function SiteNav({
14
14
  if (lijst.length === 0) return null;
15
15
  return /* @__PURE__ */ jsx("nav", { className: className ?? "xicms-nav", "aria-label": ariaLabel, children: /* @__PURE__ */ jsx("ul", { className: "xicms-nav__list", children: lijst.map((item, i) => /* @__PURE__ */ jsx(NavEntry, { item }, `${item.href}-${i}`)) }) });
16
16
  }
17
+ function abonneerOpPad(cb) {
18
+ window.addEventListener("popstate", cb);
19
+ const nav = window.navigation;
20
+ nav?.addEventListener("navigatesuccess", cb);
21
+ return () => {
22
+ window.removeEventListener("popstate", cb);
23
+ nav?.removeEventListener("navigatesuccess", cb);
24
+ };
25
+ }
26
+ function useHuidigPad() {
27
+ return useSyncExternalStore(abonneerOpPad, () => window.location.pathname, () => null);
28
+ }
29
+ function isHuidig(href, pad) {
30
+ if (!pad || isExterneLink(href)) return false;
31
+ const schoon = (p) => p.length > 1 ? p.replace(/\/+$/, "") : p;
32
+ return schoon(href.split(/[?#]/)[0]) === schoon(pad);
33
+ }
17
34
  function NavEntry({ item }) {
35
+ const pad = useHuidigPad();
36
+ const toggleRef = useRef(null);
18
37
  const LinkC = useLinkComponent();
19
38
  const kinderen = item.children ?? [];
20
39
  const [open, setOpen] = useState(false);
@@ -26,7 +45,9 @@ function NavEntry({ item }) {
26
45
  if (!ref.current?.contains(e.target)) setOpen(false);
27
46
  };
28
47
  const onKey = (e) => {
29
- if (e.key === "Escape") setOpen(false);
48
+ if (e.key !== "Escape") return;
49
+ setOpen(false);
50
+ if (ref.current?.contains(document.activeElement)) toggleRef.current?.focus();
30
51
  };
31
52
  document.addEventListener("pointerdown", onDown);
32
53
  document.addEventListener("keydown", onKey);
@@ -42,14 +63,15 @@ function NavEntry({ item }) {
42
63
  rel: extern && item.target === "_blank" ? "noopener noreferrer" : void 0
43
64
  };
44
65
  if (kinderen.length === 0) {
45
- return /* @__PURE__ */ jsx("li", { className: "xicms-nav__item", children: /* @__PURE__ */ jsx(LinkC, { className: "xicms-nav__link", ...linkProps, children: item.label }) });
66
+ return /* @__PURE__ */ jsx("li", { className: "xicms-nav__item", children: /* @__PURE__ */ jsx(LinkC, { className: "xicms-nav__link", ...linkProps, "aria-current": isHuidig(item.href, pad) ? "page" : void 0, children: item.label }) });
46
67
  }
47
68
  return /* @__PURE__ */ jsxs("li", { ref, className: `xicms-nav__item xicms-nav__item--sub${open ? " is-open" : ""}`, children: [
48
69
  /* @__PURE__ */ jsxs("span", { className: "xicms-nav__pair", children: [
49
- /* @__PURE__ */ jsx(LinkC, { className: "xicms-nav__link", ...linkProps, children: item.label }),
70
+ /* @__PURE__ */ jsx(LinkC, { className: "xicms-nav__link", ...linkProps, "aria-current": isHuidig(item.href, pad) ? "page" : void 0, children: item.label }),
50
71
  /* @__PURE__ */ jsx(
51
72
  "button",
52
73
  {
74
+ ref: toggleRef,
53
75
  type: "button",
54
76
  className: "xicms-nav__toggle",
55
77
  "aria-expanded": open,
@@ -70,6 +92,7 @@ function NavEntry({ item }) {
70
92
  target: kind.target === "_blank" ? "_blank" : void 0,
71
93
  rel: kExtern && kind.target === "_blank" ? "noopener noreferrer" : void 0,
72
94
  onClick: () => setOpen(false),
95
+ "aria-current": isHuidig(kind.href, pad) ? "page" : void 0,
73
96
  children: kind.label
74
97
  }
75
98
  ) }, `${kind.href}-${j}`);
@@ -77,6 +100,7 @@ function NavEntry({ item }) {
77
100
  ] });
78
101
  }
79
102
  export {
80
- SiteNav
103
+ SiteNav,
104
+ isHuidig
81
105
  };
82
106
  //# sourceMappingURL=SiteNav.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/site/SiteNav.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useId, useRef, useState } from \"react\";\nimport { useLinkComponent } from \"@astryxdesign/core/Link\";\nimport { useMergedSiteConfig } from \"../../settings/useSiteSettings\";\nimport { isExterneLink, navHref, type NavItem } from \"../../schema/settings\";\n\n/**\n * De hoofdnavigatie zoals de klant hem in /beheer → Menu beheert (7.24).\n *\n * Tot 7.24 schreef het Menu-paneel netjes naar `settings.nav`, meldde \"De navigatie is\n * bijgewerkt\" — en las geen enkele header dat veld. De template en de klantsites renderden\n * `siteConfig.nav` rechtstreeks uit Git, dus wat de klant in het beheer deed kwam nooit op de\n * site. Deze component is de ontbrekende consument: hij leest de samengevoegde config\n * (Firestore wint, Git is de terugval) en is daarmee de énige plek die een menu hoort te tekenen.\n *\n * SSR-veilig: de settings zitten in de server-seed (`settingsData` op XiCMSProvider), dus het menu\n * staat al in de HTML en er is geen flits van het oude menu.\n *\n * Unstyled-by-default, net als `SiteFooter`: alle opmaak hangt aan `xicms-nav*`-klassen en de\n * thema-variabelen, zodat elke site hem kan herstijlen zonder de logica te forken. De klassen die\n * de template gebruikte (`.site-header nav a`) blijven werken doordat dit een gewone `<nav>` met\n * `<a>`'s blijft.\n *\n * Submenu's (één niveau): een item mét kinderen is zélf een link naar zijn overzichtspagina, met\n * ernaast een knop die het submenu openklapt (`aria-expanded`). Zo werkt het menu zonder\n * JavaScript (alle links staan in de HTML), met het toetsenbord (knop = Enter/Spatie, Escape\n * sluit) en op touch (geen hover nodig).\n */\nexport function SiteNav({\n className,\n ariaLabel = \"Hoofdnavigatie\",\n items,\n}: {\n className?: string;\n ariaLabel?: string;\n /** Overschrijft de items (bv. voor een footer-menu); standaard de beheerde hoofdnavigatie. */\n items?: NavItem[];\n}) {\n const cfg = useMergedSiteConfig();\n const lijst = items ?? cfg.nav ?? [];\n if (lijst.length === 0) return null;\n return (\n <nav className={className ?? \"xicms-nav\"} aria-label={ariaLabel}>\n <ul className=\"xicms-nav__list\">\n {lijst.map((item, i) => (\n <NavEntry key={`${item.href}-${i}`} item={item} />\n ))}\n </ul>\n </nav>\n );\n}\n\nfunction NavEntry({ item }: { item: NavItem }) {\n const LinkC = useLinkComponent();\n const kinderen = item.children ?? [];\n const [open, setOpen] = useState(false);\n const id = useId();\n const ref = useRef<HTMLLIElement>(null);\n\n // Buiten klikken of Escape sluit het submenu — anders blijft het hangen tot je een ander opent.\n useEffect(() => {\n if (!open) return;\n const onDown = (e: PointerEvent) => {\n if (!ref.current?.contains(e.target as Node)) setOpen(false);\n };\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setOpen(false);\n };\n document.addEventListener(\"pointerdown\", onDown);\n document.addEventListener(\"keydown\", onKey);\n return () => {\n document.removeEventListener(\"pointerdown\", onDown);\n document.removeEventListener(\"keydown\", onKey);\n };\n }, [open]);\n\n const extern = isExterneLink(item.href);\n const linkProps = {\n href: navHref(item),\n target: item.target === \"_blank\" ? \"_blank\" : undefined,\n rel: extern && item.target === \"_blank\" ? \"noopener noreferrer\" : undefined,\n };\n\n if (kinderen.length === 0) {\n return (\n <li className=\"xicms-nav__item\">\n <LinkC className=\"xicms-nav__link\" {...linkProps}>{item.label}</LinkC>\n </li>\n );\n }\n\n return (\n <li ref={ref} className={`xicms-nav__item xicms-nav__item--sub${open ? \" is-open\" : \"\"}`}>\n <span className=\"xicms-nav__pair\">\n <LinkC className=\"xicms-nav__link\" {...linkProps}>{item.label}</LinkC>\n <button\n type=\"button\"\n className=\"xicms-nav__toggle\"\n aria-expanded={open}\n aria-controls={id}\n aria-label={`Submenu van ${item.label} ${open ? \"sluiten\" : \"openen\"}`}\n onClick={() => setOpen((v) => !v)}\n >\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M6 9l6 6 6-6\" />\n </svg>\n </button>\n </span>\n <ul id={id} className=\"xicms-nav__sub\" hidden={!open}>\n {kinderen.map((kind, j) => {\n const kExtern = isExterneLink(kind.href);\n return (\n <li key={`${kind.href}-${j}`} className=\"xicms-nav__subitem\">\n <LinkC\n className=\"xicms-nav__sublink\"\n href={navHref(kind)}\n target={kind.target === \"_blank\" ? \"_blank\" : undefined}\n rel={kExtern && kind.target === \"_blank\" ? \"noopener noreferrer\" : undefined}\n onClick={() => setOpen(false)}\n >\n {kind.label}\n </LinkC>\n </li>\n );\n })}\n </ul>\n </li>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/components/site/SiteNav.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useId, useRef, useState, useSyncExternalStore } from \"react\";\nimport { useLinkComponent } from \"@astryxdesign/core/Link\";\nimport { useMergedSiteConfig } from \"../../settings/useSiteSettings\";\nimport { isExterneLink, navHref, type NavItem } from \"../../schema/settings\";\n\n/**\n * De hoofdnavigatie zoals de klant hem in /beheer → Menu beheert (7.24).\n *\n * Tot 7.24 schreef het Menu-paneel netjes naar `settings.nav`, meldde \"De navigatie is\n * bijgewerkt\" — en las geen enkele header dat veld. De template en de klantsites renderden\n * `siteConfig.nav` rechtstreeks uit Git, dus wat de klant in het beheer deed kwam nooit op de\n * site. Deze component is de ontbrekende consument: hij leest de samengevoegde config\n * (Firestore wint, Git is de terugval) en is daarmee de énige plek die een menu hoort te tekenen.\n *\n * SSR-veilig: de settings zitten in de server-seed (`settingsData` op XiCMSProvider), dus het menu\n * staat al in de HTML en er is geen flits van het oude menu.\n *\n * Unstyled-by-default, net als `SiteFooter`: alle opmaak hangt aan `xicms-nav*`-klassen en de\n * thema-variabelen, zodat elke site hem kan herstijlen zonder de logica te forken. De klassen die\n * de template gebruikte (`.site-header nav a`) blijven werken doordat dit een gewone `<nav>` met\n * `<a>`'s blijft.\n *\n * Submenu's (één niveau): een item mét kinderen is zélf een link naar zijn overzichtspagina, met\n * ernaast een knop die het submenu openklapt (`aria-expanded`). Zo werkt het menu zonder\n * JavaScript (alle links staan in de HTML), met het toetsenbord (knop = Enter/Spatie, Escape\n * sluit) en op touch (geen hover nodig).\n */\nexport function SiteNav({\n className,\n ariaLabel = \"Hoofdnavigatie\",\n items,\n}: {\n className?: string;\n ariaLabel?: string;\n /** Overschrijft de items (bv. voor een footer-menu); standaard de beheerde hoofdnavigatie. */\n items?: NavItem[];\n}) {\n const cfg = useMergedSiteConfig();\n const lijst = items ?? cfg.nav ?? [];\n if (lijst.length === 0) return null;\n return (\n <nav className={className ?? \"xicms-nav\"} aria-label={ariaLabel}>\n <ul className=\"xicms-nav__list\">\n {lijst.map((item, i) => (\n <NavEntry key={`${item.href}-${i}`} item={item} />\n ))}\n </ul>\n </nav>\n );\n}\n\n/**\n * Het huidige pad, hydratie-veilig (8.3): op de server en tijdens de hydratie `null`, daarna het\n * echte pad. Luistert naar Terug/Vooruit en — waar de browser hem heeft — de Navigation API, zodat\n * ook een client-side navigatie de markering verplaatst.\n */\nfunction abonneerOpPad(cb: () => void): () => void {\n window.addEventListener(\"popstate\", cb);\n const nav = (window as unknown as { navigation?: EventTarget }).navigation;\n nav?.addEventListener(\"navigatesuccess\", cb);\n return () => {\n window.removeEventListener(\"popstate\", cb);\n nav?.removeEventListener(\"navigatesuccess\", cb);\n };\n}\nfunction useHuidigPad(): string | null {\n return useSyncExternalStore(abonneerOpPad, () => window.location.pathname, () => null);\n}\n\n/** Is dit menu-item de huidige pagina (of, voor een item met submenu, een van zijn kinderen)? */\nexport function isHuidig(href: string, pad: string | null): boolean {\n if (!pad || isExterneLink(href)) return false;\n const schoon = (p: string) => (p.length > 1 ? p.replace(/\\/+$/, \"\") : p);\n return schoon(href.split(/[?#]/)[0]) === schoon(pad);\n}\n\nfunction NavEntry({ item }: { item: NavItem }) {\n const pad = useHuidigPad();\n const toggleRef = useRef<HTMLButtonElement>(null);\n const LinkC = useLinkComponent();\n const kinderen = item.children ?? [];\n const [open, setOpen] = useState(false);\n const id = useId();\n const ref = useRef<HTMLLIElement>(null);\n\n // Buiten klikken of Escape sluit het submenu — anders blijft het hangen tot je een ander opent.\n useEffect(() => {\n if (!open) return;\n const onDown = (e: PointerEvent) => {\n if (!ref.current?.contains(e.target as Node)) setOpen(false);\n };\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\") return;\n setOpen(false);\n // 8.3: focus terug naar de knop — anders stond de toetsenbordgebruiker nergens meer.\n if (ref.current?.contains(document.activeElement)) toggleRef.current?.focus();\n };\n document.addEventListener(\"pointerdown\", onDown);\n document.addEventListener(\"keydown\", onKey);\n return () => {\n document.removeEventListener(\"pointerdown\", onDown);\n document.removeEventListener(\"keydown\", onKey);\n };\n }, [open]);\n\n const extern = isExterneLink(item.href);\n const linkProps = {\n href: navHref(item),\n target: item.target === \"_blank\" ? \"_blank\" : undefined,\n rel: extern && item.target === \"_blank\" ? \"noopener noreferrer\" : undefined,\n };\n\n if (kinderen.length === 0) {\n return (\n <li className=\"xicms-nav__item\">\n <LinkC className=\"xicms-nav__link\" {...linkProps} aria-current={isHuidig(item.href, pad) ? \"page\" : undefined}>{item.label}</LinkC>\n </li>\n );\n }\n\n return (\n <li ref={ref} className={`xicms-nav__item xicms-nav__item--sub${open ? \" is-open\" : \"\"}`}>\n <span className=\"xicms-nav__pair\">\n <LinkC className=\"xicms-nav__link\" {...linkProps} aria-current={isHuidig(item.href, pad) ? \"page\" : undefined}>{item.label}</LinkC>\n <button\n ref={toggleRef}\n type=\"button\"\n className=\"xicms-nav__toggle\"\n aria-expanded={open}\n aria-controls={id}\n aria-label={`Submenu van ${item.label} ${open ? \"sluiten\" : \"openen\"}`}\n onClick={() => setOpen((v) => !v)}\n >\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M6 9l6 6 6-6\" />\n </svg>\n </button>\n </span>\n <ul id={id} className=\"xicms-nav__sub\" hidden={!open}>\n {kinderen.map((kind, j) => {\n const kExtern = isExterneLink(kind.href);\n return (\n <li key={`${kind.href}-${j}`} className=\"xicms-nav__subitem\">\n <LinkC\n className=\"xicms-nav__sublink\"\n href={navHref(kind)}\n target={kind.target === \"_blank\" ? \"_blank\" : undefined}\n rel={kExtern && kind.target === \"_blank\" ? \"noopener noreferrer\" : undefined}\n onClick={() => setOpen(false)}\n aria-current={isHuidig(kind.href, pad) ? \"page\" : undefined}\n >\n {kind.label}\n </LinkC>\n </li>\n );\n })}\n </ul>\n </li>\n );\n}\n"],"mappings":"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","names":[]}
@@ -28,8 +28,8 @@ function DemoStudio() {
28
28
  /* @__PURE__ */ jsxs("span", { className: "xicms-demostudio__msg", children: [
29
29
  "\u270F\uFE0F ",
30
30
  /* @__PURE__ */ jsx("strong", { children: "Demo-bewerkmodus." }),
31
- " Klik onderaan op ",
32
- /* @__PURE__ */ jsx("strong", { children: "\u201CPagina bewerken\u201D" }),
31
+ " Kies onderaan ",
32
+ /* @__PURE__ */ jsx("strong", { children: "\u201CBewerken\u201D" }),
33
33
  " om blokken aan te passen. Let op: ",
34
34
  /* @__PURE__ */ jsx("strong", { children: "wijzigingen worden niet opgeslagen" }),
35
35
  " \u2014 ze staan alleen lokaal in jouw browser."
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/demo/DemoStudio.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { useAuth } from \"../auth/AuthProvider\";\nimport { useSiteConfig } from \"../config\";\nimport { DEMO_EVENT, isDemoLoggedIn, resetDemo } from \"./demoStore\";\n\n/**\n * Bovenbalk voor de DEMO-bewerkmodus (`config.demoEditing`). Biedt een pseudo-login waarmee\n * bezoekers het beheer (teksten + blokken) kunnen uitproberen, en maakt heel duidelijk dat\n * wijzigingen NIET worden opgeslagen — ze blijven alleen lokaal in de browser en zijn met één\n * klik te resetten. De echte bewerkacties (\"Pagina bewerken\", \"Uitloggen\") staan in de EditBar.\n */\nexport function DemoStudio() {\n const { demo, demoSignIn } = useAuth();\n const { siteId } = useSiteConfig();\n const [loggedIn, setLoggedIn] = useState(false);\n\n useEffect(() => {\n if (!demo) return;\n const sync = () => setLoggedIn(isDemoLoggedIn());\n sync();\n window.addEventListener(DEMO_EVENT, sync);\n return () => window.removeEventListener(DEMO_EVENT, sync);\n }, [demo]);\n\n if (!demo) return null;\n\n return (\n <div className=\"xicms-demostudio\" role=\"region\" aria-label=\"Demo-bewerkmodus\">\n {!loggedIn ? (\n <>\n <span className=\"xicms-demostudio__msg\">\n <strong>Probeer het zelf:</strong> log in als demo-beheerder en bewerk teksten, foto&apos;s en\n blokken — <strong>niets wordt opgeslagen</strong>, je wijzigingen blijven alleen in jouw browser.\n </span>\n <button type=\"button\" className=\"xicms-btn\" onClick={demoSignIn}>\n Probeer het beheer (demo-login)\n </button>\n </>\n ) : (\n <>\n <span className=\"xicms-demostudio__msg\">\n ✏️ <strong>Demo-bewerkmodus.</strong> Klik onderaan op <strong>“Pagina bewerken”</strong> om\n blokken aan te passen. Let op: <strong>wijzigingen worden niet opgeslagen</strong> — ze staan\n alleen lokaal in jouw browser.\n </span>\n <button\n type=\"button\"\n className=\"xicms-btn xicms-btn--ghost\"\n onClick={() => {\n resetDemo(siteId);\n // Herlaad zodat de pagina terugvalt op de oorspronkelijke (seed-)inhoud.\n if (typeof window !== \"undefined\") window.location.reload();\n }}\n >\n Reset demo\n </button>\n </>\n )}\n </div>\n );\n}\n"],"mappings":";AA+BQ,mBAEI,KADF,YADF;AA7BR,SAAS,WAAW,gBAAgB;AACpC,SAAS,eAAe;AACxB,SAAS,qBAAqB;AAC9B,SAAS,YAAY,gBAAgB,iBAAiB;AAQ/C,SAAS,aAAa;AAC3B,QAAM,EAAE,MAAM,WAAW,IAAI,QAAQ;AACrC,QAAM,EAAE,OAAO,IAAI,cAAc;AACjC,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAE9C,YAAU,MAAM;AACd,QAAI,CAAC,KAAM;AACX,UAAM,OAAO,MAAM,YAAY,eAAe,CAAC;AAC/C,SAAK;AACL,WAAO,iBAAiB,YAAY,IAAI;AACxC,WAAO,MAAM,OAAO,oBAAoB,YAAY,IAAI;AAAA,EAC1D,GAAG,CAAC,IAAI,CAAC;AAET,MAAI,CAAC,KAAM,QAAO;AAElB,SACE,oBAAC,SAAI,WAAU,oBAAmB,MAAK,UAAS,cAAW,oBACxD,WAAC,WACA,iCACE;AAAA,yBAAC,UAAK,WAAU,yBACd;AAAA,0BAAC,YAAO,+BAAiB;AAAA,MAAS;AAAA,MACxB,oBAAC,YAAO,oCAAsB;AAAA,MAAS;AAAA,OACnD;AAAA,IACA,oBAAC,YAAO,MAAK,UAAS,WAAU,aAAY,SAAS,YAAY,6CAEjE;AAAA,KACF,IAEA,iCACE;AAAA,yBAAC,UAAK,WAAU,yBAAwB;AAAA;AAAA,MACnC,oBAAC,YAAO,+BAAiB;AAAA,MAAS;AAAA,MAAkB,oBAAC,YAAO,yCAAiB;AAAA,MAAS;AAAA,MAC1D,oBAAC,YAAO,gDAAkC;AAAA,MAAS;AAAA,OAEpF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS,MAAM;AACb,oBAAU,MAAM;AAEhB,cAAI,OAAO,WAAW,YAAa,QAAO,SAAS,OAAO;AAAA,QAC5D;AAAA,QACD;AAAA;AAAA,IAED;AAAA,KACF,GAEJ;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/demo/DemoStudio.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { useAuth } from \"../auth/AuthProvider\";\nimport { useSiteConfig } from \"../config\";\nimport { DEMO_EVENT, isDemoLoggedIn, resetDemo } from \"./demoStore\";\n\n/**\n * Bovenbalk voor de DEMO-bewerkmodus (`config.demoEditing`). Biedt een pseudo-login waarmee\n * bezoekers het beheer (teksten + blokken) kunnen uitproberen, en maakt heel duidelijk dat\n * wijzigingen NIET worden opgeslagen — ze blijven alleen lokaal in de browser en zijn met één\n * klik te resetten. De echte bewerkacties (\"Pagina bewerken\", \"Uitloggen\") staan in de EditBar.\n */\nexport function DemoStudio() {\n const { demo, demoSignIn } = useAuth();\n const { siteId } = useSiteConfig();\n const [loggedIn, setLoggedIn] = useState(false);\n\n useEffect(() => {\n if (!demo) return;\n const sync = () => setLoggedIn(isDemoLoggedIn());\n sync();\n window.addEventListener(DEMO_EVENT, sync);\n return () => window.removeEventListener(DEMO_EVENT, sync);\n }, [demo]);\n\n if (!demo) return null;\n\n return (\n <div className=\"xicms-demostudio\" role=\"region\" aria-label=\"Demo-bewerkmodus\">\n {!loggedIn ? (\n <>\n <span className=\"xicms-demostudio__msg\">\n <strong>Probeer het zelf:</strong> log in als demo-beheerder en bewerk teksten, foto&apos;s en\n blokken — <strong>niets wordt opgeslagen</strong>, je wijzigingen blijven alleen in jouw browser.\n </span>\n <button type=\"button\" className=\"xicms-btn\" onClick={demoSignIn}>\n Probeer het beheer (demo-login)\n </button>\n </>\n ) : (\n <>\n <span className=\"xicms-demostudio__msg\">\n ✏️ <strong>Demo-bewerkmodus.</strong> Kies onderaan <strong>“Bewerken”</strong> om\n blokken aan te passen. Let op: <strong>wijzigingen worden niet opgeslagen</strong> — ze staan\n alleen lokaal in jouw browser.\n </span>\n <button\n type=\"button\"\n className=\"xicms-btn xicms-btn--ghost\"\n onClick={() => {\n resetDemo(siteId);\n // Herlaad zodat de pagina terugvalt op de oorspronkelijke (seed-)inhoud.\n if (typeof window !== \"undefined\") window.location.reload();\n }}\n >\n Reset demo\n </button>\n </>\n )}\n </div>\n );\n}\n"],"mappings":";AA+BQ,mBAEI,KADF,YADF;AA7BR,SAAS,WAAW,gBAAgB;AACpC,SAAS,eAAe;AACxB,SAAS,qBAAqB;AAC9B,SAAS,YAAY,gBAAgB,iBAAiB;AAQ/C,SAAS,aAAa;AAC3B,QAAM,EAAE,MAAM,WAAW,IAAI,QAAQ;AACrC,QAAM,EAAE,OAAO,IAAI,cAAc;AACjC,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAE9C,YAAU,MAAM;AACd,QAAI,CAAC,KAAM;AACX,UAAM,OAAO,MAAM,YAAY,eAAe,CAAC;AAC/C,SAAK;AACL,WAAO,iBAAiB,YAAY,IAAI;AACxC,WAAO,MAAM,OAAO,oBAAoB,YAAY,IAAI;AAAA,EAC1D,GAAG,CAAC,IAAI,CAAC;AAET,MAAI,CAAC,KAAM,QAAO;AAElB,SACE,oBAAC,SAAI,WAAU,oBAAmB,MAAK,UAAS,cAAW,oBACxD,WAAC,WACA,iCACE;AAAA,yBAAC,UAAK,WAAU,yBACd;AAAA,0BAAC,YAAO,+BAAiB;AAAA,MAAS;AAAA,MACxB,oBAAC,YAAO,oCAAsB;AAAA,MAAS;AAAA,OACnD;AAAA,IACA,oBAAC,YAAO,MAAK,UAAS,WAAU,aAAY,SAAS,YAAY,6CAEjE;AAAA,KACF,IAEA,iCACE;AAAA,yBAAC,UAAK,WAAU,yBAAwB;AAAA;AAAA,MACnC,oBAAC,YAAO,+BAAiB;AAAA,MAAS;AAAA,MAAe,oBAAC,YAAO,kCAAU;AAAA,MAAS;AAAA,MAChD,oBAAC,YAAO,gDAAkC;AAAA,MAAS;AAAA,OAEpF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS,MAAM;AACb,oBAAU,MAAM;AAEhB,cAAI,OAAO,WAAW,YAAa,QAAO,SAAS,OAAO;AAAA,QAC5D;AAAA,QACD;AAAA;AAAA,IAED;AAAA,KACF,GAEJ;AAEJ;","names":[]}
@@ -33,10 +33,23 @@ export declare function addDemoMedia(siteId: string, item: {
33
33
  url: string;
34
34
  name: string;
35
35
  }): MediaItem;
36
+ /**
37
+ * Verwijderen in demo-modus (8.5): lokale uploads echt weg; een geseed item wordt alleen voor
38
+ * deze sessie verborgen (de seed komt bij herladen terug, zoals de rest van de demo).
39
+ */
40
+ export declare function removeDemoMedia(siteId: string, id: string): void;
36
41
  /** Inclusief geheugen-only items (opslag-vol-vangnet) — gebruikt door de kiezer. */
37
42
  export declare function listDemoMediaAll(siteId: string): MediaItem[];
38
43
  export declare function loadDemoDraft(siteId: string, id: string): Partial<Page> | null;
39
44
  export declare function saveDemoDraft(siteId: string, id: string, patch: Partial<Page>): void;
45
+ /**
46
+ * Alle pagina's die de demo kent (8.6): geseede pagina's plus lokaal aangemaakte/bewerkte, met de
47
+ * lokale bewerking eroverheen. Voor het paginaoverzicht in het beheer — dat wachtte eerst op een
48
+ * rechtenfout van de echte database en toonde dan niets.
49
+ */
50
+ export declare function listDemoPages(siteId: string): Array<Page & {
51
+ id: string;
52
+ }>;
40
53
  /** Verwijdert alle lokale demo-bewerkingen + login voor deze site (de "Reset"-knop). */
41
54
  export declare function resetDemo(siteId: string): void;
42
55
  /**
@@ -98,6 +98,18 @@ function addDemoMedia(siteId, item) {
98
98
  emit();
99
99
  return media;
100
100
  }
101
+ function removeDemoMedia(siteId, id) {
102
+ const lokaal = loadLocalDemoMedia(siteId);
103
+ if (lokaal.some((m) => m.id === id)) {
104
+ try {
105
+ window.localStorage.setItem(mediaKey(siteId), JSON.stringify(lokaal.filter((m) => m.id !== id)));
106
+ } catch {
107
+ }
108
+ }
109
+ memoryOnlyMedia.set(siteId, (memoryOnlyMedia.get(siteId) ?? []).filter((m) => m.id !== id));
110
+ mediaSeeds.set(siteId, (mediaSeeds.get(siteId) ?? []).filter((m) => m.id !== id));
111
+ emit();
112
+ }
101
113
  function listDemoMediaAll(siteId) {
102
114
  return [...memoryOnlyMedia.get(siteId) ?? [], ...listDemoMedia(siteId)];
103
115
  }
@@ -122,6 +134,28 @@ function saveDemoDraft(siteId, id, patch) {
122
134
  }
123
135
  emit();
124
136
  }
137
+ function listDemoPages(siteId) {
138
+ const paden = /* @__PURE__ */ new Set();
139
+ for (const k of seeds.keys()) if (k.startsWith(`${siteId}::`)) paden.add(k.slice(siteId.length + 2));
140
+ if (typeof window !== "undefined") {
141
+ try {
142
+ const prefix = `${DRAFT_PREFIX}:${siteId}:`;
143
+ for (let i = 0; i < window.localStorage.length; i++) {
144
+ const k = window.localStorage.key(i);
145
+ const pad = k?.startsWith(prefix) ? demoPathForId(k.slice(prefix.length)) : null;
146
+ if (pad) paden.add(pad);
147
+ }
148
+ } catch {
149
+ }
150
+ }
151
+ const lijst = [];
152
+ for (const pad of paden) {
153
+ const id = demoIdForPath(pad);
154
+ const page = resolveDemoPage(siteId, pad) ?? loadDemoDraft(siteId, id);
155
+ if (page) lijst.push({ ...page, path: page.path ?? pad, id });
156
+ }
157
+ return lijst.sort((a, b) => a.path === "/" ? -1 : b.path === "/" ? 1 : (a.order ?? 0) - (b.order ?? 0));
158
+ }
125
159
  function resetDemo(siteId) {
126
160
  if (typeof window === "undefined") return;
127
161
  try {
@@ -156,11 +190,13 @@ export {
156
190
  isDemoLoggedIn,
157
191
  listDemoMedia,
158
192
  listDemoMediaAll,
193
+ listDemoPages,
159
194
  loadDemoDraft,
160
195
  registerDemoForm,
161
196
  registerDemoMedia,
162
197
  registerDemoNews,
163
198
  registerSeed,
199
+ removeDemoMedia,
164
200
  resetDemo,
165
201
  resolveDemoPage,
166
202
  saveDemoDraft,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/demo/demoStore.ts"],"sourcesContent":["\"use client\";\n\nimport type { Page } from \"../schema/pages\";\nimport type { MediaItem, NewsArticle } from \"../content/types\";\nimport type { FormDefinition } from \"../schema/forms\";\n\n/**\n * Lokale opslag voor de DEMO-bewerkmodus (`config.demoEditing`). Alle \"bewerkingen\" van een\n * bezoeker (teksten, blokken, publiceren) blijven UITSLUITEND in de browser van die bezoeker\n * (localStorage) — er gaat niets naar Firebase. Zo kunnen eindgebruikers het beheer veilig\n * uitproberen zonder dat er echt iets verandert. Een \"Reset\" wist alles weer.\n *\n * Bewust GEEN onderdeel van de echte (Firebase-)opslag: pagesClient en AuthProvider takken hier\n * alleen naartoe als de demo-modus actief is, en die staat alleen aan op een demo-site.\n */\n\nconst DRAFT_PREFIX = \"xicms-demo-draft\";\nconst MEDIA_PREFIX = \"xicms-demo-media\";\nconst SESSION_KEY = \"xicms-demo-session\";\nexport const DEMO_EVENT = \"xicms:demo\";\n\nlet active = false;\nconst seeds = new Map<string, Page>();\nconst newsSeeds = new Map<string, NewsArticle[]>();\nconst formSeeds = new Map<string, FormDefinition>();\nconst mediaSeeds = new Map<string, MediaItem[]>();\n\n/** Zet de demo-bewerkmodus aan/uit (door de provider, op basis van config.demoEditing). */\nexport function setDemoActive(on: boolean) {\n active = on;\n}\nexport function isDemoActive(): boolean {\n return active;\n}\n\n/** Stabiel, deterministisch draft-id per pad, zodat pagina + editor naar dezelfde opslag wijzen. */\nexport function demoIdForPath(path: string): string {\n return `demo:${path || \"/\"}`;\n}\n\n/** De omkering: uit een demo-draft-id het pad terug. `null` voor een niet-demo-id. */\nexport function demoPathForId(id: string): string | null {\n return id.startsWith(\"demo:\") ? id.slice(\"demo:\".length) : null;\n}\n\nfunction emit() {\n if (typeof window !== \"undefined\") window.dispatchEvent(new Event(DEMO_EVENT));\n}\n\n// ── Pseudo-login (sessie) ──────────────────────────────────────────────────\n// In sessionStorage: verdwijnt als het tabblad sluit — benadrukt het tijdelijke karakter.\nexport function isDemoLoggedIn(): boolean {\n if (typeof window === \"undefined\") return false;\n try {\n return window.sessionStorage.getItem(SESSION_KEY) === \"1\";\n } catch {\n return false;\n }\n}\nexport function setDemoLoggedIn(on: boolean) {\n if (typeof window === \"undefined\") return;\n try {\n if (on) window.sessionStorage.setItem(SESSION_KEY, \"1\");\n else window.sessionStorage.removeItem(SESSION_KEY);\n } catch {\n /* opslag geweigerd — login geldt dan alleen voor deze render */\n }\n emit();\n}\n\n// ── Seed-pagina's (de oorspronkelijke inhoud waar een bezoeker op verder bewerkt) ──\n/**\n * De EERSTE registratie wint. Een seed is per definitie het origineel, en het origineel verandert\n * niet tijdens een sessie. Zonder deze regel vervuilde de seed zichzelf: een demo-route registreert\n * bij module-load de zuivere pagina, maar `PublishedPage` registreert in een effect de pagina die\n * hij TOONT — en dat is in de demo seed+draft. De bewerkte tekst werd zo het \"origineel\", waarmee\n * de wijzigingen-teller schoon leek en \"blok verwerpen\" terugzette naar precies de tekst die je\n * wilde verwerpen. (De seeds leven in het geheugen van één pageload, dus \"eerste\" is per bezoek.)\n */\nexport function registerSeed(siteId: string, path: string, page: Page) {\n const key = `${siteId}::${path}`;\n if (!seeds.has(key)) seeds.set(key, page);\n}\nexport function getSeed(siteId: string, path: string): Page | null {\n return seeds.get(`${siteId}::${path}`) ?? null;\n}\n\n// ── Demo-nieuws (zodat nieuws-blokken/widgets ook in de demo gevuld zijn, zonder Firebase) ──\nexport function registerDemoNews(siteId: string, articles: NewsArticle[]) {\n newsSeeds.set(siteId, articles);\n}\nexport function getDemoNews(siteId: string): NewsArticle[] {\n return newsSeeds.get(siteId) ?? [];\n}\n\n// ── Demo-formulieren (zodat het form-blok werkt zonder Firebase; inzenden doet lokaal niets) ──\nexport function registerDemoForm(siteId: string, formId: string, def: FormDefinition) {\n formSeeds.set(`${siteId}::${formId}`, def);\n}\nexport function getDemoForm(siteId: string, formId: string): FormDefinition | null {\n return formSeeds.get(`${siteId}::${formId}`) ?? null;\n}\n\n// ── Demo-media (bibliotheek + upload zonder Firebase) ─────────────────────\n// Geseede items (bv. de foto's van de demo-site zelf) + lokale \"uploads\" als data-URL in\n// localStorage. Zo werken kiezen, uploaden en vervangen in de demo écht — alles blijft lokaal.\n\n/** Seed de mediabibliotheek van de demo (curated set; alt = zoektekst in de kiezer). */\nexport function registerDemoMedia(siteId: string, items: Array<Pick<MediaItem, \"url\" | \"name\" | \"alt\">>) {\n mediaSeeds.set(\n siteId,\n items.map((m, i) => ({ id: `demo-seed-${i}`, url: m.url, path: \"demo\", name: m.name, alt: m.alt ?? \"\" })),\n );\n}\n\nfunction mediaKey(siteId: string) {\n return `${MEDIA_PREFIX}:${siteId}`;\n}\n\nfunction loadLocalDemoMedia(siteId: string): MediaItem[] {\n if (typeof window === \"undefined\") return [];\n try {\n const raw = window.localStorage.getItem(mediaKey(siteId));\n return raw ? (JSON.parse(raw) as MediaItem[]) : [];\n } catch {\n return [];\n }\n}\n\n/** Bibliotheek in demo-modus: lokale uploads (nieuwste eerst) + de geseede set. */\nexport function listDemoMedia(siteId: string): MediaItem[] {\n return [...loadLocalDemoMedia(siteId), ...(mediaSeeds.get(siteId) ?? [])];\n}\n\n/**\n * \"Upload\" in demo-modus: bewaar de (gecomprimeerde) afbeelding als data-URL in localStorage.\n * localStorage is beperkt (~5 MB) — we houden maximaal 10 lokale uploads aan en laten bij een\n * volle opslag het item alleen voor deze sessie in het geheugen bestaan (zelfde vangnet als drafts).\n */\nconst memoryOnlyMedia = new Map<string, MediaItem[]>();\nexport function addDemoMedia(siteId: string, item: { url: string; name: string }): MediaItem {\n const media: MediaItem = {\n id: `demo-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n url: item.url,\n path: \"demo\",\n name: item.name,\n alt: \"\",\n };\n const next = [media, ...loadLocalDemoMedia(siteId)].slice(0, 10);\n try {\n window.localStorage.setItem(mediaKey(siteId), JSON.stringify(next));\n } catch {\n memoryOnlyMedia.set(siteId, [media, ...(memoryOnlyMedia.get(siteId) ?? [])]);\n }\n emit();\n return media;\n}\n\n/** Inclusief geheugen-only items (opslag-vol-vangnet) — gebruikt door de kiezer. */\nexport function listDemoMediaAll(siteId: string): MediaItem[] {\n return [...(memoryOnlyMedia.get(siteId) ?? []), ...listDemoMedia(siteId)];\n}\n\n// ── Lokale drafts (de bewerkingen) ─────────────────────────────────────────\nfunction draftKey(siteId: string, id: string) {\n return `${DRAFT_PREFIX}:${siteId}:${id}`;\n}\n\nexport function loadDemoDraft(siteId: string, id: string): Partial<Page> | null {\n if (typeof window === \"undefined\") return null;\n try {\n const raw = window.localStorage.getItem(draftKey(siteId, id));\n return raw ? (JSON.parse(raw) as Partial<Page>) : null;\n } catch {\n return null;\n }\n}\n\nexport function saveDemoDraft(siteId: string, id: string, patch: Partial<Page>) {\n if (typeof window === \"undefined\") return;\n try {\n const current = loadDemoDraft(siteId, id) ?? {};\n window.localStorage.setItem(draftKey(siteId, id), JSON.stringify({ ...current, ...patch }));\n } catch {\n /* opslag vol/geweigerd — bewerking geldt dan alleen voor deze sessie in het geheugen */\n }\n emit();\n}\n\n/** Verwijdert alle lokale demo-bewerkingen + login voor deze site (de \"Reset\"-knop). */\nexport function resetDemo(siteId: string) {\n if (typeof window === \"undefined\") return;\n try {\n const toRemove: string[] = [];\n for (let i = 0; i < window.localStorage.length; i++) {\n const k = window.localStorage.key(i);\n if (k && k.startsWith(`${DRAFT_PREFIX}:${siteId}:`)) toRemove.push(k);\n }\n toRemove.forEach((k) => window.localStorage.removeItem(k));\n window.localStorage.removeItem(mediaKey(siteId));\n memoryOnlyMedia.delete(siteId);\n window.sessionStorage.removeItem(SESSION_KEY);\n } catch {\n /* negeren */\n }\n emit();\n}\n\n/**\n * De effectieve demo-pagina = seed met lokale bewerkingen eroverheen. Gebruikt door de demo-pagina\n * om de wijzigingen van de bezoeker direct te tonen (ook na sluiten van de editor).\n */\nexport function resolveDemoPage(siteId: string, path: string): Page | null {\n const seed = getSeed(siteId, path);\n if (!seed) return null;\n const draft = loadDemoDraft(siteId, demoIdForPath(path));\n return draft ? ({ ...seed, ...draft } as Page) : seed;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/demo/demoStore.ts"],"sourcesContent":["\"use client\";\n\nimport type { Page } from \"../schema/pages\";\nimport type { MediaItem, NewsArticle } from \"../content/types\";\nimport type { FormDefinition } from \"../schema/forms\";\n\n/**\n * Lokale opslag voor de DEMO-bewerkmodus (`config.demoEditing`). Alle \"bewerkingen\" van een\n * bezoeker (teksten, blokken, publiceren) blijven UITSLUITEND in de browser van die bezoeker\n * (localStorage) — er gaat niets naar Firebase. Zo kunnen eindgebruikers het beheer veilig\n * uitproberen zonder dat er echt iets verandert. Een \"Reset\" wist alles weer.\n *\n * Bewust GEEN onderdeel van de echte (Firebase-)opslag: pagesClient en AuthProvider takken hier\n * alleen naartoe als de demo-modus actief is, en die staat alleen aan op een demo-site.\n */\n\nconst DRAFT_PREFIX = \"xicms-demo-draft\";\nconst MEDIA_PREFIX = \"xicms-demo-media\";\nconst SESSION_KEY = \"xicms-demo-session\";\nexport const DEMO_EVENT = \"xicms:demo\";\n\nlet active = false;\nconst seeds = new Map<string, Page>();\nconst newsSeeds = new Map<string, NewsArticle[]>();\nconst formSeeds = new Map<string, FormDefinition>();\nconst mediaSeeds = new Map<string, MediaItem[]>();\n\n/** Zet de demo-bewerkmodus aan/uit (door de provider, op basis van config.demoEditing). */\nexport function setDemoActive(on: boolean) {\n active = on;\n}\nexport function isDemoActive(): boolean {\n return active;\n}\n\n/** Stabiel, deterministisch draft-id per pad, zodat pagina + editor naar dezelfde opslag wijzen. */\nexport function demoIdForPath(path: string): string {\n return `demo:${path || \"/\"}`;\n}\n\n/** De omkering: uit een demo-draft-id het pad terug. `null` voor een niet-demo-id. */\nexport function demoPathForId(id: string): string | null {\n return id.startsWith(\"demo:\") ? id.slice(\"demo:\".length) : null;\n}\n\nfunction emit() {\n if (typeof window !== \"undefined\") window.dispatchEvent(new Event(DEMO_EVENT));\n}\n\n// ── Pseudo-login (sessie) ──────────────────────────────────────────────────\n// In sessionStorage: verdwijnt als het tabblad sluit — benadrukt het tijdelijke karakter.\nexport function isDemoLoggedIn(): boolean {\n if (typeof window === \"undefined\") return false;\n try {\n return window.sessionStorage.getItem(SESSION_KEY) === \"1\";\n } catch {\n return false;\n }\n}\nexport function setDemoLoggedIn(on: boolean) {\n if (typeof window === \"undefined\") return;\n try {\n if (on) window.sessionStorage.setItem(SESSION_KEY, \"1\");\n else window.sessionStorage.removeItem(SESSION_KEY);\n } catch {\n /* opslag geweigerd — login geldt dan alleen voor deze render */\n }\n emit();\n}\n\n// ── Seed-pagina's (de oorspronkelijke inhoud waar een bezoeker op verder bewerkt) ──\n/**\n * De EERSTE registratie wint. Een seed is per definitie het origineel, en het origineel verandert\n * niet tijdens een sessie. Zonder deze regel vervuilde de seed zichzelf: een demo-route registreert\n * bij module-load de zuivere pagina, maar `PublishedPage` registreert in een effect de pagina die\n * hij TOONT — en dat is in de demo seed+draft. De bewerkte tekst werd zo het \"origineel\", waarmee\n * de wijzigingen-teller schoon leek en \"blok verwerpen\" terugzette naar precies de tekst die je\n * wilde verwerpen. (De seeds leven in het geheugen van één pageload, dus \"eerste\" is per bezoek.)\n */\nexport function registerSeed(siteId: string, path: string, page: Page) {\n const key = `${siteId}::${path}`;\n if (!seeds.has(key)) seeds.set(key, page);\n}\nexport function getSeed(siteId: string, path: string): Page | null {\n return seeds.get(`${siteId}::${path}`) ?? null;\n}\n\n// ── Demo-nieuws (zodat nieuws-blokken/widgets ook in de demo gevuld zijn, zonder Firebase) ──\nexport function registerDemoNews(siteId: string, articles: NewsArticle[]) {\n newsSeeds.set(siteId, articles);\n}\nexport function getDemoNews(siteId: string): NewsArticle[] {\n return newsSeeds.get(siteId) ?? [];\n}\n\n// ── Demo-formulieren (zodat het form-blok werkt zonder Firebase; inzenden doet lokaal niets) ──\nexport function registerDemoForm(siteId: string, formId: string, def: FormDefinition) {\n formSeeds.set(`${siteId}::${formId}`, def);\n}\nexport function getDemoForm(siteId: string, formId: string): FormDefinition | null {\n return formSeeds.get(`${siteId}::${formId}`) ?? null;\n}\n\n// ── Demo-media (bibliotheek + upload zonder Firebase) ─────────────────────\n// Geseede items (bv. de foto's van de demo-site zelf) + lokale \"uploads\" als data-URL in\n// localStorage. Zo werken kiezen, uploaden en vervangen in de demo écht — alles blijft lokaal.\n\n/** Seed de mediabibliotheek van de demo (curated set; alt = zoektekst in de kiezer). */\nexport function registerDemoMedia(siteId: string, items: Array<Pick<MediaItem, \"url\" | \"name\" | \"alt\">>) {\n mediaSeeds.set(\n siteId,\n items.map((m, i) => ({ id: `demo-seed-${i}`, url: m.url, path: \"demo\", name: m.name, alt: m.alt ?? \"\" })),\n );\n}\n\nfunction mediaKey(siteId: string) {\n return `${MEDIA_PREFIX}:${siteId}`;\n}\n\nfunction loadLocalDemoMedia(siteId: string): MediaItem[] {\n if (typeof window === \"undefined\") return [];\n try {\n const raw = window.localStorage.getItem(mediaKey(siteId));\n return raw ? (JSON.parse(raw) as MediaItem[]) : [];\n } catch {\n return [];\n }\n}\n\n/** Bibliotheek in demo-modus: lokale uploads (nieuwste eerst) + de geseede set. */\nexport function listDemoMedia(siteId: string): MediaItem[] {\n return [...loadLocalDemoMedia(siteId), ...(mediaSeeds.get(siteId) ?? [])];\n}\n\n/**\n * \"Upload\" in demo-modus: bewaar de (gecomprimeerde) afbeelding als data-URL in localStorage.\n * localStorage is beperkt (~5 MB) — we houden maximaal 10 lokale uploads aan en laten bij een\n * volle opslag het item alleen voor deze sessie in het geheugen bestaan (zelfde vangnet als drafts).\n */\nconst memoryOnlyMedia = new Map<string, MediaItem[]>();\nexport function addDemoMedia(siteId: string, item: { url: string; name: string }): MediaItem {\n const media: MediaItem = {\n id: `demo-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n url: item.url,\n path: \"demo\",\n name: item.name,\n alt: \"\",\n };\n const next = [media, ...loadLocalDemoMedia(siteId)].slice(0, 10);\n try {\n window.localStorage.setItem(mediaKey(siteId), JSON.stringify(next));\n } catch {\n memoryOnlyMedia.set(siteId, [media, ...(memoryOnlyMedia.get(siteId) ?? [])]);\n }\n emit();\n return media;\n}\n\n/**\n * Verwijderen in demo-modus (8.5): lokale uploads echt weg; een geseed item wordt alleen voor\n * deze sessie verborgen (de seed komt bij herladen terug, zoals de rest van de demo).\n */\nexport function removeDemoMedia(siteId: string, id: string) {\n const lokaal = loadLocalDemoMedia(siteId);\n if (lokaal.some((m) => m.id === id)) {\n try {\n window.localStorage.setItem(mediaKey(siteId), JSON.stringify(lokaal.filter((m) => m.id !== id)));\n } catch {\n /* opslag niet beschikbaar */\n }\n }\n memoryOnlyMedia.set(siteId, (memoryOnlyMedia.get(siteId) ?? []).filter((m) => m.id !== id));\n mediaSeeds.set(siteId, (mediaSeeds.get(siteId) ?? []).filter((m) => m.id !== id));\n emit();\n}\n\n/** Inclusief geheugen-only items (opslag-vol-vangnet) — gebruikt door de kiezer. */\nexport function listDemoMediaAll(siteId: string): MediaItem[] {\n return [...(memoryOnlyMedia.get(siteId) ?? []), ...listDemoMedia(siteId)];\n}\n\n// ── Lokale drafts (de bewerkingen) ─────────────────────────────────────────\nfunction draftKey(siteId: string, id: string) {\n return `${DRAFT_PREFIX}:${siteId}:${id}`;\n}\n\nexport function loadDemoDraft(siteId: string, id: string): Partial<Page> | null {\n if (typeof window === \"undefined\") return null;\n try {\n const raw = window.localStorage.getItem(draftKey(siteId, id));\n return raw ? (JSON.parse(raw) as Partial<Page>) : null;\n } catch {\n return null;\n }\n}\n\nexport function saveDemoDraft(siteId: string, id: string, patch: Partial<Page>) {\n if (typeof window === \"undefined\") return;\n try {\n const current = loadDemoDraft(siteId, id) ?? {};\n window.localStorage.setItem(draftKey(siteId, id), JSON.stringify({ ...current, ...patch }));\n } catch {\n /* opslag vol/geweigerd — bewerking geldt dan alleen voor deze sessie in het geheugen */\n }\n emit();\n}\n\n/**\n * Alle pagina's die de demo kent (8.6): geseede pagina's plus lokaal aangemaakte/bewerkte, met de\n * lokale bewerking eroverheen. Voor het paginaoverzicht in het beheer — dat wachtte eerst op een\n * rechtenfout van de echte database en toonde dan niets.\n */\nexport function listDemoPages(siteId: string): Array<Page & { id: string }> {\n const paden = new Set<string>();\n for (const k of seeds.keys()) if (k.startsWith(`${siteId}::`)) paden.add(k.slice(siteId.length + 2));\n if (typeof window !== \"undefined\") {\n try {\n const prefix = `${DRAFT_PREFIX}:${siteId}:`;\n for (let i = 0; i < window.localStorage.length; i++) {\n const k = window.localStorage.key(i);\n const pad = k?.startsWith(prefix) ? demoPathForId(k.slice(prefix.length)) : null;\n if (pad) paden.add(pad);\n }\n } catch {\n /* opslag geweigerd */\n }\n }\n const lijst: Array<Page & { id: string }> = [];\n for (const pad of paden) {\n const id = demoIdForPath(pad);\n const page = (resolveDemoPage(siteId, pad) ?? loadDemoDraft(siteId, id)) as Page | null;\n if (page) lijst.push({ ...page, path: page.path ?? pad, id });\n }\n return lijst.sort((a, b) => (a.path === \"/\" ? -1 : b.path === \"/\" ? 1 : (a.order ?? 0) - (b.order ?? 0)));\n}\n\n/** Verwijdert alle lokale demo-bewerkingen + login voor deze site (de \"Reset\"-knop). */\nexport function resetDemo(siteId: string) {\n if (typeof window === \"undefined\") return;\n try {\n const toRemove: string[] = [];\n for (let i = 0; i < window.localStorage.length; i++) {\n const k = window.localStorage.key(i);\n if (k && k.startsWith(`${DRAFT_PREFIX}:${siteId}:`)) toRemove.push(k);\n }\n toRemove.forEach((k) => window.localStorage.removeItem(k));\n window.localStorage.removeItem(mediaKey(siteId));\n memoryOnlyMedia.delete(siteId);\n window.sessionStorage.removeItem(SESSION_KEY);\n } catch {\n /* negeren */\n }\n emit();\n}\n\n/**\n * De effectieve demo-pagina = seed met lokale bewerkingen eroverheen. Gebruikt door de demo-pagina\n * om de wijzigingen van de bezoeker direct te tonen (ook na sluiten van de editor).\n */\nexport function resolveDemoPage(siteId: string, path: string): Page | null {\n const seed = getSeed(siteId, path);\n if (!seed) return null;\n const draft = loadDemoDraft(siteId, demoIdForPath(path));\n return draft ? ({ ...seed, ...draft } as Page) : seed;\n}\n"],"mappings":"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","names":[]}