@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
@@ -19,42 +19,16 @@ import { SnapshotsCard } from "./SnapshotsCard.js";
19
19
  import { MailSettings } from "./MailSettings.js";
20
20
  import { useAuth } from "../../auth/AuthProvider.js";
21
21
  import { MediaPickerButton } from "../media/MediaPicker.js";
22
- import { contrast, contrastOordeel, naarHex6, tekstOp, LETTERTYPE_PAREN } from "../lib/kleur.js";
23
- function KleurVeld({ label, hint, value, placeholder, onChange }) {
24
- return /* @__PURE__ */ jsx(Field, { label, hint, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
25
- /* @__PURE__ */ jsx(
26
- "input",
27
- {
28
- type: "color",
29
- "aria-label": `${label} kiezen`,
30
- value: naarHex6(value || placeholder, "#ffffff"),
31
- onChange: (e) => onChange(e.target.value),
32
- className: "h-9 w-11 shrink-0 cursor-pointer rounded-md border border-slate-200 bg-transparent p-0.5"
33
- }
34
- ),
35
- /* @__PURE__ */ jsx(Input, { value, placeholder, onChange: (e) => onChange(e.target.value) })
36
- ] }) });
37
- }
38
- function ContrastRegel({ primary, background }) {
39
- const knop = contrastOordeel(contrast(primary, tekstOp(primary)));
40
- const opAchtergrond = contrastOordeel(contrast(primary, background || "#ffffff"));
41
- if (!knop && !opAchtergrond) return null;
42
- const kleur = (t) => t === "goed" ? "text-emerald-700" : t === "matig" ? "text-amber-700" : "text-red-700";
43
- return /* @__PURE__ */ jsxs("div", { className: "grid gap-1 text-xs", children: [
44
- knop && /* @__PURE__ */ jsxs("p", { className: kleur(knop.toon), children: [
45
- "Knoptekst op merkkleur: ",
46
- knop.tekst.replace(/^Contrast /, "")
47
- ] }),
48
- opAchtergrond && /* @__PURE__ */ jsxs("p", { className: kleur(opAchtergrond.toon), children: [
49
- "Merkkleur als tekst op de achtergrond: ",
50
- opAchtergrond.tekst.replace(/^Contrast /, "")
51
- ] }),
52
- /* @__PURE__ */ jsxs("p", { className: "text-slate-500", children: [
53
- "Voorbeeld: ",
54
- /* @__PURE__ */ jsx("span", { className: "rounded-md px-2 py-0.5 font-medium", style: { background: primary, color: tekstOp(primary) }, children: "Knop" })
55
- ] })
56
- ] });
57
- }
22
+ import { gewisteVelden, metGewisteVelden } from "../lib/gewisteVelden.js";
23
+ import { useOnopgeslagen } from "../lib/onopgeslagen.js";
24
+ import { VorigeTerugzetten } from "./VorigeTerugzetten.js";
25
+ import { BedrijfInstellingen, KopInstellingen } from "./BedrijfInstellingen.js";
26
+ import { LinkVeld } from "../ui/LinkVeld.js";
27
+ import { zodFoutTekst } from "../lib/zodFout.js";
28
+ import { subscribePages } from "../lib/pagesClient.js";
29
+ import { isDemoActive } from "../../demo/demoStore.js";
30
+ import { ContrastRegel, KleurVeld } from "../ui/KleurVeld.js";
31
+ import { LETTERTYPE_PAREN } from "../lib/kleur.js";
58
32
  function SettingsPanel({ siteId }) {
59
33
  const { toast } = useToast();
60
34
  const confirm = useConfirm();
@@ -64,6 +38,15 @@ function SettingsPanel({ siteId }) {
64
38
  const technisch = role === "superadmin";
65
39
  const [s, setS] = useState({});
66
40
  const [loaded, setLoaded] = useState(false);
41
+ const opgeslagenRef = useRef({});
42
+ const basisRef = useRef(null);
43
+ const sRef = useRef(s);
44
+ sRef.current = s;
45
+ const [elders, setElders] = useState(null);
46
+ const [laadFout, setLaadFout] = useState(null);
47
+ const [bezig, setBezig] = useState(false);
48
+ const nietOpgeslagen = loaded && basisRef.current !== null && JSON.stringify(s) !== JSON.stringify(basisRef.current);
49
+ useOnopgeslagen(nietOpgeslagen);
67
50
  const [exporting, setExporting] = useState(false);
68
51
  const [restoring, setRestoring] = useState(false);
69
52
  const restoreInput = useRef(null);
@@ -136,6 +119,11 @@ function SettingsPanel({ siteId }) {
136
119
  }
137
120
  }
138
121
  const [sectie, setSectie] = useState("algemeen");
122
+ const [livePaden, setLivePaden] = useState(null);
123
+ useEffect(() => {
124
+ if (sectie !== "redirects" || isDemoActive()) return;
125
+ return subscribePages(siteId, (p) => setLivePaden(new Set(p.filter((x) => x.published && !x.trashed).map((x) => x.path.replace(/\/+$/, "") || "/"))));
126
+ }, [sectie, siteId]);
139
127
  useEffect(() => {
140
128
  const db = getDb();
141
129
  if (!db) {
@@ -144,34 +132,67 @@ function SettingsPanel({ siteId }) {
144
132
  }
145
133
  return onSnapshot(doc(db, "sites", siteId, "settings", "site"), (snap) => {
146
134
  const uitDb = snap.exists() ? snap.data() : {};
147
- setS({
135
+ opgeslagenRef.current = uitDb;
136
+ const volgend = {
148
137
  ...uitDb,
149
138
  name: uitDb.name ?? cfg.name,
150
139
  domain: uitDb.domain ?? cfg.domain,
151
- contactEmail: uitDb.contactEmail ?? cfg.contactEmail
152
- });
140
+ contactEmail: uitDb.contactEmail ?? cfg.contactEmail,
141
+ // 8.13: ook het bedrijfsprofiel en de kop tonen wat de site nu gebruikt (startwaarde uit
142
+ // de site-config) — anders lijken ze leeg terwijl de site ze wél toont.
143
+ business: uitDb.business ?? cfg.business,
144
+ header: uitDb.header ?? cfg.header
145
+ };
146
+ if (basisRef.current !== null && JSON.stringify(sRef.current) !== JSON.stringify(basisRef.current)) {
147
+ setElders(volgend);
148
+ return;
149
+ }
150
+ basisRef.current = volgend;
151
+ setS(volgend);
152
+ setElders(null);
153
+ setLoaded(true);
154
+ }, (err) => {
153
155
  setLoaded(true);
156
+ if (isDemoActive()) {
157
+ const uitConfig = { name: cfg.name, domain: cfg.domain, contactEmail: cfg.contactEmail, business: cfg.business, header: cfg.header };
158
+ basisRef.current = uitConfig;
159
+ setS(uitConfig);
160
+ return;
161
+ }
162
+ console.error("[xicms] instellingen laden mislukt:", err);
163
+ setLaadFout(err.message);
154
164
  });
155
- }, [siteId, cfg.name, cfg.domain, cfg.contactEmail]);
165
+ }, [siteId, cfg.name, cfg.domain, cfg.contactEmail, cfg.business, cfg.header]);
156
166
  async function save() {
157
167
  const db = getDb();
158
168
  if (!db) return;
159
169
  const parsed = SiteSettingsSchema.safeParse(s);
160
170
  if (!parsed.success) {
161
- toast({ title: "Ongeldige instellingen", description: parsed.error.issues[0]?.message, tone: "error" });
171
+ toast({ title: "Nog niet op te slaan", description: zodFoutTekst(parsed.error.issues[0]), tone: "error" });
162
172
  return;
163
173
  }
174
+ setBezig(true);
164
175
  try {
165
176
  const app = getFirebaseApp();
166
177
  if (!app) throw new Error("Firebase is niet geconfigureerd.");
167
178
  const fn = callable(app, "saveSiteSettings");
168
- const res = await fn({ siteId, settings: parsed.data });
179
+ const res = await fn({ siteId, settings: metGewisteVelden(parsed.data, gewisteVelden(opgeslagenRef.current, s)) });
180
+ basisRef.current = s;
181
+ setElders(null);
169
182
  toast({ title: "Opgeslagen", description: res.data?.message ?? "Wijzigingen zijn live.", tone: "success" });
170
183
  } catch (e) {
171
184
  toast({ title: "Opslaan mislukt", description: e.message, tone: "error" });
185
+ } finally {
186
+ setBezig(false);
172
187
  }
173
188
  }
174
- if (!loaded) return /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500", children: "Laden\u2026" });
189
+ if (!loaded) return /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500", role: "status", children: "Instellingen laden\u2026" });
190
+ if (laadFout && basisRef.current === null) {
191
+ return /* @__PURE__ */ jsxs(Card, { children: [
192
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-red-700", role: "alert", children: "De instellingen konden niet geladen worden. Ververs de pagina; blijft dit gebeuren, neem dan contact op met Xi Webdesign." }),
193
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-slate-500", children: laadFout })
194
+ ] });
195
+ }
175
196
  const forms = s.forms ?? { mode: "xicms" };
176
197
  const theme = s.theme ?? { primary: "#4f46e5" };
177
198
  const donkerModus = theme.dark?.mode ?? (theme.dark?.auto ? "auto" : "light");
@@ -184,7 +205,9 @@ function SettingsPanel({ siteId }) {
184
205
  const setModule = (id, next) => setS({ ...s, modules: { ...s.modules, [id]: next } });
185
206
  const SECTIES = [
186
207
  { sleutel: "algemeen", label: "Algemeen" },
208
+ { sleutel: "bedrijf", label: "Bedrijf" },
187
209
  { sleutel: "huisstijl", label: "Huisstijl" },
210
+ { sleutel: "kop", label: "Kop" },
188
211
  { sleutel: "seo", label: "SEO" },
189
212
  { sleutel: "footer", label: "Footer" },
190
213
  { sleutel: "redirects", label: "Doorverwijzingen" },
@@ -207,6 +230,23 @@ function SettingsPanel({ siteId }) {
207
230
  },
208
231
  x.sleutel
209
232
  )) }),
233
+ elders && /* @__PURE__ */ jsxs("div", { role: "alert", className: "flex flex-wrap items-center gap-3 rounded-lg border border-amber-300 bg-amber-50 px-4 py-3 text-sm text-amber-900", children: [
234
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: "De instellingen zijn intussen ergens anders gewijzigd (in een ander tabblad, of door een collega)." }),
235
+ /* @__PURE__ */ jsx(
236
+ Button,
237
+ {
238
+ size: "sm",
239
+ variant: "secondary",
240
+ onClick: () => {
241
+ basisRef.current = elders;
242
+ setS(elders);
243
+ setElders(null);
244
+ },
245
+ children: "Nieuwste laden (mijn wijzigingen vervallen)"
246
+ }
247
+ ),
248
+ /* @__PURE__ */ jsx(Button, { size: "sm", variant: "ghost", onClick: () => setElders(null), children: "Mijn versie houden" })
249
+ ] }),
210
250
  sectie === "algemeen" && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Card, { children: [
211
251
  /* @__PURE__ */ jsx("h3", { className: "mb-3 text-base font-semibold", children: "Algemeen" }),
212
252
  /* @__PURE__ */ jsxs("div", { className: "grid gap-3 md:grid-cols-2", children: [
@@ -215,12 +255,15 @@ function SettingsPanel({ siteId }) {
215
255
  technisch ? /* @__PURE__ */ jsx(Field, { label: "Domein", hint: "Technisch: bepaalt inloglinks, sitemap en de revalidate-ping. Alleen superadmin.", children: /* @__PURE__ */ jsx(Input, { value: s.domain ?? "", onChange: (e) => setS({ ...s, domain: e.target.value }) }) }) : s.domain && /* @__PURE__ */ jsx(Field, { label: "Domein", children: /* @__PURE__ */ jsxs("p", { className: "text-sm text-slate-600", children: [
216
256
  s.domain,
217
257
  " ",
218
- /* @__PURE__ */ jsx("span", { className: "text-xs text-slate-400", children: "\u2014 wijzigen via XiWebdesign" })
258
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-slate-500", children: "\u2014 wijzigen via XiWebdesign" })
219
259
  ] }) })
220
260
  ] })
221
261
  ] }) }),
