@xiwebdesign/xicms-core 4.17.1

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 (436) hide show
  1. package/dist/XiCMSProvider.d.ts +58 -0
  2. package/dist/XiCMSProvider.js +165 -0
  3. package/dist/XiCMSProvider.js.map +1 -0
  4. package/dist/admin/AdminApp.d.ts +4 -0
  5. package/dist/admin/AdminApp.js +62 -0
  6. package/dist/admin/AdminApp.js.map +1 -0
  7. package/dist/admin/AdminHelp.d.ts +2 -0
  8. package/dist/admin/AdminHelp.js +65 -0
  9. package/dist/admin/AdminHelp.js.map +1 -0
  10. package/dist/admin/NewsEditor.d.ts +2 -0
  11. package/dist/admin/NewsEditor.js +171 -0
  12. package/dist/admin/NewsEditor.js.map +1 -0
  13. package/dist/admin/SuperadminPanel.d.ts +4 -0
  14. package/dist/admin/SuperadminPanel.js +101 -0
  15. package/dist/admin/SuperadminPanel.js.map +1 -0
  16. package/dist/admin/blockEditors/StyleEditor.d.ts +10 -0
  17. package/dist/admin/blockEditors/StyleEditor.js +78 -0
  18. package/dist/admin/blockEditors/StyleEditor.js.map +1 -0
  19. package/dist/admin/blockEditors/index.d.ts +16 -0
  20. package/dist/admin/blockEditors/index.js +1602 -0
  21. package/dist/admin/blockEditors/index.js.map +1 -0
  22. package/dist/admin/editors/RichTextEditor.d.ts +10 -0
  23. package/dist/admin/editors/RichTextEditor.js +86 -0
  24. package/dist/admin/editors/RichTextEditor.js.map +1 -0
  25. package/dist/admin/forms/FormsPanel.d.ts +3 -0
  26. package/dist/admin/forms/FormsPanel.js +203 -0
  27. package/dist/admin/forms/FormsPanel.js.map +1 -0
  28. package/dist/admin/index.d.ts +21 -0
  29. package/dist/admin/index.js +38 -0
  30. package/dist/admin/index.js.map +1 -0
  31. package/dist/admin/lib/compressImage.d.ts +12 -0
  32. package/dist/admin/lib/compressImage.js +53 -0
  33. package/dist/admin/lib/compressImage.js.map +1 -0
  34. package/dist/admin/lib/mediaUsage.d.ts +9 -0
  35. package/dist/admin/lib/mediaUsage.js +25 -0
  36. package/dist/admin/lib/mediaUsage.js.map +1 -0
  37. package/dist/admin/lib/pagesClient.d.ts +38 -0
  38. package/dist/admin/lib/pagesClient.js +143 -0
  39. package/dist/admin/lib/pagesClient.js.map +1 -0
  40. package/dist/admin/lib/slugify.d.ts +2 -0
  41. package/dist/admin/lib/slugify.js +7 -0
  42. package/dist/admin/lib/slugify.js.map +1 -0
  43. package/dist/admin/lib/upload.d.ts +13 -0
  44. package/dist/admin/lib/upload.js +40 -0
  45. package/dist/admin/lib/upload.js.map +1 -0
  46. package/dist/admin/lib/zodFields.d.ts +27 -0
  47. package/dist/admin/lib/zodFields.js +48 -0
  48. package/dist/admin/lib/zodFields.js.map +1 -0
  49. package/dist/admin/media/MediaManager.d.ts +3 -0
  50. package/dist/admin/media/MediaManager.js +132 -0
  51. package/dist/admin/media/MediaManager.js.map +1 -0
  52. package/dist/admin/media/MediaPicker.d.ts +24 -0
  53. package/dist/admin/media/MediaPicker.js +93 -0
  54. package/dist/admin/media/MediaPicker.js.map +1 -0
  55. package/dist/admin/pages/PageEditor.d.ts +5 -0
  56. package/dist/admin/pages/PageEditor.js +239 -0
  57. package/dist/admin/pages/PageEditor.js.map +1 -0
  58. package/dist/admin/pages/PagesPanel.d.ts +3 -0
  59. package/dist/admin/pages/PagesPanel.js +92 -0
  60. package/dist/admin/pages/PagesPanel.js.map +1 -0
  61. package/dist/admin/panelRegistry.d.ts +20 -0
  62. package/dist/admin/panelRegistry.js +23 -0
  63. package/dist/admin/panelRegistry.js.map +1 -0
  64. package/dist/admin/patterns/PatternInserter.d.ts +10 -0
  65. package/dist/admin/patterns/PatternInserter.js +58 -0
  66. package/dist/admin/patterns/PatternInserter.js.map +1 -0
  67. package/dist/admin/settings/SettingsPanel.d.ts +3 -0
  68. package/dist/admin/settings/SettingsPanel.js +304 -0
  69. package/dist/admin/settings/SettingsPanel.js.map +1 -0
  70. package/dist/admin/settings/moduleSettingsForm.d.ts +12 -0
  71. package/dist/admin/settings/moduleSettingsForm.js +45 -0
  72. package/dist/admin/settings/moduleSettingsForm.js.map +1 -0
  73. package/dist/admin/stats/StatsPanel.d.ts +4 -0
  74. package/dist/admin/stats/StatsPanel.js +80 -0
  75. package/dist/admin/stats/StatsPanel.js.map +1 -0
  76. package/dist/admin/ui/ArrayEditor.d.ts +16 -0
  77. package/dist/admin/ui/ArrayEditor.js +38 -0
  78. package/dist/admin/ui/ArrayEditor.js.map +1 -0
  79. package/dist/admin/ui/ConfirmDialog.d.ts +22 -0
  80. package/dist/admin/ui/ConfirmDialog.js +47 -0
  81. package/dist/admin/ui/ConfirmDialog.js.map +1 -0
  82. package/dist/admin/ui/cn.d.ts +3 -0
  83. package/dist/admin/ui/cn.js +9 -0
  84. package/dist/admin/ui/cn.js.map +1 -0
  85. package/dist/admin/ui/dialog.d.ts +9 -0
  86. package/dist/admin/ui/dialog.js +47 -0
  87. package/dist/admin/ui/dialog.js.map +1 -0
  88. package/dist/admin/ui/index.d.ts +7 -0
  89. package/dist/admin/ui/index.js +29 -0
  90. package/dist/admin/ui/index.js.map +1 -0
  91. package/dist/admin/ui/primitives.d.ts +37 -0
  92. package/dist/admin/ui/primitives.js +137 -0
  93. package/dist/admin/ui/primitives.js.map +1 -0
  94. package/dist/admin/ui/select.d.ts +11 -0
  95. package/dist/admin/ui/select.js +27 -0
  96. package/dist/admin/ui/select.js.map +1 -0
  97. package/dist/admin/ui/switch.d.ts +6 -0
  98. package/dist/admin/ui/switch.js +22 -0
  99. package/dist/admin/ui/switch.js.map +1 -0
  100. package/dist/admin/ui/tabs.d.ts +5 -0
  101. package/dist/admin/ui/tabs.js +36 -0
  102. package/dist/admin/ui/tabs.js.map +1 -0
  103. package/dist/admin/ui/toast.d.ts +19 -0
  104. package/dist/admin/ui/toast.js +24 -0
  105. package/dist/admin/ui/toast.js.map +1 -0
  106. package/dist/admin/visual/VisualEditor.d.ts +10 -0
  107. package/dist/admin/visual/VisualEditor.js +597 -0
  108. package/dist/admin/visual/VisualEditor.js.map +1 -0
  109. package/dist/admin/visual/reorder.d.ts +6 -0
  110. package/dist/admin/visual/reorder.js +12 -0
  111. package/dist/admin/visual/reorder.js.map +1 -0
  112. package/dist/admin.css +1 -0
  113. package/dist/auth/AuthProvider.d.ts +30 -0
  114. package/dist/auth/AuthProvider.js +110 -0
  115. package/dist/auth/AuthProvider.js.map +1 -0
  116. package/dist/auth/LoginForm.d.ts +4 -0
  117. package/dist/auth/LoginForm.js +122 -0
  118. package/dist/auth/LoginForm.js.map +1 -0
  119. package/dist/auth/roles.d.ts +15 -0
  120. package/dist/auth/roles.js +21 -0
  121. package/dist/auth/roles.js.map +1 -0
  122. package/dist/blocks/BlockErrorBoundary.d.ts +32 -0
  123. package/dist/blocks/BlockErrorBoundary.js +39 -0
  124. package/dist/blocks/BlockErrorBoundary.js.map +1 -0
  125. package/dist/blocks/BlockRenderer.d.ts +15 -0
  126. package/dist/blocks/BlockRenderer.js +24 -0
  127. package/dist/blocks/BlockRenderer.js.map +1 -0
  128. package/dist/blocks/blockStyle.d.ts +14 -0
  129. package/dist/blocks/blockStyle.js +14 -0
  130. package/dist/blocks/blockStyle.js.map +1 -0
  131. package/dist/blocks/builtins/Accordion.d.ts +2 -0
  132. package/dist/blocks/builtins/Accordion.js +45 -0
  133. package/dist/blocks/builtins/Accordion.js.map +1 -0
  134. package/dist/blocks/builtins/Agenda.d.ts +23 -0
  135. package/dist/blocks/builtins/Agenda.js +102 -0
  136. package/dist/blocks/builtins/Agenda.js.map +1 -0
  137. package/dist/blocks/builtins/Banner.d.ts +2 -0
  138. package/dist/blocks/builtins/Banner.js +45 -0
  139. package/dist/blocks/builtins/Banner.js.map +1 -0
  140. package/dist/blocks/builtins/BeforeAfter.d.ts +2 -0
  141. package/dist/blocks/builtins/BeforeAfter.js +44 -0
  142. package/dist/blocks/builtins/BeforeAfter.js.map +1 -0
  143. package/dist/blocks/builtins/Booking.d.ts +2 -0
  144. package/dist/blocks/builtins/Booking.js +27 -0
  145. package/dist/blocks/builtins/Booking.js.map +1 -0
  146. package/dist/blocks/builtins/Breadcrumbs.d.ts +10 -0
  147. package/dist/blocks/builtins/Breadcrumbs.js +73 -0
  148. package/dist/blocks/builtins/Breadcrumbs.js.map +1 -0
  149. package/dist/blocks/builtins/Cards.d.ts +2 -0
  150. package/dist/blocks/builtins/Cards.js +94 -0
  151. package/dist/blocks/builtins/Cards.js.map +1 -0
  152. package/dist/blocks/builtins/Columns.d.ts +2 -0
  153. package/dist/blocks/builtins/Columns.js +22 -0
  154. package/dist/blocks/builtins/Columns.js.map +1 -0
  155. package/dist/blocks/builtins/Contact.d.ts +7 -0
  156. package/dist/blocks/builtins/Contact.js +121 -0
  157. package/dist/blocks/builtins/Contact.js.map +1 -0
  158. package/dist/blocks/builtins/Countdown.d.ts +18 -0
  159. package/dist/blocks/builtins/Countdown.js +65 -0
  160. package/dist/blocks/builtins/Countdown.js.map +1 -0
  161. package/dist/blocks/builtins/Cta.d.ts +2 -0
  162. package/dist/blocks/builtins/Cta.js +52 -0
  163. package/dist/blocks/builtins/Cta.js.map +1 -0
  164. package/dist/blocks/builtins/Downloads.d.ts +2 -0
  165. package/dist/blocks/builtins/Downloads.js +32 -0
  166. package/dist/blocks/builtins/Downloads.js.map +1 -0
  167. package/dist/blocks/builtins/Elements.d.ts +4 -0
  168. package/dist/blocks/builtins/Elements.js +64 -0
  169. package/dist/blocks/builtins/Elements.js.map +1 -0
  170. package/dist/blocks/builtins/Embed.d.ts +2 -0
  171. package/dist/blocks/builtins/Embed.js +30 -0
  172. package/dist/blocks/builtins/Embed.js.map +1 -0
  173. package/dist/blocks/builtins/Faq.d.ts +6 -0
  174. package/dist/blocks/builtins/Faq.js +110 -0
  175. package/dist/blocks/builtins/Faq.js.map +1 -0
  176. package/dist/blocks/builtins/FormBlock.d.ts +2 -0
  177. package/dist/blocks/builtins/FormBlock.js +221 -0
  178. package/dist/blocks/builtins/FormBlock.js.map +1 -0
  179. package/dist/blocks/builtins/Gallery.d.ts +23 -0
  180. package/dist/blocks/builtins/Gallery.js +177 -0
  181. package/dist/blocks/builtins/Gallery.js.map +1 -0
  182. package/dist/blocks/builtins/Hero.d.ts +2 -0
  183. package/dist/blocks/builtins/Hero.js +47 -0
  184. package/dist/blocks/builtins/Hero.js.map +1 -0
  185. package/dist/blocks/builtins/ImageBlock.d.ts +2 -0
  186. package/dist/blocks/builtins/ImageBlock.js +24 -0
  187. package/dist/blocks/builtins/ImageBlock.js.map +1 -0
  188. package/dist/blocks/builtins/Jobs.d.ts +8 -0
  189. package/dist/blocks/builtins/Jobs.js +65 -0
  190. package/dist/blocks/builtins/Jobs.js.map +1 -0
  191. package/dist/blocks/builtins/Layout.d.ts +3 -0
  192. package/dist/blocks/builtins/Layout.js +67 -0
  193. package/dist/blocks/builtins/Layout.js.map +1 -0
  194. package/dist/blocks/builtins/MapBlock.d.ts +2 -0
  195. package/dist/blocks/builtins/MapBlock.js +31 -0
  196. package/dist/blocks/builtins/MapBlock.js.map +1 -0
  197. package/dist/blocks/builtins/NewsListBlock.d.ts +2 -0
  198. package/dist/blocks/builtins/NewsListBlock.js +24 -0
  199. package/dist/blocks/builtins/NewsListBlock.js.map +1 -0
  200. package/dist/blocks/builtins/Newsletter.d.ts +2 -0
  201. package/dist/blocks/builtins/Newsletter.js +84 -0
  202. package/dist/blocks/builtins/Newsletter.js.map +1 -0
  203. package/dist/blocks/builtins/OpenNowBadge.d.ts +9 -0
  204. package/dist/blocks/builtins/OpenNowBadge.js +20 -0
  205. package/dist/blocks/builtins/OpenNowBadge.js.map +1 -0
  206. package/dist/blocks/builtins/OpeningHours.d.ts +2 -0
  207. package/dist/blocks/builtins/OpeningHours.js +47 -0
  208. package/dist/blocks/builtins/OpeningHours.js.map +1 -0
  209. package/dist/blocks/builtins/PdfBlock.d.ts +2 -0
  210. package/dist/blocks/builtins/PdfBlock.js +97 -0
  211. package/dist/blocks/builtins/PdfBlock.js.map +1 -0
  212. package/dist/blocks/builtins/Portfolio.d.ts +2 -0
  213. package/dist/blocks/builtins/Portfolio.js +94 -0
  214. package/dist/blocks/builtins/Portfolio.js.map +1 -0
  215. package/dist/blocks/builtins/Pricing.d.ts +6 -0
  216. package/dist/blocks/builtins/Pricing.js +77 -0
  217. package/dist/blocks/builtins/Pricing.js.map +1 -0
  218. package/dist/blocks/builtins/RichTextBlock.d.ts +2 -0
  219. package/dist/blocks/builtins/RichTextBlock.js +18 -0
  220. package/dist/blocks/builtins/RichTextBlock.js.map +1 -0
  221. package/dist/blocks/builtins/Search.d.ts +2 -0
  222. package/dist/blocks/builtins/Search.js +99 -0
  223. package/dist/blocks/builtins/Search.js.map +1 -0
  224. package/dist/blocks/builtins/Sections.d.ts +5 -0
  225. package/dist/blocks/builtins/Sections.js +183 -0
  226. package/dist/blocks/builtins/Sections.js.map +1 -0
  227. package/dist/blocks/builtins/Slider.d.ts +2 -0
  228. package/dist/blocks/builtins/Slider.js +131 -0
  229. package/dist/blocks/builtins/Slider.js.map +1 -0
  230. package/dist/blocks/builtins/Spacer.d.ts +2 -0
  231. package/dist/blocks/builtins/Spacer.js +19 -0
  232. package/dist/blocks/builtins/Spacer.js.map +1 -0
  233. package/dist/blocks/builtins/Team.d.ts +2 -0
  234. package/dist/blocks/builtins/Team.js +70 -0
  235. package/dist/blocks/builtins/Team.js.map +1 -0
  236. package/dist/blocks/builtins/Testimonials.d.ts +8 -0
  237. package/dist/blocks/builtins/Testimonials.js +82 -0
  238. package/dist/blocks/builtins/Testimonials.js.map +1 -0
  239. package/dist/blocks/builtins/Video.d.ts +9 -0
  240. package/dist/blocks/builtins/Video.js +77 -0
  241. package/dist/blocks/builtins/Video.js.map +1 -0
  242. package/dist/blocks/builtins/WhatsappChat.d.ts +8 -0
  243. package/dist/blocks/builtins/WhatsappChat.js +51 -0
  244. package/dist/blocks/builtins/WhatsappChat.js.map +1 -0
  245. package/dist/blocks/builtins/Widgets.d.ts +13 -0
  246. package/dist/blocks/builtins/Widgets.js +308 -0
  247. package/dist/blocks/builtins/Widgets.js.map +1 -0
  248. package/dist/blocks/builtins/consentEmbed.d.ts +17 -0
  249. package/dist/blocks/builtins/consentEmbed.js +31 -0
  250. package/dist/blocks/builtins/consentEmbed.js.map +1 -0
  251. package/dist/blocks/builtins/index.d.ts +46 -0
  252. package/dist/blocks/builtins/index.js +121 -0
  253. package/dist/blocks/builtins/index.js.map +1 -0
  254. package/dist/blocks/builtins/lib/bookingUrl.d.ts +8 -0
  255. package/dist/blocks/builtins/lib/bookingUrl.js +50 -0
  256. package/dist/blocks/builtins/lib/bookingUrl.js.map +1 -0
  257. package/dist/blocks/builtins/lib/fileIcon.d.ts +2 -0
  258. package/dist/blocks/builtins/lib/fileIcon.js +45 -0
  259. package/dist/blocks/builtins/lib/fileIcon.js.map +1 -0
  260. package/dist/blocks/builtins/lib/ics.d.ts +17 -0
  261. package/dist/blocks/builtins/lib/ics.js +50 -0
  262. package/dist/blocks/builtins/lib/ics.js.map +1 -0
  263. package/dist/blocks/builtins/lib/openingHours.d.ts +20 -0
  264. package/dist/blocks/builtins/lib/openingHours.js +79 -0
  265. package/dist/blocks/builtins/lib/openingHours.js.map +1 -0
  266. package/dist/blocks/builtins/lib/searchRank.d.ts +22 -0
  267. package/dist/blocks/builtins/lib/searchRank.js +45 -0
  268. package/dist/blocks/builtins/lib/searchRank.js.map +1 -0
  269. package/dist/blocks/builtins/lib/submitForm.d.ts +6 -0
  270. package/dist/blocks/builtins/lib/submitForm.js +14 -0
  271. package/dist/blocks/builtins/lib/submitForm.js.map +1 -0
  272. package/dist/blocks/context.d.ts +8 -0
  273. package/dist/blocks/context.js +20 -0
  274. package/dist/blocks/context.js.map +1 -0
  275. package/dist/blocks/index.d.ts +9 -0
  276. package/dist/blocks/index.js +21 -0
  277. package/dist/blocks/index.js.map +1 -0
  278. package/dist/blocks/registry.d.ts +75 -0
  279. package/dist/blocks/registry.js +71 -0
  280. package/dist/blocks/registry.js.map +1 -0
  281. package/dist/blocks/ui/index.d.ts +35 -0
  282. package/dist/blocks/ui/index.js +48 -0
  283. package/dist/blocks/ui/index.js.map +1 -0
  284. package/dist/components/EditBar.d.ts +2 -0
  285. package/dist/components/EditBar.js +20 -0
  286. package/dist/components/EditBar.js.map +1 -0
  287. package/dist/components/EditableImage.d.ts +18 -0
  288. package/dist/components/EditableImage.js +62 -0
  289. package/dist/components/EditableImage.js.map +1 -0
  290. package/dist/components/EditableRichText.d.ts +14 -0
  291. package/dist/components/EditableRichText.js +26 -0
  292. package/dist/components/EditableRichText.js.map +1 -0
  293. package/dist/components/EditableText.d.ts +21 -0
  294. package/dist/components/EditableText.js +25 -0
  295. package/dist/components/EditableText.js.map +1 -0
  296. package/dist/components/News.d.ts +38 -0
  297. package/dist/components/News.js +128 -0
  298. package/dist/components/News.js.map +1 -0
  299. package/dist/components/PageView.d.ts +8 -0
  300. package/dist/components/PageView.js +28 -0
  301. package/dist/components/PageView.js.map +1 -0
  302. package/dist/components/ResponsiveImage.d.ts +16 -0
  303. package/dist/components/ResponsiveImage.js +39 -0
  304. package/dist/components/ResponsiveImage.js.map +1 -0
  305. package/dist/components/site/SiteFooter.d.ts +12 -0
  306. package/dist/components/site/SiteFooter.js +34 -0
  307. package/dist/components/site/SiteFooter.js.map +1 -0
  308. package/dist/config.d.ts +8 -0
  309. package/dist/config.js +17 -0
  310. package/dist/config.js.map +1 -0
  311. package/dist/content/ContentProvider.d.ts +23 -0
  312. package/dist/content/ContentProvider.js +86 -0
  313. package/dist/content/ContentProvider.js.map +1 -0
  314. package/dist/content/types.d.ts +41 -0
  315. package/dist/content/types.js +1 -0
  316. package/dist/content/types.js.map +1 -0
  317. package/dist/demo/DemoStudio.d.ts +7 -0
  318. package/dist/demo/DemoStudio.js +54 -0
  319. package/dist/demo/DemoStudio.js.map +1 -0
  320. package/dist/demo/demoStore.d.ts +26 -0
  321. package/dist/demo/demoStore.js +115 -0
  322. package/dist/demo/demoStore.js.map +1 -0
  323. package/dist/editor/EditorProvider.d.ts +12 -0
  324. package/dist/editor/EditorProvider.js +22 -0
  325. package/dist/editor/EditorProvider.js.map +1 -0
  326. package/dist/firebase/admin.d.ts +7 -0
  327. package/dist/firebase/admin.js +31 -0
  328. package/dist/firebase/admin.js.map +1 -0
  329. package/dist/firebase/appcheck.d.ts +6 -0
  330. package/dist/firebase/appcheck.js +23 -0
  331. package/dist/firebase/appcheck.js.map +1 -0
  332. package/dist/firebase/client.d.ts +9 -0
  333. package/dist/firebase/client.js +44 -0
  334. package/dist/firebase/client.js.map +1 -0
  335. package/dist/firebase/region.d.ts +5 -0
  336. package/dist/firebase/region.js +7 -0
  337. package/dist/firebase/region.js.map +1 -0
  338. package/dist/index.d.ts +54 -0
  339. package/dist/index.js +172 -0
  340. package/dist/index.js.map +1 -0
  341. package/dist/layers.css +13 -0
  342. package/dist/lock/DemoLock.d.ts +5 -0
  343. package/dist/lock/DemoLock.js +35 -0
  344. package/dist/lock/DemoLock.js.map +1 -0
  345. package/dist/media/ImageContext.d.ts +41 -0
  346. package/dist/media/ImageContext.js +74 -0
  347. package/dist/media/ImageContext.js.map +1 -0
  348. package/dist/modules/builtins.d.ts +46 -0
  349. package/dist/modules/builtins.js +462 -0
  350. package/dist/modules/builtins.js.map +1 -0
  351. package/dist/modules/consent/ConsentBanner.d.ts +42 -0
  352. package/dist/modules/consent/ConsentBanner.js +119 -0
  353. package/dist/modules/consent/ConsentBanner.js.map +1 -0
  354. package/dist/modules/consent/useConsent.d.ts +28 -0
  355. package/dist/modules/consent/useConsent.js +52 -0
  356. package/dist/modules/consent/useConsent.js.map +1 -0
  357. package/dist/modules/context.d.ts +20 -0
  358. package/dist/modules/context.js +31 -0
  359. package/dist/modules/context.js.map +1 -0
  360. package/dist/modules/contract.d.ts +9 -0
  361. package/dist/modules/contract.js +38 -0
  362. package/dist/modules/contract.js.map +1 -0
  363. package/dist/modules/defineModule.d.ts +11 -0
  364. package/dist/modules/defineModule.js +7 -0
  365. package/dist/modules/defineModule.js.map +1 -0
  366. package/dist/modules/index.d.ts +13 -0
  367. package/dist/modules/index.js +44 -0
  368. package/dist/modules/index.js.map +1 -0
  369. package/dist/modules/overrides.d.ts +17 -0
  370. package/dist/modules/overrides.js +25 -0
  371. package/dist/modules/overrides.js.map +1 -0
  372. package/dist/modules/registry.d.ts +40 -0
  373. package/dist/modules/registry.js +79 -0
  374. package/dist/modules/registry.js.map +1 -0
  375. package/dist/modules/types.d.ts +66 -0
  376. package/dist/modules/types.js +1 -0
  377. package/dist/modules/types.js.map +1 -0
  378. package/dist/patterns/builtins.d.ts +31 -0
  379. package/dist/patterns/builtins.js +415 -0
  380. package/dist/patterns/builtins.js.map +1 -0
  381. package/dist/patterns/index.d.ts +6 -0
  382. package/dist/patterns/index.js +9 -0
  383. package/dist/patterns/index.js.map +1 -0
  384. package/dist/patterns/patterns.d.ts +28 -0
  385. package/dist/patterns/patterns.js +53 -0
  386. package/dist/patterns/patterns.js.map +1 -0
  387. package/dist/render/PageRenderer.d.ts +13 -0
  388. package/dist/render/PageRenderer.js +14 -0
  389. package/dist/render/PageRenderer.js.map +1 -0
  390. package/dist/render/PublishedPage.d.ts +13 -0
  391. package/dist/render/PublishedPage.js +16 -0
  392. package/dist/render/PublishedPage.js.map +1 -0
  393. package/dist/schema/blocks.d.ts +15052 -0
  394. package/dist/schema/blocks.js +794 -0
  395. package/dist/schema/blocks.js.map +1 -0
  396. package/dist/schema/forms.d.ts +111 -0
  397. package/dist/schema/forms.js +47 -0
  398. package/dist/schema/forms.js.map +1 -0
  399. package/dist/schema/index.d.ts +11 -0
  400. package/dist/schema/index.js +16 -0
  401. package/dist/schema/index.js.map +1 -0
  402. package/dist/schema/pages.d.ts +674 -0
  403. package/dist/schema/pages.js +37 -0
  404. package/dist/schema/pages.js.map +1 -0
  405. package/dist/schema/seo.d.ts +29 -0
  406. package/dist/schema/seo.js +17 -0
  407. package/dist/schema/seo.js.map +1 -0
  408. package/dist/schema/settings.d.ts +1126 -0
  409. package/dist/schema/settings.js +128 -0
  410. package/dist/schema/settings.js.map +1 -0
  411. package/dist/schema/siteConfig.d.ts +722 -0
  412. package/dist/schema/siteConfig.js +39 -0
  413. package/dist/schema/siteConfig.js.map +1 -0
  414. package/dist/server/env.d.ts +10 -0
  415. package/dist/server/env.js +36 -0
  416. package/dist/server/env.js.map +1 -0
  417. package/dist/server/index.d.ts +10 -0
  418. package/dist/server/index.js +51 -0
  419. package/dist/server/index.js.map +1 -0
  420. package/dist/server/pages.d.ts +15 -0
  421. package/dist/server/pages.js +99 -0
  422. package/dist/server/pages.js.map +1 -0
  423. package/dist/server/sanitize.d.ts +2 -0
  424. package/dist/server/sanitize.js +55 -0
  425. package/dist/server/sanitize.js.map +1 -0
  426. package/dist/server/seo.d.ts +116 -0
  427. package/dist/server/seo.js +179 -0
  428. package/dist/server/seo.js.map +1 -0
  429. package/dist/settings/useSiteSettings.d.ts +25 -0
  430. package/dist/settings/useSiteSettings.js +68 -0
  431. package/dist/settings/useSiteSettings.js.map +1 -0
  432. package/dist/styles.css +2495 -0
  433. package/dist/theme/presets.d.ts +12 -0
  434. package/dist/theme/presets.js +147 -0
  435. package/dist/theme/presets.js.map +1 -0
  436. package/package.json +112 -0
