@xiwebdesign/xicms-core 7.30.0 → 8.15.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 (463) hide show
  1. package/dist/XiCMSProvider.js +22 -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 -56
  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 +247 -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 +144 -0
  133. package/dist/admin/settings/BedrijfInstellingen.js.map +1 -0
  134. package/dist/admin/settings/MailSettings.js +2 -2
  135. package/dist/admin/settings/MailSettings.js.map +1 -1
  136. package/dist/admin/settings/MailTemplates.js +5 -4
  137. package/dist/admin/settings/MailTemplates.js.map +1 -1
  138. package/dist/admin/settings/SettingsPanel.js +120 -78
  139. package/dist/admin/settings/SettingsPanel.js.map +1 -1
  140. package/dist/admin/settings/SnapshotsCard.js +4 -4
  141. package/dist/admin/settings/SnapshotsCard.js.map +1 -1
  142. package/dist/admin/settings/VorigeTerugzetten.d.ts +15 -0
  143. package/dist/admin/settings/VorigeTerugzetten.js +89 -0
  144. package/dist/admin/settings/VorigeTerugzetten.js.map +1 -0
  145. package/dist/admin/shop/CategoriesTab.js +6 -4
  146. package/dist/admin/shop/CategoriesTab.js.map +1 -1
  147. package/dist/admin/shop/DiscountsTab.js +4 -2
  148. package/dist/admin/shop/DiscountsTab.js.map +1 -1
  149. package/dist/admin/shop/OrdersTab.js +57 -19
  150. package/dist/admin/shop/OrdersTab.js.map +1 -1
  151. package/dist/admin/shop/ProductPaneel.js +2 -1
  152. package/dist/admin/shop/ProductPaneel.js.map +1 -1
  153. package/dist/admin/shop/ProductsTab.js +40 -19
  154. package/dist/admin/shop/ProductsTab.js.map +1 -1
  155. package/dist/admin/shop/ShopPanel.js +13 -1
  156. package/dist/admin/shop/ShopPanel.js.map +1 -1
  157. package/dist/admin/shop/ShopSettingsTab.js +27 -1
  158. package/dist/admin/shop/ShopSettingsTab.js.map +1 -1
  159. package/dist/admin/shop/productClient.js +7 -3
  160. package/dist/admin/shop/productClient.js.map +1 -1
  161. package/dist/admin/stats/NietGevonden.d.ts +10 -0
  162. package/dist/admin/stats/NietGevonden.js +78 -0
  163. package/dist/admin/stats/NietGevonden.js.map +1 -0
  164. package/dist/admin/stats/StatsPanel.js +6 -1
  165. package/dist/admin/stats/StatsPanel.js.map +1 -1
  166. package/dist/admin/stats/lib.d.ts +2 -0
  167. package/dist/admin/stats/lib.js.map +1 -1
  168. package/dist/admin/ui/ConfirmDialog.js +10 -1
  169. package/dist/admin/ui/ConfirmDialog.js.map +1 -1
  170. package/dist/admin/ui/Icon.d.ts +34 -0
  171. package/dist/admin/ui/Icon.js +44 -0
  172. package/dist/admin/ui/Icon.js.map +1 -0
  173. package/dist/admin/ui/ImageField.d.ts +15 -0
  174. package/dist/admin/ui/ImageField.js +67 -0
  175. package/dist/admin/ui/ImageField.js.map +1 -0
  176. package/dist/admin/ui/KleurVeld.d.ts +25 -0
  177. package/dist/admin/ui/KleurVeld.js +76 -0
  178. package/dist/admin/ui/KleurVeld.js.map +1 -0
  179. package/dist/admin/ui/LaadStaat.d.ts +21 -0
  180. package/dist/admin/ui/LaadStaat.js +43 -0
  181. package/dist/admin/ui/LaadStaat.js.map +1 -0
  182. package/dist/admin/ui/LeesbaarheidPaneel.d.ts +10 -0
  183. package/dist/admin/ui/LeesbaarheidPaneel.js +68 -0
  184. package/dist/admin/ui/LeesbaarheidPaneel.js.map +1 -0
  185. package/dist/admin/ui/LinkDialog.d.ts +22 -0
  186. package/dist/admin/ui/LinkDialog.js +131 -0
  187. package/dist/admin/ui/LinkDialog.js.map +1 -0
  188. package/dist/admin/ui/LinkVeld.d.ts +14 -0
  189. package/dist/admin/ui/LinkVeld.js +49 -0
  190. package/dist/admin/ui/LinkVeld.js.map +1 -0
  191. package/dist/admin/ui/PreviewLinkResultaat.d.ts +14 -0
  192. package/dist/admin/ui/PreviewLinkResultaat.js +52 -0
  193. package/dist/admin/ui/PreviewLinkResultaat.js.map +1 -0
  194. package/dist/admin/ui/charts.js +5 -5
  195. package/dist/admin/ui/charts.js.map +1 -1
  196. package/dist/admin/ui/primitives.d.ts +16 -6
  197. package/dist/admin/ui/primitives.js +98 -26
  198. package/dist/admin/ui/primitives.js.map +1 -1
  199. package/dist/admin/ui/select.js +5 -2
  200. package/dist/admin/ui/select.js.map +1 -1
  201. package/dist/admin/ui/switch.d.ts +3 -1
  202. package/dist/admin/ui/switch.js +6 -3
  203. package/dist/admin/ui/switch.js.map +1 -1
  204. package/dist/admin/ui/toast.d.ts +2 -1
  205. package/dist/admin/ui/toast.js +17 -11
  206. package/dist/admin/ui/toast.js.map +1 -1
  207. package/dist/admin/visual/BlokKiezer.d.ts +34 -0
  208. package/dist/admin/visual/BlokKiezer.js +225 -0
  209. package/dist/admin/visual/BlokKiezer.js.map +1 -0
  210. package/dist/admin/visual/InlineGereedschap.d.ts +52 -0
  211. package/dist/admin/visual/InlineGereedschap.js +356 -0
  212. package/dist/admin/visual/InlineGereedschap.js.map +1 -0
  213. package/dist/admin/visual/InlineRijkeTekst.d.ts +23 -0
  214. package/dist/admin/visual/InlineRijkeTekst.js +152 -0
  215. package/dist/admin/visual/InlineRijkeTekst.js.map +1 -0
  216. package/dist/admin/visual/VisualEditor.js +273 -125
  217. package/dist/admin/visual/VisualEditor.js.map +1 -1
  218. package/dist/admin.css +1 -1
  219. package/dist/bedrijf/bedrijf.d.ts +36 -0
  220. package/dist/bedrijf/bedrijf.js +110 -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 +29 -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 +1 -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/index.d.ts +3 -0
  309. package/dist/blocks/builtins/index.js +6 -0
  310. package/dist/blocks/builtins/index.js.map +1 -1
  311. package/dist/blocks/builtins/lib/autoComplete.d.ts +7 -0
  312. package/dist/blocks/builtins/lib/autoComplete.js +20 -0
  313. package/dist/blocks/builtins/lib/autoComplete.js.map +1 -0
  314. package/dist/blocks/builtins/lib/bookingUrl.d.ts +2 -2
  315. package/dist/blocks/builtins/lib/bookingUrl.js +1 -1
  316. package/dist/blocks/builtins/lib/bookingUrl.js.map +1 -1
  317. package/dist/blocks/builtins/lib/ical.d.ts +24 -0
  318. package/dist/blocks/builtins/lib/ical.js +82 -0
  319. package/dist/blocks/builtins/lib/ical.js.map +1 -0
  320. package/dist/blocks/builtins/lib/vandaag.d.ts +8 -0
  321. package/dist/blocks/builtins/lib/vandaag.js +22 -0
  322. package/dist/blocks/builtins/lib/vandaag.js.map +1 -0
  323. package/dist/blocks/registry.d.ts +6 -0
  324. package/dist/blocks/registry.js.map +1 -1
  325. package/dist/blocks/ui/index.js +1 -0
  326. package/dist/blocks/ui/index.js.map +1 -1
  327. package/dist/components/EditBar.js +2 -4
  328. package/dist/components/EditBar.js.map +1 -1
  329. package/dist/components/News.js +26 -18
  330. package/dist/components/News.js.map +1 -1
  331. package/dist/components/PageView.d.ts +7 -1
  332. package/dist/components/PageView.js +17 -0
  333. package/dist/components/PageView.js.map +1 -1
  334. package/dist/components/ResponsiveImage.js +18 -20
  335. package/dist/components/ResponsiveImage.js.map +1 -1
  336. package/dist/components/site/SiteFooter.d.ts +6 -1
  337. package/dist/components/site/SiteFooter.js +61 -9
  338. package/dist/components/site/SiteFooter.js.map +1 -1
  339. package/dist/components/site/SiteHeader.d.ts +15 -0
  340. package/dist/components/site/SiteHeader.js +70 -0
  341. package/dist/components/site/SiteHeader.js.map +1 -0
  342. package/dist/components/site/SiteNav.d.ts +2 -0
  343. package/dist/components/site/SiteNav.js +29 -5
  344. package/dist/components/site/SiteNav.js.map +1 -1
  345. package/dist/demo/DemoStudio.js +2 -2
  346. package/dist/demo/DemoStudio.js.map +1 -1
  347. package/dist/demo/demoStore.d.ts +13 -0
  348. package/dist/demo/demoStore.js +36 -0
  349. package/dist/demo/demoStore.js.map +1 -1
  350. package/dist/editor/EditorProvider.js +15 -4
  351. package/dist/editor/EditorProvider.js.map +1 -1
  352. package/dist/index.d.ts +4 -1
  353. package/dist/index.js +16 -1
  354. package/dist/index.js.map +1 -1
  355. package/dist/media/ImageContext.d.ts +17 -0
  356. package/dist/media/ImageContext.js +65 -20
  357. package/dist/media/ImageContext.js.map +1 -1
  358. package/dist/media/altInHtml.d.ts +9 -0
  359. package/dist/media/altInHtml.js +17 -0
  360. package/dist/media/altInHtml.js.map +1 -0
  361. package/dist/media/srcset.d.ts +12 -0
  362. package/dist/media/srcset.js +13 -0
  363. package/dist/media/srcset.js.map +1 -0
  364. package/dist/modules/builtins.d.ts +1 -0
  365. package/dist/modules/builtins.js +16 -3
  366. package/dist/modules/builtins.js.map +1 -1
  367. package/dist/modules/shop/blocks/Cart.js +5 -3
  368. package/dist/modules/shop/blocks/Cart.js.map +1 -1
  369. package/dist/modules/shop/blocks/Checkout.js +56 -35
  370. package/dist/modules/shop/blocks/Checkout.js.map +1 -1
  371. package/dist/modules/shop/blocks/Donation.js +4 -4
  372. package/dist/modules/shop/blocks/Donation.js.map +1 -1
  373. package/dist/modules/shop/blocks/ProductDetail.js +19 -3
  374. package/dist/modules/shop/blocks/ProductDetail.js.map +1 -1
  375. package/dist/modules/shop/blocks/ProductGrid.d.ts +3 -1
  376. package/dist/modules/shop/blocks/ProductGrid.js +8 -4
  377. package/dist/modules/shop/blocks/ProductGrid.js.map +1 -1
  378. package/dist/modules/shop/blocks/ShopCategories.js +4 -3
  379. package/dist/modules/shop/blocks/ShopCategories.js.map +1 -1
  380. package/dist/modules/shop/lib.d.ts +4 -0
  381. package/dist/modules/shop/lib.js +14 -0
  382. package/dist/modules/shop/lib.js.map +1 -1
  383. package/dist/modules/shop/settings.d.ts +3 -0
  384. package/dist/modules/shop/settings.js +14 -0
  385. package/dist/modules/shop/settings.js.map +1 -1
  386. package/dist/modules/shop/strings.d.ts +4 -0
  387. package/dist/modules/shop/strings.js +8 -0
  388. package/dist/modules/shop/strings.js.map +1 -1
  389. package/dist/next/envCheck.d.ts +42 -0
  390. package/dist/next/envCheck.js +106 -0
  391. package/dist/next/envCheck.js.map +1 -0
  392. package/dist/next/index.cjs +185 -2
  393. package/dist/next/index.d.ts +2 -0
  394. package/dist/next/index.js +8 -1
  395. package/dist/next/index.js.map +1 -1
  396. package/dist/next/securityHeaders.d.ts +36 -0
  397. package/dist/next/securityHeaders.js +74 -0
  398. package/dist/next/securityHeaders.js.map +1 -0
  399. package/dist/patterns/builtins.d.ts +7 -0
  400. package/dist/patterns/builtins.js +138 -3
  401. package/dist/patterns/builtins.js.map +1 -1
  402. package/dist/releaseNotes.js +140 -0
  403. package/dist/releaseNotes.js.map +1 -1
  404. package/dist/render/PublishedPage.d.ts +2 -1
  405. package/dist/render/PublishedPage.js +10 -4
  406. package/dist/render/PublishedPage.js.map +1 -1
  407. package/dist/schema/blocks.d.ts +470 -0
  408. package/dist/schema/blocks.js +102 -4
  409. package/dist/schema/blocks.js.map +1 -1
  410. package/dist/schema/business.d.ts +117 -0
  411. package/dist/schema/business.js +73 -0
  412. package/dist/schema/business.js.map +1 -0
  413. package/dist/schema/fields.d.ts +2 -1
  414. package/dist/schema/fields.js.map +1 -1
  415. package/dist/schema/forms.d.ts +18 -0
  416. package/dist/schema/forms.js +18 -3
  417. package/dist/schema/forms.js.map +1 -1
  418. package/dist/schema/mail.d.ts +10 -0
  419. package/dist/schema/mail.js +7 -0
  420. package/dist/schema/mail.js.map +1 -1
  421. package/dist/schema/settings.d.ts +101 -0
  422. package/dist/schema/settings.js +24 -3
  423. package/dist/schema/settings.js.map +1 -1
  424. package/dist/schema/shop.d.ts +2 -0
  425. package/dist/schema/shop.js +4 -0
  426. package/dist/schema/shop.js.map +1 -1
  427. package/dist/schema/shopGeld.d.ts +1 -0
  428. package/dist/schema/shopGeld.js +1 -0
  429. package/dist/schema/shopGeld.js.map +1 -1
  430. package/dist/schema/siteConfig.d.ts +68 -1
  431. package/dist/schema/siteConfig.js +7 -2
  432. package/dist/schema/siteConfig.js.map +1 -1
  433. package/dist/server/blockData.d.ts +1 -1
  434. package/dist/server/blockData.js +74 -18
  435. package/dist/server/blockData.js.map +1 -1
  436. package/dist/server/cspRapport.d.ts +20 -0
  437. package/dist/server/cspRapport.js +56 -0
  438. package/dist/server/cspRapport.js.map +1 -0
  439. package/dist/server/fonts.d.ts +3 -0
  440. package/dist/server/fonts.js +39 -0
  441. package/dist/server/fonts.js.map +1 -0
  442. package/dist/server/index.d.ts +3 -0
  443. package/dist/server/index.js +8 -0
  444. package/dist/server/index.js.map +1 -1
  445. package/dist/server/sanitize.js +15 -2
  446. package/dist/server/sanitize.js.map +1 -1
  447. package/dist/settings/useSiteSettings.js +4 -1
  448. package/dist/settings/useSiteSettings.js.map +1 -1
  449. package/dist/starters/starters.d.ts +69 -0
  450. package/dist/starters/starters.js +171 -0
  451. package/dist/starters/starters.js.map +1 -0
  452. package/dist/styles.css +1149 -208
  453. package/dist/theme/color.d.ts +10 -0
  454. package/dist/theme/color.js +17 -1
  455. package/dist/theme/color.js.map +1 -1
  456. package/dist/theme/fontFallback.d.ts +23 -0
  457. package/dist/theme/fontFallback.js +58 -0
  458. package/dist/theme/fontFallback.js.map +1 -0
  459. package/dist/theme/fonts.d.ts +11 -0
  460. package/dist/theme/fonts.js +16 -0
  461. package/dist/theme/fonts.js.map +1 -0
  462. package/dist/version.js +1 -1
  463. package/package.json +6 -4