262
+ sectie === "bedrijf" && /* @__PURE__ */ jsx(BedrijfInstellingen, { siteId, waarde: s.business, onChange: (business) => setS({ ...s, business }), dirty: nietOpgeslagen }),
263
+ sectie === "kop" && /* @__PURE__ */ jsx(KopInstellingen, { siteId, waarde: s.header, onChange: (header) => setS({ ...s, header }), dirty: nietOpgeslagen }),
222
264
  sectie === "huisstijl" && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Card, { children: [
223
- /* @__PURE__ */ jsx("h3", { className: "mb-3 text-base font-semibold", children: "Huisstijl" }),
265
+ /* @__PURE__ */ jsx("h3", { className: "mb-1 text-base font-semibold", children: "Huisstijl" }),
266
+ /* @__PURE__ */ jsx("div", { className: "mb-3", children: /* @__PURE__ */ jsx(VorigeTerugzetten, { siteId, sleutel: "theme", dirty: nietOpgeslagen }) }),
224
267
  /* @__PURE__ */ jsxs("div", { className: "grid gap-3", children: [
225
268
  /* @__PURE__ */ jsx(Field, { label: "Thema-preset", hint: "Vult kleuren, lettertype en afronding in \xE9\xE9n keer in.", children: /* @__PURE__ */ jsx(
226
269
  Select,
@@ -240,7 +283,7 @@ function SettingsPanel({ siteId }) {
240
283
  /* @__PURE__ */ jsx(KleurVeld, { label: "Achtergrondkleur", value: theme.background ?? "", placeholder: "#ffffff", onChange: (v) => setS({ ...s, theme: { ...theme, background: v } }) }),
241
284
  /* @__PURE__ */ jsx(KleurVeld, { label: "Tekstkleur", value: theme.foreground ?? "", placeholder: "#0f172a", onChange: (v) => setS({ ...s, theme: { ...theme, foreground: v } }) })
242
285
  ] }),
243
- /* @__PURE__ */ jsx(ContrastRegel, { primary: theme.primary, background: theme.background }),
286
+ /* @__PURE__ */ jsx(ContrastRegel, { primary: theme.primary, background: theme.background, foreground: theme.foreground }),
244
287
  /* @__PURE__ */ jsx(Field, { label: "Lettertype", hint: "Een uitgekozen combinatie voor tekst en koppen. Geavanceerd: eigen fontFamily/fontUrl via de sitecode.", children: /* @__PURE__ */ jsx(
245
288
  Select,
246
289
  {
@@ -273,31 +316,21 @@ function SettingsPanel({ siteId }) {
273
316
  )
274
317
  }
275
318
  ),
276
- donkerModus !== "light" && /* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-3", children: [
277
- /* @__PURE__ */ jsx(Field, { label: "Donkere achtergrond", children: /* @__PURE__ */ jsx(
278
- Input,
279
- {
280
- value: theme.dark?.background ?? "",
281
- onChange: (e) => setS({ ...s, theme: { ...theme, dark: { ...theme.dark ?? {}, background: e.target.value } } }),
282
- placeholder: "#0f172a"
283
- }
284
- ) }),
285
- /* @__PURE__ */ jsx(Field, { label: "Donkere tekstkleur", children: /* @__PURE__ */ jsx(
286
- Input,
287
- {
288
- value: theme.dark?.foreground ?? "",
289
- onChange: (e) => setS({ ...s, theme: { ...theme, dark: { ...theme.dark ?? {}, foreground: e.target.value } } }),
290
- placeholder: "#e2e8f0"
291
- }
292
- ) }),
293
- /* @__PURE__ */ jsx(Field, { label: "Donkere merkkleur", hint: "Laat leeg om dezelfde te gebruiken.", children: /* @__PURE__ */ jsx(
294
- Input,
319
+ donkerModus !== "light" && /* @__PURE__ */ jsxs("div", { className: "grid gap-3", children: [
320
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-3", children: [
321
+ /* @__PURE__ */ jsx(KleurVeld, { label: "Donkere achtergrond", value: theme.dark?.background ?? "", placeholder: "#0f172a", onChange: (v) => setS({ ...s, theme: { ...theme, dark: { ...theme.dark ?? {}, background: v } } }) }),
322
+ /* @__PURE__ */ jsx(KleurVeld, { label: "Donkere tekstkleur", value: theme.dark?.foreground ?? "", placeholder: "#e2e8f0", onChange: (v) => setS({ ...s, theme: { ...theme, dark: { ...theme.dark ?? {}, foreground: v } } }) }),
323
+ /* @__PURE__ */ jsx(KleurVeld, { label: "Donkere merkkleur", hint: "Leeg = dezelfde als licht.", value: theme.dark?.primary ?? "", placeholder: theme.primary, onChange: (v) => setS({ ...s, theme: { ...theme, dark: { ...theme.dark ?? {}, primary: v } } }) })
324
+ ] }),
325
+ /* @__PURE__ */ jsx(
326
+ ContrastRegel,
295
327
  {
296
- value: theme.dark?.primary ?? "",
297
- onChange: (e) => setS({ ...s, theme: { ...theme, dark: { ...theme.dark ?? {}, primary: e.target.value } } }),
298
- placeholder: theme.primary
328
+ primary: theme.dark?.primary || theme.primary,
329
+ background: theme.dark?.background || "#0f172a",
330
+ foreground: theme.dark?.foreground || "#e2e8f0"
299
331
  }
300
- ) })
332
+ ),
333
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-amber-800", children: "Controleer na het opslaan je logo en foto's met een witte achtergrond: die vallen op een donkere site vaak weg." })
301
334
  ] }),
302
335
  /* @__PURE__ */ jsx(Field, { label: "Logo (e-mail & factuur)", hint: "PNG/JPG uit je mediabibliotheek. Verschijnt in de mail-header en op de factuur-PDF.", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
303
336
  theme.logo && // eslint-disable-next-line @next/next/no-img-element
@@ -321,7 +354,8 @@ function SettingsPanel({ siteId }) {
321
354
  ] }) }),
322
355
  sectie === "footer" && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Card, { children: [
323
356
  /* @__PURE__ */ jsx("h3", { className: "mb-1 text-base font-semibold", children: "Footer" }),
324
- /* @__PURE__ */ jsx("p", { className: "mb-3 text-xs text-slate-500", children: "Kolommen met links, social-links en copyright. Wijzigingen zijn direct live." }),
357
+ /* @__PURE__ */ jsx("p", { className: "mb-1 text-xs text-slate-500", children: "Kolommen met links, social-links en copyright. Wijzigingen zijn direct live." }),
358
+ /* @__PURE__ */ jsx("div", { className: "mb-3", children: /* @__PURE__ */ jsx(VorigeTerugzetten, { siteId, sleutel: "footer", dirty: nietOpgeslagen }) }),
325
359
  /* @__PURE__ */ jsxs("div", { className: "grid gap-4", children: [
326
360
  /* @__PURE__ */ jsxs("div", { children: [
327
361
  /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Kolommen" }),
@@ -342,9 +376,9 @@ function SettingsPanel({ siteId }) {
342
376
  onChange: (links) => update({ links }),
343
377
  newItem: () => ({ label: "", href: "" }),
344
378
  addLabel: "+ Link",
345
- renderRow: (link, updL) => /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
346
- /* @__PURE__ */ jsx(Input, { value: link.label, placeholder: "Label", onChange: (e) => updL({ label: e.target.value }) }),
347
- /* @__PURE__ */ jsx(Input, { value: link.href, placeholder: "/pad of https://\u2026", onChange: (e) => updL({ href: e.target.value }) })
379
+ renderRow: (link, updL) => /* @__PURE__ */ jsxs("div", { className: "grid gap-2 sm:grid-cols-2", children: [
380
+ /* @__PURE__ */ jsx(Input, { value: link.label, placeholder: "Tekst van de link", onChange: (e) => updL({ label: e.target.value }) }),
381
+ /* @__PURE__ */ jsx(LinkVeld, { siteId, value: link.href, onChange: (href) => updL({ href }) })
348
382
  ] })
349
383
  }
350
384
  )
@@ -390,8 +424,13 @@ function SettingsPanel({ siteId }) {
390
424
  emptyLabel: "Nog geen doorverwijzingen.",
391
425
  renderRow: (r, update) => /* @__PURE__ */ jsxs("div", { className: "grid gap-2 md:grid-cols-[1fr_auto_1fr] md:items-end", children: [
392
426
  /* @__PURE__ */ jsx(Field, { label: "Van (oud adres)", children: /* @__PURE__ */ jsx(Input, { value: r.from, placeholder: "/oude-pagina", onChange: (e) => update({ from: e.target.value }) }) }),
393
- /* @__PURE__ */ jsx("span", { className: "hidden pb-2 text-slate-400 md:block", "aria-hidden": "true", children: "\u2192" }),
394
- /* @__PURE__ */ jsx(Field, { label: "Naar (nieuw adres)", children: /* @__PURE__ */ jsx(Input, { value: r.to, placeholder: "/nieuwe-pagina", onChange: (e) => update({ to: e.target.value }) }) })
427
+ /* @__PURE__ */ jsx("span", { className: "hidden pb-2 text-slate-500 md:block", "aria-hidden": "true", children: "\u2192" }),
428
+ /* @__PURE__ */ jsx(Field, { label: "Naar (nieuw adres)", children: /* @__PURE__ */ jsx(Input, { value: r.to, placeholder: "/nieuwe-pagina", onChange: (e) => update({ to: e.target.value }) }) }),
429
+ (() => {
430
+ const norm = (p) => p.split(/[?#]/)[0].replace(/\/+$/, "") || "/";
431
+ const melding = norm(r.from) === "/" ? "De homepage kan niet doorverwijzen \u2014 deze regel doet niets." : norm(r.from) === norm(r.to) ? "Van en naar zijn hetzelfde adres." : livePaden && !livePaden.has(norm(r.to)) ? `Er staat geen live pagina op ${norm(r.to)}; bezoekers komen dan alsnog op een foutpagina.` : null;
432
+ return melding ? /* @__PURE__ */ jsx("p", { className: "text-xs text-amber-700 md:col-span-3", children: melding }) : null;
433
+ })()
395
434
  ] })
396
435
  }
397
436
  )
@@ -463,7 +502,7 @@ function SettingsPanel({ siteId }) {
463
502
  /* @__PURE__ */ jsx("h3", { className: "mb-1 text-base font-semibold", children: "Back-up & herstel" }),
464
503
  /* @__PURE__ */ jsx("p", { className: "mb-3 text-xs text-slate-500", children: "Sla alle content van deze site (pagina's, nieuws, formulieren, instellingen en je foto-galerij) op in \xE9\xE9n bestand. Bewaar dat veilig; je kunt het later weer terugzetten. De foto-bestanden zelf blijven in de cloud staan \u2014 de back-up bevat de teksten, instellingen en verwijzingen." }),
465
504
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
466
- /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => void downloadBackup(), disabled: exporting || restoring, children: exporting ? "Bezig\u2026" : "Back-up downloaden" }),
505
+ /* @__PURE__ */ jsx(Button, { loading: exporting, variant: "secondary", onClick: () => void downloadBackup(), disabled: exporting || restoring, children: "Back-up downloaden" }),
467
506
  /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => restoreInput.current?.click(), disabled: restoring || exporting, children: restoring ? "Terugzetten\u2026" : "Back-up terugzetten\u2026" }),
468
507
  /* @__PURE__ */ jsx(
469
508
  "input",
@@ -480,11 +519,14 @@ function SettingsPanel({ siteId }) {
480
519
  }
481
520
  )
482
521
  ] }),
483
- /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-slate-400", children: "Terugzetten vervangt de huidige content door de back-up. We maken automatisch eerst een back-up van de huidige stand, zodat je nooit iets kwijtraakt." })
522
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-slate-500", children: "Terugzetten vervangt de huidige content door de back-up. We maken automatisch eerst een back-up van de huidige stand, zodat je nooit iets kwijtraakt." })
484
523
  ] }),
485
524
  /* @__PURE__ */ jsx(SnapshotsCard, { siteId })
486
525
  ] }),