@@ -0,0 +1,304 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useRef, useState } from "react";
4
+ import { doc, onSnapshot, writeBatch } from "firebase/firestore";
5
+ import { getFunctions, httpsCallable } from "firebase/functions";
6
+ import { getDb, getFirebaseApp } from "../../firebase/client";
7
+ import { functionsRegion } from "../../firebase/region";
8
+ import { SiteSettingsSchema, toPublicSettings } from "../../schema/settings";
9
+ import { useModules } from "../../modules/context";
10
+ import { builtinThemePresets } from "../../theme/presets";
11
+ import { Button, Card, Field, Input } from "../ui/primitives";
12
+ import { Select } from "../ui/select";
13
+ import { Switch } from "../ui/switch";
14
+ import { ArrayEditor } from "../ui/ArrayEditor";
15
+ import { useToast } from "../ui/toast";
16
+ import { useConfirm } from "../ui/ConfirmDialog";
17
+ import { ModuleSettingsForm } from "./moduleSettingsForm";
18
+ function SettingsPanel({ siteId }) {
19
+ const { toast } = useToast();
20
+ const confirm = useConfirm();
21
+ const { defs } = useModules();
22
+ const [s, setS] = useState({});
23
+ const [loaded, setLoaded] = useState(false);
24
+ const [exporting, setExporting] = useState(false);
25
+ const [restoring, setRestoring] = useState(false);
26
+ const restoreInput = useRef(null);
27
+ async function downloadBackup(silent = false) {
28
+ const app = getFirebaseApp();
29
+ if (!app) return false;
30
+ setExporting(true);
31
+ try {
32
+ const fn = httpsCallable(
33
+ getFunctions(app, functionsRegion()),
34
+ "exportSite"
35
+ );
36
+ const res = await fn({ siteId });
37
+ const blob = new Blob([JSON.stringify(res.data, null, 2)], { type: "application/json" });
38
+ const url = URL.createObjectURL(blob);
39
+ const a = document.createElement("a");
40
+ a.href = url;
41
+ a.download = `xicms-backup-${siteId}-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.json`;
42
+ a.click();
43
+ URL.revokeObjectURL(url);
44
+ if (!silent) toast({ title: "Back-up gedownload", tone: "success" });
45
+ return true;
46
+ } catch (e) {
47
+ toast({ title: "Back-up mislukt", description: e.message, tone: "error" });
48
+ return false;
49
+ } finally {
50
+ setExporting(false);
51
+ }
52
+ }
53
+ async function restoreFromFile(file) {
54
+ let backup;
55
+ try {
56
+ backup = JSON.parse(await file.text());
57
+ } catch {
58
+ toast({ title: "Ongeldig bestand", description: "Dit is geen geldig back-upbestand.", tone: "error" });
59
+ return;
60
+ }
61
+ if (backup._format !== "xicms-export") {
62
+ toast({ title: "Ongeldig bestand", description: "Dit lijkt geen XiCMS-back-up.", tone: "error" });
63
+ return;
64
+ }
65
+ if (backup.siteId && backup.siteId !== siteId) {
66
+ const ok2 = await confirm({
67
+ title: "Back-up van een andere site",
68
+ description: `Deze back-up is van \u201C${String(backup.siteId)}\u201D, niet van deze site (${siteId}). Toch terugzetten?`,
69
+ confirmLabel: "Toch terugzetten",
70
+ tone: "danger"
71
+ });
72
+ if (!ok2) return;
73
+ }
74
+ const ok = await confirm({
75
+ title: "Back-up terugzetten?",
76
+ 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.`,
77
+ confirmLabel: "Terugzetten",
78
+ tone: "danger"
79
+ });
80
+ if (!ok) return;
81
+ setRestoring(true);
82
+ try {
83
+ await downloadBackup(true);
84
+ const app = getFirebaseApp();
85
+ if (!app) throw new Error("Firebase niet geconfigureerd.");
86
+ const fn = httpsCallable(getFunctions(app, functionsRegion()), "restoreSite");
87
+ await fn({ siteId, backup });
88
+ toast({ title: "Back-up teruggezet", description: "Herlaad de pagina om alles bij te werken.", tone: "success" });
89
+ } catch (e) {
90
+ toast({ title: "Terugzetten mislukt", description: e.message, tone: "error" });
91
+ } finally {
92
+ setRestoring(false);
93
+ }
94
+ }
95
+ useEffect(() => {
96
+ const db = getDb();
97
+ if (!db) {
98
+ setLoaded(true);
99
+ return;
100
+ }
101
+ return onSnapshot(doc(db, "sites", siteId, "settings", "site"), (snap) => {
102
+ if (snap.exists()) setS(snap.data());
103
+ setLoaded(true);
104
+ });
105
+ }, [siteId]);
106
+ async function save() {
107
+ const db = getDb();
108
+ if (!db) return;
109
+ const parsed = SiteSettingsSchema.safeParse(s);
110
+ if (!parsed.success) {
111
+ toast({ title: "Ongeldige instellingen", description: parsed.error.issues[0]?.message, tone: "error" });
112
+ return;
113
+ }
114
+ try {
115
+ const batch = writeBatch(db);
116
+ batch.set(doc(db, "sites", siteId, "settings", "site"), parsed.data, { merge: true });
117
+ batch.set(doc(db, "sites", siteId, "settings", "public"), toPublicSettings(parsed.data), { merge: true });
118
+ await batch.commit();
119
+ toast({ title: "Opgeslagen", description: "Wijzigingen zijn direct live.", tone: "success" });
120
+ } catch (e) {
121
+ toast({ title: "Opslaan mislukt", description: e.message, tone: "error" });
122
+ }
123
+ }
124
+ if (!loaded) return /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500", children: "Laden\u2026" });
125
+ const forms = s.forms ?? { mode: "xicms" };
126
+ const theme = s.theme ?? { primary: "#4f46e5" };
127
+ const footer = s.footer ?? {};
128
+ const moduleState = (id, defaultEnabled) => {
129
+ const raw = s.modules?.[id];
130
+ if (typeof raw === "boolean") return { enabled: raw, config: {} };
131
+ return { enabled: raw?.enabled ?? defaultEnabled, config: raw?.config ?? {} };
132
+ };
133
+ const setModule = (id, next) => setS({ ...s, modules: { ...s.modules, [id]: next } });
134
+ return /* @__PURE__ */ jsxs("div", { className: "grid gap-4", children: [
135
+ /* @__PURE__ */ jsxs(Card, { children: [
136
+ /* @__PURE__ */ jsx("h3", { className: "mb-3 text-base font-semibold", children: "Algemeen" }),
137
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-3 md:grid-cols-2", children: [
138
+ /* @__PURE__ */ jsx(Field, { label: "Sitenaam", children: /* @__PURE__ */ jsx(Input, { value: s.name ?? "", onChange: (e) => setS({ ...s, name: e.target.value }) }) }),
139
+ /* @__PURE__ */ jsx(Field, { label: "Domein", children: /* @__PURE__ */ jsx(Input, { value: s.domain ?? "", onChange: (e) => setS({ ...s, domain: e.target.value }) }) }),
140
+ /* @__PURE__ */ jsx(Field, { label: "Contact-e-mail", children: /* @__PURE__ */ jsx(Input, { value: s.contactEmail ?? "", onChange: (e) => setS({ ...s, contactEmail: e.target.value }) }) })
141
+ ] })
142
+ ] }),
143
+ /* @__PURE__ */ jsxs(Card, { children: [
144
+ /* @__PURE__ */ jsx("h3", { className: "mb-3 text-base font-semibold", children: "Huisstijl" }),
145
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-3", children: [
146
+ /* @__PURE__ */ jsx(Field, { label: "Thema-preset", hint: "Vult kleuren, lettertype en afronding in \xE9\xE9n keer in.", children: /* @__PURE__ */ jsx(
147
+ Select,
148
+ {
149
+ value: "",
150
+ placeholder: "Kies een preset\u2026",
151
+ onValueChange: (id) => {
152
+ const preset = builtinThemePresets.find((p) => p.id === id);
153
+ if (preset) setS({ ...s, theme: { ...theme, ...preset.theme } });
154
+ },
155
+ options: builtinThemePresets.map((p) => ({ value: p.id, label: p.label }))
156
+ }
157
+ ) }),
158
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-3 md:grid-cols-2", children: [
159
+ /* @__PURE__ */ jsx(Field, { label: "Primaire kleur", children: /* @__PURE__ */ jsx(Input, { value: theme.primary, onChange: (e) => setS({ ...s, theme: { ...theme, primary: e.target.value } }) }) }),
160
+ /* @__PURE__ */ jsx(Field, { label: "Accentkleur", children: /* @__PURE__ */ jsx(Input, { value: theme.accent ?? "", onChange: (e) => setS({ ...s, theme: { ...theme, accent: e.target.value } }) }) }),
161
+ /* @__PURE__ */ jsx(Field, { label: "Achtergrondkleur", children: /* @__PURE__ */ jsx(Input, { value: theme.background ?? "", onChange: (e) => setS({ ...s, theme: { ...theme, background: e.target.value } }), placeholder: "#ffffff" }) }),
162
+ /* @__PURE__ */ jsx(Field, { label: "Tekstkleur", children: /* @__PURE__ */ jsx(Input, { value: theme.foreground ?? "", onChange: (e) => setS({ ...s, theme: { ...theme, foreground: e.target.value } }), placeholder: "#0f172a" }) })
163
+ ] })
164
+ ] })
165
+ ] }),
166
+ /* @__PURE__ */ jsxs(Card, { children: [
167
+ /* @__PURE__ */ jsx("h3", { className: "mb-3 text-base font-semibold", children: "SEO (standaard)" }),
168
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-3", children: [
169
+ /* @__PURE__ */ jsx(Field, { label: "Standaard-omschrijving", children: /* @__PURE__ */ jsx(Input, { value: s.seoDefaults?.description ?? "", onChange: (e) => setS({ ...s, seoDefaults: { ...s.seoDefaults, description: e.target.value } }) }) }),
170
+ /* @__PURE__ */ jsx(Field, { label: "OG-afbeelding (URL)", children: /* @__PURE__ */ jsx(Input, { value: s.seoDefaults?.ogImage ?? "", onChange: (e) => setS({ ...s, seoDefaults: { ...s.seoDefaults, ogImage: e.target.value } }) }) })
171
+ ] })
172
+ ] }),
173
+ /* @__PURE__ */ jsxs(Card, { children: [
174
+ /* @__PURE__ */ jsx("h3", { className: "mb-1 text-base font-semibold", children: "Footer" }),
175
+ /* @__PURE__ */ jsx("p", { className: "mb-3 text-xs text-slate-500", children: "Kolommen met links, social-links en copyright. Wijzigingen zijn direct live." }),
176
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-4", children: [
177
+ /* @__PURE__ */ jsxs("div", { children: [
178
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Kolommen" }),
179
+ /* @__PURE__ */ jsx(
180
+ ArrayEditor,
181
+ {
182
+ items: footer.columns ?? [],
183
+ onChange: (columns) => setS({ ...s, footer: { ...footer, columns } }),
184
+ newItem: () => ({ heading: "", links: [] }),
185
+ addLabel: "+ Kolom",
186
+ emptyLabel: "Nog geen kolommen.",
187
+ renderRow: (col, update) => /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
188
+ /* @__PURE__ */ jsx(Field, { label: "Kop", children: /* @__PURE__ */ jsx(Input, { value: col.heading ?? "", onChange: (e) => update({ heading: e.target.value }) }) }),
189
+ /* @__PURE__ */ jsx(
190
+ ArrayEditor,
191
+ {
192
+ items: col.links ?? [],
193
+ onChange: (links) => update({ links }),
194
+ newItem: () => ({ label: "", href: "" }),
195
+ addLabel: "+ Link",
196
+ renderRow: (link, updL) => /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
197
+ /* @__PURE__ */ jsx(Input, { value: link.label, placeholder: "Label", onChange: (e) => updL({ label: e.target.value }) }),
198
+ /* @__PURE__ */ jsx(Input, { value: link.href, placeholder: "/pad of https://\u2026", onChange: (e) => updL({ href: e.target.value }) })
199
+ ] })
200
+ }
201
+ )
202
+ ] })
203
+ }
204
+ )
205
+ ] }),
206
+ /* @__PURE__ */ jsxs("div", { children: [
207
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Social-links" }),
208
+ /* @__PURE__ */ jsx(
209
+ ArrayEditor,
210
+ {
211
+ items: footer.social ?? [],
212
+ onChange: (social) => setS({ ...s, footer: { ...footer, social } }),
213
+ newItem: () => ({ platform: "", href: "" }),
214
+ addLabel: "+ Social-link",
215
+ renderRow: (link, update) => /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
216
+ /* @__PURE__ */ jsx(Input, { value: link.platform, placeholder: "bv. Instagram", onChange: (e) => update({ platform: e.target.value }) }),
217
+ /* @__PURE__ */ jsx(Input, { value: link.href, placeholder: "https://\u2026", onChange: (e) => update({ href: e.target.value }) })
218
+ ] })
219
+ }
220
+ )
221
+ ] }),
222
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-3 md:grid-cols-2", children: [
223
+ /* @__PURE__ */ jsx(Field, { label: "Copyright (leeg = automatisch)", children: /* @__PURE__ */ jsx(Input, { value: footer.copyright ?? "", onChange: (e) => setS({ ...s, footer: { ...footer, copyright: e.target.value } }) }) }),
224
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 self-end text-sm", children: [
225
+ /* @__PURE__ */ jsx(Switch, { checked: footer.showAdminLink !== false, onCheckedChange: (v) => setS({ ...s, footer: { ...footer, showAdminLink: v } }) }),
226
+ "\u201CBeheer\u201D-link tonen"
227
+ ] })
228
+ ] })
229
+ ] })
230
+ ] }),
231
+ /* @__PURE__ */ jsxs(Card, { children: [
232
+ /* @__PURE__ */ jsx("h3", { className: "mb-1 text-base font-semibold", children: "Modules" }),
233
+ /* @__PURE__ */ jsx("p", { className: "mb-3 text-xs text-slate-500", children: "Zet functies aan/uit en stel ze in. Uitgezette modules verbergen hun blokken en beheer-paneel." }),
234
+ /* @__PURE__ */ jsx("div", { className: "grid gap-3", children: defs.filter((d) => !d.core).map((d) => {
235
+ const st = moduleState(d.id, d.defaultEnabled ?? true);
236
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-slate-200 p-3", children: [
237
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center justify-between gap-2", children: [
238
+ /* @__PURE__ */ jsxs("span", { children: [
239
+ /* @__PURE__ */ jsx("strong", { className: "text-sm", children: d.label }),
240
+ d.description && /* @__PURE__ */ jsx("span", { className: "block text-xs text-slate-500", children: d.description })
241
+ ] }),
242
+ /* @__PURE__ */ jsx(Switch, { checked: st.enabled, onCheckedChange: (v) => setModule(d.id, { enabled: v, config: st.config }) })
243
+ ] }),
244
+ st.enabled && d.settingsSchema && /* @__PURE__ */ jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsx(
245
+ ModuleSettingsForm,
246
+ {
247
+ schema: d.settingsSchema,
248
+ value: st.config,
249
+ onChange: (config) => setModule(d.id, { enabled: st.enabled, config })
250
+ }
251
+ ) })
252
+ ] }, d.id);
253
+ }) })
254
+ ] }),
255
+ /* @__PURE__ */ jsxs(Card, { children: [
256
+ /* @__PURE__ */ jsx("h3", { className: "mb-1 text-base font-semibold", children: "Formulier-e-mail" }),
257
+ /* @__PURE__ */ jsx("p", { className: "mb-3 text-xs text-slate-500", children: "Een provider verstuurt alleen vanaf een geverifieerd domein. Kies de XiCMS-afzender (werkt direct) of het eigen domein van de klant (vereist domeinverificatie)." }),
258
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-3 md:grid-cols-2", children: [
259
+ /* @__PURE__ */ jsx(Field, { label: "Afzender-modus", children: /* @__PURE__ */ jsx(
260
+ Select,
261
+ {
262
+ value: forms.mode,
263
+ onValueChange: (v) => setS({ ...s, forms: { ...forms, mode: v } }),
264
+ options: [
265
+ { value: "xicms", label: "XiCMS-domein (aanbevolen)" },
266
+ { value: "client", label: "Eigen domein van de klant" }
267
+ ]
268
+ }
269
+ ) }),
270
+ /* @__PURE__ */ jsx(Field, { label: "Van (from) e-mail", hint: "Moet een geverifieerd domein zijn.", children: /* @__PURE__ */ jsx(Input, { value: forms.fromEmail ?? "", onChange: (e) => setS({ ...s, forms: { ...forms, fromEmail: e.target.value } }) }) }),
271
+ /* @__PURE__ */ jsx(Field, { label: "Van (naam)", children: /* @__PURE__ */ jsx(Input, { value: forms.fromName ?? "", onChange: (e) => setS({ ...s, forms: { ...forms, fromName: e.target.value } }) }) }),
272
+ /* @__PURE__ */ jsx(Field, { label: "Notificaties naar", hint: "Meestal het mailadres van de klant.", children: /* @__PURE__ */ jsx(Input, { value: forms.notifyTo ?? "", onChange: (e) => setS({ ...s, forms: { ...forms, notifyTo: e.target.value } }) }) })
273
+ ] })
274
+ ] }),
275
+ /* @__PURE__ */ jsxs(Card, { children: [
276
+ /* @__PURE__ */ jsx("h3", { className: "mb-1 text-base font-semibold", children: "Back-up & herstel" }),
277
+ /* @__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." }),
278
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
279
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => void downloadBackup(), disabled: exporting || restoring, children: exporting ? "Bezig\u2026" : "Back-up downloaden" }),
280
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => restoreInput.current?.click(), disabled: restoring || exporting, children: restoring ? "Terugzetten\u2026" : "Back-up terugzetten\u2026" }),
281
+ /* @__PURE__ */ jsx(
282
+ "input",
283
+ {
284
+ ref: restoreInput,
285
+ type: "file",
286
+ accept: "application/json,.json",
287
+ hidden: true,
288
+ onChange: (e) => {
289
+ const f = e.target.files?.[0];
290
+ if (f) void restoreFromFile(f);
291
+ e.target.value = "";
292
+ }
293
+ }
294
+ )
295
+ ] }),
296
+ /* @__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." })
297
+ ] }),
298
+ /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(Button, { onClick: save, children: "Instellingen opslaan" }) })
299
+ ] });
300
+ }
301
+ export {
302
+ SettingsPanel
303
+ };
304
+ //# sourceMappingURL=SettingsPanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/admin/settings/SettingsPanel.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { doc, onSnapshot, writeBatch } from \"firebase/firestore\";\nimport { getFunctions, httpsCallable } from \"firebase/functions\";\nimport { getDb, getFirebaseApp } from \"../../firebase/client\";\nimport { functionsRegion } from \"../../firebase/region\";\nimport { SiteSettingsSchema, toPublicSettings, type SiteSettings } from \"../../schema/settings\";\nimport { useModules } from \"../../modules/context\";\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\";\n\nexport function SettingsPanel({ siteId }: { siteId: string }) {\n const { toast } = useToast();\n const confirm = useConfirm();\n const { defs } = useModules();\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 = httpsCallable<{ siteId: string }, Record<string, unknown>>(\n getFunctions(app, functionsRegion()),\n \"exportSite\",\n );\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 await downloadBackup(true);\n const app = getFirebaseApp();\n if (!app) throw new Error(\"Firebase niet geconfigureerd.\");\n const fn = httpsCallable(getFunctions(app, functionsRegion()), \"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 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 if (snap.exists()) setS(snap.data() as SiteSettings);\n setLoaded(true);\n });\n }, [siteId]);\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 // Volledige (rol-only) settings + de publiek-veilige subset die de live site leest —\n // atomair in één batch, zodat `site` en `public` nooit uit sync kunnen raken.\n try {\n const batch = writeBatch(db);\n batch.set(doc(db, \"sites\", siteId, \"settings\", \"site\"), parsed.data, { merge: true });\n batch.set(doc(db, \"sites\", siteId, \"settings\", \"public\"), toPublicSettings(parsed.data), { merge: true });\n await batch.commit();\n toast({ title: \"Opgeslagen\", description: \"Wijzigingen zijn direct 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 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 return (\n <div className=\"grid gap-4\">\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=\"Domein\"><Input value={s.domain ?? \"\"} onChange={(e) => setS({ ...s, domain: e.target.value })} /></Field>\n <Field label=\"Contact-e-mail\"><Input value={s.contactEmail ?? \"\"} onChange={(e) => setS({ ...s, contactEmail: e.target.value })} /></Field>\n </div>\n </Card>\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 <Field label=\"Primaire kleur\"><Input value={theme.primary} onChange={(e) => setS({ ...s, theme: { ...theme, primary: e.target.value } })} /></Field>\n <Field label=\"Accentkleur\"><Input value={theme.accent ?? \"\"} onChange={(e) => setS({ ...s, theme: { ...theme, accent: e.target.value } })} /></Field>\n <Field label=\"Achtergrondkleur\"><Input value={theme.background ?? \"\"} onChange={(e) => setS({ ...s, theme: { ...theme, background: e.target.value } })} placeholder=\"#ffffff\" /></Field>\n <Field label=\"Tekstkleur\"><Input value={theme.foreground ?? \"\"} onChange={(e) => setS({ ...s, theme: { ...theme, foreground: e.target.value } })} placeholder=\"#0f172a\" /></Field>\n </div>\n </div>\n </Card>\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=\"OG-afbeelding (URL)\">\n <Input value={s.seoDefaults?.ogImage ?? \"\"} onChange={(e) => setS({ ...s, seoDefaults: { ...s.seoDefaults, ogImage: e.target.value } })} />\n </Field>\n </div>\n </Card>\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 <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 <Card>\n <h3 className=\"mb-1 text-base font-semibold\">Formulier-e-mail</h3>\n <p className=\"mb-3 text-xs text-slate-500\">\n Een provider verstuurt alleen vanaf een geverifieerd domein. Kies de XiCMS-afzender\n (werkt direct) of het eigen domein van de klant (vereist domeinverificatie).\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 <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 <div className=\"flex justify-end\">\n <Button onClick={save}>Instellingen opslaan</Button>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["ok"]}
@@ -0,0 +1,12 @@
1
+ import type { ZodTypeAny } from "zod";
2
+ /**
3
+ * Generiek instellingen-formulier voor een module op basis van zijn `settingsSchema`. Ondersteunt
4
+ * primitieve velden (getal/boolean/tekst/enum) met leesbare labels via `.describe("…")` op het
5
+ * schema. Complexe velden (arrays/objects) blijven via site.config/code beheerd — bewust foolproof
6
+ * gehouden voor de klant (de GenericEditor voor blokken biedt daar wél een JSON-vangnet).
7
+ */
8
+ export declare function ModuleSettingsForm({ schema, value, onChange, }: {
9
+ schema: ZodTypeAny;
10
+ value: Record<string, unknown>;
11
+ onChange: (next: Record<string, unknown>) => void;
12
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,45 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { Field, Input } from "../ui/primitives";
4
+ import { Select } from "../ui/select";
5
+ import { Switch } from "../ui/switch";
6
+ import { introspectObjectSchema } from "../lib/zodFields";
7
+ function ModuleSettingsForm({
8
+ schema,
9
+ value,
10
+ onChange
11
+ }) {
12
+ const fields = introspectObjectSchema(schema).filter((f) => f.kind !== "json");
13
+ if (fields.length === 0) return null;
14
+ const set = (key, v) => onChange({ ...value, [key]: v });
15
+ return /* @__PURE__ */ jsx("div", { className: "grid gap-2 sm:grid-cols-2", children: fields.map((f) => {
16
+ if (f.kind === "boolean") {
17
+ return /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
18
+ /* @__PURE__ */ jsx(Switch, { checked: Boolean(value[f.key]), onCheckedChange: (v) => set(f.key, v) }),
19
+ f.label
20
+ ] }, f.key);
21
+ }
22
+ if (f.kind === "enum") {
23
+ return /* @__PURE__ */ jsx(Field, { label: f.label, children: /* @__PURE__ */ jsx(
24
+ Select,
25
+ {
26
+ value: String(value[f.key] ?? f.options?.[0] ?? ""),
27
+ onValueChange: (v) => set(f.key, v),
28
+ options: (f.options ?? []).map((o) => ({ value: o, label: o }))
29
+ }
30
+ ) }, f.key);
31
+ }
32
+ return /* @__PURE__ */ jsx(Field, { label: f.label, children: /* @__PURE__ */ jsx(
33
+ Input,
34
+ {
35
+ type: f.kind === "number" ? "number" : "text",
36
+ value: String(value[f.key] ?? ""),
37
+ onChange: (e) => set(f.key, f.kind === "number" ? Number(e.target.value) : e.target.value)
38
+ }
39
+ ) }, f.key);
40
+ }) });
41
+ }
42
+ export {
43
+ ModuleSettingsForm
44
+ };
45
+ //# sourceMappingURL=moduleSettingsForm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/admin/settings/moduleSettingsForm.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ZodTypeAny } from \"zod\";\nimport { Field, Input } from \"../ui/primitives\";\nimport { Select } from \"../ui/select\";\nimport { Switch } from \"../ui/switch\";\nimport { introspectObjectSchema } from \"../lib/zodFields\";\n\n/**\n * Generiek instellingen-formulier voor een module op basis van zijn `settingsSchema`. Ondersteunt\n * primitieve velden (getal/boolean/tekst/enum) met leesbare labels via `.describe(\"…\")` op het\n * schema. Complexe velden (arrays/objects) blijven via site.config/code beheerd — bewust foolproof\n * gehouden voor de klant (de GenericEditor voor blokken biedt daar wél een JSON-vangnet).\n */\nexport function ModuleSettingsForm({\n schema,\n value,\n onChange,\n}: {\n schema: ZodTypeAny;\n value: Record<string, unknown>;\n onChange: (next: Record<string, unknown>) => void;\n}) {\n const fields = introspectObjectSchema(schema).filter((f) => f.kind !== \"json\");\n if (fields.length === 0) return null;\n const set = (key: string, v: unknown) => onChange({ ...value, [key]: v });\n\n return (\n <div className=\"grid gap-2 sm:grid-cols-2\">\n {fields.map((f) => {\n if (f.kind === \"boolean\") {\n return (\n <label key={f.key} className=\"flex items-center gap-2 text-sm\">\n <Switch checked={Boolean(value[f.key])} onCheckedChange={(v) => set(f.key, v)} />\n {f.label}\n </label>\n );\n }\n if (f.kind === \"enum\") {\n return (\n <Field key={f.key} label={f.label}>\n <Select\n value={String(value[f.key] ?? f.options?.[0] ?? \"\")}\n onValueChange={(v) => set(f.key, v)}\n options={(f.options ?? []).map((o) => ({ value: o, label: o }))}\n />\n </Field>\n );\n }\n return (\n <Field key={f.key} label={f.label}>\n <Input\n type={f.kind === \"number\" ? \"number\" : \"text\"}\n value={String(value[f.key] ?? \"\")}\n onChange={(e) => set(f.key, f.kind === \"number\" ? Number(e.target.value) : e.target.value)}\n />\n </Field>\n );\n })}\n </div>\n );\n}\n"],"mappings":";AAgCY,SACE,KADF;AA7BZ,SAAS,OAAO,aAAa;AAC7B,SAAS,cAAc;AACvB,SAAS,cAAc;AACvB,SAAS,8BAA8B;AAQhC,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,SAAS,uBAAuB,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM;AAC7E,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,QAAM,MAAM,CAAC,KAAa,MAAe,SAAS,EAAE,GAAG,OAAO,CAAC,GAAG,GAAG,EAAE,CAAC;AAExE,SACE,oBAAC,SAAI,WAAU,6BACZ,iBAAO,IAAI,CAAC,MAAM;AACjB,QAAI,EAAE,SAAS,WAAW;AACxB,aACE,qBAAC,WAAkB,WAAU,mCAC3B;AAAA,4BAAC,UAAO,SAAS,QAAQ,MAAM,EAAE,GAAG,CAAC,GAAG,iBAAiB,CAAC,MAAM,IAAI,EAAE,KAAK,CAAC,GAAG;AAAA,QAC9E,EAAE;AAAA,WAFO,EAAE,GAGd;AAAA,IAEJ;AACA,QAAI,EAAE,SAAS,QAAQ;AACrB,aACE,oBAAC,SAAkB,OAAO,EAAE,OAC1B;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,OAAO,MAAM,EAAE,GAAG,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE;AAAA,UAClD,eAAe,CAAC,MAAM,IAAI,EAAE,KAAK,CAAC;AAAA,UAClC,UAAU,EAAE,WAAW,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,EAAE;AAAA;AAAA,MAChE,KALU,EAAE,GAMd;AAAA,IAEJ;AACA,WACE,oBAAC,SAAkB,OAAO,EAAE,OAC1B;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,EAAE,SAAS,WAAW,WAAW;AAAA,QACvC,OAAO,OAAO,MAAM,EAAE,GAAG,KAAK,EAAE;AAAA,QAChC,UAAU,CAAC,MAAM,IAAI,EAAE,KAAK,EAAE,SAAS,WAAW,OAAO,EAAE,OAAO,KAAK,IAAI,EAAE,OAAO,KAAK;AAAA;AAAA,IAC3F,KALU,EAAE,GAMd;AAAA,EAEJ,CAAC,GACH;AAEJ;","names":[]}
@@ -0,0 +1,4 @@
1
+ /** Eenvoudige, privacy-vriendelijke bezoekersstatistieken (eigen teller). */
2
+ export declare function StatsPanel({ siteId }: {
3
+ siteId: string;
4
+ }): import("react").JSX.Element;
@@ -0,0 +1,80 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useMemo, useState } from "react";
4
+ import { collection, getDocs } from "firebase/firestore";
5
+ import { getDb } from "../../firebase/client";
6
+ import { Card } from "../ui/primitives";
7
+ function StatsPanel({ siteId }) {
8
+ const [months, setMonths] = useState([]);
9
+ const [loading, setLoading] = useState(true);
10
+ useEffect(() => {
11
+ const db = getDb();
12
+ if (!db) {
13
+ setLoading(false);
14
+ return;
15
+ }
16
+ let active = true;
17
+ getDocs(collection(db, "sites", siteId, "stats")).then((snap) => {
18
+ if (!active) return;
19
+ setMonths(snap.docs.map((d) => ({ id: d.id, ...d.data() })));
20
+ setLoading(false);
21
+ }).catch(() => active && setLoading(false));
22
+ return () => {
23
+ active = false;
24
+ };
25
+ }, [siteId]);
26
+ const total = useMemo(() => months.reduce((s, m) => s + (m.total ?? 0), 0), [months]);
27
+ const current = useMemo(() => {
28
+ const now = /* @__PURE__ */ new Date();
29
+ const id = `${now.getUTCFullYear()}-${String(now.getUTCMonth() + 1).padStart(2, "0")}`;
30
+ return months.find((m) => m.id === id);
31
+ }, [months]);
32
+ const days = current?.days ?? {};
33
+ const maxDay = Math.max(1, ...Object.values(days));
34
+ const topPaths = Object.entries(current?.paths ?? {}).sort((a, b) => b[1] - a[1]).slice(0, 8);
35
+ if (loading) return /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500", children: "Laden\u2026" });
36
+ if (months.length === 0) {
37
+ return /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-600", children: "Nog geen bezoekersdata. Zodra de live site bezocht wordt, verschijnen hier de cijfers." }) });
38
+ }
39
+ return /* @__PURE__ */ jsxs("div", { className: "grid gap-4", children: [
40
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4 sm:grid-cols-3", children: [
41
+ /* @__PURE__ */ jsxs(Card, { children: [
42
+ /* @__PURE__ */ jsx("div", { className: "text-sm text-slate-500", children: "Totaal bezoeken" }),
43
+ /* @__PURE__ */ jsx("div", { className: "text-3xl font-bold", children: total.toLocaleString("nl-NL") })
44
+ ] }),
45
+ /* @__PURE__ */ jsxs(Card, { children: [
46
+ /* @__PURE__ */ jsx("div", { className: "text-sm text-slate-500", children: "Deze maand" }),
47
+ /* @__PURE__ */ jsx("div", { className: "text-3xl font-bold", children: (current?.total ?? 0).toLocaleString("nl-NL") })
48
+ ] }),
49
+ /* @__PURE__ */ jsxs(Card, { children: [
50
+ /* @__PURE__ */ jsx("div", { className: "text-sm text-slate-500", children: "Maanden gemeten" }),
51
+ /* @__PURE__ */ jsx("div", { className: "text-3xl font-bold", children: months.length })
52
+ ] })
53
+ ] }),
54
+ /* @__PURE__ */ jsxs(Card, { children: [
55
+ /* @__PURE__ */ jsx("h3", { className: "mb-3 text-base font-semibold", children: "Bezoeken per dag (deze maand)" }),
56
+ Object.keys(days).length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500", children: "Nog geen data deze maand." }) : /* @__PURE__ */ jsx("div", { className: "flex items-end gap-1", style: { height: 140 }, children: Array.from({ length: 31 }, (_, i) => String(i + 1).padStart(2, "0")).map((d) => /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col items-center justify-end", title: `Dag ${d}: ${days[d] ?? 0}`, children: /* @__PURE__ */ jsx(
57
+ "div",
58
+ {
59
+ className: "w-full rounded-t bg-brand-500",
60
+ style: { height: `${(days[d] ?? 0) / maxDay * 120}px` }
61
+ }
62
+ ) }, d)) })
63
+ ] }),
64
+ /* @__PURE__ */ jsxs(Card, { children: [
65
+ /* @__PURE__ */ jsx("h3", { className: "mb-3 text-base font-semibold", children: "Best bezochte pagina's (deze maand)" }),
66
+ topPaths.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500", children: "Nog geen data." }) : /* @__PURE__ */ jsx("ul", { className: "text-sm", children: topPaths.map(([p, n]) => /* @__PURE__ */ jsxs("li", { className: "flex justify-between border-b border-slate-100 py-1 last:border-0", children: [
67
+ /* @__PURE__ */ jsxs("span", { className: "truncate text-slate-700", children: [
68
+ "/",
69
+ p === "home" ? "" : p.replace(/_/g, "/")
70
+ ] }),
71
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: n.toLocaleString("nl-NL") })
72
+ ] }, p)) })
73
+ ] }),
74
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-slate-400", children: "Privacy-vriendelijk geteld (geen cookies, geen persoonsgegevens) \u2014 \xE9\xE9n telling per bezoeker-sessie per pagina." })
75
+ ] });
76
+ }
77
+ export {
78
+ StatsPanel
79
+ };
80
+ //# sourceMappingURL=StatsPanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/admin/stats/StatsPanel.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport { collection, getDocs } from \"firebase/firestore\";\nimport { getDb } from \"../../firebase/client\";\nimport { Card } from \"../ui/primitives\";\n\ninterface MonthStat {\n id: string;\n total?: number;\n days?: Record<string, number>;\n paths?: Record<string, number>;\n}\n\n/** Eenvoudige, privacy-vriendelijke bezoekersstatistieken (eigen teller). */\nexport function StatsPanel({ siteId }: { siteId: string }) {\n const [months, setMonths] = useState<MonthStat[]>([]);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n const db = getDb();\n if (!db) {\n setLoading(false);\n return;\n }\n let active = true;\n getDocs(collection(db, \"sites\", siteId, \"stats\"))\n .then((snap) => {\n if (!active) return;\n setMonths(snap.docs.map((d) => ({ id: d.id, ...(d.data() as Omit<MonthStat, \"id\">) })));\n setLoading(false);\n })\n .catch(() => active && setLoading(false));\n return () => {\n active = false;\n };\n }, [siteId]);\n\n const total = useMemo(() => months.reduce((s, m) => s + (m.total ?? 0), 0), [months]);\n const current = useMemo(() => {\n const now = new Date();\n const id = `${now.getUTCFullYear()}-${String(now.getUTCMonth() + 1).padStart(2, \"0\")}`;\n return months.find((m) => m.id === id);\n }, [months]);\n\n const days = current?.days ?? {};\n const maxDay = Math.max(1, ...Object.values(days));\n const topPaths = Object.entries(current?.paths ?? {})\n .sort((a, b) => b[1] - a[1])\n .slice(0, 8);\n\n if (loading) return <p className=\"text-sm text-slate-500\">Laden…</p>;\n\n if (months.length === 0) {\n return (\n <Card>\n <p className=\"text-sm text-slate-600\">\n Nog geen bezoekersdata. Zodra de live site bezocht wordt, verschijnen hier de cijfers.\n </p>\n </Card>\n );\n }\n\n return (\n <div className=\"grid gap-4\">\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3\">\n <Card>\n <div className=\"text-sm text-slate-500\">Totaal bezoeken</div>\n <div className=\"text-3xl font-bold\">{total.toLocaleString(\"nl-NL\")}</div>\n </Card>\n <Card>\n <div className=\"text-sm text-slate-500\">Deze maand</div>\n <div className=\"text-3xl font-bold\">{(current?.total ?? 0).toLocaleString(\"nl-NL\")}</div>\n </Card>\n <Card>\n <div className=\"text-sm text-slate-500\">Maanden gemeten</div>\n <div className=\"text-3xl font-bold\">{months.length}</div>\n </Card>\n </div>\n\n <Card>\n <h3 className=\"mb-3 text-base font-semibold\">Bezoeken per dag (deze maand)</h3>\n {Object.keys(days).length === 0 ? (\n <p className=\"text-sm text-slate-500\">Nog geen data deze maand.</p>\n ) : (\n <div className=\"flex items-end gap-1\" style={{ height: 140 }}>\n {Array.from({ length: 31 }, (_, i) => String(i + 1).padStart(2, \"0\")).map((d) => (\n <div key={d} className=\"flex flex-1 flex-col items-center justify-end\" title={`Dag ${d}: ${days[d] ?? 0}`}>\n <div\n className=\"w-full rounded-t bg-brand-500\"\n style={{ height: `${((days[d] ?? 0) / maxDay) * 120}px` }}\n />\n </div>\n ))}\n </div>\n )}\n </Card>\n\n <Card>\n <h3 className=\"mb-3 text-base font-semibold\">Best bezochte pagina's (deze maand)</h3>\n {topPaths.length === 0 ? (\n <p className=\"text-sm text-slate-500\">Nog geen data.</p>\n ) : (\n <ul className=\"text-sm\">\n {topPaths.map(([p, n]) => (\n <li key={p} className=\"flex justify-between border-b border-slate-100 py-1 last:border-0\">\n <span className=\"truncate text-slate-700\">/{p === \"home\" ? \"\" : p.replace(/_/g, \"/\")}</span>\n <span className=\"font-medium\">{n.toLocaleString(\"nl-NL\")}</span>\n </li>\n ))}\n </ul>\n )}\n </Card>\n\n <p className=\"text-xs text-slate-400\">\n Privacy-vriendelijk geteld (geen cookies, geen persoonsgegevens) — één telling per\n bezoeker-sessie per pagina.\n </p>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,16 @@
1
+ import type { ReactNode } from "react";
2
+ /**
3
+ * Generieke lijst-editor: rij toevoegen, omhoog/omlaag verplaatsen, verwijderen. Vervangt het
4
+ * herhaalde patroon in de block-editors (FAQ, galerij, openingstijden, …) en wordt hergebruikt
5
+ * voor nav/footer/social in het instellingenpaneel.
6
+ */
7
+ export declare function ArrayEditor<T>({ items, onChange, renderRow, newItem, addLabel, emptyLabel, }: {
8
+ items: T[];
9
+ onChange: (next: T[]) => void;
10
+ /** Render de bewerkbare velden van één rij. */
11
+ renderRow: (item: T, update: (patch: Partial<T>) => void, index: number) => ReactNode;
12
+ /** Maakt een nieuwe (lege) rij. */
13
+ newItem: () => T;
14
+ addLabel?: string;
15
+ emptyLabel?: string;
16
+ }): import("react").JSX.Element;
@@ -0,0 +1,38 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { Button } from "./primitives";
4
+ function ArrayEditor({
5
+ items,
6
+ onChange,
7
+ renderRow,
8
+ newItem,
9
+ addLabel = "+ Toevoegen",
10
+ emptyLabel
11
+ }) {
12
+ const set = (next) => onChange(next);
13
+ const update = (i, patch) => set(items.map((x, j) => j === i ? { ...x, ...patch } : x));
14
+ const remove = (i) => set(items.filter((_, j) => j !== i));
15
+ const move = (i, dir) => {
16
+ const j = i + dir;
17
+ if (j < 0 || j >= items.length) return;
18
+ const copy = [...items];
19
+ [copy[i], copy[j]] = [copy[j], copy[i]];
20
+ set(copy);
21
+ };
22
+ return /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
23
+ items.length === 0 && emptyLabel && /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500", children: emptyLabel }),
24
+ items.map((item, i) => /* @__PURE__ */ jsx("div", { className: "grid gap-2 rounded-lg border border-slate-200 p-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
25
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children: renderRow(item, (patch) => update(i, patch), i) }),
26
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
27
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => move(i, -1), "aria-label": "Omhoog", children: "\u2191" }),
28
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => move(i, 1), "aria-label": "Omlaag", children: "\u2193" }),
29
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => remove(i), "aria-label": "Verwijderen", children: "\u{1F5D1}" })
30
+ ] })
31
+ ] }) }, i)),
32
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: () => set([...items, newItem()]), children: addLabel }) })
33
+ ] });
34
+ }
35
+ export {
36
+ ArrayEditor
37
+ };
38
+ //# sourceMappingURL=ArrayEditor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/admin/ui/ArrayEditor.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { Button } from \"./primitives\";\n\n/**\n * Generieke lijst-editor: rij toevoegen, omhoog/omlaag verplaatsen, verwijderen. Vervangt het\n * herhaalde patroon in de block-editors (FAQ, galerij, openingstijden, …) en wordt hergebruikt\n * voor nav/footer/social in het instellingenpaneel.\n */\nexport function ArrayEditor<T>({\n items,\n onChange,\n renderRow,\n newItem,\n addLabel = \"+ Toevoegen\",\n emptyLabel,\n}: {\n items: T[];\n onChange: (next: T[]) => void;\n /** Render de bewerkbare velden van één rij. */\n renderRow: (item: T, update: (patch: Partial<T>) => void, index: number) => ReactNode;\n /** Maakt een nieuwe (lege) rij. */\n newItem: () => T;\n addLabel?: string;\n emptyLabel?: string;\n}) {\n const set = (next: T[]) => onChange(next);\n const update = (i: number, patch: Partial<T>) =>\n set(items.map((x, j) => (j === i ? { ...x, ...patch } : x)));\n const remove = (i: number) => set(items.filter((_, j) => j !== i));\n const move = (i: number, dir: -1 | 1) => {\n const j = i + dir;\n if (j < 0 || j >= items.length) return;\n const copy = [...items];\n [copy[i], copy[j]] = [copy[j], copy[i]];\n set(copy);\n };\n\n return (\n <div className=\"grid gap-2\">\n {items.length === 0 && emptyLabel && <p className=\"text-sm text-slate-500\">{emptyLabel}</p>}\n {items.map((item, i) => (\n <div key={i} className=\"grid gap-2 rounded-lg border border-slate-200 p-3\">\n <div className=\"flex items-start gap-2\">\n <div className=\"flex-1\">{renderRow(item, (patch) => update(i, patch), i)}</div>\n <div className=\"flex flex-col gap-1\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => move(i, -1)} aria-label=\"Omhoog\">↑</Button>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => move(i, 1)} aria-label=\"Omlaag\">↓</Button>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => remove(i)} aria-label=\"Verwijderen\">🗑</Button>\n </div>\n </div>\n </div>\n ))}\n <div>\n <Button type=\"button\" variant=\"secondary\" size=\"sm\" onClick={() => set([...items, newItem()])}>\n {addLabel}\n </Button>\n </div>\n </div>\n );\n}\n"],"mappings":";AAyC2C,cAK/B,YAL+B;AAtC3C,SAAS,cAAc;AAOhB,SAAS,YAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AACF,GASG;AACD,QAAM,MAAM,CAAC,SAAc,SAAS,IAAI;AACxC,QAAM,SAAS,CAAC,GAAW,UACzB,IAAI,MAAM,IAAI,CAAC,GAAG,MAAO,MAAM,IAAI,EAAE,GAAG,GAAG,GAAG,MAAM,IAAI,CAAE,CAAC;AAC7D,QAAM,SAAS,CAAC,MAAc,IAAI,MAAM,OAAO,CAAC,GAAG,MAAM,MAAM,CAAC,CAAC;AACjE,QAAM,OAAO,CAAC,GAAW,QAAgB;AACvC,UAAM,IAAI,IAAI;AACd,QAAI,IAAI,KAAK,KAAK,MAAM,OAAQ;AAChC,UAAM,OAAO,CAAC,GAAG,KAAK;AACtB,KAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC;AACtC,QAAI,IAAI;AAAA,EACV;AAEA,SACE,qBAAC,SAAI,WAAU,cACZ;AAAA,UAAM,WAAW,KAAK,cAAc,oBAAC,OAAE,WAAU,0BAA0B,sBAAW;AAAA,IACtF,MAAM,IAAI,CAAC,MAAM,MAChB,oBAAC,SAAY,WAAU,qDACrB,+BAAC,SAAI,WAAU,0BACb;AAAA,0BAAC,SAAI,WAAU,UAAU,oBAAU,MAAM,CAAC,UAAU,OAAO,GAAG,KAAK,GAAG,CAAC,GAAE;AAAA,MACzE,qBAAC,SAAI,WAAU,uBACb;AAAA,4BAAC,UAAO,MAAK,UAAS,SAAQ,SAAQ,MAAK,MAAK,SAAS,MAAM,KAAK,GAAG,EAAE,GAAG,cAAW,UAAS,oBAAC;AAAA,QACjG,oBAAC,UAAO,MAAK,UAAS,SAAQ,SAAQ,MAAK,MAAK,SAAS,MAAM,KAAK,GAAG,CAAC,GAAG,cAAW,UAAS,oBAAC;AAAA,QAChG,oBAAC,UAAO,MAAK,UAAS,SAAQ,SAAQ,MAAK,MAAK,SAAS,MAAM,OAAO,CAAC,GAAG,cAAW,eAAc,uBAAE;AAAA,SACvG;AAAA,OACF,KARQ,CASV,CACD;AAAA,IACD,oBAAC,SACC,8BAAC,UAAO,MAAK,UAAS,SAAQ,aAAY,MAAK,MAAK,SAAS,MAAM,IAAI,CAAC,GAAG,OAAO,QAAQ,CAAC,CAAC,GACzF,oBACH,GACF;AAAA,KACF;AAEJ;","names":[]}