@@ -0,0 +1,67 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useId } from "react";
4
+ import { MediaPickerButton } from "../media/MediaPicker.js";
5
+ import { Button, Input } from "./primitives.js";
6
+ function ImageField({
7
+ siteId,
8
+ value,
9
+ onChange,
10
+ wat = "foto",
11
+ verwijderbaar = true
12
+ }) {
13
+ const id = useId();
14
+ const url = value?.trim() || void 0;
15
+ return /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
16
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
17
+ url ? (
18
+ // eslint-disable-next-line @next/next/no-img-element
19
+ /* @__PURE__ */ jsx(
20
+ "img",
21
+ {
22
+ src: url,
23
+ alt: "",
24
+ className: "h-16 w-16 shrink-0 rounded-lg border border-slate-200 object-cover",
25
+ style: { background: "var(--color-background-muted)" }
26
+ }
27
+ )
28
+ ) : /* @__PURE__ */ jsx(
29
+ "div",
30
+ {
31
+ "aria-hidden": true,
32
+ className: "grid h-16 w-16 shrink-0 place-items-center rounded-lg border border-dashed border-slate-300 text-xl text-slate-400",
33
+ children: "\u{1F5BC}"
34
+ }
35
+ ),
36
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
37
+ /* @__PURE__ */ jsx(
38
+ MediaPickerButton,
39
+ {
40
+ siteId,
41
+ label: url ? "Wijzigen" : `Kies een ${wat}`,
42
+ variant: url ? "secondary" : "primary",
43
+ onSelect: (m) => onChange(m.url, m)
44
+ }
45
+ ),
46
+ url && verwijderbaar && /* @__PURE__ */ jsx(Button, { type: "button", size: "sm", variant: "ghost", onClick: () => onChange(void 0), children: "Weghalen" })
47
+ ] })
48
+ ] }),
49
+ /* @__PURE__ */ jsxs("details", { className: "text-xs text-slate-500", children: [
50
+ /* @__PURE__ */ jsx("summary", { className: "cursor-pointer select-none", children: "Ander adres (externe afbeelding)" }),
51
+ /* @__PURE__ */ jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsx(
52
+ Input,
53
+ {
54
+ id,
55
+ "aria-label": `Adres van de ${wat}`,
56
+ value: value ?? "",
57
+ onChange: (e) => onChange(e.target.value || void 0),
58
+ placeholder: "https://\u2026"
59
+ }
60
+ ) })
61
+ ] })
62
+ ] });
63
+ }
64
+ export {
65
+ ImageField
66
+ };
67
+ //# sourceMappingURL=ImageField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/admin/ui/ImageField.tsx"],"sourcesContent":["\"use client\";\n\nimport { useId } from \"react\";\nimport { MediaPickerButton, type PickedMedia } from \"../media/MediaPicker\";\nimport { Button, Input } from \"./primitives\";\n\n/**\n * Fotoveld (8.2): wat de klant ziet is de FOTO, niet een URL. Eerst was elk beeldveld een\n * tekstvak met \"URL of kies →\" en een knop ernaast — de meest gebruikte handeling (\"foto\n * wijzigen\") begon met een onleesbaar adres. Nu: een miniatuur, \"Wijzigen\" via de mediabibliotheek\n * en \"Weghalen\". Een adres plakken kan nog onder \"Ander adres\" (voor een externe afbeelding).\n */\nexport function ImageField({\n siteId,\n value,\n onChange,\n wat = \"foto\",\n verwijderbaar = true,\n}: {\n siteId: string;\n value: string | undefined;\n onChange: (url: string | undefined, media?: PickedMedia) => void;\n /** Hoe het beeld heet in knoppen (\"foto\", \"logo\", \"achtergrond\"). */\n wat?: string;\n verwijderbaar?: boolean;\n}) {\n const id = useId();\n const url = value?.trim() || undefined;\n return (\n <div className=\"grid gap-2\">\n <div className=\"flex items-center gap-3\">\n {url ? (\n // eslint-disable-next-line @next/next/no-img-element\n <img\n src={url}\n alt=\"\"\n className=\"h-16 w-16 shrink-0 rounded-lg border border-slate-200 object-cover\"\n style={{ background: \"var(--color-background-muted)\" }}\n />\n ) : (\n <div\n aria-hidden\n className=\"grid h-16 w-16 shrink-0 place-items-center rounded-lg border border-dashed border-slate-300 text-xl text-slate-400\"\n >\n 🖼\n </div>\n )}\n <div className=\"flex flex-wrap gap-2\">\n <MediaPickerButton\n siteId={siteId}\n label={url ? \"Wijzigen\" : `Kies een ${wat}`}\n variant={url ? \"secondary\" : \"primary\"}\n onSelect={(m) => onChange(m.url, m)}\n />\n {url && verwijderbaar && (\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={() => onChange(undefined)}>\n Weghalen\n </Button>\n )}\n </div>\n </div>\n <details className=\"text-xs text-slate-500\">\n <summary className=\"cursor-pointer select-none\">Ander adres (externe afbeelding)</summary>\n <div className=\"mt-2\">\n <Input\n id={id}\n aria-label={`Adres van de ${wat}`}\n value={value ?? \"\"}\n onChange={(e) => onChange(e.target.value || undefined)}\n placeholder=\"https://…\"\n />\n </div>\n </details>\n </div>\n );\n}\n"],"mappings":";AAiCU,cAcF,YAdE;AA/BV,SAAS,aAAa;AACtB,SAAS,yBAA2C;AACpD,SAAS,QAAQ,aAAa;AAQvB,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAM;AAAA,EACN,gBAAgB;AAClB,GAOG;AACD,QAAM,KAAK,MAAM;AACjB,QAAM,MAAM,OAAO,KAAK,KAAK;AAC7B,SACE,qBAAC,SAAI,WAAU,cACb;AAAA,yBAAC,SAAI,WAAU,2BACZ;AAAA;AAAA;AAAA,QAEC;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,KAAI;AAAA,YACJ,WAAU;AAAA,YACV,OAAO,EAAE,YAAY,gCAAgC;AAAA;AAAA,QACvD;AAAA,UAEA;AAAA,QAAC;AAAA;AAAA,UACC,eAAW;AAAA,UACX,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,MAEF,qBAAC,SAAI,WAAU,wBACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,OAAO,MAAM,aAAa,YAAY,GAAG;AAAA,YACzC,SAAS,MAAM,cAAc;AAAA,YAC7B,UAAU,CAAC,MAAM,SAAS,EAAE,KAAK,CAAC;AAAA;AAAA,QACpC;AAAA,QACC,OAAO,iBACN,oBAAC,UAAO,MAAK,UAAS,MAAK,MAAK,SAAQ,SAAQ,SAAS,MAAM,SAAS,MAAS,GAAG,sBAEpF;AAAA,SAEJ;AAAA,OACF;AAAA,IACA,qBAAC,aAAQ,WAAU,0BACjB;AAAA,0BAAC,aAAQ,WAAU,8BAA6B,8CAAgC;AAAA,MAChF,oBAAC,SAAI,WAAU,QACb;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,cAAY,gBAAgB,GAAG;AAAA,UAC/B,OAAO,SAAS;AAAA,UAChB,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,SAAS,MAAS;AAAA,UACrD,aAAY;AAAA;AAAA,MACd,GACF;AAAA,OACF;AAAA,KACF;AAEJ;","names":[]}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Kleurveld (7.24, gedeeld sinds 8.2): een echte kleurkiezer naast het hex-veld. De hex blijft
3
+ * (plakken uit een huisstijlgids), de kiezer erbij voorkomt "#ff00" en oranje-dat-geel-moest-zijn.
4
+ * Met `stalen` toont hij eerst de huisstijlkleuren van de site als één-klik-keuze — wie een
5
+ * blokachtergrond kiest, wil meestal een kleur die al in de site zit.
6
+ */
7
+ export declare function KleurVeld({ label, hint, value, placeholder, onChange, stalen, wisbaar, }: {
8
+ label: string;
9
+ hint?: string;
10
+ value: string;
11
+ placeholder?: string;
12
+ onChange: (v: string) => void;
13
+ stalen?: {
14
+ label: string;
15
+ kleur: string;
16
+ }[];
17
+ /** Toon een "Geen"-knop die de kleur leegmaakt. */
18
+ wisbaar?: boolean;
19
+ }): import("react").JSX.Element;
20
+ /** Contrastregel onder de merkkleur: knoptekst op de merkkleur, en merkkleur op de achtergrond. */
21
+ export declare function ContrastRegel({ primary, background, foreground }: {
22
+ primary: string;
23
+ background?: string;
24
+ foreground?: string;
25
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,76 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { contrast, contrastOordeel, naarHex6, tekstOp } from "../lib/kleur.js";
4
+ import { Field, Input } from "./primitives.js";
5
+ function KleurVeld({
6
+ label,
7
+ hint,
8
+ value,
9
+ placeholder,
10
+ onChange,
11
+ stalen,
12
+ wisbaar
13
+ }) {
14
+ const bruikbaar = (stalen ?? []).filter((x) => /^#[0-9a-f]{3,8}$/i.test(x.kleur.trim()));
15
+ return /* @__PURE__ */ jsx(Field, { label, hint, children: /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
16
+ bruikbaar.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1.5", role: "group", "aria-label": `${label}: huisstijlkleuren`, children: [
17
+ bruikbaar.map((x) => /* @__PURE__ */ jsx(
18
+ "button",
19
+ {
20
+ type: "button",
21
+ title: x.label,
22
+ "aria-label": `${x.label} (${x.kleur})`,
23
+ "aria-pressed": value.toLowerCase() === x.kleur.toLowerCase(),
24
+ onClick: () => onChange(x.kleur),
25
+ className: "xicms-admin-btn h-7 w-7 rounded-full border border-slate-300 aria-[pressed=true]:ring-2 aria-[pressed=true]:ring-slate-900",
26
+ style: { background: x.kleur }
27
+ },
28
+ x.label
29
+ )),
30
+ wisbaar && /* @__PURE__ */ jsx("button", { type: "button", onClick: () => onChange(""), className: "xicms-admin-btn ml-1 rounded px-2 py-1 text-xs text-slate-600 hover:bg-slate-100", children: "Geen" })
31
+ ] }),
32
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
33
+ /* @__PURE__ */ jsx(
34
+ "input",
35
+ {
36
+ type: "color",
37
+ "aria-label": `${label} kiezen`,
38
+ value: naarHex6(value || placeholder, "#ffffff"),
39
+ onChange: (e) => onChange(e.target.value),
40
+ className: "h-9 w-11 shrink-0 cursor-pointer rounded-md border border-slate-200 bg-transparent p-0.5"
41
+ }
42
+ ),
43
+ /* @__PURE__ */ jsx(Input, { value, placeholder, onChange: (e) => onChange(e.target.value), "aria-label": `${label} (kleurcode)` })
44
+ ] })
45
+ ] }) });
46
+ }
47
+ function ContrastRegel({ primary, background, foreground }) {
48
+ const knop = contrastOordeel(contrast(primary, tekstOp(primary)));
49
+ const opAchtergrond = contrastOordeel(contrast(primary, background || "#ffffff"));
50
+ const tekst = foreground ? contrastOordeel(contrast(foreground, background || "#ffffff")) : null;
51
+ if (!knop && !opAchtergrond && !tekst) return null;
52
+ const kleur = (t) => t === "goed" ? "text-emerald-700" : t === "matig" ? "text-amber-700" : "text-red-700";
53
+ return /* @__PURE__ */ jsxs("div", { className: "grid gap-1 text-xs", children: [
54
+ knop && /* @__PURE__ */ jsxs("p", { className: kleur(knop.toon), children: [
55
+ "Knoptekst op merkkleur: ",
56
+ knop.tekst.replace(/^Contrast /, "")
57
+ ] }),
58
+ opAchtergrond && /* @__PURE__ */ jsxs("p", { className: kleur(opAchtergrond.toon), children: [
59
+ "Merkkleur als tekst op de achtergrond: ",
60
+ opAchtergrond.tekst.replace(/^Contrast /, "")
61
+ ] }),
62
+ tekst && /* @__PURE__ */ jsxs("p", { className: kleur(tekst.toon === "matig" ? "slecht" : tekst.toon), children: [
63
+ "Tekst op de achtergrond: ",
64
+ tekst.tekst.replace(/^Contrast /, "").replace(/voldoende voor knoppen en koppen, krap voor kleine tekst/, "te weinig voor lopende tekst (minimaal 4,5)")
65
+ ] }),
66
+ /* @__PURE__ */ jsxs("p", { className: "text-slate-500", children: [
67
+ "Voorbeeld: ",
68
+ /* @__PURE__ */ jsx("span", { className: "rounded-md px-2 py-0.5 font-medium", style: { background: primary, color: tekstOp(primary) }, children: "Knop" })
69
+ ] })
70
+ ] });
71
+ }
72
+ export {
73
+ ContrastRegel,
74
+ KleurVeld
75
+ };
76
+ //# sourceMappingURL=KleurVeld.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/admin/ui/KleurVeld.tsx"],"sourcesContent":["\"use client\";\n\nimport { contrast, contrastOordeel, naarHex6, tekstOp } from \"../lib/kleur\";\nimport { Field, Input } from \"./primitives\";\n\n/**\n * Kleurveld (7.24, gedeeld sinds 8.2): een echte kleurkiezer naast het hex-veld. De hex blijft\n * (plakken uit een huisstijlgids), de kiezer erbij voorkomt \"#ff00\" en oranje-dat-geel-moest-zijn.\n * Met `stalen` toont hij eerst de huisstijlkleuren van de site als één-klik-keuze — wie een\n * blokachtergrond kiest, wil meestal een kleur die al in de site zit.\n */\nexport function KleurVeld({\n label,\n hint,\n value,\n placeholder,\n onChange,\n stalen,\n wisbaar,\n}: {\n label: string;\n hint?: string;\n value: string;\n placeholder?: string;\n onChange: (v: string) => void;\n stalen?: { label: string; kleur: string }[];\n /** Toon een \"Geen\"-knop die de kleur leegmaakt. */\n wisbaar?: boolean;\n}) {\n const bruikbaar = (stalen ?? []).filter((x) => /^#[0-9a-f]{3,8}$/i.test(x.kleur.trim()));\n return (\n <Field label={label} hint={hint}>\n <div className=\"grid gap-2\">\n {bruikbaar.length > 0 && (\n <div className=\"flex flex-wrap items-center gap-1.5\" role=\"group\" aria-label={`${label}: huisstijlkleuren`}>\n {bruikbaar.map((x) => (\n <button\n key={x.label}\n type=\"button\"\n title={x.label}\n aria-label={`${x.label} (${x.kleur})`}\n aria-pressed={value.toLowerCase() === x.kleur.toLowerCase()}\n onClick={() => onChange(x.kleur)}\n className=\"xicms-admin-btn h-7 w-7 rounded-full border border-slate-300 aria-[pressed=true]:ring-2 aria-[pressed=true]:ring-slate-900\"\n style={{ background: x.kleur }}\n />\n ))}\n {wisbaar && (\n <button type=\"button\" onClick={() => onChange(\"\")} className=\"xicms-admin-btn ml-1 rounded px-2 py-1 text-xs text-slate-600 hover:bg-slate-100\">\n Geen\n </button>\n )}\n </div>\n )}\n <div className=\"flex items-center gap-2\">\n <input\n type=\"color\"\n aria-label={`${label} kiezen`}\n value={naarHex6(value || placeholder, \"#ffffff\")}\n onChange={(e) => onChange(e.target.value)}\n className=\"h-9 w-11 shrink-0 cursor-pointer rounded-md border border-slate-200 bg-transparent p-0.5\"\n />\n <Input value={value} placeholder={placeholder} onChange={(e) => onChange(e.target.value)} aria-label={`${label} (kleurcode)`} />\n </div>\n </div>\n </Field>\n );\n}\n\n/** Contrastregel onder de merkkleur: knoptekst op de merkkleur, en merkkleur op de achtergrond. */\nexport function ContrastRegel({ primary, background, foreground }: { primary: string; background?: string; foreground?: string }) {\n const knop = contrastOordeel(contrast(primary, tekstOp(primary)));\n const opAchtergrond = contrastOordeel(contrast(primary, background || \"#ffffff\"));\n // 8.10: ook de gewone tekst op de achtergrond — lichtgrijze tekst op wit ging ongemerkt live.\n const tekst = foreground ? contrastOordeel(contrast(foreground, background || \"#ffffff\")) : null;\n if (!knop && !opAchtergrond && !tekst) return null;\n const kleur = (t: \"goed\" | \"matig\" | \"slecht\") => (t === \"goed\" ? \"text-emerald-700\" : t === \"matig\" ? \"text-amber-700\" : \"text-red-700\");\n return (\n <div className=\"grid gap-1 text-xs\">\n {knop && <p className={kleur(knop.toon)}>Knoptekst op merkkleur: {knop.tekst.replace(/^Contrast /, \"\")}</p>}\n {opAchtergrond && <p className={kleur(opAchtergrond.toon)}>Merkkleur als tekst op de achtergrond: {opAchtergrond.tekst.replace(/^Contrast /, \"\")}</p>}\n {tekst && <p className={kleur(tekst.toon === \"matig\" ? \"slecht\" : tekst.toon)}>Tekst op de achtergrond: {tekst.tekst.replace(/^Contrast /, \"\").replace(/voldoende voor knoppen en koppen, krap voor kleine tekst/, \"te weinig voor lopende tekst (minimaal 4,5)\")}</p>}\n <p className=\"text-slate-500\">Voorbeeld: <span className=\"rounded-md px-2 py-0.5 font-medium\" style={{ background: primary, color: tekstOp(primary) }}>Knop</span></p>\n </div>\n );\n}\n\n"],"mappings":";AAkCU,SAEI,KAFJ;AAhCV,SAAS,UAAU,iBAAiB,UAAU,eAAe;AAC7D,SAAS,OAAO,aAAa;AAQtB,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GASG;AACD,QAAM,aAAa,UAAU,CAAC,GAAG,OAAO,CAAC,MAAM,oBAAoB,KAAK,EAAE,MAAM,KAAK,CAAC,CAAC;AACvF,SACE,oBAAC,SAAM,OAAc,MACnB,+BAAC,SAAI,WAAU,cACZ;AAAA,cAAU,SAAS,KAClB,qBAAC,SAAI,WAAU,uCAAsC,MAAK,SAAQ,cAAY,GAAG,KAAK,sBACnF;AAAA,gBAAU,IAAI,CAAC,MACd;AAAA,QAAC;AAAA;AAAA,UAEC,MAAK;AAAA,UACL,OAAO,EAAE;AAAA,UACT,cAAY,GAAG,EAAE,KAAK,KAAK,EAAE,KAAK;AAAA,UAClC,gBAAc,MAAM,YAAY,MAAM,EAAE,MAAM,YAAY;AAAA,UAC1D,SAAS,MAAM,SAAS,EAAE,KAAK;AAAA,UAC/B,WAAU;AAAA,UACV,OAAO,EAAE,YAAY,EAAE,MAAM;AAAA;AAAA,QAPxB,EAAE;AAAA,MAQT,CACD;AAAA,MACA,WACC,oBAAC,YAAO,MAAK,UAAS,SAAS,MAAM,SAAS,EAAE,GAAG,WAAU,oFAAmF,kBAEhJ;AAAA,OAEJ;AAAA,IAEF,qBAAC,SAAI,WAAU,2BACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,cAAY,GAAG,KAAK;AAAA,UACpB,OAAO,SAAS,SAAS,aAAa,SAAS;AAAA,UAC/C,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,UACxC,WAAU;AAAA;AAAA,MACZ;AAAA,MACA,oBAAC,SAAM,OAAc,aAA0B,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK,GAAG,cAAY,GAAG,KAAK,gBAAgB;AAAA,OAChI;AAAA,KACF,GACF;AAEJ;AAGO,SAAS,cAAc,EAAE,SAAS,YAAY,WAAW,GAAkE;AAChI,QAAM,OAAO,gBAAgB,SAAS,SAAS,QAAQ,OAAO,CAAC,CAAC;AAChE,QAAM,gBAAgB,gBAAgB,SAAS,SAAS,cAAc,SAAS,CAAC;AAEhF,QAAM,QAAQ,aAAa,gBAAgB,SAAS,YAAY,cAAc,SAAS,CAAC,IAAI;AAC5F,MAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,MAAO,QAAO;AAC9C,QAAM,QAAQ,CAAC,MAAoC,MAAM,SAAS,qBAAqB,MAAM,UAAU,mBAAmB;AAC1H,SACE,qBAAC,SAAI,WAAU,sBACZ;AAAA,YAAQ,qBAAC,OAAE,WAAW,MAAM,KAAK,IAAI,GAAG;AAAA;AAAA,MAAyB,KAAK,MAAM,QAAQ,cAAc,EAAE;AAAA,OAAE;AAAA,IACtG,iBAAiB,qBAAC,OAAE,WAAW,MAAM,cAAc,IAAI,GAAG;AAAA;AAAA,MAAwC,cAAc,MAAM,QAAQ,cAAc,EAAE;AAAA,OAAE;AAAA,IAChJ,SAAS,qBAAC,OAAE,WAAW,MAAM,MAAM,SAAS,UAAU,WAAW,MAAM,IAAI,GAAG;AAAA;AAAA,MAA0B,MAAM,MAAM,QAAQ,cAAc,EAAE,EAAE,QAAQ,4DAA4D,6CAA6C;AAAA,OAAE;AAAA,IAClQ,qBAAC,OAAE,WAAU,kBAAiB;AAAA;AAAA,MAAW,oBAAC,UAAK,WAAU,sCAAqC,OAAO,EAAE,YAAY,SAAS,OAAO,QAAQ,OAAO,EAAE,GAAG,kBAAI;AAAA,OAAO;AAAA,KACpK;AAEJ;","names":[]}
@@ -0,0 +1,21 @@
1
+ import type { ReactNode } from "react";
2
+ /**
3
+ * Drie toestanden voor elke live lijst in /beheer (8.1): laden, fout, data. Eerst kenden de meeste
4
+ * lijsten alleen "data": tijdens het laden én na een fout (rechten, App Check, geen verbinding)
5
+ * stond er "Nog geen pagina's — maak je eerste", wat een klant letterlijk nam.
6
+ */
7
+ export declare function LaadStaat({ laden, fout, opnieuw, wat, children, }: {
8
+ laden: boolean;
9
+ fout: string | null;
10
+ opnieuw?: () => void;
11
+ /** Wat er geladen wordt, in een zin als "De pagina's konden niet worden geladen." */
12
+ wat?: string;
13
+ children: ReactNode;
14
+ }): import("react").JSX.Element;
15
+ export declare function FoutMelding({ wat, detail, opnieuw }: {
16
+ wat: string;
17
+ detail?: string;
18
+ opnieuw?: () => void;
19
+ }): import("react").JSX.Element;
20
+ /** Foutmelding uit een Firestore-/callable-fout, voor in `LaadStaat`. */
21
+ export declare function foutTekst(e: unknown): string;
@@ -0,0 +1,43 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { Button, Card } from "./primitives.js";
4
+ import { isDemoActive } from "../../demo/demoStore.js";
5
+ function LaadStaat({
6
+ laden,
7
+ fout,
8
+ opnieuw,
9
+ wat = "gegevens",
10
+ children
11
+ }) {
12
+ if (fout) return /* @__PURE__ */ jsx(FoutMelding, { wat, detail: fout, opnieuw });
13
+ if (laden) {
14
+ return /* @__PURE__ */ jsx("p", { className: "py-2 text-sm text-slate-500", role: "status", "aria-live": "polite", children: `${hoofdletter(wat)} laden\u2026` });
15
+ }
16
+ return /* @__PURE__ */ jsx(Fragment, { children });
17
+ }
18
+ function FoutMelding({ wat, detail, opnieuw }) {
19
+ if (isDemoActive()) {
20
+ return /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs("p", { className: "text-sm text-slate-600", role: "status", children: [
21
+ "In deze demo is dit onderdeel leeg. Bij je eigen site zie je hier ",
22
+ wat,
23
+ "."
24
+ ] }) });
25
+ }
26
+ return /* @__PURE__ */ jsx(Card, { className: "border-red-200", children: /* @__PURE__ */ jsxs("div", { role: "alert", className: "grid gap-2", children: [
27
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-red-800", children: `${hoofdletter(wat)} konden niet worden geladen.` }),
28
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-slate-600", children: /permission|insufficient/i.test(detail ?? "") ? "Je account heeft hier (nog) geen toegang toe. Log opnieuw in; helpt dat niet, neem dan contact op met Xi Webdesign." : "Controleer je internetverbinding en probeer het opnieuw." }),
29
+ opnieuw && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, { size: "sm", variant: "secondary", onClick: opnieuw, children: "Opnieuw proberen" }) })
30
+ ] }) });
31
+ }
32
+ function foutTekst(e) {
33
+ return e instanceof Error ? e.message : String(e);
34
+ }
35
+ function hoofdletter(s) {
36
+ return s.charAt(0).toUpperCase() + s.slice(1);
37
+ }
38
+ export {
39
+ FoutMelding,
40
+ LaadStaat,
41
+ foutTekst
42
+ };
43
+ //# sourceMappingURL=LaadStaat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/admin/ui/LaadStaat.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { Button, Card } from \"./primitives\";\nimport { isDemoActive } from \"../../demo/demoStore\";\n\n/**\n * Drie toestanden voor elke live lijst in /beheer (8.1): laden, fout, data. Eerst kenden de meeste\n * lijsten alleen \"data\": tijdens het laden én na een fout (rechten, App Check, geen verbinding)\n * stond er \"Nog geen pagina's — maak je eerste\", wat een klant letterlijk nam.\n */\nexport function LaadStaat({\n laden,\n fout,\n opnieuw,\n wat = \"gegevens\",\n children,\n}: {\n laden: boolean;\n fout: string | null;\n opnieuw?: () => void;\n /** Wat er geladen wordt, in een zin als \"De pagina's konden niet worden geladen.\" */\n wat?: string;\n children: ReactNode;\n}) {\n if (fout) return <FoutMelding wat={wat} detail={fout} opnieuw={opnieuw} />;\n if (laden) {\n return (\n <p className=\"py-2 text-sm text-slate-500\" role=\"status\" aria-live=\"polite\">\n {`${hoofdletter(wat)} laden…`}\n </p>\n );\n }\n return <>{children}</>;\n}\n\nexport function FoutMelding({ wat, detail, opnieuw }: { wat: string; detail?: string; opnieuw?: () => void }) {\n // In de demo is er geen database om uit te lezen; een rode foutmelding zou een proefklant\n // afschrikken voor iets wat bij een echte site gewoon werkt.\n if (isDemoActive()) {\n return (\n <Card>\n <p className=\"text-sm text-slate-600\" role=\"status\">\n In deze demo is dit onderdeel leeg. Bij je eigen site zie je hier {wat}.\n </p>\n </Card>\n );\n }\n return (\n <Card className=\"border-red-200\">\n <div role=\"alert\" className=\"grid gap-2\">\n <p className=\"text-sm font-medium text-red-800\">{`${hoofdletter(wat)} konden niet worden geladen.`}</p>\n <p className=\"text-xs text-slate-600\">\n {/permission|insufficient/i.test(detail ?? \"\")\n ? \"Je account heeft hier (nog) geen toegang toe. Log opnieuw in; helpt dat niet, neem dan contact op met Xi Webdesign.\"\n : \"Controleer je internetverbinding en probeer het opnieuw.\"}\n </p>\n {opnieuw && (\n <div>\n <Button size=\"sm\" variant=\"secondary\" onClick={opnieuw}>Opnieuw proberen</Button>\n </div>\n )}\n </div>\n </Card>\n );\n}\n\n/** Foutmelding uit een Firestore-/callable-fout, voor in `LaadStaat`. */\nexport function foutTekst(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\nfunction hoofdletter(s: string): string {\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n"],"mappings":";AAyBmB,SAQV,UARU,KAiBX,YAjBW;AAtBnB,SAAS,QAAQ,YAAY;AAC7B,SAAS,oBAAoB;AAOtB,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAM;AAAA,EACN;AACF,GAOG;AACD,MAAI,KAAM,QAAO,oBAAC,eAAY,KAAU,QAAQ,MAAM,SAAkB;AACxE,MAAI,OAAO;AACT,WACE,oBAAC,OAAE,WAAU,+BAA8B,MAAK,UAAS,aAAU,UAChE,aAAG,YAAY,GAAG,CAAC,gBACtB;AAAA,EAEJ;AACA,SAAO,gCAAG,UAAS;AACrB;AAEO,SAAS,YAAY,EAAE,KAAK,QAAQ,QAAQ,GAA2D;AAG5G,MAAI,aAAa,GAAG;AAClB,WACE,oBAAC,QACC,+BAAC,OAAE,WAAU,0BAAyB,MAAK,UAAS;AAAA;AAAA,MACiB;AAAA,MAAI;AAAA,OACzE,GACF;AAAA,EAEJ;AACA,SACE,oBAAC,QAAK,WAAU,kBACd,+BAAC,SAAI,MAAK,SAAQ,WAAU,cAC1B;AAAA,wBAAC,OAAE,WAAU,oCAAoC,aAAG,YAAY,GAAG,CAAC,gCAA+B;AAAA,IACnG,oBAAC,OAAE,WAAU,0BACV,qCAA2B,KAAK,UAAU,EAAE,IACzC,wHACA,4DACN;AAAA,IACC,WACC,oBAAC,SACC,8BAAC,UAAO,MAAK,MAAK,SAAQ,aAAY,SAAS,SAAS,8BAAgB,GAC1E;AAAA,KAEJ,GACF;AAEJ;AAGO,SAAS,UAAU,GAAoB;AAC5C,SAAO,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AAClD;AAEA,SAAS,YAAY,GAAmB;AACtC,SAAO,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC;AAC9C;","names":[]}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Leesbaarheid van een tekst (8.5): score, niveau, woorden, leestijd en concrete tips. Rekent
3
+ * lokaal (geen netwerk), uitgesteld zodat typen nooit hapert. Ingeklapt toont hij één regel; open
4
+ * de details voor de tips.
5
+ */
6
+ export declare function LeesbaarheidPaneel({ html, tekst, titel }: {
7
+ html?: string;
8
+ tekst?: string;
9
+ titel?: string;
10
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,68 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useDeferredValue, useMemo } from "react";
4
+ import { htmlNaarTekst, meetLeesbaarheid } from "../lib/leesbaarheid.js";
5
+ const KLEUR = { goed: "#15803d", matig: "#b45309", slecht: "#b91c1c" };
6
+ function LeesbaarheidPaneel({ html, tekst, titel = "Leesbaarheid" }) {
7
+ const bron = useDeferredValue(tekst ?? htmlNaarTekst(html ?? ""));
8
+ const r = useMemo(() => meetLeesbaarheid(bron), [bron]);
9
+ if (r.woorden === 0) return null;
10
+ const kleur = KLEUR[r.niveau.toon];
11
+ return /* @__PURE__ */ jsxs("details", { className: "rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm", children: [
12
+ /* @__PURE__ */ jsxs("summary", { className: "flex cursor-pointer select-none flex-wrap items-center gap-x-3 gap-y-1", children: [
13
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-slate-800", children: titel }),
14
+ /* @__PURE__ */ jsxs(
15
+ "span",
16
+ {
17
+ className: "inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium",
18
+ style: { background: `${kleur}14`, color: kleur },
19
+ children: [
20
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "inline-block h-2 w-2 rounded-full", style: { background: kleur } }),
21
+ r.niveau.naam,
22
+ " \xB7 ",
23
+ r.score,
24
+ "/100"
25
+ ]
26
+ }
27
+ ),
28
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-slate-500", children: [
29
+ r.woorden,
30
+ " woorden \xB7 ca. ",
31
+ r.leestijd,
32
+ " min lezen"
33
+ ] }),
34
+ r.tips.length > 0 && /* @__PURE__ */ jsxs("span", { className: "text-xs text-slate-600", children: [
35
+ "\xB7 ",
36
+ r.tips.length,
37
+ " ",
38
+ r.tips.length === 1 ? "tip" : "tips"
39
+ ] })
40
+ ] }),
41
+ /* @__PURE__ */ jsxs("div", { className: "mt-3 grid gap-3", children: [
42
+ /* @__PURE__ */ jsxs("div", { children: [
43
+ /* @__PURE__ */ jsx("div", { className: "relative h-2 overflow-hidden rounded-full bg-slate-100", role: "meter", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": r.score, "aria-label": "Leesbaarheidsscore", children: /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 rounded-full", style: { width: `${r.score}%`, background: kleur } }) }),
44
+ /* @__PURE__ */ jsxs("div", { className: "mt-1 flex justify-between text-[11px] text-slate-500", children: [
45
+ /* @__PURE__ */ jsx("span", { children: "moeilijk" }),
46
+ /* @__PURE__ */ jsx("span", { children: "B1 (streven)" }),
47
+ /* @__PURE__ */ jsx("span", { children: "makkelijk" })
48
+ ] })
49
+ ] }),
50
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-slate-600", children: r.niveau.uitleg }),
51
+ /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-2 gap-2 text-xs sm:grid-cols-4", children: [
52
+ ["Woorden", r.woorden],
53
+ ["Zinnen", r.zinnen],
54
+ ["Woorden per zin", r.woordenPerZin],
55
+ ["Leestijd", `${r.leestijd} min`]
56
+ ].map(([k, v]) => /* @__PURE__ */ jsxs("div", { className: "rounded-md bg-slate-50 px-2 py-1.5", children: [
57
+ /* @__PURE__ */ jsx("dt", { className: "text-slate-500", children: k }),
58
+ /* @__PURE__ */ jsx("dd", { className: "font-medium text-slate-800", children: v })
59
+ ] }, String(k))) }),
60
+ r.tips.length > 0 && /* @__PURE__ */ jsx("ul", { className: "grid list-disc gap-1 pl-5 text-xs text-slate-700", children: r.tips.map((t, i) => /* @__PURE__ */ jsx("li", { children: t }, i)) }),
61
+ /* @__PURE__ */ jsx("p", { className: "text-[11px] text-slate-500", children: "Een indicatie (Flesch-Douma), geen oordeel: korte zinnen en gewone woorden lezen het prettigst." })
62
+ ] })
63
+ ] });
64
+ }
65
+ export {
66
+ LeesbaarheidPaneel
67
+ };
68
+ //# sourceMappingURL=LeesbaarheidPaneel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/admin/ui/LeesbaarheidPaneel.tsx"],"sourcesContent":["\"use client\";\n\nimport { useDeferredValue, useMemo } from \"react\";\nimport { htmlNaarTekst, meetLeesbaarheid } from \"../lib/leesbaarheid\";\n\nconst KLEUR = { goed: \"#15803d\", matig: \"#b45309\", slecht: \"#b91c1c\" } as const;\n\n/**\n * Leesbaarheid van een tekst (8.5): score, niveau, woorden, leestijd en concrete tips. Rekent\n * lokaal (geen netwerk), uitgesteld zodat typen nooit hapert. Ingeklapt toont hij één regel; open\n * de details voor de tips.\n */\nexport function LeesbaarheidPaneel({ html, tekst, titel = \"Leesbaarheid\" }: { html?: string; tekst?: string; titel?: string }) {\n const bron = useDeferredValue(tekst ?? htmlNaarTekst(html ?? \"\"));\n const r = useMemo(() => meetLeesbaarheid(bron), [bron]);\n if (r.woorden === 0) return null;\n const kleur = KLEUR[r.niveau.toon];\n return (\n <details className=\"rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm\">\n <summary className=\"flex cursor-pointer select-none flex-wrap items-center gap-x-3 gap-y-1\">\n <span className=\"font-medium text-slate-800\">{titel}</span>\n <span\n className=\"inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium\"\n style={{ background: `${kleur}14`, color: kleur }}\n >\n <span aria-hidden className=\"inline-block h-2 w-2 rounded-full\" style={{ background: kleur }} />\n {r.niveau.naam} · {r.score}/100\n </span>\n <span className=\"text-xs text-slate-500\">\n {r.woorden} woorden · ca. {r.leestijd} min lezen\n </span>\n {r.tips.length > 0 && <span className=\"text-xs text-slate-600\">· {r.tips.length} {r.tips.length === 1 ? \"tip\" : \"tips\"}</span>}\n </summary>\n <div className=\"mt-3 grid gap-3\">\n <div>\n <div className=\"relative h-2 overflow-hidden rounded-full bg-slate-100\" role=\"meter\" aria-valuemin={0} aria-valuemax={100} aria-valuenow={r.score} aria-label=\"Leesbaarheidsscore\">\n <div className=\"absolute inset-y-0 left-0 rounded-full\" style={{ width: `${r.score}%`, background: kleur }} />\n </div>\n <div className=\"mt-1 flex justify-between text-[11px] text-slate-500\">\n <span>moeilijk</span>\n <span>B1 (streven)</span>\n <span>makkelijk</span>\n </div>\n </div>\n <p className=\"text-xs text-slate-600\">{r.niveau.uitleg}</p>\n <dl className=\"grid grid-cols-2 gap-2 text-xs sm:grid-cols-4\">\n {[\n [\"Woorden\", r.woorden],\n [\"Zinnen\", r.zinnen],\n [\"Woorden per zin\", r.woordenPerZin],\n [\"Leestijd\", `${r.leestijd} min`],\n ].map(([k, v]) => (\n <div key={String(k)} className=\"rounded-md bg-slate-50 px-2 py-1.5\">\n <dt className=\"text-slate-500\">{k}</dt>\n <dd className=\"font-medium text-slate-800\">{v}</dd>\n </div>\n ))}\n </dl>\n {r.tips.length > 0 && (\n <ul className=\"grid list-disc gap-1 pl-5 text-xs text-slate-700\">\n {r.tips.map((t, i) => (\n <li key={i}>{t}</li>\n ))}\n </ul>\n )}\n <p className=\"text-[11px] text-slate-500\">Een indicatie (Flesch-Douma), geen oordeel: korte zinnen en gewone woorden lezen het prettigst.</p>\n </div>\n </details>\n );\n}\n"],"mappings":";AAoBQ,cACA,YADA;AAlBR,SAAS,kBAAkB,eAAe;AAC1C,SAAS,eAAe,wBAAwB;AAEhD,MAAM,QAAQ,EAAE,MAAM,WAAW,OAAO,WAAW,QAAQ,UAAU;AAO9D,SAAS,mBAAmB,EAAE,MAAM,OAAO,QAAQ,eAAe,GAAsD;AAC7H,QAAM,OAAO,iBAAiB,SAAS,cAAc,QAAQ,EAAE,CAAC;AAChE,QAAM,IAAI,QAAQ,MAAM,iBAAiB,IAAI,GAAG,CAAC,IAAI,CAAC;AACtD,MAAI,EAAE,YAAY,EAAG,QAAO;AAC5B,QAAM,QAAQ,MAAM,EAAE,OAAO,IAAI;AACjC,SACE,qBAAC,aAAQ,WAAU,iEACjB;AAAA,yBAAC,aAAQ,WAAU,0EACjB;AAAA,0BAAC,UAAK,WAAU,8BAA8B,iBAAM;AAAA,MACpD;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO,EAAE,YAAY,GAAG,KAAK,MAAM,OAAO,MAAM;AAAA,UAEhD;AAAA,gCAAC,UAAK,eAAW,MAAC,WAAU,qCAAoC,OAAO,EAAE,YAAY,MAAM,GAAG;AAAA,YAC7F,EAAE,OAAO;AAAA,YAAK;AAAA,YAAI,EAAE;AAAA,YAAM;AAAA;AAAA;AAAA,MAC7B;AAAA,MACA,qBAAC,UAAK,WAAU,0BACb;AAAA,UAAE;AAAA,QAAQ;AAAA,QAAgB,EAAE;AAAA,QAAS;AAAA,SACxC;AAAA,MACC,EAAE,KAAK,SAAS,KAAK,qBAAC,UAAK,WAAU,0BAAyB;AAAA;AAAA,QAAG,EAAE,KAAK;AAAA,QAAO;AAAA,QAAE,EAAE,KAAK,WAAW,IAAI,QAAQ;AAAA,SAAO;AAAA,OACzH;AAAA,IACA,qBAAC,SAAI,WAAU,mBACb;AAAA,2BAAC,SACC;AAAA,4BAAC,SAAI,WAAU,0DAAyD,MAAK,SAAQ,iBAAe,GAAG,iBAAe,KAAK,iBAAe,EAAE,OAAO,cAAW,sBAC5J,8BAAC,SAAI,WAAU,0CAAyC,OAAO,EAAE,OAAO,GAAG,EAAE,KAAK,KAAK,YAAY,MAAM,GAAG,GAC9G;AAAA,QACA,qBAAC,SAAI,WAAU,wDACb;AAAA,8BAAC,UAAK,sBAAQ;AAAA,UACd,oBAAC,UAAK,0BAAY;AAAA,UAClB,oBAAC,UAAK,uBAAS;AAAA,WACjB;AAAA,SACF;AAAA,MACA,oBAAC,OAAE,WAAU,0BAA0B,YAAE,OAAO,QAAO;AAAA,MACvD,oBAAC,QAAG,WAAU,iDACX;AAAA,QACC,CAAC,WAAW,EAAE,OAAO;AAAA,QACrB,CAAC,UAAU,EAAE,MAAM;AAAA,QACnB,CAAC,mBAAmB,EAAE,aAAa;AAAA,QACnC,CAAC,YAAY,GAAG,EAAE,QAAQ,MAAM;AAAA,MAClC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MACV,qBAAC,SAAoB,WAAU,sCAC7B;AAAA,4BAAC,QAAG,WAAU,kBAAkB,aAAE;AAAA,QAClC,oBAAC,QAAG,WAAU,8BAA8B,aAAE;AAAA,WAFtC,OAAO,CAAC,CAGlB,CACD,GACH;AAAA,MACC,EAAE,KAAK,SAAS,KACf,oBAAC,QAAG,WAAU,oDACX,YAAE,KAAK,IAAI,CAAC,GAAG,MACd,oBAAC,QAAY,eAAJ,CAAM,CAChB,GACH;AAAA,MAEF,oBAAC,OAAE,WAAU,8BAA6B,6GAA+F;AAAA,OAC3I;AAAA,KACF;AAEJ;","names":[]}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Link plaatsen of wijzigen (8.2). Verving `window.prompt("Link-URL")` in de inline editor en de
3
+ * rich-text-editor: geen keuze uit eigen pagina's (dus typefouten → 404), niet te stijlen, en op
4
+ * een telefoon nauwelijks bruikbaar. Hier kies je een pagina van de site, of typ je een webadres
5
+ * of e-mailadres; "www.voorbeeld.nl" wordt vanzelf "https://www.voorbeeld.nl".
6
+ */
7
+ export declare function LinkDialog({ open, onOpenChange, siteId, huidig, huidigNieuwTabblad, onKlaar, }: {
8
+ open: boolean;
9
+ onOpenChange: (v: boolean) => void;
10
+ /** Zonder siteId (bv. een editor buiten een site) alleen het webadres-tabblad. */
11
+ siteId?: string;
12
+ /** De link die er nu staat (leeg = nieuwe link). */
13
+ huidig?: string;
14
+ /** Opende de bestaande link in een nieuw tabblad? */
15
+ huidigNieuwTabblad?: boolean;
16
+ /** `null` = link weghalen. */
17
+ onKlaar: (href: string | null, opties?: {
18
+ nieuwTabblad: boolean;
19
+ }) => void;
20
+ }): import("react").JSX.Element;
21
+ /** "www.x.nl" → "https://www.x.nl", "a@b.nl" → "mailto:a@b.nl"; gevaarlijke schema's weigeren. */
22
+ export declare function normaliseerAdres(ruw: string): string;
@@ -0,0 +1,131 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useMemo, useState } from "react";
4
+ import { subscribePages } from "../lib/pagesClient.js";
5
+ import { Dialog, DialogContent, DialogFooter } from "./dialog.js";
6
+ import { Button, Field, Input } from "./primitives.js";
7
+ import { Select } from "./select.js";
8
+ import { Switch } from "./switch.js";
9
+ function LinkDialog({
10
+ open,
11
+ onOpenChange,
12
+ siteId,
13
+ huidig,
14
+ huidigNieuwTabblad,
15
+ onKlaar
16
+ }) {
17
+ const [pages, setPages] = useState([]);
18
+ useEffect(() => open && siteId ? subscribePages(siteId, setPages) : void 0, [open, siteId]);
19
+ const [soort, setSoort] = useState("pagina");
20
+ const [pad, setPad] = useState("");
21
+ const [adres, setAdres] = useState("");
22
+ const [fout, setFout] = useState(null);
23
+ const [nieuwTabblad, setNieuwTabblad] = useState(false);
24
+ const [tabbladAangeraakt, setTabbladAangeraakt] = useState(false);
25
+ useEffect(() => {
26
+ if (!open) return;
27
+ setFout(null);
28
+ setTabbladAangeraakt(huidigNieuwTabblad !== void 0 && Boolean(huidig));
29
+ setNieuwTabblad(Boolean(huidigNieuwTabblad));
30
+ const h = huidig?.trim() ?? "";
31
+ if (siteId && (h === "" || h.startsWith("/") && !h.startsWith("//"))) {
32
+ setSoort("pagina");
33
+ setPad(h);
34
+ setAdres("");
35
+ } else {
36
+ setSoort("adres");
37
+ setPad("");
38
+ setAdres(h);
39
+ }
40
+ }, [open, huidig, siteId, huidigNieuwTabblad]);
41
+ useEffect(() => {
42
+ if (!tabbladAangeraakt) setNieuwTabblad(soort === "adres" && !/^(mailto|tel):/i.test(adres.trim()));
43
+ }, [soort, adres, tabbladAangeraakt]);
44
+ const opties = useMemo(() => {
45
+ const o = pages.filter((p) => !p.trashed).sort((a, b) => a.path < b.path ? -1 : 1).map((p) => ({ value: p.path, label: `${p.title || p.path} (${p.path})${p.published ? "" : " \u2014 nog niet live"}` }));
46
+ if (pad && !o.some((x) => x.value === pad)) o.unshift({ value: pad, label: pad });
47
+ return o;
48
+ }, [pages, pad]);
49
+ function plaats() {
50
+ const href = soort === "pagina" ? pad : normaliseerAdres(adres);
51
+ if (!href) {
52
+ setFout(soort === "pagina" ? "Kies een pagina." : "Vul een webadres of e-mailadres in.");
53
+ return;
54
+ }
55
+ onKlaar(href, { nieuwTabblad: nieuwTabblad && !/^(mailto|tel):/i.test(href) });
56
+ onOpenChange(false);
57
+ }
58
+ return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsx(DialogContent, { title: huidig ? "Link wijzigen" : "Link plaatsen", children: /* @__PURE__ */ jsxs(
59
+ "form",
60
+ {
61
+ className: "grid gap-3",
62
+ onSubmit: (e) => {
63
+ e.preventDefault();
64
+ plaats();
65
+ },
66
+ children: [
67
+ siteId && /* @__PURE__ */ jsx("div", { role: "radiogroup", "aria-label": "Soort link", className: "flex flex-wrap gap-2", children: [
68
+ ["pagina", "Pagina op deze site"],
69
+ ["adres", "Webadres of e-mail"]
70
+ ].map(([k, label]) => /* @__PURE__ */ jsx(
71
+ "button",
72
+ {
73
+ type: "button",
74
+ role: "radio",
75
+ "aria-checked": soort === k,
76
+ onClick: () => setSoort(k),
77
+ className: "xicms-admin-btn rounded-lg border px-3 py-1.5 text-sm aria-[checked=true]:border-transparent aria-[checked=true]:bg-slate-900 aria-[checked=true]:text-white",
78
+ style: { borderColor: "var(--color-border)" },
79
+ children: label
80
+ },
81
+ k
82
+ )) }),
83
+ soort === "pagina" ? /* @__PURE__ */ jsx(Field, { label: "Pagina", children: /* @__PURE__ */ jsx(Select, { value: pad, onValueChange: setPad, options: opties, placeholder: "Kies een pagina\u2026" }) }) : /* @__PURE__ */ jsx(Field, { label: "Adres", hint: "bv. www.voorbeeld.nl of naam@voorbeeld.nl", children: /* @__PURE__ */ jsx(Input, { value: adres, onChange: (e) => setAdres(e.target.value), placeholder: "www.voorbeeld.nl", autoFocus: true }) }),
84
+ /* @__PURE__ */ jsx(
85
+ Switch,
86
+ {
87
+ checked: nieuwTabblad,
88
+ onCheckedChange: (v) => {
89
+ setTabbladAangeraakt(true);
90
+ setNieuwTabblad(v);
91
+ },
92
+ label: "Openen in een nieuw tabblad"
93
+ }
94
+ ),
95
+ fout && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-sm text-red-700", children: fout }),
96
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
97
+ huidig && /* @__PURE__ */ jsx(
98
+ Button,
99
+ {
100
+ type: "button",
101
+ variant: "dangerGhost",
102
+ className: "mr-auto",
103
+ onClick: () => {
104
+ onKlaar(null);
105
+ onOpenChange(false);
106
+ },
107
+ children: "Link weghalen"
108
+ }
109
+ ),
110
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", onClick: () => onOpenChange(false), children: "Annuleren" }),
111
+ /* @__PURE__ */ jsx(Button, { type: "submit", children: huidig ? "Wijzigen" : "Link plaatsen" })
112
+ ] })
113
+ ]
114
+ }
115
+ ) }) });
116
+ }
117
+ function normaliseerAdres(ruw) {
118
+ const a = ruw.trim();
119
+ if (!a) return "";
120
+ if (/^(javascript|data|vbscript):/i.test(a)) return "";
121
+ if (/^(https?:|mailto:|tel:)/i.test(a)) return a;
122
+ if (a.startsWith("/") || a.startsWith("#")) return a;
123
+ if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(a)) return `mailto:${a}`;
124
+ if (/^\+?[\d\s()-]{6,}$/.test(a)) return `tel:${a.replace(/[^\d+]/g, "")}`;
125
+ return `https://${a}`;
126
+ }
127
+ export {
128
+ LinkDialog,
129
+ normaliseerAdres
130
+ };
131
+ //# sourceMappingURL=LinkDialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/admin/ui/LinkDialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport { subscribePages, type DraftPage } from \"../lib/pagesClient\";\nimport { Dialog, DialogContent, DialogFooter } from \"./dialog\";\nimport { Button, Field, Input } from \"./primitives\";\nimport { Select } from \"./select\";\nimport { Switch } from \"./switch\";\n\n/**\n * Link plaatsen of wijzigen (8.2). Verving `window.prompt(\"Link-URL\")` in de inline editor en de\n * rich-text-editor: geen keuze uit eigen pagina's (dus typefouten → 404), niet te stijlen, en op\n * een telefoon nauwelijks bruikbaar. Hier kies je een pagina van de site, of typ je een webadres\n * of e-mailadres; \"www.voorbeeld.nl\" wordt vanzelf \"https://www.voorbeeld.nl\".\n */\nexport function LinkDialog({\n open,\n onOpenChange,\n siteId,\n huidig,\n huidigNieuwTabblad,\n onKlaar,\n}: {\n open: boolean;\n onOpenChange: (v: boolean) => void;\n /** Zonder siteId (bv. een editor buiten een site) alleen het webadres-tabblad. */\n siteId?: string;\n /** De link die er nu staat (leeg = nieuwe link). */\n huidig?: string;\n /** Opende de bestaande link in een nieuw tabblad? */\n huidigNieuwTabblad?: boolean;\n /** `null` = link weghalen. */\n onKlaar: (href: string | null, opties?: { nieuwTabblad: boolean }) => void;\n}) {\n const [pages, setPages] = useState<DraftPage[]>([]);\n useEffect(() => (open && siteId ? subscribePages(siteId, setPages) : undefined), [open, siteId]);\n\n const [soort, setSoort] = useState<\"pagina\" | \"adres\">(\"pagina\");\n const [pad, setPad] = useState(\"\");\n const [adres, setAdres] = useState(\"\");\n const [fout, setFout] = useState<string | null>(null);\n /**\n * In een nieuw tabblad openen (8.5, naar het voorbeeld van AstraCMS' linkvenster). Standaard: aan\n * voor een link naar een andere site, uit voor een eigen pagina — zelf om te zetten.\n */\n const [nieuwTabblad, setNieuwTabblad] = useState(false);\n const [tabbladAangeraakt, setTabbladAangeraakt] = useState(false);\n\n // Bij openen: de bestaande link in het juiste tabblad zetten.\n useEffect(() => {\n if (!open) return;\n setFout(null);\n setTabbladAangeraakt(huidigNieuwTabblad !== undefined && Boolean(huidig));\n setNieuwTabblad(Boolean(huidigNieuwTabblad));\n const h = huidig?.trim() ?? \"\";\n if (siteId && (h === \"\" || (h.startsWith(\"/\") && !h.startsWith(\"//\")))) {\n setSoort(\"pagina\");\n setPad(h);\n setAdres(\"\");\n } else {\n setSoort(\"adres\");\n setPad(\"\");\n setAdres(h);\n }\n }, [open, huidig, siteId, huidigNieuwTabblad]);\n\n // Volgt de soort, tot de gebruiker de schakelaar zelf omzet.\n useEffect(() => {\n if (!tabbladAangeraakt) setNieuwTabblad(soort === \"adres\" && !/^(mailto|tel):/i.test(adres.trim()));\n }, [soort, adres, tabbladAangeraakt]);\n\n const opties = useMemo(() => {\n const o = pages\n .filter((p) => !p.trashed)\n .sort((a, b) => (a.path < b.path ? -1 : 1))\n .map((p) => ({ value: p.path, label: `${p.title || p.path} (${p.path})${p.published ? \"\" : \" — nog niet live\"}` }));\n if (pad && !o.some((x) => x.value === pad)) o.unshift({ value: pad, label: pad });\n return o;\n }, [pages, pad]);\n\n function plaats() {\n const href = soort === \"pagina\" ? pad : normaliseerAdres(adres);\n if (!href) {\n setFout(soort === \"pagina\" ? \"Kies een pagina.\" : \"Vul een webadres of e-mailadres in.\");\n return;\n }\n onKlaar(href, { nieuwTabblad: nieuwTabblad && !/^(mailto|tel):/i.test(href) });\n onOpenChange(false);\n }\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent title={huidig ? \"Link wijzigen\" : \"Link plaatsen\"}>\n <form\n className=\"grid gap-3\"\n onSubmit={(e) => {\n e.preventDefault();\n plaats();\n }}\n >\n {siteId && (\n <div role=\"radiogroup\" aria-label=\"Soort link\" className=\"flex flex-wrap gap-2\">\n {(\n [\n [\"pagina\", \"Pagina op deze site\"],\n [\"adres\", \"Webadres of e-mail\"],\n ] as const\n ).map(([k, label]) => (\n <button\n key={k}\n type=\"button\"\n role=\"radio\"\n aria-checked={soort === k}\n onClick={() => setSoort(k)}\n className=\"xicms-admin-btn rounded-lg border px-3 py-1.5 text-sm aria-[checked=true]:border-transparent aria-[checked=true]:bg-slate-900 aria-[checked=true]:text-white\"\n style={{ borderColor: \"var(--color-border)\" }}\n >\n {label}\n </button>\n ))}\n </div>\n )}\n {soort === \"pagina\" ? (\n <Field label=\"Pagina\">\n <Select value={pad} onValueChange={setPad} options={opties} placeholder=\"Kies een pagina…\" />\n </Field>\n ) : (\n <Field label=\"Adres\" hint=\"bv. www.voorbeeld.nl of naam@voorbeeld.nl\">\n <Input value={adres} onChange={(e) => setAdres(e.target.value)} placeholder=\"www.voorbeeld.nl\" autoFocus />\n </Field>\n )}\n <Switch\n checked={nieuwTabblad}\n onCheckedChange={(v) => {\n setTabbladAangeraakt(true);\n setNieuwTabblad(v);\n }}\n label=\"Openen in een nieuw tabblad\"\n />\n {fout && (\n <p role=\"alert\" className=\"text-sm text-red-700\">\n {fout}\n </p>\n )}\n <DialogFooter>\n {huidig && (\n <Button\n type=\"button\"\n variant=\"dangerGhost\"\n className=\"mr-auto\"\n onClick={() => {\n onKlaar(null);\n onOpenChange(false);\n }}\n >\n Link weghalen\n </Button>\n )}\n <Button type=\"button\" variant=\"secondary\" onClick={() => onOpenChange(false)}>\n Annuleren\n </Button>\n <Button type=\"submit\">{huidig ? \"Wijzigen\" : \"Link plaatsen\"}</Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n\n/** \"www.x.nl\" → \"https://www.x.nl\", \"a@b.nl\" → \"mailto:a@b.nl\"; gevaarlijke schema's weigeren. */\nexport function normaliseerAdres(ruw: string): string {\n const a = ruw.trim();\n if (!a) return \"\";\n if (/^(javascript|data|vbscript):/i.test(a)) return \"\";\n if (/^(https?:|mailto:|tel:)/i.test(a)) return a;\n if (a.startsWith(\"/\") || a.startsWith(\"#\")) return a;\n if (/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(a)) return `mailto:${a}`;\n if (/^\\+?[\\d\\s()-]{6,}$/.test(a)) return `tel:${a.replace(/[^\\d+]/g, \"\")}`;\n return `https://${a}`;\n}\n"],"mappings":";AA4Gc,cAoCJ,YApCI;AA1Gd,SAAS,WAAW,SAAS,gBAAgB;AAC7C,SAAS,sBAAsC;AAC/C,SAAS,QAAQ,eAAe,oBAAoB;AACpD,SAAS,QAAQ,OAAO,aAAa;AACrC,SAAS,cAAc;AACvB,SAAS,cAAc;AAQhB,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAWG;AACD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAsB,CAAC,CAAC;AAClD,YAAU,MAAO,QAAQ,SAAS,eAAe,QAAQ,QAAQ,IAAI,QAAY,CAAC,MAAM,MAAM,CAAC;AAE/F,QAAM,CAAC,OAAO,QAAQ,IAAI,SAA6B,QAAQ;AAC/D,QAAM,CAAC,KAAK,MAAM,IAAI,SAAS,EAAE;AACjC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,QAAM,CAAC,MAAM,OAAO,IAAI,SAAwB,IAAI;AAKpD,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,KAAK;AACtD,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,SAAS,KAAK;AAGhE,YAAU,MAAM;AACd,QAAI,CAAC,KAAM;AACX,YAAQ,IAAI;AACZ,yBAAqB,uBAAuB,UAAa,QAAQ,MAAM,CAAC;AACxE,oBAAgB,QAAQ,kBAAkB,CAAC;AAC3C,UAAM,IAAI,QAAQ,KAAK,KAAK;AAC5B,QAAI,WAAW,MAAM,MAAO,EAAE,WAAW,GAAG,KAAK,CAAC,EAAE,WAAW,IAAI,IAAK;AACtE,eAAS,QAAQ;AACjB,aAAO,CAAC;AACR,eAAS,EAAE;AAAA,IACb,OAAO;AACL,eAAS,OAAO;AAChB,aAAO,EAAE;AACT,eAAS,CAAC;AAAA,IACZ;AAAA,EACF,GAAG,CAAC,MAAM,QAAQ,QAAQ,kBAAkB,CAAC;AAG7C,YAAU,MAAM;AACd,QAAI,CAAC,kBAAmB,iBAAgB,UAAU,WAAW,CAAC,kBAAkB,KAAK,MAAM,KAAK,CAAC,CAAC;AAAA,EACpG,GAAG,CAAC,OAAO,OAAO,iBAAiB,CAAC;AAEpC,QAAM,SAAS,QAAQ,MAAM;AAC3B,UAAM,IAAI,MACP,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,EACxB,KAAK,CAAC,GAAG,MAAO,EAAE,OAAO,EAAE,OAAO,KAAK,CAAE,EACzC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,GAAG,EAAE,SAAS,EAAE,IAAI,KAAK,EAAE,IAAI,IAAI,EAAE,YAAY,KAAK,uBAAkB,GAAG,EAAE;AACpH,QAAI,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,EAAG,GAAE,QAAQ,EAAE,OAAO,KAAK,OAAO,IAAI,CAAC;AAChF,WAAO;AAAA,EACT,GAAG,CAAC,OAAO,GAAG,CAAC;AAEf,WAAS,SAAS;AAChB,UAAM,OAAO,UAAU,WAAW,MAAM,iBAAiB,KAAK;AAC9D,QAAI,CAAC,MAAM;AACT,cAAQ,UAAU,WAAW,qBAAqB,qCAAqC;AACvF;AAAA,IACF;AACA,YAAQ,MAAM,EAAE,cAAc,gBAAgB,CAAC,kBAAkB,KAAK,IAAI,EAAE,CAAC;AAC7E,iBAAa,KAAK;AAAA,EACpB;AAEA,SACE,oBAAC,UAAO,MAAY,cAClB,8BAAC,iBAAc,OAAO,SAAS,kBAAkB,iBAC/C;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,UAAU,CAAC,MAAM;AACf,UAAE,eAAe;AACjB,eAAO;AAAA,MACT;AAAA,MAEC;AAAA,kBACD,oBAAC,SAAI,MAAK,cAAa,cAAW,cAAa,WAAU,wBAErD;AAAA,UACE,CAAC,UAAU,qBAAqB;AAAA,UAChC,CAAC,SAAS,oBAAoB;AAAA,QAChC,EACA,IAAI,CAAC,CAAC,GAAG,KAAK,MACd;AAAA,UAAC;AAAA;AAAA,YAEC,MAAK;AAAA,YACL,MAAK;AAAA,YACL,gBAAc,UAAU;AAAA,YACxB,SAAS,MAAM,SAAS,CAAC;AAAA,YACzB,WAAU;AAAA,YACV,OAAO,EAAE,aAAa,sBAAsB;AAAA,YAE3C;AAAA;AAAA,UARI;AAAA,QASP,CACD,GACH;AAAA,QAEC,UAAU,WACT,oBAAC,SAAM,OAAM,UACX,8BAAC,UAAO,OAAO,KAAK,eAAe,QAAQ,SAAS,QAAQ,aAAY,yBAAmB,GAC7F,IAEA,oBAAC,SAAM,OAAM,SAAQ,MAAK,6CACxB,8BAAC,SAAM,OAAO,OAAO,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK,GAAG,aAAY,oBAAmB,WAAS,MAAC,GAC3G;AAAA,QAEF;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,iBAAiB,CAAC,MAAM;AACtB,mCAAqB,IAAI;AACzB,8BAAgB,CAAC;AAAA,YACnB;AAAA,YACA,OAAM;AAAA;AAAA,QACR;AAAA,QACC,QACC,oBAAC,OAAE,MAAK,SAAQ,WAAU,wBACvB,gBACH;AAAA,QAEF,qBAAC,gBACE;AAAA,oBACC;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,WAAU;AAAA,cACV,SAAS,MAAM;AACb,wBAAQ,IAAI;AACZ,6BAAa,KAAK;AAAA,cACpB;AAAA,cACD;AAAA;AAAA,UAED;AAAA,UAEF,oBAAC,UAAO,MAAK,UAAS,SAAQ,aAAY,SAAS,MAAM,aAAa,KAAK,GAAG,uBAE9E;AAAA,UACA,oBAAC,UAAO,MAAK,UAAU,mBAAS,aAAa,iBAAgB;AAAA,WAC/D;AAAA;AAAA;AAAA,EACF,GACF,GACF;AAEJ;AAGO,SAAS,iBAAiB,KAAqB;AACpD,QAAM,IAAI,IAAI,KAAK;AACnB,MAAI,CAAC,EAAG,QAAO;AACf,MAAI,gCAAgC,KAAK,CAAC,EAAG,QAAO;AACpD,MAAI,2BAA2B,KAAK,CAAC,EAAG,QAAO;AAC/C,MAAI,EAAE,WAAW,GAAG,KAAK,EAAE,WAAW,GAAG,EAAG,QAAO;AACnD,MAAI,6BAA6B,KAAK,CAAC,EAAG,QAAO,UAAU,CAAC;AAC5D,MAAI,qBAAqB,KAAK,CAAC,EAAG,QAAO,OAAO,EAAE,QAAQ,WAAW,EAAE,CAAC;AACxE,SAAO,WAAW,CAAC;AACrB;","names":[]}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Een linkveld zoals een klant het leest (8.10): "Contact (/contact)" of "www.voorbeeld.nl", met
3
+ * "Kies…" ernaast dat het linkvenster opent — pagina uit de lijst, of een webadres/e-mail/telefoon.
4
+ *
5
+ * Vervangt de kale tekstvakken bij knoppen in de hero, de oproepbalk, de footer en de automatisch
6
+ * gegenereerde formulieren. Daar typte je "/contakt" of liet je "#" staan, en de knop deed niets of
7
+ * gaf een 404; de controle vóór publiceren ving dat pas achteraf.
8
+ */
9
+ export declare function LinkVeld({ siteId, value, onChange, leegTekst, }: {
10
+ siteId?: string;
11
+ value: string | undefined;
12
+ onChange: (href: string) => void;
13
+ leegTekst?: string;
14
+ }): import("react").JSX.Element;
@@ -0,0 +1,49 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useState } from "react";
4
+ import { subscribePages } from "../lib/pagesClient.js";
5
+ import { LinkDialog } from "./LinkDialog.js";
6
+ import { Button } from "./primitives.js";
7
+ function LinkVeld({
8
+ siteId,
9
+ value,
10
+ onChange,
11
+ leegTekst = "Nog geen link"
12
+ }) {
13
+ const [open, setOpen] = useState(false);
14
+ const [pages, setPages] = useState([]);
15
+ useEffect(() => siteId ? subscribePages(siteId, setPages) : void 0, [siteId]);
16
+ const href = (value ?? "").trim();
17
+ const pagina = href.startsWith("/") ? pages.find((p) => !p.trashed && p.path === href.split(/[?#]/)[0]) : void 0;
18
+ const leeg = !href || href === "#";
19
+ const tekst = leeg ? leegTekst : pagina ? `${pagina.title || pagina.path} (${href})` : href.replace(/^https?:\/\//, "").replace(/^mailto:/, "e-mail: ").replace(/^tel:/, "bel: ");
20
+ const waarschuwing = pagina && !pagina.published ? "Deze pagina staat nog niet live." : null;
21
+ return /* @__PURE__ */ jsxs("div", { className: "grid gap-1", children: [
22
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
23
+ /* @__PURE__ */ jsx(
24
+ "span",
25
+ {
26
+ className: `min-w-0 flex-1 truncate rounded-md border border-slate-200 bg-white px-2.5 py-1.5 text-sm ${leeg ? "text-slate-500 italic" : "text-slate-800"}`,
27
+ title: href || void 0,
28
+ children: tekst
29
+ }
30
+ ),
31
+ /* @__PURE__ */ jsx(Button, { size: "sm", variant: "secondary", onClick: () => setOpen(true), children: leeg ? "Kies\u2026" : "Wijzig\u2026" })
32
+ ] }),
33
+ waarschuwing && /* @__PURE__ */ jsx("p", { className: "text-xs text-amber-700", children: waarschuwing }),
34
+ /* @__PURE__ */ jsx(
35
+ LinkDialog,
36
+ {
37
+ open,
38
+ onOpenChange: setOpen,
39
+ siteId,
40
+ huidig: leeg ? "" : href,
41
+ onKlaar: (nieuw) => onChange(nieuw ?? "")
42
+ }
43
+ )
44
+ ] });
45
+ }
46
+ export {
47
+ LinkVeld
48
+ };
49
+ //# sourceMappingURL=LinkVeld.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/admin/ui/LinkVeld.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { subscribePages, type DraftPage } from \"../lib/pagesClient\";\nimport { LinkDialog } from \"./LinkDialog\";\nimport { Button } from \"./primitives\";\n\n/**\n * Een linkveld zoals een klant het leest (8.10): \"Contact (/contact)\" of \"www.voorbeeld.nl\", met\n * \"Kies…\" ernaast dat het linkvenster opent — pagina uit de lijst, of een webadres/e-mail/telefoon.\n *\n * Vervangt de kale tekstvakken bij knoppen in de hero, de oproepbalk, de footer en de automatisch\n * gegenereerde formulieren. Daar typte je \"/contakt\" of liet je \"#\" staan, en de knop deed niets of\n * gaf een 404; de controle vóór publiceren ving dat pas achteraf.\n */\nexport function LinkVeld({\n siteId,\n value,\n onChange,\n leegTekst = \"Nog geen link\",\n}: {\n siteId?: string;\n value: string | undefined;\n onChange: (href: string) => void;\n leegTekst?: string;\n}) {\n const [open, setOpen] = useState(false);\n const [pages, setPages] = useState<DraftPage[]>([]);\n useEffect(() => (siteId ? subscribePages(siteId, setPages) : undefined), [siteId]);\n\n const href = (value ?? \"\").trim();\n const pagina = href.startsWith(\"/\") ? pages.find((p) => !p.trashed && p.path === href.split(/[?#]/)[0]) : undefined;\n const leeg = !href || href === \"#\";\n const tekst = leeg\n ? leegTekst\n : pagina\n ? `${pagina.title || pagina.path} (${href})`\n : href.replace(/^https?:\\/\\//, \"\").replace(/^mailto:/, \"e-mail: \").replace(/^tel:/, \"bel: \");\n // Alleen \"nog niet live\": een pad zonder werkversie kan best bestaan (een pagina uit de sitecode,\n // de webwinkel, de demo) — \"bestaat niet\" zou dan een valse schrik zijn.\n const waarschuwing = pagina && !pagina.published ? \"Deze pagina staat nog niet live.\" : null;\n\n return (\n <div className=\"grid gap-1\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <span\n className={`min-w-0 flex-1 truncate rounded-md border border-slate-200 bg-white px-2.5 py-1.5 text-sm ${leeg ? \"text-slate-500 italic\" : \"text-slate-800\"}`}\n title={href || undefined}\n >\n {tekst}\n </span>\n <Button size=\"sm\" variant=\"secondary\" onClick={() => setOpen(true)}>\n {leeg ? \"Kies…\" : \"Wijzig…\"}\n </Button>\n </div>\n {waarschuwing && <p className=\"text-xs text-amber-700\">{waarschuwing}</p>}\n <LinkDialog\n open={open}\n onOpenChange={setOpen}\n siteId={siteId}\n huidig={leeg ? \"\" : href}\n onKlaar={(nieuw) => onChange(nieuw ?? \"\")}\n />\n </div>\n );\n}\n"],"mappings":";AA4CM,SACE,KADF;AA1CN,SAAS,WAAW,gBAAgB;AACpC,SAAS,sBAAsC;AAC/C,SAAS,kBAAkB;AAC3B,SAAS,cAAc;AAUhB,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AACd,GAKG;AACD,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAsB,CAAC,CAAC;AAClD,YAAU,MAAO,SAAS,eAAe,QAAQ,QAAQ,IAAI,QAAY,CAAC,MAAM,CAAC;AAEjF,QAAM,QAAQ,SAAS,IAAI,KAAK;AAChC,QAAM,SAAS,KAAK,WAAW,GAAG,IAAI,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,SAAS,KAAK,MAAM,MAAM,EAAE,CAAC,CAAC,IAAI;AAC1G,QAAM,OAAO,CAAC,QAAQ,SAAS;AAC/B,QAAM,QAAQ,OACV,YACA,SACE,GAAG,OAAO,SAAS,OAAO,IAAI,KAAK,IAAI,MACvC,KAAK,QAAQ,gBAAgB,EAAE,EAAE,QAAQ,YAAY,UAAU,EAAE,QAAQ,SAAS,OAAO;AAG/F,QAAM,eAAe,UAAU,CAAC,OAAO,YAAY,qCAAqC;AAExF,SACE,qBAAC,SAAI,WAAU,cACb;AAAA,yBAAC,SAAI,WAAU,mCACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,6FAA6F,OAAO,0BAA0B,gBAAgB;AAAA,UACzJ,OAAO,QAAQ;AAAA,UAEd;AAAA;AAAA,MACH;AAAA,MACA,oBAAC,UAAO,MAAK,MAAK,SAAQ,aAAY,SAAS,MAAM,QAAQ,IAAI,GAC9D,iBAAO,eAAU,gBACpB;AAAA,OACF;AAAA,IACC,gBAAgB,oBAAC,OAAE,WAAU,0BAA0B,wBAAa;AAAA,IACrE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,cAAc;AAAA,QACd;AAAA,QACA,QAAQ,OAAO,KAAK;AAAA,QACpB,SAAS,CAAC,UAAU,SAAS,SAAS,EAAE;AAAA;AAAA,IAC1C;AAAA,KACF;AAEJ;","names":[]}