487
- /* @__PURE__ */ jsx("div", { className: "sticky bottom-0 -mx-4 flex justify-end border-t px-4 py-3", style: { borderColor: "var(--color-border)", background: "var(--admin-canvas)" }, children: /* @__PURE__ */ jsx(Button, { onClick: save, children: "Instellingen opslaan" }) })
526
+ sectie !== "backup" && sectie !== "mail" && /* @__PURE__ */ jsxs("div", { className: "sticky bottom-0 -mx-4 flex items-center justify-end gap-3 border-t px-4 py-3", style: { borderColor: "var(--color-border)", background: "var(--admin-canvas)" }, children: [
527
+ nietOpgeslagen && /* @__PURE__ */ jsx("span", { className: "text-sm text-amber-700", role: "status", children: "\u2022 Niet opgeslagen" }),
528
+ /* @__PURE__ */ jsx(Button, { loading: bezig, onClick: save, disabled: bezig, children: "Opslaan \u2014 direct live" })
529
+ ] })
488
530
  ] })
489
531
  );
490
532
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/settings/SettingsPanel.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { doc, onSnapshot } from \"firebase/firestore\";\nimport { callable } from \"../../firebase/functionsClient\";\nimport { getDb, getFirebaseApp } from \"../../firebase/client\";\nimport { SiteSettingsSchema, type SiteSettings } from \"../../schema/settings\";\nimport { useModules } from \"../../modules/context\";\nimport { useSiteConfig } from \"../../config\";\nimport type { ModulesSiteConfig } from \"../../modules/types\";\nimport { builtinThemePresets } from \"../../theme/presets\";\nimport { Button, Card, Field, Input } from \"../ui/primitives\";\nimport { Select } from \"../ui/select\";\nimport { Switch } from \"../ui/switch\";\nimport { ArrayEditor } from \"../ui/ArrayEditor\";\nimport { useToast } from \"../ui/toast\";\nimport { useConfirm } from \"../ui/ConfirmDialog\";\nimport { ModuleSettingsForm } from \"./moduleSettingsForm\";\nimport { SnapshotsCard } from \"./SnapshotsCard\";\nimport { MailSettings } from \"./MailSettings\";\nimport { useAuth } from \"../../auth/AuthProvider\";\nimport { MediaPickerButton } from \"../media/MediaPicker\";\nimport { contrast, contrastOordeel, naarHex6, tekstOp, LETTERTYPE_PAREN } from \"../lib/kleur\";\nimport type { Redirect } from \"../../schema/settings\";\n\n/**\n * Kleurveld (7.24): een echte kleurkiezer naast het hex-veld. De hex blijft (plakken uit een\n * huisstijlgids), de kiezer erbij voorkomt \"#ff00\" en oranje-dat-geel-moest-zijn.\n */\nfunction KleurVeld({ label, hint, value, placeholder, onChange }: { label: string; hint?: string; value: string; placeholder?: string; onChange: (v: string) => void }) {\n return (\n <Field label={label} hint={hint}>\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)} />\n </div>\n </Field>\n );\n}\n\n/** Contrastregel onder de merkkleur: knoptekst op de merkkleur, en merkkleur op de achtergrond. */\nfunction ContrastRegel({ primary, background }: { primary: string; background?: string }) {\n const knop = contrastOordeel(contrast(primary, tekstOp(primary)));\n const opAchtergrond = contrastOordeel(contrast(primary, background || \"#ffffff\"));\n if (!knop && !opAchtergrond) 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 <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\nexport function SettingsPanel({ siteId }: { siteId: string }) {\n const { toast } = useToast();\n const confirm = useConfirm();\n const { defs } = useModules();\n const cfg = useSiteConfig();\n /**\n * Wat de KLANT hier ziet (7.24): content en weergave — naam, huisstijl, SEO, footer,\n * doorverwijzingen, back-up. Het technische deel (domein, modules aan/uit, mailprovider en\n * afzender-identiteit) is bureauwerk met productiegevolgen en staat alleen open voor de\n * superadmin. Niet verstopt maar afwezig: een klant hoeft niet te weten dat het bestaat.\n */\n const { role } = useAuth();\n const technisch = role === \"superadmin\";\n const [s, setS] = useState<SiteSettings>({});\n const [loaded, setLoaded] = useState(false);\n const [exporting, setExporting] = useState(false);\n const [restoring, setRestoring] = useState(false);\n const restoreInput = useRef<HTMLInputElement>(null);\n\n async function downloadBackup(silent = false): Promise<boolean> {\n const app = getFirebaseApp();\n if (!app) return false;\n setExporting(true);\n try {\n const fn = callable<{ siteId: string }, Record<string, unknown>>(app, \"exportSite\");\n const res = await fn({ siteId });\n const blob = new Blob([JSON.stringify(res.data, null, 2)], { type: \"application/json\" });\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = `xicms-backup-${siteId}-${new Date().toISOString().slice(0, 10)}.json`;\n a.click();\n URL.revokeObjectURL(url);\n if (!silent) toast({ title: \"Back-up gedownload\", tone: \"success\" });\n return true;\n } catch (e) {\n toast({ title: \"Back-up mislukt\", description: (e as Error).message, tone: \"error\" });\n return false;\n } finally {\n setExporting(false);\n }\n }\n\n async function restoreFromFile(file: File) {\n let backup: Record<string, unknown>;\n try {\n backup = JSON.parse(await file.text()) as Record<string, unknown>;\n } catch {\n toast({ title: \"Ongeldig bestand\", description: \"Dit is geen geldig back-upbestand.\", tone: \"error\" });\n return;\n }\n if (backup._format !== \"xicms-export\") {\n toast({ title: \"Ongeldig bestand\", description: \"Dit lijkt geen XiCMS-back-up.\", tone: \"error\" });\n return;\n }\n if (backup.siteId && backup.siteId !== siteId) {\n const ok = await confirm({\n title: \"Back-up van een andere site\",\n description: `Deze back-up is van “${String(backup.siteId)}”, niet van deze site (${siteId}). Toch terugzetten?`,\n confirmLabel: \"Toch terugzetten\",\n tone: \"danger\",\n });\n if (!ok) return;\n }\n const ok = await confirm({\n title: \"Back-up terugzetten?\",\n description: `Dit VERVANGT alle huidige pagina's, nieuws, media en instellingen door de inhoud van de back-up${backup.exportedAt ? ` van ${new Date(String(backup.exportedAt)).toLocaleString(\"nl-NL\")}` : \"\"}. We maken eerst automatisch een back-up van de huidige stand.`,\n confirmLabel: \"Terugzetten\",\n tone: \"danger\",\n });\n if (!ok) return;\n setRestoring(true);\n try {\n // Veiligheid: eerst de huidige stand wegschrijven (als download) vóór we overschrijven.\n // Lukt die back-up niet, dan NIET doorgaan met de destructieve restore (anders ben je de\n // huidige stand kwijt zonder vangnet). De gebruiker kan het daarna opnieuw proberen.\n if (!(await downloadBackup(true))) {\n toast({ title: \"Terugzetten afgebroken\", description: \"De veiligheidsback-up van de huidige stand mislukte; er is niets overschreven.\", tone: \"error\" });\n return;\n }\n const app = getFirebaseApp();\n if (!app) throw new Error(\"Firebase niet geconfigureerd.\");\n const fn = callable(app, \"restoreSite\");\n await fn({ siteId, backup });\n toast({ title: \"Back-up teruggezet\", description: \"Herlaad de pagina om alles bij te werken.\", tone: \"success\" });\n } catch (e) {\n toast({ title: \"Terugzetten mislukt\", description: (e as Error).message, tone: \"error\" });\n } finally {\n setRestoring(false);\n }\n }\n\n /**\n * Instellingen was één scroll van negen kaarten — van sitenaam tot back-up, alles onder elkaar.\n * Dat leest niet als \"waar stel ik mijn huisstijl in?\" maar als \"zoek het maar\". De kaarten zijn\n * nu per onderwerp gegroepeerd; je ziet er één tegelijk. De staat zit in `s` hierboven, dus\n * wisselen van sectie raakt niets kwijt en één \"Opslaan\" bewaart nog steeds het geheel.\n */\n const [sectie, setSectie] = useState<string>(\"algemeen\");\n\n useEffect(() => {\n const db = getDb();\n if (!db) {\n setLoaded(true);\n return;\n }\n return onSnapshot(doc(db, \"sites\", siteId, \"settings\", \"site\"), (snap) => {\n const uitDb = snap.exists() ? (snap.data() as SiteSettings) : {};\n // Sitenaam, domein en contact-e-mail stonden hier leeg, en dat las als \"niet ingevuld\".\n // Ze wáren ingevuld, alleen ergens anders: in `content/site.config.ts`, waar ze bij het\n // bouwen van de site zijn gezet. Het instellingen-document kent ze pas zodra iemand hier\n // op Opslaan drukt, en dat had nog nooit iemand gedaan.\n //\n // Terugvallen op de site-config maakt het eerlijk: je ziet de waarde die de site\n // daadwerkelijk gebruikt, en kunt hem van daaruit aanpassen. Wat in het document staat wint\n // altijd — anders zou een bewust leeggemaakt veld telkens terugkomen.\n setS({\n ...uitDb,\n name: uitDb.name ?? cfg.name,\n domain: uitDb.domain ?? cfg.domain,\n contactEmail: uitDb.contactEmail ?? cfg.contactEmail,\n });\n setLoaded(true);\n });\n }, [siteId, cfg.name, cfg.domain, cfg.contactEmail]);\n\n async function save() {\n const db = getDb();\n if (!db) return;\n const parsed = SiteSettingsSchema.safeParse(s);\n if (!parsed.success) {\n toast({ title: \"Ongeldige instellingen\", description: parsed.error.issues[0]?.message, tone: \"error\" });\n return;\n }\n // Via de callable i.p.v. rechtstreeks: die valideert server-side, leidt de publieke subset\n // zelf af (zodat `site` en `public` niet uit elkaar kunnen lopen) én duwt de cache-tag door,\n // waardoor de wijziging binnen seconden live staat i.p.v. na het ISR-vangnet.\n try {\n const app = getFirebaseApp();\n if (!app) throw new Error(\"Firebase is niet geconfigureerd.\");\n const fn = callable(app, \"saveSiteSettings\");\n const res = await fn({ siteId, settings: parsed.data });\n toast({ title: \"Opgeslagen\", description: (res.data as { message?: string })?.message ?? \"Wijzigingen zijn live.\", tone: \"success\" });\n } catch (e) {\n toast({ title: \"Opslaan mislukt\", description: (e as Error).message, tone: \"error\" });\n }\n }\n\n if (!loaded) return <p className=\"text-sm text-slate-500\">Laden…</p>;\n\n const forms = s.forms ?? { mode: \"xicms\" as const };\n const theme = s.theme ?? { primary: \"#4f46e5\" };\n // Zelfde terugval als XiCMSProvider: `mode` wint, anders de oude boolean.\n const donkerModus: \"light\" | \"dark\" | \"auto\" = theme.dark?.mode ?? (theme.dark?.auto ? \"auto\" : \"light\");\n const footer = s.footer ?? {};\n\n // Hulpfuncties voor de module-instellingen.\n const moduleState = (id: string, defaultEnabled: boolean) => {\n const raw = (s.modules as ModulesSiteConfig | undefined)?.[id];\n if (typeof raw === \"boolean\") return { enabled: raw, config: {} as Record<string, unknown> };\n return { enabled: raw?.enabled ?? defaultEnabled, config: raw?.config ?? {} };\n };\n const setModule = (id: string, next: { enabled: boolean; config: Record<string, unknown> }) =>\n setS({ ...s, modules: { ...(s.modules as ModulesSiteConfig | undefined), [id]: next } });\n\n const SECTIES: { sleutel: string; label: string }[] = [\n { sleutel: \"algemeen\", label: \"Algemeen\" },\n { sleutel: \"huisstijl\", label: \"Huisstijl\" },\n { sleutel: \"seo\", label: \"SEO\" },\n { sleutel: \"footer\", label: \"Footer\" },\n { sleutel: \"redirects\", label: \"Doorverwijzingen\" },\n ...(technisch ? [{ sleutel: \"modules\", label: \"Modules\" }, { sleutel: \"mail\", label: \"E-mail\" }] : []),\n { sleutel: \"backup\", label: \"Back-up\" },\n ];\n const redirects: Redirect[] = s.redirects ?? [];\n\n return (\n /* Een formulier leest niet op 1300px breed; een invoerveld hoort niet breder te zijn dan de\n tekst die erin komt. Vandaar een leesbreedte in plaats van het hele werkblad vullen. */\n <div className=\"grid max-w-4xl gap-4\">\n <nav aria-label=\"Onderdelen van de instellingen\" className=\"flex flex-wrap gap-1\">\n {SECTIES.map((x) => (\n <button\n key={x.sleutel}\n type=\"button\"\n aria-current={sectie === x.sleutel ? \"page\" : undefined}\n onClick={() => setSectie(x.sleutel)}\n className=\"rounded-lg px-3 py-1.5 text-sm font-medium text-slate-600 hover:bg-slate-200 hover:text-slate-900 focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:outline-none aria-[current=page]:bg-slate-200 aria-[current=page]:text-slate-900\"\n >\n {x.label}\n </button>\n ))}\n </nav>\n\n {sectie === \"algemeen\" && (\n <>\n <Card>\n <h3 className=\"mb-3 text-base font-semibold\">Algemeen</h3>\n <div className=\"grid gap-3 md:grid-cols-2\">\n <Field label=\"Sitenaam\"><Input value={s.name ?? \"\"} onChange={(e) => setS({ ...s, name: e.target.value })} /></Field>\n <Field label=\"Contact-e-mail\" hint=\"Waar bezoekers en formulieren je bereiken.\"><Input value={s.contactEmail ?? \"\"} onChange={(e) => setS({ ...s, contactEmail: e.target.value })} /></Field>\n {technisch ? (\n <Field label=\"Domein\" hint=\"Technisch: bepaalt inloglinks, sitemap en de revalidate-ping. Alleen superadmin.\"><Input value={s.domain ?? \"\"} onChange={(e) => setS({ ...s, domain: e.target.value })} /></Field>\n ) : (\n s.domain && <Field label=\"Domein\"><p className=\"text-sm text-slate-600\">{s.domain} <span className=\"text-xs text-slate-400\">— wijzigen via XiWebdesign</span></p></Field>\n )}\n </div>\n </Card>\n </>\n )}\n\n {sectie === \"huisstijl\" && (\n <>\n <Card>\n <h3 className=\"mb-3 text-base font-semibold\">Huisstijl</h3>\n <div className=\"grid gap-3\">\n <Field label=\"Thema-preset\" hint=\"Vult kleuren, lettertype en afronding in één keer in.\">\n <Select\n value=\"\"\n placeholder=\"Kies een preset…\"\n onValueChange={(id) => {\n const preset = builtinThemePresets.find((p) => p.id === id);\n if (preset) setS({ ...s, theme: { ...theme, ...preset.theme } });\n }}\n options={builtinThemePresets.map((p) => ({ value: p.id, label: p.label }))}\n />\n </Field>\n <div className=\"grid gap-3 md:grid-cols-2\">\n <KleurVeld label=\"Merkkleur\" hint=\"Knoppen, links, accenten — en je e-mails en factuur-PDF\" value={theme.primary} onChange={(v) => setS({ ...s, theme: { ...theme, primary: v } })} />\n <KleurVeld label=\"Accentkleur\" value={theme.accent ?? \"\"} placeholder={theme.primary} onChange={(v) => setS({ ...s, theme: { ...theme, accent: v } })} />\n <KleurVeld label=\"Achtergrondkleur\" value={theme.background ?? \"\"} placeholder=\"#ffffff\" onChange={(v) => setS({ ...s, theme: { ...theme, background: v } })} />\n <KleurVeld label=\"Tekstkleur\" value={theme.foreground ?? \"\"} placeholder=\"#0f172a\" onChange={(v) => setS({ ...s, theme: { ...theme, foreground: v } })} />\n </div>\n <ContrastRegel primary={theme.primary} background={theme.background} />\n <Field label=\"Lettertype\" hint=\"Een uitgekozen combinatie voor tekst en koppen. Geavanceerd: eigen fontFamily/fontUrl via de sitecode.\">\n <Select\n value={LETTERTYPE_PAREN.find((p) => p.fontFamily === theme.fontFamily && (p.headingFont ?? \"\") === (theme.headingFont ?? \"\"))?.id ?? \"\"}\n placeholder={theme.fontFamily ? `Eigen: ${theme.fontFamily.split(\",\")[0].replace(/'/g, \"\")}` : \"Kies een lettertype…\"}\n onValueChange={(id) => {\n const paar = LETTERTYPE_PAREN.find((p) => p.id === id);\n if (!paar) return;\n setS({ ...s, theme: { ...theme, fontFamily: paar.fontFamily, headingFont: paar.headingFont, fontUrl: paar.fontUrl || undefined } });\n }}\n options={LETTERTYPE_PAREN.map((p) => ({ value: p.id, label: p.label }))}\n />\n </Field>\n {/* Donkere modus. Het schema en de rendering ondersteunden dit al, maar er was geen knop:\n donker aanzetten kon alleen door site.config.ts te bewerken — dus niet door de klant\n zelf. De kleuren verschijnen pas als ze ergens toe doen; bij \"altijd licht\" zou een\n donkere achtergrondkleur alleen verwarren. */}\n <Field\n label=\"Donkere modus\"\n hint={\n donkerModus === \"auto\"\n ? \"Volgt de voorkeur van de bezoeker: wie zijn telefoon of computer op donker heeft staan, ziet de site donker.\"\n : donkerModus === \"dark\"\n ? \"De site is voor iedereen donker, ongeacht de voorkeur van de bezoeker.\"\n : \"De site is voor iedereen licht.\"\n }\n >\n <Select\n value={donkerModus}\n onValueChange={(v) =>\n setS({ ...s, theme: { ...theme, dark: { ...(theme.dark ?? {}), mode: v as \"light\" | \"dark\" | \"auto\" } } })\n }\n options={[\n { value: \"light\", label: \"Altijd licht\" },\n { value: \"dark\", label: \"Altijd donker\" },\n { value: \"auto\", label: \"Automatisch — volg de bezoeker\" },\n ]}\n />\n </Field>\n {donkerModus !== \"light\" && (\n <div className=\"grid gap-3 sm:grid-cols-3\">\n <Field label=\"Donkere achtergrond\">\n <Input\n value={theme.dark?.background ?? \"\"}\n onChange={(e) => setS({ ...s, theme: { ...theme, dark: { ...(theme.dark ?? {}), background: e.target.value } } })}\n placeholder=\"#0f172a\"\n />\n </Field>\n <Field label=\"Donkere tekstkleur\">\n <Input\n value={theme.dark?.foreground ?? \"\"}\n onChange={(e) => setS({ ...s, theme: { ...theme, dark: { ...(theme.dark ?? {}), foreground: e.target.value } } })}\n placeholder=\"#e2e8f0\"\n />\n </Field>\n {/* Een merkkleur die op wit werkt is op zwart vaak te donker; daarom een eigen waarde. */}\n <Field label=\"Donkere merkkleur\" hint=\"Laat leeg om dezelfde te gebruiken.\">\n <Input\n value={theme.dark?.primary ?? \"\"}\n onChange={(e) => setS({ ...s, theme: { ...theme, dark: { ...(theme.dark ?? {}), primary: e.target.value } } })}\n placeholder={theme.primary}\n />\n </Field>\n </div>\n )}\n <Field label=\"Logo (e-mail & factuur)\" hint=\"PNG/JPG uit je mediabibliotheek. Verschijnt in de mail-header en op de factuur-PDF.\">\n <div className=\"flex flex-wrap items-center gap-2\">\n {theme.logo && (\n // eslint-disable-next-line @next/next/no-img-element\n <img src={theme.logo} alt=\"\" className=\"h-10 max-w-40 rounded-md border border-slate-200 bg-white object-contain p-1\" />\n )}\n <MediaPickerButton siteId={siteId} label={theme.logo ? \"Ander logo\" : \"Kies / upload\"} onSelect={(m) => setS({ ...s, theme: { ...theme, logo: m.url } })} />\n {theme.logo && <Button variant=\"ghost\" size=\"sm\" onClick={() => setS({ ...s, theme: { ...theme, logo: undefined } })}>Weghalen</Button>}\n </div>\n </Field>\n </div>\n </Card>\n </>\n )}\n\n {sectie === \"seo\" && (\n <>\n <Card>\n <h3 className=\"mb-3 text-base font-semibold\">SEO (standaard)</h3>\n <div className=\"grid gap-3\">\n <Field label=\"Standaard-omschrijving\">\n <Input value={s.seoDefaults?.description ?? \"\"} onChange={(e) => setS({ ...s, seoDefaults: { ...s.seoDefaults, description: e.target.value } })} />\n </Field>\n <Field label=\"Standaardafbeelding bij het delen\" hint=\"Voorbeeld op social media/WhatsApp voor pagina's zonder eigen afbeelding. Liefst 1200×630.\">\n <div className=\"flex flex-wrap items-center gap-2\">\n {s.seoDefaults?.ogImage && (\n // eslint-disable-next-line @next/next/no-img-element\n <img src={s.seoDefaults.ogImage} alt=\"\" className=\"h-14 w-24 rounded-md border border-slate-200 object-cover\" />\n )}\n <MediaPickerButton siteId={siteId} label={s.seoDefaults?.ogImage ? \"Andere kiezen\" : \"Kies / upload\"} onSelect={(m) => setS({ ...s, seoDefaults: { ...s.seoDefaults, ogImage: m.url } })} />\n {s.seoDefaults?.ogImage && <Button variant=\"ghost\" size=\"sm\" onClick={() => setS({ ...s, seoDefaults: { ...s.seoDefaults, ogImage: undefined } })}>Weghalen</Button>}\n </div>\n </Field>\n </div>\n </Card>\n </>\n )}\n\n {sectie === \"footer\" && (\n <>\n <Card>\n <h3 className=\"mb-1 text-base font-semibold\">Footer</h3>\n <p className=\"mb-3 text-xs text-slate-500\">Kolommen met links, social-links en copyright. Wijzigingen zijn direct live.</p>\n <div className=\"grid gap-4\">\n <div>\n <span className=\"text-sm font-medium\">Kolommen</span>\n <ArrayEditor\n items={footer.columns ?? []}\n onChange={(columns) => setS({ ...s, footer: { ...footer, columns } })}\n newItem={() => ({ heading: \"\", links: [] })}\n addLabel=\"+ Kolom\"\n emptyLabel=\"Nog geen kolommen.\"\n renderRow={(col, update) => (\n <div className=\"grid gap-2\">\n <Field label=\"Kop\"><Input value={col.heading ?? \"\"} onChange={(e) => update({ heading: e.target.value })} /></Field>\n <ArrayEditor\n items={col.links ?? []}\n onChange={(links) => update({ links })}\n newItem={() => ({ label: \"\", href: \"\" })}\n addLabel=\"+ Link\"\n renderRow={(link, updL) => (\n <div className=\"grid grid-cols-2 gap-2\">\n <Input value={link.label} placeholder=\"Label\" onChange={(e) => updL({ label: e.target.value })} />\n <Input value={link.href} placeholder=\"/pad of https://…\" onChange={(e) => updL({ href: e.target.value })} />\n </div>\n )}\n />\n </div>\n )}\n />\n </div>\n <div>\n <span className=\"text-sm font-medium\">Social-links</span>\n <ArrayEditor\n items={footer.social ?? []}\n onChange={(social) => setS({ ...s, footer: { ...footer, social } })}\n newItem={() => ({ platform: \"\", href: \"\" })}\n addLabel=\"+ Social-link\"\n renderRow={(link, update) => (\n <div className=\"grid grid-cols-2 gap-2\">\n <Input value={link.platform} placeholder=\"bv. Instagram\" onChange={(e) => update({ platform: e.target.value })} />\n <Input value={link.href} placeholder=\"https://…\" onChange={(e) => update({ href: e.target.value })} />\n </div>\n )}\n />\n </div>\n <div className=\"grid gap-3 md:grid-cols-2\">\n <Field label=\"Copyright (leeg = automatisch)\">\n <Input value={footer.copyright ?? \"\"} onChange={(e) => setS({ ...s, footer: { ...footer, copyright: e.target.value } })} />\n </Field>\n <label className=\"flex items-center gap-2 self-end text-sm\">\n <Switch checked={footer.showAdminLink !== false} onCheckedChange={(v) => setS({ ...s, footer: { ...footer, showAdminLink: v } })} />\n “Beheer”-link tonen\n </label>\n </div>\n </div>\n </Card>\n </>\n )}\n\n {sectie === \"redirects\" && (\n <>\n <Card>\n <h3 className=\"mb-1 text-base font-semibold\">Doorverwijzingen</h3>\n <p className=\"mb-3 text-xs text-slate-500\">\n Een oud adres dat naar een nieuw adres wijst. Ontstaat vanzelf als je het adres van een pagina\n wijzigt en publiceert; hier kun je er zelf toevoegen (bijvoorbeeld van je vorige website) of\n opruimen. Alleen adressen binnen deze site.\n </p>\n <ArrayEditor<Redirect>\n items={redirects}\n onChange={(lijst) => setS({ ...s, redirects: lijst })}\n newItem={() => ({ from: \"/\", to: \"/\" })}\n addLabel=\"+ Doorverwijzing\"\n emptyLabel=\"Nog geen doorverwijzingen.\"\n renderRow={(r, update) => (\n <div className=\"grid gap-2 md:grid-cols-[1fr_auto_1fr] md:items-end\">\n <Field label=\"Van (oud adres)\"><Input value={r.from} placeholder=\"/oude-pagina\" onChange={(e) => update({ from: e.target.value })} /></Field>\n <span className=\"hidden pb-2 text-slate-400 md:block\" aria-hidden=\"true\">→</span>\n <Field label=\"Naar (nieuw adres)\"><Input value={r.to} placeholder=\"/nieuwe-pagina\" onChange={(e) => update({ to: e.target.value })} /></Field>\n </div>\n )}\n />\n </Card>\n </>\n )}\n\n {sectie === \"modules\" && technisch && (\n <>\n <Card>\n <h3 className=\"mb-1 text-base font-semibold\">Modules</h3>\n <p className=\"mb-3 text-xs text-slate-500\">Zet functies aan/uit en stel ze in. Uitgezette modules verbergen hun blokken en beheer-paneel.</p>\n <div className=\"grid gap-3\">\n {defs\n .filter((d) => !d.core)\n .map((d) => {\n const st = moduleState(d.id, d.defaultEnabled ?? true);\n return (\n <div key={d.id} className=\"rounded-lg border border-slate-200 p-3\">\n <label className=\"flex items-center justify-between gap-2\">\n <span>\n <strong className=\"text-sm\">{d.label}</strong>\n {d.description && <span className=\"block text-xs text-slate-500\">{d.description}</span>}\n </span>\n <Switch checked={st.enabled} onCheckedChange={(v) => setModule(d.id, { enabled: v, config: st.config })} />\n </label>\n {st.enabled && d.settingsSchema && (\n <div className=\"mt-3\">\n <ModuleSettingsForm\n schema={d.settingsSchema}\n value={st.config}\n onChange={(config) => setModule(d.id, { enabled: st.enabled, config })}\n />\n </div>\n )}\n </div>\n );\n })}\n </div>\n </Card>\n </>\n )}\n\n {sectie === \"mail\" && technisch && (\n <>\n {/* Site-brede mailprovider + opmaak (formulieren én shop). Zie docs/SHARED-SETTINGS.md. */}\n <MailSettings siteId={siteId} />\n\n <Card>\n <h3 className=\"mb-1 text-base font-semibold\">E-mailteksten</h3>\n <p className=\"text-sm text-slate-600\">\n De teksten van automatische e-mails bewerk je bij het onderdeel zelf: formulier-mails onder{\" \"}\n <strong>Formulieren</strong>, webwinkel-mails onder <strong>Webwinkel → E-mails</strong>. Provider en\n opmaak (logo, huisstijlkleur) gelden site-breed en stel je hier in.\n </p>\n </Card>\n\n <Card>\n <h3 className=\"mb-1 text-base font-semibold\">Formulier-afzender</h3>\n <p className=\"mb-3 text-xs text-slate-500\">\n De afzender-identiteit die formulier-notificaties gebruiken. Kies de XiCMS-afzender\n (werkt direct) of het eigen domein van de klant (vereist domeinverificatie). De provider\n waarmee daadwerkelijk verstuurd wordt, stel je hierboven bij <strong>E-mail</strong> in.\n </p>\n <div className=\"grid gap-3 md:grid-cols-2\">\n <Field label=\"Afzender-modus\">\n <Select\n value={forms.mode}\n onValueChange={(v) => setS({ ...s, forms: { ...forms, mode: v as \"xicms\" | \"client\" } })}\n options={[\n { value: \"xicms\", label: \"XiCMS-domein (aanbevolen)\" },\n { value: \"client\", label: \"Eigen domein van de klant\" },\n ]}\n />\n </Field>\n <Field label=\"Van (from) e-mail\" hint=\"Moet een geverifieerd domein zijn.\">\n <Input value={forms.fromEmail ?? \"\"} onChange={(e) => setS({ ...s, forms: { ...forms, fromEmail: e.target.value } })} />\n </Field>\n <Field label=\"Van (naam)\"><Input value={forms.fromName ?? \"\"} onChange={(e) => setS({ ...s, forms: { ...forms, fromName: e.target.value } })} /></Field>\n <Field label=\"Notificaties naar\" hint=\"Meestal het mailadres van de klant.\">\n <Input value={forms.notifyTo ?? \"\"} onChange={(e) => setS({ ...s, forms: { ...forms, notifyTo: e.target.value } })} />\n </Field>\n </div>\n </Card>\n </>\n )}\n\n {sectie === \"backup\" && (\n <>\n <Card>\n <h3 className=\"mb-1 text-base font-semibold\">Back-up &amp; herstel</h3>\n <p className=\"mb-3 text-xs text-slate-500\">\n Sla alle content van deze site (pagina's, nieuws, formulieren, instellingen en je foto-galerij)\n op in één bestand. Bewaar dat veilig; je kunt het later weer terugzetten. De foto-bestanden\n zelf blijven in de cloud staan — de back-up bevat de teksten, instellingen en verwijzingen.\n </p>\n <div className=\"flex flex-wrap gap-2\">\n <Button variant=\"secondary\" onClick={() => void downloadBackup()} disabled={exporting || restoring}>\n {exporting ? \"Bezig…\" : \"Back-up downloaden\"}\n </Button>\n <Button variant=\"secondary\" onClick={() => restoreInput.current?.click()} disabled={restoring || exporting}>\n {restoring ? \"Terugzetten…\" : \"Back-up terugzetten…\"}\n </Button>\n <input\n ref={restoreInput}\n type=\"file\"\n accept=\"application/json,.json\"\n hidden\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) void restoreFromFile(f);\n e.target.value = \"\";\n }}\n />\n </div>\n <p className=\"mt-2 text-xs text-slate-400\">\n Terugzetten vervangt de huidige content door de back-up. We maken automatisch eerst een\n back-up van de huidige stand, zodat je nooit iets kwijtraakt.\n </p>\n </Card>\n\n <SnapshotsCard siteId={siteId} />\n </>\n )}\n\n {/* Sticky: één formulier, één opslaan-knop — die moet bereikbaar blijven vanuit elke sectie,\n ook onderaan een lange (Huisstijl, Footer). */}\n <div className=\"sticky bottom-0 -mx-4 flex justify-end border-t px-4 py-3\" style={{ borderColor: \"var(--color-border)\", background: \"var(--admin-canvas)\" }}>\n <Button onClick={save}>Instellingen opslaan</Button>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["ok"]}
1
+ {"version":3,"sources":["../../../src/admin/settings/SettingsPanel.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { doc, onSnapshot } from \"firebase/firestore\";\nimport { callable } from \"../../firebase/functionsClient\";\nimport { getDb, getFirebaseApp } from \"../../firebase/client\";\nimport { SiteSettingsSchema, type SiteSettings } from \"../../schema/settings\";\nimport { useModules } from \"../../modules/context\";\nimport { useSiteConfig } from \"../../config\";\nimport type { ModulesSiteConfig } from \"../../modules/types\";\nimport { builtinThemePresets } from \"../../theme/presets\";\nimport { Button, Card, Field, Input } from \"../ui/primitives\";\nimport { Select } from \"../ui/select\";\nimport { Switch } from \"../ui/switch\";\nimport { ArrayEditor } from \"../ui/ArrayEditor\";\nimport { useToast } from \"../ui/toast\";\nimport { useConfirm } from \"../ui/ConfirmDialog\";\nimport { ModuleSettingsForm } from \"./moduleSettingsForm\";\nimport { SnapshotsCard } from \"./SnapshotsCard\";\nimport { MailSettings } from \"./MailSettings\";\nimport { useAuth } from \"../../auth/AuthProvider\";\nimport { MediaPickerButton } from \"../media/MediaPicker\";\nimport { gewisteVelden, metGewisteVelden } from \"../lib/gewisteVelden\";\nimport { useOnopgeslagen } from \"../lib/onopgeslagen\";\nimport { VorigeTerugzetten } from \"./VorigeTerugzetten\";\nimport { BedrijfInstellingen, KopInstellingen } from \"./BedrijfInstellingen\";\nimport { LinkVeld } from \"../ui/LinkVeld\";\nimport { zodFoutTekst } from \"../lib/zodFout\";\nimport { subscribePages } from \"../lib/pagesClient\";\nimport { isDemoActive } from \"../../demo/demoStore\";\nimport { ContrastRegel, KleurVeld } from \"../ui/KleurVeld\";\nimport { contrast, contrastOordeel, naarHex6, tekstOp, LETTERTYPE_PAREN } from \"../lib/kleur\";\nimport type { Redirect } from \"../../schema/settings\";\n\nexport function SettingsPanel({ siteId }: { siteId: string }) {\n const { toast } = useToast();\n const confirm = useConfirm();\n const { defs } = useModules();\n const cfg = useSiteConfig();\n /**\n * Wat de KLANT hier ziet (7.24): content en weergave — naam, huisstijl, SEO, footer,\n * doorverwijzingen, back-up. Het technische deel (domein, modules aan/uit, mailprovider en\n * afzender-identiteit) is bureauwerk met productiegevolgen en staat alleen open voor de\n * superadmin. Niet verstopt maar afwezig: een klant hoeft niet te weten dat het bestaat.\n */\n const { role } = useAuth();\n const technisch = role === \"superadmin\";\n const [s, setS] = useState<SiteSettings>({});\n const [loaded, setLoaded] = useState(false);\n /** Wat er nu in de database staat (om gewiste velden te herkennen). */\n const opgeslagenRef = useRef<SiteSettings>({});\n /** De laatst geladen/opgeslagen formulierstaat: wijkt `s` hiervan af, dan is er onopgeslagen werk. */\n const basisRef = useRef<SiteSettings | null>(null);\n const sRef = useRef(s);\n sRef.current = s;\n /** Een nieuwere versie van elders, binnengekomen terwijl hier onopgeslagen werk stond. */\n const [elders, setElders] = useState<SiteSettings | null>(null);\n const [laadFout, setLaadFout] = useState<string | null>(null);\n const [bezig, setBezig] = useState(false);\n const nietOpgeslagen = loaded && basisRef.current !== null && JSON.stringify(s) !== JSON.stringify(basisRef.current);\n useOnopgeslagen(nietOpgeslagen);\n const [exporting, setExporting] = useState(false);\n const [restoring, setRestoring] = useState(false);\n const restoreInput = useRef<HTMLInputElement>(null);\n\n async function downloadBackup(silent = false): Promise<boolean> {\n const app = getFirebaseApp();\n if (!app) return false;\n setExporting(true);\n try {\n const fn = callable<{ siteId: string }, Record<string, unknown>>(app, \"exportSite\");\n const res = await fn({ siteId });\n const blob = new Blob([JSON.stringify(res.data, null, 2)], { type: \"application/json\" });\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = `xicms-backup-${siteId}-${new Date().toISOString().slice(0, 10)}.json`;\n a.click();\n URL.revokeObjectURL(url);\n if (!silent) toast({ title: \"Back-up gedownload\", tone: \"success\" });\n return true;\n } catch (e) {\n toast({ title: \"Back-up mislukt\", description: (e as Error).message, tone: \"error\" });\n return false;\n } finally {\n setExporting(false);\n }\n }\n\n async function restoreFromFile(file: File) {\n let backup: Record<string, unknown>;\n try {\n backup = JSON.parse(await file.text()) as Record<string, unknown>;\n } catch {\n toast({ title: \"Ongeldig bestand\", description: \"Dit is geen geldig back-upbestand.\", tone: \"error\" });\n return;\n }\n if (backup._format !== \"xicms-export\") {\n toast({ title: \"Ongeldig bestand\", description: \"Dit lijkt geen XiCMS-back-up.\", tone: \"error\" });\n return;\n }\n if (backup.siteId && backup.siteId !== siteId) {\n const ok = await confirm({\n title: \"Back-up van een andere site\",\n description: `Deze back-up is van “${String(backup.siteId)}”, niet van deze site (${siteId}). Toch terugzetten?`,\n confirmLabel: \"Toch terugzetten\",\n tone: \"danger\",\n });\n if (!ok) return;\n }\n const ok = await confirm({\n title: \"Back-up terugzetten?\",\n description: `Dit VERVANGT alle huidige pagina's, nieuws, media en instellingen door de inhoud van de back-up${backup.exportedAt ? ` van ${new Date(String(backup.exportedAt)).toLocaleString(\"nl-NL\")}` : \"\"}. We maken eerst automatisch een back-up van de huidige stand.`,\n confirmLabel: \"Terugzetten\",\n tone: \"danger\",\n });\n if (!ok) return;\n setRestoring(true);\n try {\n // Veiligheid: eerst de huidige stand wegschrijven (als download) vóór we overschrijven.\n // Lukt die back-up niet, dan NIET doorgaan met de destructieve restore (anders ben je de\n // huidige stand kwijt zonder vangnet). De gebruiker kan het daarna opnieuw proberen.\n if (!(await downloadBackup(true))) {\n toast({ title: \"Terugzetten afgebroken\", description: \"De veiligheidsback-up van de huidige stand mislukte; er is niets overschreven.\", tone: \"error\" });\n return;\n }\n const app = getFirebaseApp();\n if (!app) throw new Error(\"Firebase niet geconfigureerd.\");\n const fn = callable(app, \"restoreSite\");\n await fn({ siteId, backup });\n toast({ title: \"Back-up teruggezet\", description: \"Herlaad de pagina om alles bij te werken.\", tone: \"success\" });\n } catch (e) {\n toast({ title: \"Terugzetten mislukt\", description: (e as Error).message, tone: \"error\" });\n } finally {\n setRestoring(false);\n }\n }\n\n /**\n * Instellingen was één scroll van negen kaarten — van sitenaam tot back-up, alles onder elkaar.\n * Dat leest niet als \"waar stel ik mijn huisstijl in?\" maar als \"zoek het maar\". De kaarten zijn\n * nu per onderwerp gegroepeerd; je ziet er één tegelijk. De staat zit in `s` hierboven, dus\n * wisselen van sectie raakt niets kwijt en één \"Opslaan\" bewaart nog steeds het geheel.\n */\n const [sectie, setSectie] = useState<string>(\"algemeen\");\n // Live paden, voor de controle van doorverwijzingen (8.10).\n const [livePaden, setLivePaden] = useState<Set<string> | null>(null);\n useEffect(() => {\n if (sectie !== \"redirects\" || isDemoActive()) return;\n return subscribePages(siteId, (p) => setLivePaden(new Set(p.filter((x) => x.published && !x.trashed).map((x) => x.path.replace(/\\/+$/, \"\") || \"/\"))));\n }, [sectie, siteId]);\n\n useEffect(() => {\n const db = getDb();\n if (!db) {\n setLoaded(true);\n return;\n }\n return onSnapshot(doc(db, \"sites\", siteId, \"settings\", \"site\"), (snap) => {\n const uitDb = snap.exists() ? (snap.data() as SiteSettings) : {};\n opgeslagenRef.current = uitDb;\n // Sitenaam, domein en contact-e-mail stonden hier leeg, en dat las als \"niet ingevuld\".\n // Ze wáren ingevuld, alleen ergens anders: in `content/site.config.ts`, waar ze bij het\n // bouwen van de site zijn gezet. Het instellingen-document kent ze pas zodra iemand hier\n // op Opslaan drukt, en dat had nog nooit iemand gedaan.\n //\n // Terugvallen op de site-config maakt het eerlijk: je ziet de waarde die de site\n // daadwerkelijk gebruikt, en kunt hem van daaruit aanpassen. Wat in het document staat wint\n // altijd — anders zou een bewust leeggemaakt veld telkens terugkomen.\n const volgend: SiteSettings = {\n ...uitDb,\n name: uitDb.name ?? cfg.name,\n domain: uitDb.domain ?? cfg.domain,\n contactEmail: uitDb.contactEmail ?? cfg.contactEmail,\n // 8.13: ook het bedrijfsprofiel en de kop tonen wat de site nu gebruikt (startwaarde uit\n // de site-config) — anders lijken ze leeg terwijl de site ze wél toont.\n business: uitDb.business ?? cfg.business,\n header: uitDb.header ?? cfg.header,\n };\n // 8.1: een snapshot (eigen opslag van het Menu, een collega) overschreef wat je hier aan het\n // typen was. Zolang er onopgeslagen wijzigingen zijn, nemen we hem niet over maar melden\n // we hem; de gebruiker kiest.\n if (basisRef.current !== null && JSON.stringify(sRef.current) !== JSON.stringify(basisRef.current)) {\n setElders(volgend);\n return;\n }\n basisRef.current = volgend;\n setS(volgend);\n setElders(null);\n setLoaded(true);\n }, (err) => {\n setLoaded(true);\n // Demo: geen database; de instellingen tonen dan wat de site-config zegt.\n if (isDemoActive()) {\n const uitConfig = { name: cfg.name, domain: cfg.domain, contactEmail: cfg.contactEmail, business: cfg.business, header: cfg.header };\n basisRef.current = uitConfig;\n setS(uitConfig);\n return;\n }\n console.error(\"[xicms] instellingen laden mislukt:\", err);\n setLaadFout(err.message);\n });\n }, [siteId, cfg.name, cfg.domain, cfg.contactEmail, cfg.business, cfg.header]);\n\n async function save() {\n const db = getDb();\n if (!db) return;\n const parsed = SiteSettingsSchema.safeParse(s);\n if (!parsed.success) {\n toast({ title: \"Nog niet op te slaan\", description: zodFoutTekst(parsed.error.issues[0]), tone: \"error\" });\n return;\n }\n // Via de callable i.p.v. rechtstreeks: die valideert server-side, leidt de publieke subset\n // zelf af (zodat `site` en `public` niet uit elkaar kunnen lopen) én duwt de cache-tag door,\n // waardoor de wijziging binnen seconden live staat i.p.v. na het ISR-vangnet.\n setBezig(true);\n try {\n const app = getFirebaseApp();\n if (!app) throw new Error(\"Firebase is niet geconfigureerd.\");\n const fn = callable(app, \"saveSiteSettings\");\n // Leeggemaakte velden als `null` meesturen, anders laat de server-merge ze staan (8.1).\n const res = await fn({ siteId, settings: metGewisteVelden(parsed.data, gewisteVelden(opgeslagenRef.current, s)) });\n basisRef.current = s;\n setElders(null);\n toast({ title: \"Opgeslagen\", description: (res.data as { message?: string })?.message ?? \"Wijzigingen zijn live.\", tone: \"success\" });\n } catch (e) {\n toast({ title: \"Opslaan mislukt\", description: (e as Error).message, tone: \"error\" });\n } finally {\n setBezig(false);\n }\n }\n\n if (!loaded) return <p className=\"text-sm text-slate-500\" role=\"status\">Instellingen laden…</p>;\n if (laadFout && basisRef.current === null) {\n return (\n <Card>\n <p className=\"text-sm text-red-700\" role=\"alert\">\n De instellingen konden niet geladen worden. Ververs de pagina; blijft dit gebeuren, neem dan contact op met Xi Webdesign.\n </p>\n <p className=\"mt-1 text-xs text-slate-500\">{laadFout}</p>\n </Card>\n );\n }\n\n const forms = s.forms ?? { mode: \"xicms\" as const };\n const theme = s.theme ?? { primary: \"#4f46e5\" };\n // Zelfde terugval als XiCMSProvider: `mode` wint, anders de oude boolean.\n const donkerModus: \"light\" | \"dark\" | \"auto\" = theme.dark?.mode ?? (theme.dark?.auto ? \"auto\" : \"light\");\n const footer = s.footer ?? {};\n\n // Hulpfuncties voor de module-instellingen.\n const moduleState = (id: string, defaultEnabled: boolean) => {\n const raw = (s.modules as ModulesSiteConfig | undefined)?.[id];\n if (typeof raw === \"boolean\") return { enabled: raw, config: {} as Record<string, unknown> };\n return { enabled: raw?.enabled ?? defaultEnabled, config: raw?.config ?? {} };\n };\n const setModule = (id: string, next: { enabled: boolean; config: Record<string, unknown> }) =>\n setS({ ...s, modules: { ...(s.modules as ModulesSiteConfig | undefined), [id]: next } });\n\n const SECTIES: { sleutel: string; label: string }[] = [\n { sleutel: \"algemeen\", label: \"Algemeen\" },\n { sleutel: \"bedrijf\", label: \"Bedrijf\" },\n { sleutel: \"huisstijl\", label: \"Huisstijl\" },\n { sleutel: \"kop\", label: \"Kop\" },\n { sleutel: \"seo\", label: \"SEO\" },\n { sleutel: \"footer\", label: \"Footer\" },\n { sleutel: \"redirects\", label: \"Doorverwijzingen\" },\n ...(technisch ? [{ sleutel: \"modules\", label: \"Modules\" }, { sleutel: \"mail\", label: \"E-mail\" }] : []),\n { sleutel: \"backup\", label: \"Back-up\" },\n ];\n const redirects: Redirect[] = s.redirects ?? [];\n\n return (\n /* Een formulier leest niet op 1300px breed; een invoerveld hoort niet breder te zijn dan de\n tekst die erin komt. Vandaar een leesbreedte in plaats van het hele werkblad vullen. */\n <div className=\"grid max-w-4xl gap-4\">\n <nav aria-label=\"Onderdelen van de instellingen\" className=\"flex flex-wrap gap-1\">\n {SECTIES.map((x) => (\n <button\n key={x.sleutel}\n type=\"button\"\n aria-current={sectie === x.sleutel ? \"page\" : undefined}\n onClick={() => setSectie(x.sleutel)}\n className=\"rounded-lg px-3 py-1.5 text-sm font-medium text-slate-600 hover:bg-slate-200 hover:text-slate-900 focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:outline-none aria-[current=page]:bg-slate-200 aria-[current=page]:text-slate-900\"\n >\n {x.label}\n </button>\n ))}\n </nav>\n\n {elders && (\n <div role=\"alert\" className=\"flex flex-wrap items-center gap-3 rounded-lg border border-amber-300 bg-amber-50 px-4 py-3 text-sm text-amber-900\">\n <span className=\"flex-1\">De instellingen zijn intussen ergens anders gewijzigd (in een ander tabblad, of door een collega).</span>\n <Button\n size=\"sm\"\n variant=\"secondary\"\n onClick={() => {\n basisRef.current = elders;\n setS(elders);\n setElders(null);\n }}\n >\n Nieuwste laden (mijn wijzigingen vervallen)\n </Button>\n <Button size=\"sm\" variant=\"ghost\" onClick={() => setElders(null)}>Mijn versie houden</Button>\n </div>\n )}\n\n {sectie === \"algemeen\" && (\n <>\n <Card>\n <h3 className=\"mb-3 text-base font-semibold\">Algemeen</h3>\n <div className=\"grid gap-3 md:grid-cols-2\">\n <Field label=\"Sitenaam\"><Input value={s.name ?? \"\"} onChange={(e) => setS({ ...s, name: e.target.value })} /></Field>\n <Field label=\"Contact-e-mail\" hint=\"Waar bezoekers en formulieren je bereiken.\"><Input value={s.contactEmail ?? \"\"} onChange={(e) => setS({ ...s, contactEmail: e.target.value })} /></Field>\n {technisch ? (\n <Field label=\"Domein\" hint=\"Technisch: bepaalt inloglinks, sitemap en de revalidate-ping. Alleen superadmin.\"><Input value={s.domain ?? \"\"} onChange={(e) => setS({ ...s, domain: e.target.value })} /></Field>\n ) : (\n s.domain && <Field label=\"Domein\"><p className=\"text-sm text-slate-600\">{s.domain} <span className=\"text-xs text-slate-500\">— wijzigen via XiWebdesign</span></p></Field>\n )}\n </div>\n </Card>\n </>\n )}\n\n {sectie === \"bedrijf\" && (\n <BedrijfInstellingen siteId={siteId} waarde={s.business} onChange={(business) => setS({ ...s, business })} dirty={nietOpgeslagen} />\n )}\n {sectie === \"kop\" && (\n <KopInstellingen siteId={siteId} waarde={s.header} onChange={(header) => setS({ ...s, header })} dirty={nietOpgeslagen} />\n )}\n\n {sectie === \"huisstijl\" && (\n <>\n <Card>\n <h3 className=\"mb-1 text-base font-semibold\">Huisstijl</h3>\n <div className=\"mb-3\"><VorigeTerugzetten siteId={siteId} sleutel=\"theme\" dirty={nietOpgeslagen} /></div>\n <div className=\"grid gap-3\">\n <Field label=\"Thema-preset\" hint=\"Vult kleuren, lettertype en afronding in één keer in.\">\n <Select\n value=\"\"\n placeholder=\"Kies een preset…\"\n onValueChange={(id) => {\n const preset = builtinThemePresets.find((p) => p.id === id);\n if (preset) setS({ ...s, theme: { ...theme, ...preset.theme } });\n }}\n options={builtinThemePresets.map((p) => ({ value: p.id, label: p.label }))}\n />\n </Field>\n <div className=\"grid gap-3 md:grid-cols-2\">\n <KleurVeld label=\"Merkkleur\" hint=\"Knoppen, links, accenten — en je e-mails en factuur-PDF\" value={theme.primary} onChange={(v) => setS({ ...s, theme: { ...theme, primary: v } })} />\n <KleurVeld label=\"Accentkleur\" value={theme.accent ?? \"\"} placeholder={theme.primary} onChange={(v) => setS({ ...s, theme: { ...theme, accent: v } })} />\n <KleurVeld label=\"Achtergrondkleur\" value={theme.background ?? \"\"} placeholder=\"#ffffff\" onChange={(v) => setS({ ...s, theme: { ...theme, background: v } })} />\n <KleurVeld label=\"Tekstkleur\" value={theme.foreground ?? \"\"} placeholder=\"#0f172a\" onChange={(v) => setS({ ...s, theme: { ...theme, foreground: v } })} />\n </div>\n <ContrastRegel primary={theme.primary} background={theme.background} foreground={theme.foreground} />\n <Field label=\"Lettertype\" hint=\"Een uitgekozen combinatie voor tekst en koppen. Geavanceerd: eigen fontFamily/fontUrl via de sitecode.\">\n <Select\n value={LETTERTYPE_PAREN.find((p) => p.fontFamily === theme.fontFamily && (p.headingFont ?? \"\") === (theme.headingFont ?? \"\"))?.id ?? \"\"}\n placeholder={theme.fontFamily ? `Eigen: ${theme.fontFamily.split(\",\")[0].replace(/'/g, \"\")}` : \"Kies een lettertype…\"}\n onValueChange={(id) => {\n const paar = LETTERTYPE_PAREN.find((p) => p.id === id);\n if (!paar) return;\n setS({ ...s, theme: { ...theme, fontFamily: paar.fontFamily, headingFont: paar.headingFont, fontUrl: paar.fontUrl || undefined } });\n }}\n options={LETTERTYPE_PAREN.map((p) => ({ value: p.id, label: p.label }))}\n />\n </Field>\n {/* Donkere modus. Het schema en de rendering ondersteunden dit al, maar er was geen knop:\n donker aanzetten kon alleen door site.config.ts te bewerken — dus niet door de klant\n zelf. De kleuren verschijnen pas als ze ergens toe doen; bij \"altijd licht\" zou een\n donkere achtergrondkleur alleen verwarren. */}\n <Field\n label=\"Donkere modus\"\n hint={\n donkerModus === \"auto\"\n ? \"Volgt de voorkeur van de bezoeker: wie zijn telefoon of computer op donker heeft staan, ziet de site donker.\"\n : donkerModus === \"dark\"\n ? \"De site is voor iedereen donker, ongeacht de voorkeur van de bezoeker.\"\n : \"De site is voor iedereen licht.\"\n }\n >\n <Select\n value={donkerModus}\n onValueChange={(v) =>\n setS({ ...s, theme: { ...theme, dark: { ...(theme.dark ?? {}), mode: v as \"light\" | \"dark\" | \"auto\" } } })\n }\n options={[\n { value: \"light\", label: \"Altijd licht\" },\n { value: \"dark\", label: \"Altijd donker\" },\n { value: \"auto\", label: \"Automatisch — volg de bezoeker\" },\n ]}\n />\n </Field>\n {donkerModus !== \"light\" && (\n <div className=\"grid gap-3\">\n <div className=\"grid gap-3 sm:grid-cols-3\">\n {/* 8.10: echte kleurkiezers met contrastoordeel — grijs-op-grijs ging hier ongemerkt live. */}\n <KleurVeld label=\"Donkere achtergrond\" value={theme.dark?.background ?? \"\"} placeholder=\"#0f172a\" onChange={(v) => setS({ ...s, theme: { ...theme, dark: { ...(theme.dark ?? {}), background: v } } })} />\n <KleurVeld label=\"Donkere tekstkleur\" value={theme.dark?.foreground ?? \"\"} placeholder=\"#e2e8f0\" onChange={(v) => setS({ ...s, theme: { ...theme, dark: { ...(theme.dark ?? {}), foreground: v } } })} />\n {/* Een merkkleur die op wit werkt is op zwart vaak te donker; daarom een eigen waarde. */}\n <KleurVeld label=\"Donkere merkkleur\" hint=\"Leeg = dezelfde als licht.\" value={theme.dark?.primary ?? \"\"} placeholder={theme.primary} onChange={(v) => setS({ ...s, theme: { ...theme, dark: { ...(theme.dark ?? {}), primary: v } } })} />\n </div>\n <ContrastRegel\n primary={theme.dark?.primary || theme.primary}\n background={theme.dark?.background || \"#0f172a\"}\n foreground={theme.dark?.foreground || \"#e2e8f0\"}\n />\n <p className=\"text-xs text-amber-800\">\n Controleer na het opslaan je logo en foto&apos;s met een witte achtergrond: die vallen op een donkere site vaak weg.\n </p>\n </div>\n )}\n <Field label=\"Logo (e-mail & factuur)\" hint=\"PNG/JPG uit je mediabibliotheek. Verschijnt in de mail-header en op de factuur-PDF.\">\n <div className=\"flex flex-wrap items-center gap-2\">\n {theme.logo && (\n // eslint-disable-next-line @next/next/no-img-element\n <img src={theme.logo} alt=\"\" className=\"h-10 max-w-40 rounded-md border border-slate-200 bg-white object-contain p-1\" />\n )}\n <MediaPickerButton siteId={siteId} label={theme.logo ? \"Ander logo\" : \"Kies / upload\"} onSelect={(m) => setS({ ...s, theme: { ...theme, logo: m.url } })} />\n {theme.logo && <Button variant=\"ghost\" size=\"sm\" onClick={() => setS({ ...s, theme: { ...theme, logo: undefined } })}>Weghalen</Button>}\n </div>\n </Field>\n </div>\n </Card>\n </>\n )}\n\n {sectie === \"seo\" && (\n <>\n <Card>\n <h3 className=\"mb-3 text-base font-semibold\">SEO (standaard)</h3>\n <div className=\"grid gap-3\">\n <Field label=\"Standaard-omschrijving\">\n <Input value={s.seoDefaults?.description ?? \"\"} onChange={(e) => setS({ ...s, seoDefaults: { ...s.seoDefaults, description: e.target.value } })} />\n </Field>\n <Field label=\"Standaardafbeelding bij het delen\" hint=\"Voorbeeld op social media/WhatsApp voor pagina's zonder eigen afbeelding. Liefst 1200×630.\">\n <div className=\"flex flex-wrap items-center gap-2\">\n {s.seoDefaults?.ogImage && (\n // eslint-disable-next-line @next/next/no-img-element\n <img src={s.seoDefaults.ogImage} alt=\"\" className=\"h-14 w-24 rounded-md border border-slate-200 object-cover\" />\n )}\n <MediaPickerButton siteId={siteId} label={s.seoDefaults?.ogImage ? \"Andere kiezen\" : \"Kies / upload\"} onSelect={(m) => setS({ ...s, seoDefaults: { ...s.seoDefaults, ogImage: m.url } })} />\n {s.seoDefaults?.ogImage && <Button variant=\"ghost\" size=\"sm\" onClick={() => setS({ ...s, seoDefaults: { ...s.seoDefaults, ogImage: undefined } })}>Weghalen</Button>}\n </div>\n </Field>\n </div>\n </Card>\n </>\n )}\n\n {sectie === \"footer\" && (\n <>\n <Card>\n <h3 className=\"mb-1 text-base font-semibold\">Footer</h3>\n <p className=\"mb-1 text-xs text-slate-500\">Kolommen met links, social-links en copyright. Wijzigingen zijn direct live.</p>\n <div className=\"mb-3\"><VorigeTerugzetten siteId={siteId} sleutel=\"footer\" dirty={nietOpgeslagen} /></div>\n <div className=\"grid gap-4\">\n <div>\n <span className=\"text-sm font-medium\">Kolommen</span>\n <ArrayEditor\n items={footer.columns ?? []}\n onChange={(columns) => setS({ ...s, footer: { ...footer, columns } })}\n newItem={() => ({ heading: \"\", links: [] })}\n addLabel=\"+ Kolom\"\n emptyLabel=\"Nog geen kolommen.\"\n renderRow={(col, update) => (\n <div className=\"grid gap-2\">\n <Field label=\"Kop\"><Input value={col.heading ?? \"\"} onChange={(e) => update({ heading: e.target.value })} /></Field>\n <ArrayEditor\n items={col.links ?? []}\n onChange={(links) => update({ links })}\n newItem={() => ({ label: \"\", href: \"\" })}\n addLabel=\"+ Link\"\n renderRow={(link, updL) => (\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <Input value={link.label} placeholder=\"Tekst van de link\" onChange={(e) => updL({ label: e.target.value })} />\n <LinkVeld siteId={siteId} value={link.href} onChange={(href) => updL({ href })} />\n </div>\n )}\n />\n </div>\n )}\n />\n </div>\n <div>\n <span className=\"text-sm font-medium\">Social-links</span>\n <ArrayEditor\n items={footer.social ?? []}\n onChange={(social) => setS({ ...s, footer: { ...footer, social } })}\n newItem={() => ({ platform: \"\", href: \"\" })}\n addLabel=\"+ Social-link\"\n renderRow={(link, update) => (\n <div className=\"grid grid-cols-2 gap-2\">\n <Input value={link.platform} placeholder=\"bv. Instagram\" onChange={(e) => update({ platform: e.target.value })} />\n <Input value={link.href} placeholder=\"https://…\" onChange={(e) => update({ href: e.target.value })} />\n </div>\n )}\n />\n </div>\n <div className=\"grid gap-3 md:grid-cols-2\">\n <Field label=\"Copyright (leeg = automatisch)\">\n <Input value={footer.copyright ?? \"\"} onChange={(e) => setS({ ...s, footer: { ...footer, copyright: e.target.value } })} />\n </Field>\n <label className=\"flex items-center gap-2 self-end text-sm\">\n <Switch checked={footer.showAdminLink !== false} onCheckedChange={(v) => setS({ ...s, footer: { ...footer, showAdminLink: v } })} />\n “Beheer”-link tonen\n </label>\n </div>\n </div>\n </Card>\n </>\n )}\n\n {sectie === \"redirects\" && (\n <>\n <Card>\n <h3 className=\"mb-1 text-base font-semibold\">Doorverwijzingen</h3>\n <p className=\"mb-3 text-xs text-slate-500\">\n Een oud adres dat naar een nieuw adres wijst. Ontstaat vanzelf als je het adres van een pagina\n wijzigt en publiceert; hier kun je er zelf toevoegen (bijvoorbeeld van je vorige website) of\n opruimen. Alleen adressen binnen deze site.\n </p>\n <ArrayEditor<Redirect>\n items={redirects}\n onChange={(lijst) => setS({ ...s, redirects: lijst })}\n newItem={() => ({ from: \"/\", to: \"/\" })}\n addLabel=\"+ Doorverwijzing\"\n emptyLabel=\"Nog geen doorverwijzingen.\"\n renderRow={(r, update) => (\n <div className=\"grid gap-2 md:grid-cols-[1fr_auto_1fr] md:items-end\">\n <Field label=\"Van (oud adres)\"><Input value={r.from} placeholder=\"/oude-pagina\" onChange={(e) => update({ from: e.target.value })} /></Field>\n <span className=\"hidden pb-2 text-slate-500 md:block\" aria-hidden=\"true\">→</span>\n <Field label=\"Naar (nieuw adres)\"><Input value={r.to} placeholder=\"/nieuwe-pagina\" onChange={(e) => update({ to: e.target.value })} /></Field>\n {/* 8.10: een doorverwijzing naar een pagina die niet (live) bestaat is alsnog een 404. */}\n {(() => {\n const norm = (p: string) => (p.split(/[?#]/)[0].replace(/\\/+$/, \"\") || \"/\");\n const melding =\n norm(r.from) === \"/\"\n ? \"De homepage kan niet doorverwijzen — deze regel doet niets.\"\n : norm(r.from) === norm(r.to)\n ? \"Van en naar zijn hetzelfde adres.\"\n : livePaden && !livePaden.has(norm(r.to))\n ? `Er staat geen live pagina op ${norm(r.to)}; bezoekers komen dan alsnog op een foutpagina.`\n : null;\n return melding ? <p className=\"text-xs text-amber-700 md:col-span-3\">{melding}</p> : null;\n })()}\n </div>\n )}\n />\n </Card>\n </>\n )}\n\n {sectie === \"modules\" && technisch && (\n <>\n <Card>\n <h3 className=\"mb-1 text-base font-semibold\">Modules</h3>\n <p className=\"mb-3 text-xs text-slate-500\">Zet functies aan/uit en stel ze in. Uitgezette modules verbergen hun blokken en beheer-paneel.</p>\n <div className=\"grid gap-3\">\n {defs\n .filter((d) => !d.core)\n .map((d) => {\n const st = moduleState(d.id, d.defaultEnabled ?? true);\n return (\n <div key={d.id} className=\"rounded-lg border border-slate-200 p-3\">\n <label className=\"flex items-center justify-between gap-2\">\n <span>\n <strong className=\"text-sm\">{d.label}</strong>\n {d.description && <span className=\"block text-xs text-slate-500\">{d.description}</span>}\n </span>\n <Switch checked={st.enabled} onCheckedChange={(v) => setModule(d.id, { enabled: v, config: st.config })} />\n </label>\n {st.enabled && d.settingsSchema && (\n <div className=\"mt-3\">\n <ModuleSettingsForm\n schema={d.settingsSchema}\n value={st.config}\n onChange={(config) => setModule(d.id, { enabled: st.enabled, config })}\n />\n </div>\n )}\n </div>\n );\n })}\n </div>\n </Card>\n </>\n )}\n\n {sectie === \"mail\" && technisch && (\n <>\n {/* Site-brede mailprovider + opmaak (formulieren én shop). Zie docs/SHARED-SETTINGS.md. */}\n <MailSettings siteId={siteId} />\n\n <Card>\n <h3 className=\"mb-1 text-base font-semibold\">E-mailteksten</h3>\n <p className=\"text-sm text-slate-600\">\n De teksten van automatische e-mails bewerk je bij het onderdeel zelf: formulier-mails onder{\" \"}\n <strong>Formulieren</strong>, webwinkel-mails onder <strong>Webwinkel → E-mails</strong>. Provider en\n opmaak (logo, huisstijlkleur) gelden site-breed en stel je hier in.\n </p>\n </Card>\n\n <Card>\n <h3 className=\"mb-1 text-base font-semibold\">Formulier-afzender</h3>\n <p className=\"mb-3 text-xs text-slate-500\">\n De afzender-identiteit die formulier-notificaties gebruiken. Kies de XiCMS-afzender\n (werkt direct) of het eigen domein van de klant (vereist domeinverificatie). De provider\n waarmee daadwerkelijk verstuurd wordt, stel je hierboven bij <strong>E-mail</strong> in.\n </p>\n <div className=\"grid gap-3 md:grid-cols-2\">\n <Field label=\"Afzender-modus\">\n <Select\n value={forms.mode}\n onValueChange={(v) => setS({ ...s, forms: { ...forms, mode: v as \"xicms\" | \"client\" } })}\n options={[\n { value: \"xicms\", label: \"XiCMS-domein (aanbevolen)\" },\n { value: \"client\", label: \"Eigen domein van de klant\" },\n ]}\n />\n </Field>\n <Field label=\"Van (from) e-mail\" hint=\"Moet een geverifieerd domein zijn.\">\n <Input value={forms.fromEmail ?? \"\"} onChange={(e) => setS({ ...s, forms: { ...forms, fromEmail: e.target.value } })} />\n </Field>\n <Field label=\"Van (naam)\"><Input value={forms.fromName ?? \"\"} onChange={(e) => setS({ ...s, forms: { ...forms, fromName: e.target.value } })} /></Field>\n <Field label=\"Notificaties naar\" hint=\"Meestal het mailadres van de klant.\">\n <Input value={forms.notifyTo ?? \"\"} onChange={(e) => setS({ ...s, forms: { ...forms, notifyTo: e.target.value } })} />\n </Field>\n </div>\n </Card>\n </>\n )}\n\n {sectie === \"backup\" && (\n <>\n <Card>\n <h3 className=\"mb-1 text-base font-semibold\">Back-up &amp; herstel</h3>\n <p className=\"mb-3 text-xs text-slate-500\">\n Sla alle content van deze site (pagina's, nieuws, formulieren, instellingen en je foto-galerij)\n op in één bestand. Bewaar dat veilig; je kunt het later weer terugzetten. De foto-bestanden\n zelf blijven in de cloud staan — de back-up bevat de teksten, instellingen en verwijzingen.\n </p>\n <div className=\"flex flex-wrap gap-2\">\n <Button loading={exporting} variant=\"secondary\" onClick={() => void downloadBackup()} disabled={exporting || restoring}>\n {\"Back-up downloaden\"}\n </Button>\n <Button variant=\"secondary\" onClick={() => restoreInput.current?.click()} disabled={restoring || exporting}>\n {restoring ? \"Terugzetten…\" : \"Back-up terugzetten…\"}\n </Button>\n <input\n ref={restoreInput}\n type=\"file\"\n accept=\"application/json,.json\"\n hidden\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) void restoreFromFile(f);\n e.target.value = \"\";\n }}\n />\n </div>\n <p className=\"mt-2 text-xs text-slate-500\">\n Terugzetten vervangt de huidige content door de back-up. We maken automatisch eerst een\n back-up van de huidige stand, zodat je nooit iets kwijtraakt.\n </p>\n </Card>\n\n <SnapshotsCard siteId={siteId} />\n </>\n )}\n\n {/* Sticky: één formulier, één opslaan-knop — die moet bereikbaar blijven vanuit elke sectie,\n ook onderaan een lange (Huisstijl, Footer). */}\n {/* Niet bij Back-up en E-mail: die hebben hun eigen knoppen, en deze deed daar niets. */}\n {sectie !== \"backup\" && sectie !== \"mail\" && (\n <div className=\"sticky bottom-0 -mx-4 flex items-center justify-end gap-3 border-t px-4 py-3\" style={{ borderColor: \"var(--color-border)\", background: \"var(--admin-canvas)\" }}>\n {nietOpgeslagen && <span className=\"text-sm text-amber-700\" role=\"status\">• Niet opgeslagen</span>}\n <Button loading={bezig} onClick={save} disabled={bezig}>{\"Opslaan — direct live\"}</Button>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["ok"]}