@xiwebdesign/xicms-core 4.17.1 → 5.0.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 (169) hide show
  1. package/dist/XiCMSProvider.d.ts +7 -0
  2. package/dist/XiCMSProvider.js +32 -7
  3. package/dist/XiCMSProvider.js.map +1 -1
  4. package/dist/admin/blockEditors/GenericEditor.d.ts +22 -0
  5. package/dist/admin/blockEditors/GenericEditor.js +201 -0
  6. package/dist/admin/blockEditors/GenericEditor.js.map +1 -0
  7. package/dist/admin/blockEditors/SymbolRefEditor.d.ts +2 -0
  8. package/dist/admin/blockEditors/SymbolRefEditor.js +55 -0
  9. package/dist/admin/blockEditors/SymbolRefEditor.js.map +1 -0
  10. package/dist/admin/blockEditors/index.d.ts +11 -6
  11. package/dist/admin/blockEditors/index.js +49 -620
  12. package/dist/admin/blockEditors/index.js.map +1 -1
  13. package/dist/admin/customBlocks/CustomBlocksPanel.d.ts +3 -0
  14. package/dist/admin/customBlocks/CustomBlocksPanel.js +145 -0
  15. package/dist/admin/customBlocks/CustomBlocksPanel.js.map +1 -0
  16. package/dist/admin/lib/compressImage.d.ts +4 -2
  17. package/dist/admin/lib/compressImage.js +7 -5
  18. package/dist/admin/lib/compressImage.js.map +1 -1
  19. package/dist/admin/lib/mediaUsage.d.ts +4 -3
  20. package/dist/admin/lib/mediaUsage.js +21 -10
  21. package/dist/admin/lib/mediaUsage.js.map +1 -1
  22. package/dist/admin/lib/symbolsClient.d.ts +13 -0
  23. package/dist/admin/lib/symbolsClient.js +51 -0
  24. package/dist/admin/lib/symbolsClient.js.map +1 -0
  25. package/dist/admin/lib/upload.d.ts +4 -0
  26. package/dist/admin/lib/upload.js +26 -6
  27. package/dist/admin/lib/upload.js.map +1 -1
  28. package/dist/admin/lib/zodFields.d.ts +18 -0
  29. package/dist/admin/lib/zodFields.js +65 -2
  30. package/dist/admin/lib/zodFields.js.map +1 -1
  31. package/dist/admin/media/MediaManager.js +23 -7
  32. package/dist/admin/media/MediaManager.js.map +1 -1
  33. package/dist/admin/media/MediaPicker.js +12 -2
  34. package/dist/admin/media/MediaPicker.js.map +1 -1
  35. package/dist/admin/panelRegistry.js +3 -0
  36. package/dist/admin/panelRegistry.js.map +1 -1
  37. package/dist/admin/settings/SettingsPanel.js +6 -1
  38. package/dist/admin/settings/SettingsPanel.js.map +1 -1
  39. package/dist/admin/settings/SnapshotsCard.d.ts +3 -0
  40. package/dist/admin/settings/SnapshotsCard.js +98 -0
  41. package/dist/admin/settings/SnapshotsCard.js.map +1 -0
  42. package/dist/admin/visual/TranslationPanel.d.ts +13 -0
  43. package/dist/admin/visual/TranslationPanel.js +73 -0
  44. package/dist/admin/visual/TranslationPanel.js.map +1 -0
  45. package/dist/admin/visual/VisualEditor.js +146 -18
  46. package/dist/admin/visual/VisualEditor.js.map +1 -1
  47. package/dist/admin.css +1 -1
  48. package/dist/agentFiles/catalog.d.ts +21 -0
  49. package/dist/agentFiles/catalog.js +78 -0
  50. package/dist/agentFiles/catalog.js.map +1 -0
  51. package/dist/agentFiles/files.d.ts +59 -0
  52. package/dist/agentFiles/files.js +109 -0
  53. package/dist/agentFiles/files.js.map +1 -0
  54. package/dist/blocks/builtins/Agenda.d.ts +6 -0
  55. package/dist/blocks/builtins/Agenda.js +14 -6
  56. package/dist/blocks/builtins/Agenda.js.map +1 -1
  57. package/dist/blocks/builtins/BeforeAfter.js +1 -0
  58. package/dist/blocks/builtins/BeforeAfter.js.map +1 -1
  59. package/dist/blocks/builtins/Breadcrumbs.js +5 -1
  60. package/dist/blocks/builtins/Breadcrumbs.js.map +1 -1
  61. package/dist/blocks/builtins/Cards.js +4 -2
  62. package/dist/blocks/builtins/Cards.js.map +1 -1
  63. package/dist/blocks/builtins/Contact.js +2 -1
  64. package/dist/blocks/builtins/Contact.js.map +1 -1
  65. package/dist/blocks/builtins/Cta.js +1 -0
  66. package/dist/blocks/builtins/Cta.js.map +1 -1
  67. package/dist/blocks/builtins/Elements.js +1 -0
  68. package/dist/blocks/builtins/Elements.js.map +1 -1
  69. package/dist/blocks/builtins/Faq.js +5 -4
  70. package/dist/blocks/builtins/Faq.js.map +1 -1
  71. package/dist/blocks/builtins/Gallery.js +2 -2
  72. package/dist/blocks/builtins/Gallery.js.map +1 -1
  73. package/dist/blocks/builtins/Hero.js +2 -2
  74. package/dist/blocks/builtins/Hero.js.map +1 -1
  75. package/dist/blocks/builtins/Jobs.d.ts +8 -1
  76. package/dist/blocks/builtins/Jobs.js +38 -21
  77. package/dist/blocks/builtins/Jobs.js.map +1 -1
  78. package/dist/blocks/builtins/MapBlock.js +31 -4
  79. package/dist/blocks/builtins/MapBlock.js.map +1 -1
  80. package/dist/blocks/builtins/PdfBlock.js +2 -3
  81. package/dist/blocks/builtins/PdfBlock.js.map +1 -1
  82. package/dist/blocks/builtins/Portfolio.js +2 -2
  83. package/dist/blocks/builtins/Portfolio.js.map +1 -1
  84. package/dist/blocks/builtins/Pricing.d.ts +2 -0
  85. package/dist/blocks/builtins/Pricing.js +18 -10
  86. package/dist/blocks/builtins/Pricing.js.map +1 -1
  87. package/dist/blocks/builtins/Sections.js +4 -2
  88. package/dist/blocks/builtins/Sections.js.map +1 -1
  89. package/dist/blocks/builtins/Slider.js +21 -3
  90. package/dist/blocks/builtins/Slider.js.map +1 -1
  91. package/dist/blocks/builtins/SymbolRef.d.ts +2 -0
  92. package/dist/blocks/builtins/SymbolRef.js +61 -0
  93. package/dist/blocks/builtins/SymbolRef.js.map +1 -0
  94. package/dist/blocks/builtins/Testimonials.js +21 -18
  95. package/dist/blocks/builtins/Testimonials.js.map +1 -1
  96. package/dist/blocks/builtins/WhatsappChat.js +1 -1
  97. package/dist/blocks/builtins/WhatsappChat.js.map +1 -1
  98. package/dist/blocks/builtins/Widgets.js +2 -3
  99. package/dist/blocks/builtins/Widgets.js.map +1 -1
  100. package/dist/blocks/builtins/lib/ics.js +1 -1
  101. package/dist/blocks/builtins/lib/ics.js.map +1 -1
  102. package/dist/blocks/builtins/lib/openingHours.d.ts +4 -1
  103. package/dist/blocks/builtins/lib/openingHours.js +11 -5
  104. package/dist/blocks/builtins/lib/openingHours.js.map +1 -1
  105. package/dist/blocks/customTemplate/definition.d.ts +7 -0
  106. package/dist/blocks/customTemplate/definition.js +34 -0
  107. package/dist/blocks/customTemplate/definition.js.map +1 -0
  108. package/dist/blocks/customTemplate/interpret.d.ts +10 -0
  109. package/dist/blocks/customTemplate/interpret.js +136 -0
  110. package/dist/blocks/customTemplate/interpret.js.map +1 -0
  111. package/dist/blocks/registry.d.ts +8 -0
  112. package/dist/blocks/registry.js.map +1 -1
  113. package/dist/demo/demoStore.d.ts +11 -1
  114. package/dist/demo/demoStore.js +50 -0
  115. package/dist/demo/demoStore.js.map +1 -1
  116. package/dist/firebase/client.js +2 -1
  117. package/dist/firebase/client.js.map +1 -1
  118. package/dist/i18n/overlay.d.ts +61 -0
  119. package/dist/i18n/overlay.js +90 -0
  120. package/dist/i18n/overlay.js.map +1 -0
  121. package/dist/index.d.ts +11 -9
  122. package/dist/index.js +34 -9
  123. package/dist/index.js.map +1 -1
  124. package/dist/modules/builtins.js +3 -2
  125. package/dist/modules/builtins.js.map +1 -1
  126. package/dist/modules/consent/useConsent.js +15 -3
  127. package/dist/modules/consent/useConsent.js.map +1 -1
  128. package/dist/schema/blocks.d.ts +183 -3
  129. package/dist/schema/blocks.js +12 -1
  130. package/dist/schema/blocks.js.map +1 -1
  131. package/dist/schema/customBlocks.d.ts +47 -0
  132. package/dist/schema/customBlocks.js +32 -0
  133. package/dist/schema/customBlocks.js.map +1 -0
  134. package/dist/schema/fields.d.ts +122 -0
  135. package/dist/schema/fields.js +120 -0
  136. package/dist/schema/fields.js.map +1 -0
  137. package/dist/schema/forms.d.ts +6 -6
  138. package/dist/schema/pages.d.ts +15 -1
  139. package/dist/schema/pages.js +6 -2
  140. package/dist/schema/pages.js.map +1 -1
  141. package/dist/schema/siteConfig.d.ts +14 -8
  142. package/dist/schema/siteConfig.js +2 -1
  143. package/dist/schema/siteConfig.js.map +1 -1
  144. package/dist/schema/symbols.d.ts +205 -0
  145. package/dist/schema/symbols.js +18 -0
  146. package/dist/schema/symbols.js.map +1 -0
  147. package/dist/server/index.d.ts +2 -1
  148. package/dist/server/index.js +24 -0
  149. package/dist/server/index.js.map +1 -1
  150. package/dist/server/pages.d.ts +21 -0
  151. package/dist/server/pages.js +77 -0
  152. package/dist/server/pages.js.map +1 -1
  153. package/dist/server/seo.d.ts +12 -3
  154. package/dist/server/seo.js +23 -11
  155. package/dist/server/seo.js.map +1 -1
  156. package/dist/styles.css +62 -6
  157. package/package.json +1 -1
  158. package/dist/components/EditableImage.d.ts +0 -18
  159. package/dist/components/EditableImage.js +0 -62
  160. package/dist/components/EditableImage.js.map +0 -1
  161. package/dist/components/EditableRichText.d.ts +0 -14
  162. package/dist/components/EditableRichText.js +0 -26
  163. package/dist/components/EditableRichText.js.map +0 -1
  164. package/dist/components/EditableText.d.ts +0 -21
  165. package/dist/components/EditableText.js +0 -25
  166. package/dist/components/EditableText.js.map +0 -1
  167. package/dist/content/ContentProvider.d.ts +0 -23
  168. package/dist/content/ContentProvider.js +0 -86
  169. package/dist/content/ContentProvider.js.map +0 -1
@@ -1,11 +1,13 @@
1
1
  "use client";
2
2
  const DRAFT_PREFIX = "xicms-demo-draft";
3
+ const MEDIA_PREFIX = "xicms-demo-media";
3
4
  const SESSION_KEY = "xicms-demo-session";
4
5
  const DEMO_EVENT = "xicms:demo";
5
6
  let active = false;
6
7
  const seeds = /* @__PURE__ */ new Map();
7
8
  const newsSeeds = /* @__PURE__ */ new Map();
8
9
  const formSeeds = /* @__PURE__ */ new Map();
10
+ const mediaSeeds = /* @__PURE__ */ new Map();
9
11
  function setDemoActive(on) {
10
12
  active = on;
11
13
  }
@@ -53,6 +55,48 @@ function registerDemoForm(siteId, formId, def) {
53
55
  function getDemoForm(siteId, formId) {
54
56
  return formSeeds.get(`${siteId}::${formId}`) ?? null;
55
57
  }
58
+ function registerDemoMedia(siteId, items) {
59
+ mediaSeeds.set(
60
+ siteId,
61
+ items.map((m, i) => ({ id: `demo-seed-${i}`, url: m.url, path: "demo", name: m.name, alt: m.alt ?? "" }))
62
+ );
63
+ }
64
+ function mediaKey(siteId) {
65
+ return `${MEDIA_PREFIX}:${siteId}`;
66
+ }
67
+ function loadLocalDemoMedia(siteId) {
68
+ if (typeof window === "undefined") return [];
69
+ try {
70
+ const raw = window.localStorage.getItem(mediaKey(siteId));
71
+ return raw ? JSON.parse(raw) : [];
72
+ } catch {
73
+ return [];
74
+ }
75
+ }
76
+ function listDemoMedia(siteId) {
77
+ return [...loadLocalDemoMedia(siteId), ...mediaSeeds.get(siteId) ?? []];
78
+ }
79
+ const memoryOnlyMedia = /* @__PURE__ */ new Map();
80
+ function addDemoMedia(siteId, item) {
81
+ const media = {
82
+ id: `demo-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
83
+ url: item.url,
84
+ path: "demo",
85
+ name: item.name,
86
+ alt: ""
87
+ };
88
+ const next = [media, ...loadLocalDemoMedia(siteId)].slice(0, 10);
89
+ try {
90
+ window.localStorage.setItem(mediaKey(siteId), JSON.stringify(next));
91
+ } catch {
92
+ memoryOnlyMedia.set(siteId, [media, ...memoryOnlyMedia.get(siteId) ?? []]);
93
+ }
94
+ emit();
95
+ return media;
96
+ }
97
+ function listDemoMediaAll(siteId) {
98
+ return [...memoryOnlyMedia.get(siteId) ?? [], ...listDemoMedia(siteId)];
99
+ }
56
100
  function draftKey(siteId, id) {
57
101
  return `${DRAFT_PREFIX}:${siteId}:${id}`;
58
102
  }
@@ -83,6 +127,8 @@ function resetDemo(siteId) {
83
127
  if (k && k.startsWith(`${DRAFT_PREFIX}:${siteId}:`)) toRemove.push(k);
84
128
  }
85
129
  toRemove.forEach((k) => window.localStorage.removeItem(k));
130
+ window.localStorage.removeItem(mediaKey(siteId));
131
+ memoryOnlyMedia.delete(siteId);
86
132
  window.sessionStorage.removeItem(SESSION_KEY);
87
133
  } catch {
88
134
  }
@@ -96,14 +142,18 @@ function resolveDemoPage(siteId, path) {
96
142
  }
97
143
  export {
98
144
  DEMO_EVENT,
145
+ addDemoMedia,
99
146
  demoIdForPath,
100
147
  getDemoForm,
101
148
  getDemoNews,
102
149
  getSeed,
103
150
  isDemoActive,
104
151
  isDemoLoggedIn,
152
+ listDemoMedia,
153
+ listDemoMediaAll,
105
154
  loadDemoDraft,
106
155
  registerDemoForm,
156
+ registerDemoMedia,
107
157
  registerDemoNews,
108
158
  registerSeed,
109
159
  resetDemo,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/demo/demoStore.ts"],"sourcesContent":["\"use client\";\n\nimport type { Page } from \"../schema/pages\";\nimport type { NewsArticle } from \"../content/types\";\nimport type { FormDefinition } from \"../schema/forms\";\n\n/**\n * Lokale opslag voor de DEMO-bewerkmodus (`config.demoEditing`). Alle \"bewerkingen\" van een\n * bezoeker (teksten, blokken, publiceren) blijven UITSLUITEND in de browser van die bezoeker\n * (localStorage) — er gaat niets naar Firebase. Zo kunnen eindgebruikers het beheer veilig\n * uitproberen zonder dat er echt iets verandert. Een \"Reset\" wist alles weer.\n *\n * Bewust GEEN onderdeel van de echte (Firebase-)opslag: pagesClient en AuthProvider takken hier\n * alleen naartoe als de demo-modus actief is, en die staat alleen aan op een demo-site.\n */\n\nconst DRAFT_PREFIX = \"xicms-demo-draft\";\nconst SESSION_KEY = \"xicms-demo-session\";\nexport const DEMO_EVENT = \"xicms:demo\";\n\nlet active = false;\nconst seeds = new Map<string, Page>();\nconst newsSeeds = new Map<string, NewsArticle[]>();\nconst formSeeds = new Map<string, FormDefinition>();\n\n/** Zet de demo-bewerkmodus aan/uit (door de provider, op basis van config.demoEditing). */\nexport function setDemoActive(on: boolean) {\n active = on;\n}\nexport function isDemoActive(): boolean {\n return active;\n}\n\n/** Stabiel, deterministisch draft-id per pad, zodat pagina + editor naar dezelfde opslag wijzen. */\nexport function demoIdForPath(path: string): string {\n return `demo:${path || \"/\"}`;\n}\n\nfunction emit() {\n if (typeof window !== \"undefined\") window.dispatchEvent(new Event(DEMO_EVENT));\n}\n\n// ── Pseudo-login (sessie) ──────────────────────────────────────────────────\n// In sessionStorage: verdwijnt als het tabblad sluit — benadrukt het tijdelijke karakter.\nexport function isDemoLoggedIn(): boolean {\n if (typeof window === \"undefined\") return false;\n try {\n return window.sessionStorage.getItem(SESSION_KEY) === \"1\";\n } catch {\n return false;\n }\n}\nexport function setDemoLoggedIn(on: boolean) {\n if (typeof window === \"undefined\") return;\n try {\n if (on) window.sessionStorage.setItem(SESSION_KEY, \"1\");\n else window.sessionStorage.removeItem(SESSION_KEY);\n } catch {\n /* opslag geweigerd — login geldt dan alleen voor deze render */\n }\n emit();\n}\n\n// ── Seed-pagina's (de oorspronkelijke inhoud waar een bezoeker op verder bewerkt) ──\nexport function registerSeed(siteId: string, path: string, page: Page) {\n seeds.set(`${siteId}::${path}`, page);\n}\nexport function getSeed(siteId: string, path: string): Page | null {\n return seeds.get(`${siteId}::${path}`) ?? null;\n}\n\n// ── Demo-nieuws (zodat nieuws-blokken/widgets ook in de demo gevuld zijn, zonder Firebase) ──\nexport function registerDemoNews(siteId: string, articles: NewsArticle[]) {\n newsSeeds.set(siteId, articles);\n}\nexport function getDemoNews(siteId: string): NewsArticle[] {\n return newsSeeds.get(siteId) ?? [];\n}\n\n// ── Demo-formulieren (zodat het form-blok werkt zonder Firebase; inzenden doet lokaal niets) ──\nexport function registerDemoForm(siteId: string, formId: string, def: FormDefinition) {\n formSeeds.set(`${siteId}::${formId}`, def);\n}\nexport function getDemoForm(siteId: string, formId: string): FormDefinition | null {\n return formSeeds.get(`${siteId}::${formId}`) ?? null;\n}\n\n// ── Lokale drafts (de bewerkingen) ─────────────────────────────────────────\nfunction draftKey(siteId: string, id: string) {\n return `${DRAFT_PREFIX}:${siteId}:${id}`;\n}\n\nexport function loadDemoDraft(siteId: string, id: string): Partial<Page> | null {\n if (typeof window === \"undefined\") return null;\n try {\n const raw = window.localStorage.getItem(draftKey(siteId, id));\n return raw ? (JSON.parse(raw) as Partial<Page>) : null;\n } catch {\n return null;\n }\n}\n\nexport function saveDemoDraft(siteId: string, id: string, patch: Partial<Page>) {\n if (typeof window === \"undefined\") return;\n try {\n const current = loadDemoDraft(siteId, id) ?? {};\n window.localStorage.setItem(draftKey(siteId, id), JSON.stringify({ ...current, ...patch }));\n } catch {\n /* opslag vol/geweigerd — bewerking geldt dan alleen voor deze sessie in het geheugen */\n }\n emit();\n}\n\n/** Verwijdert alle lokale demo-bewerkingen + login voor deze site (de \"Reset\"-knop). */\nexport function resetDemo(siteId: string) {\n if (typeof window === \"undefined\") return;\n try {\n const toRemove: string[] = [];\n for (let i = 0; i < window.localStorage.length; i++) {\n const k = window.localStorage.key(i);\n if (k && k.startsWith(`${DRAFT_PREFIX}:${siteId}:`)) toRemove.push(k);\n }\n toRemove.forEach((k) => window.localStorage.removeItem(k));\n window.sessionStorage.removeItem(SESSION_KEY);\n } catch {\n /* negeren */\n }\n emit();\n}\n\n/**\n * De effectieve demo-pagina = seed met lokale bewerkingen eroverheen. Gebruikt door de demo-pagina\n * om de wijzigingen van de bezoeker direct te tonen (ook na sluiten van de editor).\n */\nexport function resolveDemoPage(siteId: string, path: string): Page | null {\n const seed = getSeed(siteId, path);\n if (!seed) return null;\n const draft = loadDemoDraft(siteId, demoIdForPath(path));\n return draft ? ({ ...seed, ...draft } as Page) : seed;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/demo/demoStore.ts"],"sourcesContent":["\"use client\";\n\nimport type { Page } from \"../schema/pages\";\nimport type { MediaItem, NewsArticle } from \"../content/types\";\nimport type { FormDefinition } from \"../schema/forms\";\n\n/**\n * Lokale opslag voor de DEMO-bewerkmodus (`config.demoEditing`). Alle \"bewerkingen\" van een\n * bezoeker (teksten, blokken, publiceren) blijven UITSLUITEND in de browser van die bezoeker\n * (localStorage) — er gaat niets naar Firebase. Zo kunnen eindgebruikers het beheer veilig\n * uitproberen zonder dat er echt iets verandert. Een \"Reset\" wist alles weer.\n *\n * Bewust GEEN onderdeel van de echte (Firebase-)opslag: pagesClient en AuthProvider takken hier\n * alleen naartoe als de demo-modus actief is, en die staat alleen aan op een demo-site.\n */\n\nconst DRAFT_PREFIX = \"xicms-demo-draft\";\nconst MEDIA_PREFIX = \"xicms-demo-media\";\nconst SESSION_KEY = \"xicms-demo-session\";\nexport const DEMO_EVENT = \"xicms:demo\";\n\nlet active = false;\nconst seeds = new Map<string, Page>();\nconst newsSeeds = new Map<string, NewsArticle[]>();\nconst formSeeds = new Map<string, FormDefinition>();\nconst mediaSeeds = new Map<string, MediaItem[]>();\n\n/** Zet de demo-bewerkmodus aan/uit (door de provider, op basis van config.demoEditing). */\nexport function setDemoActive(on: boolean) {\n active = on;\n}\nexport function isDemoActive(): boolean {\n return active;\n}\n\n/** Stabiel, deterministisch draft-id per pad, zodat pagina + editor naar dezelfde opslag wijzen. */\nexport function demoIdForPath(path: string): string {\n return `demo:${path || \"/\"}`;\n}\n\nfunction emit() {\n if (typeof window !== \"undefined\") window.dispatchEvent(new Event(DEMO_EVENT));\n}\n\n// ── Pseudo-login (sessie) ──────────────────────────────────────────────────\n// In sessionStorage: verdwijnt als het tabblad sluit — benadrukt het tijdelijke karakter.\nexport function isDemoLoggedIn(): boolean {\n if (typeof window === \"undefined\") return false;\n try {\n return window.sessionStorage.getItem(SESSION_KEY) === \"1\";\n } catch {\n return false;\n }\n}\nexport function setDemoLoggedIn(on: boolean) {\n if (typeof window === \"undefined\") return;\n try {\n if (on) window.sessionStorage.setItem(SESSION_KEY, \"1\");\n else window.sessionStorage.removeItem(SESSION_KEY);\n } catch {\n /* opslag geweigerd — login geldt dan alleen voor deze render */\n }\n emit();\n}\n\n// ── Seed-pagina's (de oorspronkelijke inhoud waar een bezoeker op verder bewerkt) ──\nexport function registerSeed(siteId: string, path: string, page: Page) {\n seeds.set(`${siteId}::${path}`, page);\n}\nexport function getSeed(siteId: string, path: string): Page | null {\n return seeds.get(`${siteId}::${path}`) ?? null;\n}\n\n// ── Demo-nieuws (zodat nieuws-blokken/widgets ook in de demo gevuld zijn, zonder Firebase) ──\nexport function registerDemoNews(siteId: string, articles: NewsArticle[]) {\n newsSeeds.set(siteId, articles);\n}\nexport function getDemoNews(siteId: string): NewsArticle[] {\n return newsSeeds.get(siteId) ?? [];\n}\n\n// ── Demo-formulieren (zodat het form-blok werkt zonder Firebase; inzenden doet lokaal niets) ──\nexport function registerDemoForm(siteId: string, formId: string, def: FormDefinition) {\n formSeeds.set(`${siteId}::${formId}`, def);\n}\nexport function getDemoForm(siteId: string, formId: string): FormDefinition | null {\n return formSeeds.get(`${siteId}::${formId}`) ?? null;\n}\n\n// ── Demo-media (bibliotheek + upload zonder Firebase) ─────────────────────\n// Geseede items (bv. de foto's van de demo-site zelf) + lokale \"uploads\" als data-URL in\n// localStorage. Zo werken kiezen, uploaden en vervangen in de demo écht — alles blijft lokaal.\n\n/** Seed de mediabibliotheek van de demo (curated set; alt = zoektekst in de kiezer). */\nexport function registerDemoMedia(siteId: string, items: Array<Pick<MediaItem, \"url\" | \"name\" | \"alt\">>) {\n mediaSeeds.set(\n siteId,\n items.map((m, i) => ({ id: `demo-seed-${i}`, url: m.url, path: \"demo\", name: m.name, alt: m.alt ?? \"\" })),\n );\n}\n\nfunction mediaKey(siteId: string) {\n return `${MEDIA_PREFIX}:${siteId}`;\n}\n\nfunction loadLocalDemoMedia(siteId: string): MediaItem[] {\n if (typeof window === \"undefined\") return [];\n try {\n const raw = window.localStorage.getItem(mediaKey(siteId));\n return raw ? (JSON.parse(raw) as MediaItem[]) : [];\n } catch {\n return [];\n }\n}\n\n/** Bibliotheek in demo-modus: lokale uploads (nieuwste eerst) + de geseede set. */\nexport function listDemoMedia(siteId: string): MediaItem[] {\n return [...loadLocalDemoMedia(siteId), ...(mediaSeeds.get(siteId) ?? [])];\n}\n\n/**\n * \"Upload\" in demo-modus: bewaar de (gecomprimeerde) afbeelding als data-URL in localStorage.\n * localStorage is beperkt (~5 MB) — we houden maximaal 10 lokale uploads aan en laten bij een\n * volle opslag het item alleen voor deze sessie in het geheugen bestaan (zelfde vangnet als drafts).\n */\nconst memoryOnlyMedia = new Map<string, MediaItem[]>();\nexport function addDemoMedia(siteId: string, item: { url: string; name: string }): MediaItem {\n const media: MediaItem = {\n id: `demo-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n url: item.url,\n path: \"demo\",\n name: item.name,\n alt: \"\",\n };\n const next = [media, ...loadLocalDemoMedia(siteId)].slice(0, 10);\n try {\n window.localStorage.setItem(mediaKey(siteId), JSON.stringify(next));\n } catch {\n memoryOnlyMedia.set(siteId, [media, ...(memoryOnlyMedia.get(siteId) ?? [])]);\n }\n emit();\n return media;\n}\n\n/** Inclusief geheugen-only items (opslag-vol-vangnet) — gebruikt door de kiezer. */\nexport function listDemoMediaAll(siteId: string): MediaItem[] {\n return [...(memoryOnlyMedia.get(siteId) ?? []), ...listDemoMedia(siteId)];\n}\n\n// ── Lokale drafts (de bewerkingen) ─────────────────────────────────────────\nfunction draftKey(siteId: string, id: string) {\n return `${DRAFT_PREFIX}:${siteId}:${id}`;\n}\n\nexport function loadDemoDraft(siteId: string, id: string): Partial<Page> | null {\n if (typeof window === \"undefined\") return null;\n try {\n const raw = window.localStorage.getItem(draftKey(siteId, id));\n return raw ? (JSON.parse(raw) as Partial<Page>) : null;\n } catch {\n return null;\n }\n}\n\nexport function saveDemoDraft(siteId: string, id: string, patch: Partial<Page>) {\n if (typeof window === \"undefined\") return;\n try {\n const current = loadDemoDraft(siteId, id) ?? {};\n window.localStorage.setItem(draftKey(siteId, id), JSON.stringify({ ...current, ...patch }));\n } catch {\n /* opslag vol/geweigerd — bewerking geldt dan alleen voor deze sessie in het geheugen */\n }\n emit();\n}\n\n/** Verwijdert alle lokale demo-bewerkingen + login voor deze site (de \"Reset\"-knop). */\nexport function resetDemo(siteId: string) {\n if (typeof window === \"undefined\") return;\n try {\n const toRemove: string[] = [];\n for (let i = 0; i < window.localStorage.length; i++) {\n const k = window.localStorage.key(i);\n if (k && k.startsWith(`${DRAFT_PREFIX}:${siteId}:`)) toRemove.push(k);\n }\n toRemove.forEach((k) => window.localStorage.removeItem(k));\n window.localStorage.removeItem(mediaKey(siteId));\n memoryOnlyMedia.delete(siteId);\n window.sessionStorage.removeItem(SESSION_KEY);\n } catch {\n /* negeren */\n }\n emit();\n}\n\n/**\n * De effectieve demo-pagina = seed met lokale bewerkingen eroverheen. Gebruikt door de demo-pagina\n * om de wijzigingen van de bezoeker direct te tonen (ook na sluiten van de editor).\n */\nexport function resolveDemoPage(siteId: string, path: string): Page | null {\n const seed = getSeed(siteId, path);\n if (!seed) return null;\n const draft = loadDemoDraft(siteId, demoIdForPath(path));\n return draft ? ({ ...seed, ...draft } as Page) : seed;\n}\n"],"mappings":"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","names":[]}
@@ -32,7 +32,8 @@ function getDb() {
32
32
  }
33
33
  function getBucket() {
34
34
  const app = getFirebaseApp();
35
- return app ? getStorage(app) : null;
35
+ if (!app || !readConfig().storageBucket) return null;
36
+ return getStorage(app);
36
37
  }
37
38
  export {
38
39
  getBucket,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/firebase/client.ts"],"sourcesContent":["\"use client\";\n\nimport { initializeApp, getApps, getApp, type FirebaseApp } from \"firebase/app\";\nimport { getAuth, type Auth } from \"firebase/auth\";\nimport { getFirestore, type Firestore } from \"firebase/firestore\";\nimport { getStorage, type FirebaseStorage } from \"firebase/storage\";\n\n/**\n * Client-side Firebase, volledig env-gedreven (NEXT_PUBLIC_*). Als de env niet is ingevuld\n * geven alle helpers `null` terug, zodat een site ook zónder Firebase blijft werken (dan\n * toont hij alleen de standaardteksten en is bewerken uitgeschakeld).\n */\nfunction readConfig() {\n return {\n apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,\n authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,\n projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,\n storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,\n messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,\n appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,\n };\n}\n\nexport function isFirebaseConfigured(): boolean {\n const cfg = readConfig();\n return Boolean(cfg.apiKey && cfg.projectId);\n}\n\nexport function getFirebaseApp(): FirebaseApp | null {\n if (!isFirebaseConfigured()) return null;\n if (getApps().length) return getApp();\n return initializeApp(readConfig() as Record<string, string>);\n}\n\nexport function getFirebaseAuth(): Auth | null {\n const app = getFirebaseApp();\n return app ? getAuth(app) : null;\n}\n\nexport function getDb(): Firestore | null {\n const app = getFirebaseApp();\n return app ? getFirestore(app) : null;\n}\n\nexport function getBucket(): FirebaseStorage | null {\n const app = getFirebaseApp();\n return app ? getStorage(app) : null;\n}\n"],"mappings":";AAEA,SAAS,eAAe,SAAS,cAAgC;AACjE,SAAS,eAA0B;AACnC,SAAS,oBAAoC;AAC7C,SAAS,kBAAwC;AAOjD,SAAS,aAAa;AACpB,SAAO;AAAA,IACL,QAAQ,QAAQ,IAAI;AAAA,IACpB,YAAY,QAAQ,IAAI;AAAA,IACxB,WAAW,QAAQ,IAAI;AAAA,IACvB,eAAe,QAAQ,IAAI;AAAA,IAC3B,mBAAmB,QAAQ,IAAI;AAAA,IAC/B,OAAO,QAAQ,IAAI;AAAA,EACrB;AACF;AAEO,SAAS,uBAAgC;AAC9C,QAAM,MAAM,WAAW;AACvB,SAAO,QAAQ,IAAI,UAAU,IAAI,SAAS;AAC5C;AAEO,SAAS,iBAAqC;AACnD,MAAI,CAAC,qBAAqB,EAAG,QAAO;AACpC,MAAI,QAAQ,EAAE,OAAQ,QAAO,OAAO;AACpC,SAAO,cAAc,WAAW,CAA2B;AAC7D;AAEO,SAAS,kBAA+B;AAC7C,QAAM,MAAM,eAAe;AAC3B,SAAO,MAAM,QAAQ,GAAG,IAAI;AAC9B;AAEO,SAAS,QAA0B;AACxC,QAAM,MAAM,eAAe;AAC3B,SAAO,MAAM,aAAa,GAAG,IAAI;AACnC;AAEO,SAAS,YAAoC;AAClD,QAAM,MAAM,eAAe;AAC3B,SAAO,MAAM,WAAW,GAAG,IAAI;AACjC;","names":[]}
1
+ {"version":3,"sources":["../../src/firebase/client.ts"],"sourcesContent":["\"use client\";\n\nimport { initializeApp, getApps, getApp, type FirebaseApp } from \"firebase/app\";\nimport { getAuth, type Auth } from \"firebase/auth\";\nimport { getFirestore, type Firestore } from \"firebase/firestore\";\nimport { getStorage, type FirebaseStorage } from \"firebase/storage\";\n\n/**\n * Client-side Firebase, volledig env-gedreven (NEXT_PUBLIC_*). Als de env niet is ingevuld\n * geven alle helpers `null` terug, zodat een site ook zónder Firebase blijft werken (dan\n * toont hij alleen de standaardteksten en is bewerken uitgeschakeld).\n */\nfunction readConfig() {\n return {\n apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,\n authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,\n projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,\n storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,\n messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,\n appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,\n };\n}\n\nexport function isFirebaseConfigured(): boolean {\n const cfg = readConfig();\n return Boolean(cfg.apiKey && cfg.projectId);\n}\n\nexport function getFirebaseApp(): FirebaseApp | null {\n if (!isFirebaseConfigured()) return null;\n if (getApps().length) return getApp();\n return initializeApp(readConfig() as Record<string, string>);\n}\n\nexport function getFirebaseAuth(): Auth | null {\n const app = getFirebaseApp();\n return app ? getAuth(app) : null;\n}\n\nexport function getDb(): Firestore | null {\n const app = getFirebaseApp();\n return app ? getFirestore(app) : null;\n}\n\nexport function getBucket(): FirebaseStorage | null {\n const app = getFirebaseApp();\n // Zonder storageBucket geeft getStorage() een client zónder default bucket terug, waarna\n // storageRef() een cryptisch `storage/no-default-bucket` gooit (of de upload stil hangt). Geef\n // hier `null` zodat de aanroeper de nette \"Storage niet geconfigureerd\"-melding kan tonen.\n if (!app || !readConfig().storageBucket) return null;\n return getStorage(app);\n}\n"],"mappings":";AAEA,SAAS,eAAe,SAAS,cAAgC;AACjE,SAAS,eAA0B;AACnC,SAAS,oBAAoC;AAC7C,SAAS,kBAAwC;AAOjD,SAAS,aAAa;AACpB,SAAO;AAAA,IACL,QAAQ,QAAQ,IAAI;AAAA,IACpB,YAAY,QAAQ,IAAI;AAAA,IACxB,WAAW,QAAQ,IAAI;AAAA,IACvB,eAAe,QAAQ,IAAI;AAAA,IAC3B,mBAAmB,QAAQ,IAAI;AAAA,IAC/B,OAAO,QAAQ,IAAI;AAAA,EACrB;AACF;AAEO,SAAS,uBAAgC;AAC9C,QAAM,MAAM,WAAW;AACvB,SAAO,QAAQ,IAAI,UAAU,IAAI,SAAS;AAC5C;AAEO,SAAS,iBAAqC;AACnD,MAAI,CAAC,qBAAqB,EAAG,QAAO;AACpC,MAAI,QAAQ,EAAE,OAAQ,QAAO,OAAO;AACpC,SAAO,cAAc,WAAW,CAA2B;AAC7D;AAEO,SAAS,kBAA+B;AAC7C,QAAM,MAAM,eAAe;AAC3B,SAAO,MAAM,QAAQ,GAAG,IAAI;AAC9B;AAEO,SAAS,QAA0B;AACxC,QAAM,MAAM,eAAe;AAC3B,SAAO,MAAM,aAAa,GAAG,IAAI;AACnC;AAEO,SAAS,YAAoC;AAClD,QAAM,MAAM,eAAe;AAI3B,MAAI,CAAC,OAAO,CAAC,WAAW,EAAE,cAAe,QAAO;AAChD,SAAO,WAAW,GAAG;AACvB;","names":[]}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Localisatie (5.0) — primo's locale-per-waarde vertaald naar een ADDITIEVE overlay:
3
+ * de blokkenstructuur blijft canoniek (de default-taal), en per pagina/symbool ligt er
4
+ * een `translations`-map overheen: `{ [locale]: { "<blokKey>.<veldpad>": "vertaalde tekst" } }`.
5
+ * Speciale sleutels: `title` (paginatitel) en `seo.<veld>` (SEO-overlay). Waarden zijn altijd
6
+ * strings — structuurwijzigingen (blokken toevoegen/verplaatsen) gebeuren alléén canoniek.
7
+ *
8
+ * Server-safe: geen React, geen Firebase — bruikbaar in server/pages.ts én in de editor.
9
+ */
10
+ import { z } from "zod";
11
+ /** `{ [locale]: { "hero1.title": "Willkommen", "seo.description": "…" } }` */
12
+ export declare const TranslationsSchema: z.ZodRecord<z.ZodString, z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodString>, Record<string, string>, Record<string, string>>>;
13
+ export type Translations = z.infer<typeof TranslationsSchema>;
14
+ export interface LocaleConfig {
15
+ /** Alle talen van de site, default-taal eerst (bv. ["nl", "de", "en"]). */
16
+ locales: string[];
17
+ defaultLocale: string;
18
+ }
19
+ /** Normaliseert de site-config naar een LocaleConfig (default: alleen `lang` ?? "nl"). */
20
+ export declare function siteLocales(site: {
21
+ locales?: string[];
22
+ defaultLocale?: string;
23
+ lang?: string;
24
+ }): LocaleConfig;
25
+ /**
26
+ * Herkent een taalprefix in Next-catch-all-segmenten: `/de/over-ons` → locale "de", pad "/over-ons".
27
+ * De default-taal heeft géén prefix (canonieke URL's blijven ongewijzigd).
28
+ */
29
+ export declare function parseLocaleSlugs(slugs: string[] | undefined, cfg: LocaleConfig): {
30
+ locale: string;
31
+ slugs: string[];
32
+ };
33
+ /** Pad mét taalprefix voor niet-default talen: ("/over-ons", "de") → "/de/over-ons". */
34
+ export declare function localizedPath(path: string, locale: string, defaultLocale: string): string;
35
+ /**
36
+ * Past één taal-overlay toe op een lijst blokken. Alleen bestaande, tekstuele velden worden
37
+ * overschreven: het doelpad moet oplosbaar zijn en de canonieke waarde moet een string (of leeg)
38
+ * zijn — zo kan een verouderde vertaalsleutel nooit de structuur breken (overlay-drift).
39
+ */
40
+ export declare function localizeBlocks<T extends {
41
+ _key?: string;
42
+ }>(blocks: T[], overlay: Record<string, string> | undefined): T[];
43
+ /**
44
+ * Past een taal-overlay toe op een hele pagina (titel + seo + blokken). Geeft de pagina
45
+ * ongewijzigd terug voor de default-taal of zonder vertalingen — nul overhead voor
46
+ * ééntalige sites.
47
+ */
48
+ export declare function localizePage<T extends {
49
+ title?: string;
50
+ seo?: Record<string, unknown>;
51
+ blocks?: unknown[];
52
+ translations?: Translations;
53
+ }>(page: T, locale: string | undefined, defaultLocale: string): T;
54
+ /**
55
+ * Ruimt wees-vertalingen op: sleutels die naar een niet (meer) bestaand blok wijzen vervallen
56
+ * (`title` en `seo.*` blijven altijd). Draait bij publiceren zodat de overlay niet oneindig
57
+ * aangroeit wanneer blokken verwijderd worden.
58
+ */
59
+ export declare function pruneTranslations(translations: Translations | undefined, blocks: Array<{
60
+ _key?: string;
61
+ }> | undefined): Translations | undefined;
@@ -0,0 +1,90 @@
1
+ import { z } from "zod";
2
+ const TranslationsSchema = z.record(
3
+ z.string().min(2).max(10),
4
+ z.record(z.string().min(1).max(300), z.string().max(2e4)).refine((m) => Object.keys(m).length <= 2e3, {
5
+ message: "te veel vertaalsleutels (max 2000 per taal)"
6
+ })
7
+ );
8
+ function siteLocales(site) {
9
+ const defaultLocale = site.defaultLocale ?? site.lang ?? "nl";
10
+ const locales = [defaultLocale, ...(site.locales ?? []).filter((l) => l !== defaultLocale)];
11
+ return { locales: [...new Set(locales)], defaultLocale };
12
+ }
13
+ function parseLocaleSlugs(slugs, cfg) {
14
+ const list = slugs ?? [];
15
+ const first = list[0];
16
+ if (first && first !== cfg.defaultLocale && cfg.locales.includes(first)) {
17
+ return { locale: first, slugs: list.slice(1) };
18
+ }
19
+ return { locale: cfg.defaultLocale, slugs: list };
20
+ }
21
+ function localizedPath(path, locale, defaultLocale) {
22
+ if (locale === defaultLocale) return path;
23
+ return `/${locale}${path === "/" ? "" : path}`;
24
+ }
25
+ function getPath(obj, keys) {
26
+ return keys.reduce((o, k) => o == null ? void 0 : o[k], obj);
27
+ }
28
+ function setPath(obj, keys, value) {
29
+ const clone = (v) => Array.isArray(v) ? [...v] : { ...v };
30
+ const root = clone(obj);
31
+ let cur = root;
32
+ for (let i = 0; i < keys.length - 1; i++) {
33
+ cur[keys[i]] = clone(cur[keys[i]]);
34
+ cur = cur[keys[i]];
35
+ }
36
+ cur[keys[keys.length - 1]] = value;
37
+ return root;
38
+ }
39
+ function localizeBlocks(blocks, overlay) {
40
+ if (!overlay || blocks.length === 0) return blocks;
41
+ let out = blocks;
42
+ for (const [key, value] of Object.entries(overlay)) {
43
+ if (typeof value !== "string") continue;
44
+ const [blockKey, ...rest] = key.split(".");
45
+ if (rest.length === 0) continue;
46
+ const idx = out.findIndex((b) => b?._key === blockKey);
47
+ if (idx < 0) continue;
48
+ const parent = rest.length > 1 ? getPath(out[idx], rest.slice(0, -1)) : out[idx];
49
+ if (parent == null || typeof parent !== "object") continue;
50
+ const current = parent[rest[rest.length - 1]];
51
+ if (current !== void 0 && typeof current !== "string") continue;
52
+ if (out === blocks) out = [...blocks];
53
+ out[idx] = setPath(out[idx], rest, value);
54
+ }
55
+ return out;
56
+ }
57
+ function localizePage(page, locale, defaultLocale) {
58
+ if (!locale || locale === defaultLocale) return page;
59
+ const overlay = page.translations?.[locale];
60
+ if (!overlay) return page;
61
+ let out = { ...page, blocks: localizeBlocks(page.blocks ?? [], overlay) };
62
+ for (const [key, value] of Object.entries(overlay)) {
63
+ if (typeof value !== "string") continue;
64
+ if (key === "title") out = { ...out, title: value };
65
+ else if (key.startsWith("seo.")) out = { ...out, seo: { ...out.seo ?? {}, [key.slice(4)]: value } };
66
+ }
67
+ return out;
68
+ }
69
+ function pruneTranslations(translations, blocks) {
70
+ if (!translations) return void 0;
71
+ const keys = new Set((blocks ?? []).map((b) => b?._key).filter(Boolean));
72
+ const out = {};
73
+ for (const [locale, overlay] of Object.entries(translations)) {
74
+ const kept = Object.fromEntries(
75
+ Object.entries(overlay).filter(([k]) => k === "title" || k.startsWith("seo.") || keys.has(k.split(".")[0]))
76
+ );
77
+ if (Object.keys(kept).length > 0) out[locale] = kept;
78
+ }
79
+ return Object.keys(out).length > 0 ? out : void 0;
80
+ }
81
+ export {
82
+ TranslationsSchema,
83
+ localizeBlocks,
84
+ localizePage,
85
+ localizedPath,
86
+ parseLocaleSlugs,
87
+ pruneTranslations,
88
+ siteLocales
89
+ };
90
+ //# sourceMappingURL=overlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/i18n/overlay.ts"],"sourcesContent":["/**\n * Localisatie (5.0) — primo's locale-per-waarde vertaald naar een ADDITIEVE overlay:\n * de blokkenstructuur blijft canoniek (de default-taal), en per pagina/symbool ligt er\n * een `translations`-map overheen: `{ [locale]: { \"<blokKey>.<veldpad>\": \"vertaalde tekst\" } }`.\n * Speciale sleutels: `title` (paginatitel) en `seo.<veld>` (SEO-overlay). Waarden zijn altijd\n * strings — structuurwijzigingen (blokken toevoegen/verplaatsen) gebeuren alléén canoniek.\n *\n * Server-safe: geen React, geen Firebase — bruikbaar in server/pages.ts én in de editor.\n */\nimport { z } from \"zod\";\n\n/** `{ [locale]: { \"hero1.title\": \"Willkommen\", \"seo.description\": \"…\" } }` */\nexport const TranslationsSchema = z.record(\n z.string().min(2).max(10),\n z.record(z.string().min(1).max(300), z.string().max(20_000)).refine((m) => Object.keys(m).length <= 2000, {\n message: \"te veel vertaalsleutels (max 2000 per taal)\",\n }),\n);\nexport type Translations = z.infer<typeof TranslationsSchema>;\n\nexport interface LocaleConfig {\n /** Alle talen van de site, default-taal eerst (bv. [\"nl\", \"de\", \"en\"]). */\n locales: string[];\n defaultLocale: string;\n}\n\n/** Normaliseert de site-config naar een LocaleConfig (default: alleen `lang` ?? \"nl\"). */\nexport function siteLocales(site: { locales?: string[]; defaultLocale?: string; lang?: string }): LocaleConfig {\n const defaultLocale = site.defaultLocale ?? site.lang ?? \"nl\";\n const locales = [defaultLocale, ...(site.locales ?? []).filter((l) => l !== defaultLocale)];\n return { locales: [...new Set(locales)], defaultLocale };\n}\n\n/**\n * Herkent een taalprefix in Next-catch-all-segmenten: `/de/over-ons` → locale \"de\", pad \"/over-ons\".\n * De default-taal heeft géén prefix (canonieke URL's blijven ongewijzigd).\n */\nexport function parseLocaleSlugs(\n slugs: string[] | undefined,\n cfg: LocaleConfig,\n): { locale: string; slugs: string[] } {\n const list = slugs ?? [];\n const first = list[0];\n if (first && first !== cfg.defaultLocale && cfg.locales.includes(first)) {\n return { locale: first, slugs: list.slice(1) };\n }\n return { locale: cfg.defaultLocale, slugs: list };\n}\n\n/** Pad mét taalprefix voor niet-default talen: (\"/over-ons\", \"de\") → \"/de/over-ons\". */\nexport function localizedPath(path: string, locale: string, defaultLocale: string): string {\n if (locale === defaultLocale) return path;\n return `/${locale}${path === \"/\" ? \"\" : path}`;\n}\n\n/* Zelfde gepunte-pad-helpers als de visuele editor: immutable schrijven op \"items.0.title\". */\nfunction getPath(obj: unknown, keys: string[]): unknown {\n return keys.reduce<unknown>((o, k) => (o == null ? undefined : (o as Record<string, unknown>)[k]), obj);\n}\nfunction setPath<T>(obj: T, keys: string[], value: unknown): T {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const clone = (v: unknown): any => (Array.isArray(v) ? [...v] : { ...(v as object) });\n const root = clone(obj);\n let cur = root;\n for (let i = 0; i < keys.length - 1; i++) {\n cur[keys[i]] = clone(cur[keys[i]]);\n cur = cur[keys[i]];\n }\n cur[keys[keys.length - 1]] = value;\n return root as T;\n}\n\n/**\n * Past één taal-overlay toe op een lijst blokken. Alleen bestaande, tekstuele velden worden\n * overschreven: het doelpad moet oplosbaar zijn en de canonieke waarde moet een string (of leeg)\n * zijn — zo kan een verouderde vertaalsleutel nooit de structuur breken (overlay-drift).\n */\nexport function localizeBlocks<T extends { _key?: string }>(blocks: T[], overlay: Record<string, string> | undefined): T[] {\n if (!overlay || blocks.length === 0) return blocks;\n let out = blocks;\n for (const [key, value] of Object.entries(overlay)) {\n if (typeof value !== \"string\") continue;\n const [blockKey, ...rest] = key.split(\".\");\n if (rest.length === 0) continue;\n const idx = out.findIndex((b) => b?._key === blockKey);\n if (idx < 0) continue;\n const parent = rest.length > 1 ? getPath(out[idx], rest.slice(0, -1)) : out[idx];\n if (parent == null || typeof parent !== \"object\") continue;\n const current = (parent as Record<string, unknown>)[rest[rest.length - 1]];\n if (current !== undefined && typeof current !== \"string\") continue;\n if (out === blocks) out = [...blocks];\n out[idx] = setPath(out[idx], rest, value);\n }\n return out;\n}\n\n/**\n * Past een taal-overlay toe op een hele pagina (titel + seo + blokken). Geeft de pagina\n * ongewijzigd terug voor de default-taal of zonder vertalingen — nul overhead voor\n * ééntalige sites.\n */\nexport function localizePage<\n T extends { title?: string; seo?: Record<string, unknown>; blocks?: unknown[]; translations?: Translations },\n>(page: T, locale: string | undefined, defaultLocale: string): T {\n if (!locale || locale === defaultLocale) return page;\n const overlay = page.translations?.[locale];\n if (!overlay) return page;\n let out: T = { ...page, blocks: localizeBlocks((page.blocks ?? []) as { _key?: string }[], overlay) };\n for (const [key, value] of Object.entries(overlay)) {\n if (typeof value !== \"string\") continue;\n if (key === \"title\") out = { ...out, title: value };\n else if (key.startsWith(\"seo.\")) out = { ...out, seo: { ...(out.seo ?? {}), [key.slice(4)]: value } };\n }\n return out;\n}\n\n/**\n * Ruimt wees-vertalingen op: sleutels die naar een niet (meer) bestaand blok wijzen vervallen\n * (`title` en `seo.*` blijven altijd). Draait bij publiceren zodat de overlay niet oneindig\n * aangroeit wanneer blokken verwijderd worden.\n */\nexport function pruneTranslations(\n translations: Translations | undefined,\n blocks: Array<{ _key?: string }> | undefined,\n): Translations | undefined {\n if (!translations) return undefined;\n const keys = new Set((blocks ?? []).map((b) => b?._key).filter(Boolean));\n const out: Translations = {};\n for (const [locale, overlay] of Object.entries(translations)) {\n const kept = Object.fromEntries(\n Object.entries(overlay).filter(([k]) => k === \"title\" || k.startsWith(\"seo.\") || keys.has(k.split(\".\")[0])),\n );\n if (Object.keys(kept).length > 0) out[locale] = kept;\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -20,6 +20,16 @@ export { definePattern, instantiatePattern, collectPatternTypes, builtinPatterns
20
20
  export { builtinThemePresets, type ThemePreset } from "./theme/presets";
21
21
  export { defineSiteConfig } from "./schema/siteConfig";
22
22
  export type { SiteConfig, SiteMode } from "./schema/siteConfig";
23
+ export { FieldSchema, FieldsSchema, fieldsToZod, fieldsDefaults, isFieldVisible, isRichTextKey } from "./schema/fields";
24
+ export type { Field, FieldHints, ShowIf } from "./schema/fields";
25
+ export { SymbolSchema } from "./schema/symbols";
26
+ export type { Symbol, StoredSymbol } from "./schema/symbols";
27
+ export { CustomBlockSchema } from "./schema/customBlocks";
28
+ export type { CustomBlock, CustomBlock as CustomBlockData } from "./schema/customBlocks";
29
+ export { customBlockToDefinition } from "./blocks/customTemplate/definition";
30
+ export { interpretTemplate, scopeCss } from "./blocks/customTemplate/interpret";
31
+ export { siteLocales, parseLocaleSlugs, localizedPath, localizePage, localizeBlocks, pruneTranslations, TranslationsSchema, } from "./i18n/overlay";
32
+ export type { Translations, LocaleConfig } from "./i18n/overlay";
23
33
  export type { ThemeTokens, NavItem, SiteSettings, FormsSender } from "./schema/settings";
24
34
  export type { Seo } from "./schema/seo";
25
35
  export type { Page, PageStatus } from "./schema/pages";
@@ -27,15 +37,7 @@ export type { FormDefinition, FormField } from "./schema/forms";
27
37
  export { AuthProvider, useAuth } from "./auth/AuthProvider";
28
38
  export { LoginForm } from "./auth/LoginForm";
29
39
  export { roleForSite, canEdit, canManageSite, isSuperadmin, type Role, type XiClaims, } from "./auth/roles";
30
- /** @deprecated Gebruik het block-model (pagina's/drafts) + de visuele editor i.p.v. `cms/content`. */
31
- export { ContentProvider, useContent } from "./content/ContentProvider";
32
40
  export type { NewsArticle, MediaItem, MediaVariant } from "./content/types";
33
- /** @deprecated Gebruik een block met `data-xicms-edit` — inline bewerken loopt via de visuele editor. */
34
- export { EditableText } from "./components/EditableText";
35
- /** @deprecated Gebruik een richText-block — inline bewerken loopt via de visuele editor. */
36
- export { EditableRichText } from "./components/EditableRichText";
37
- /** @deprecated Gebruik een image-block (inline vervangen via de mediakiezer in de visuele editor). */
38
- export { EditableImage } from "./components/EditableImage";
39
41
  export { EditBar } from "./components/EditBar";
40
42
  export { ResponsiveImage } from "./components/ResponsiveImage";
41
43
  export { PageView } from "./components/PageView";
@@ -48,7 +50,7 @@ export { PageRenderer } from "./render/PageRenderer";
48
50
  export { PublishedPage } from "./render/PublishedPage";
49
51
  export { defineModule, resolveModules, isModuleActive, ModulesProvider, useModules, useModuleActive, useModuleSettings, applyBlockOverrides, moduleIdForBlockType, builtinModules, validateModuleContract, assertModuleContract, useConsent, ConsentBanner, ConsentGate, ConsentReopenLink, type ConsentState, type ConsentSettings, type ConsentCategory, type ModuleDefinition, type ModuleSiteSetting, type ModulesSiteConfig, type Capability, type ResolvedModules, type BlockOverride, type BlockOverrides, } from "./modules";
50
52
  export { DemoLock } from "./lock/DemoLock";
51
- export { registerSeed, resolveDemoPage, loadDemoDraft, demoIdForPath, registerDemoNews, registerDemoForm, DEMO_EVENT, } from "./demo/demoStore";
53
+ export { registerSeed, resolveDemoPage, loadDemoDraft, demoIdForPath, registerDemoNews, registerDemoForm, registerDemoMedia, DEMO_EVENT, } from "./demo/demoStore";
52
54
  export { DemoStudio } from "./demo/DemoStudio";
53
55
  export { getFirebaseApp, getFirebaseAuth, getDb, getBucket, isFirebaseConfigured, } from "./firebase/client";
54
56
  export { initAppCheck } from "./firebase/appcheck";
package/dist/index.js CHANGED
@@ -19,6 +19,20 @@ import {
19
19
  } from "./patterns";
20
20
  import { builtinThemePresets } from "./theme/presets";
21
21
  import { defineSiteConfig } from "./schema/siteConfig";
22
+ import { FieldSchema, FieldsSchema, fieldsToZod, fieldsDefaults, isFieldVisible, isRichTextKey } from "./schema/fields";
23
+ import { SymbolSchema } from "./schema/symbols";
24
+ import { CustomBlockSchema } from "./schema/customBlocks";
25
+ import { customBlockToDefinition } from "./blocks/customTemplate/definition";
26
+ import { interpretTemplate, scopeCss } from "./blocks/customTemplate/interpret";
27
+ import {
28
+ siteLocales,
29
+ parseLocaleSlugs,
30
+ localizedPath,
31
+ localizePage,
32
+ localizeBlocks,
33
+ pruneTranslations,
34
+ TranslationsSchema
35
+ } from "./i18n/overlay";
22
36
  import { AuthProvider, useAuth } from "./auth/AuthProvider";
23
37
  import { LoginForm } from "./auth/LoginForm";
24
38
  import {
@@ -27,10 +41,6 @@ import {
27
41
  canManageSite,
28
42
  isSuperadmin
29
43
  } from "./auth/roles";
30
- import { ContentProvider, useContent } from "./content/ContentProvider";
31
- import { EditableText } from "./components/EditableText";
32
- import { EditableRichText } from "./components/EditableRichText";
33
- import { EditableImage } from "./components/EditableImage";
34
44
  import { EditBar } from "./components/EditBar";
35
45
  import { ResponsiveImage } from "./components/ResponsiveImage";
36
46
  import { PageView } from "./components/PageView";
@@ -73,6 +83,7 @@ import {
73
83
  demoIdForPath,
74
84
  registerDemoNews,
75
85
  registerDemoForm,
86
+ registerDemoMedia,
76
87
  DEMO_EVENT
77
88
  } from "./demo/demoStore";
78
89
  import { DemoStudio } from "./demo/DemoStudio";
@@ -91,15 +102,14 @@ export {
91
102
  ConsentEmbed,
92
103
  ConsentGate,
93
104
  ConsentReopenLink,
94
- ContentProvider,
105
+ CustomBlockSchema,
95
106
  DEMO_EVENT,
96
107
  DemoLock,
97
108
  DemoStudio,
98
109
  EditBar,
99
- EditableImage,
100
- EditableRichText,
101
- EditableText,
102
110
  EditorProvider,
111
+ FieldSchema,
112
+ FieldsSchema,
103
113
  ImageProvider,
104
114
  Img,
105
115
  InlineImageEditProvider,
@@ -115,6 +125,8 @@ export {
115
125
  ResponsiveImage,
116
126
  SiteFooter,
117
127
  SiteSettingsProvider,
128
+ SymbolSchema,
129
+ TranslationsSchema,
118
130
  XiCMSProvider,
119
131
  applyBlockOverrides,
120
132
  assertModuleContract,
@@ -127,33 +139,46 @@ export {
127
139
  canManageSite,
128
140
  collectPatternTypes,
129
141
  createRegistry,
142
+ customBlockToDefinition,
130
143
  defineBlock,
131
144
  defineModule,
132
145
  definePattern,
133
146
  defineSiteConfig,
134
147
  defineTheme,
135
148
  demoIdForPath,
149
+ fieldsDefaults,
150
+ fieldsToZod,
136
151
  getBucket,
137
152
  getDb,
138
153
  getFirebaseApp,
139
154
  getFirebaseAuth,
140
155
  initAppCheck,
141
156
  instantiatePattern,
157
+ interpretTemplate,
158
+ isFieldVisible,
142
159
  isFirebaseConfigured,
143
160
  isModuleActive,
161
+ isRichTextKey,
144
162
  isSuperadmin,
145
163
  loadDemoDraft,
164
+ localizeBlocks,
165
+ localizePage,
166
+ localizedPath,
146
167
  mergeRegistry,
147
168
  moduleIdForBlockType,
169
+ parseLocaleSlugs,
170
+ pruneTranslations,
148
171
  registerDemoForm,
172
+ registerDemoMedia,
149
173
  registerDemoNews,
150
174
  registerSeed,
151
175
  resolveDemoPage,
152
176
  resolveModules,
153
177
  roleForSite,
178
+ scopeCss,
179
+ siteLocales,
154
180
  useAuth,
155
181
  useConsent,
156
- useContent,
157
182
  useEditor,
158
183
  useImageComponent,
159
184
  useLinkComponent,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Publieke runtime-API van @xiwebdesign/xicms-core (lichte client/runtime laag).\n * - Admin (TipTap/Radix) zit in \"@xiwebdesign/xicms-core/admin\".\n * - Server-only code (firebase-admin, sanitize, SEO) zit in \"@xiwebdesign/xicms-core/server\".\n * - Pure schema's in \"@xiwebdesign/xicms-core/schema\".\n */\n\n// Provider & config\nexport { XiCMSProvider } from \"./XiCMSProvider\";\nexport { useSiteConfig } from \"./config\";\n\n// Theming & design-primitieven (maatwerk zonder core te forken).\n// - `defineTheme` maakt een eigen Astryx-thema (tokens + component-overrides) → geef door als\n// XiCMSProvider `astryxTheme`-prop.\n// - De `ui`-primitieven (Card/Stack/Grid/Heading/Text/Btn…) zijn de bouwstenen waarop de ingebouwde\n// blokken draaien; gebruik ze in eigen blokken voor een consistent maar te herstijlen uiterlijk.\nexport { defineTheme, useTheme } from \"@astryxdesign/core/theme\";\nexport type { DefinedTheme } from \"@astryxdesign/core/theme\";\n// Framework-router-integratie: geef `next/link` door als XiCMSProvider `linkComponent`-prop\n// (soepele client-nav + prefetch op alle Astryx-knoppen/links). `useLinkComponent` voor eigen blokken.\nexport { LinkProvider, useLinkComponent } from \"@astryxdesign/core/Link\";\nexport type { LinkComponentType } from \"@astryxdesign/core/Link\";\n// Beeldoptimalisatie: geef `next/image` door als XiCMSProvider `imageComponent`-prop. `Img` is de\n// wrapper die de blokken gebruiken; `useImageComponent` voor eigen blokken.\nexport { Img, ImageProvider, useImageComponent, InlineImageEditProvider } from \"./media/ImageContext\";\nexport type { ImageComponentType, ImgProps } from \"./media/ImageContext\";\nexport * from \"./blocks/ui\";\nexport {\n SiteSettingsProvider,\n useSiteSettings,\n useMergedSiteConfig,\n} from \"./settings/useSiteSettings\";\nexport { SiteFooter } from \"./components/site/SiteFooter\";\nexport { EditorProvider, useEditor } from \"./editor/EditorProvider\";\nexport {\n definePattern,\n instantiatePattern,\n collectPatternTypes,\n builtinPatterns,\n type Pattern,\n type PatternBlock,\n} from \"./patterns\";\nexport { builtinThemePresets, type ThemePreset } from \"./theme/presets\";\nexport { defineSiteConfig } from \"./schema/siteConfig\";\nexport type { SiteConfig, SiteMode } from \"./schema/siteConfig\";\nexport type { ThemeTokens, NavItem, SiteSettings, FormsSender } from \"./schema/settings\";\nexport type { Seo } from \"./schema/seo\";\nexport type { Page, PageStatus } from \"./schema/pages\";\nexport type { FormDefinition, FormField } from \"./schema/forms\";\n\n// Auth\nexport { AuthProvider, useAuth } from \"./auth/AuthProvider\";\nexport { LoginForm } from \"./auth/LoginForm\";\nexport {\n roleForSite,\n canEdit,\n canManageSite,\n isSuperadmin,\n type Role,\n type XiClaims,\n} from \"./auth/roles\";\n\n// Content (LEGACY inline editing, v1 plat model — vervangen door het block-model + de visuele\n// editor). Blijft werken en geëxporteerd voor bestaande sites; verwijdering volgt op z'n vroegst\n// in de eerstvolgende major. Nieuw werk: gebruik blocks + data-xicms-edit voor inline bewerken.\n/** @deprecated Gebruik het block-model (pagina's/drafts) + de visuele editor i.p.v. `cms/content`. */\nexport { ContentProvider, useContent } from \"./content/ContentProvider\";\nexport type { NewsArticle, MediaItem, MediaVariant } from \"./content/types\";\n\n// Bewerkbare componenten (legacy inline)\n/** @deprecated Gebruik een block met `data-xicms-edit` — inline bewerken loopt via de visuele editor. */\nexport { EditableText } from \"./components/EditableText\";\n/** @deprecated Gebruik een richText-block — inline bewerken loopt via de visuele editor. */\nexport { EditableRichText } from \"./components/EditableRichText\";\n/** @deprecated Gebruik een image-block (inline vervangen via de mediakiezer in de visuele editor). */\nexport { EditableImage } from \"./components/EditableImage\";\nexport { EditBar } from \"./components/EditBar\";\nexport { ResponsiveImage } from \"./components/ResponsiveImage\";\nexport { PageView } from \"./components/PageView\";\nexport { NewsList, NewsArticleView, useNews } from \"./components/News\";\n\n// Block-systeem (runtime: registry + renderer; editors zitten in /admin)\nexport {\n defineBlock,\n createRegistry,\n mergeRegistry,\n validateBlocks,\n buildBlockAddOptions,\n type BlockDefinition,\n type BlockRegistry,\n type BlockRenderProps,\n type BlockEditorProps,\n type BlockCategory,\n} from \"./blocks/registry\";\nexport { BlockRenderer } from \"./blocks/BlockRenderer\";\nexport { RegistryProvider, useRegistry } from \"./blocks/context\";\nexport { builtinBlocks, ConsentEmbed } from \"./blocks/builtins\";\nexport { PageRenderer } from \"./render/PageRenderer\";\nexport { PublishedPage } from \"./render/PublishedPage\";\n\n// Module-systeem (XiCMS 3.0): modules bundelen blocks + instellingen; per site aan/uit + te stylen.\nexport {\n defineModule,\n resolveModules,\n isModuleActive,\n ModulesProvider,\n useModules,\n useModuleActive,\n useModuleSettings,\n applyBlockOverrides,\n moduleIdForBlockType,\n builtinModules,\n validateModuleContract,\n assertModuleContract,\n useConsent,\n ConsentBanner,\n ConsentGate,\n ConsentReopenLink,\n type ConsentState,\n type ConsentSettings,\n type ConsentCategory,\n type ModuleDefinition,\n type ModuleSiteSetting,\n type ModulesSiteConfig,\n type Capability,\n type ResolvedModules,\n type BlockOverride,\n type BlockOverrides,\n} from \"./modules\";\n\n// Demo-lock\nexport { DemoLock } from \"./lock/DemoLock\";\n\n// Demo-bewerkmodus (lokaal-only): seed registreren + de live (lokaal-bewerkte) pagina ophalen\nexport {\n registerSeed,\n resolveDemoPage,\n loadDemoDraft,\n demoIdForPath,\n registerDemoNews,\n registerDemoForm,\n DEMO_EVENT,\n} from \"./demo/demoStore\";\nexport { DemoStudio } from \"./demo/DemoStudio\";\n\n// Firebase (client)\nexport {\n getFirebaseApp,\n getFirebaseAuth,\n getDb,\n getBucket,\n isFirebaseConfigured,\n} from \"./firebase/client\";\nexport { initAppCheck } from \"./firebase/appcheck\";\n"],"mappings":"AAQA,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAO9B,SAAS,aAAa,gBAAgB;AAItC,SAAS,cAAc,wBAAwB;AAI/C,SAAS,KAAK,eAAe,mBAAmB,+BAA+B;AAE/E,cAAc;AACd;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB,iBAAiB;AAC1C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP,SAAS,2BAA6C;AACtD,SAAS,wBAAwB;AAQjC,SAAS,cAAc,eAAe;AACtC,SAAS,iBAAiB;AAC1B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAMP,SAAS,iBAAiB,kBAAkB;AAK5C,SAAS,oBAAoB;AAE7B,SAAS,wBAAwB;AAEjC,SAAS,qBAAqB;AAC9B,SAAS,eAAe;AACxB,SAAS,uBAAuB;AAChC,SAAS,gBAAgB;AACzB,SAAS,UAAU,iBAAiB,eAAe;AAGnD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAMK;AACP,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB,mBAAmB;AAC9C,SAAS,eAAe,oBAAoB;AAC5C,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAG9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAWK;AAGP,SAAS,gBAAgB;AAGzB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAG3B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,oBAAoB;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Publieke runtime-API van @xiwebdesign/xicms-core (lichte client/runtime laag).\n * - Admin (TipTap/Radix) zit in \"@xiwebdesign/xicms-core/admin\".\n * - Server-only code (firebase-admin, sanitize, SEO) zit in \"@xiwebdesign/xicms-core/server\".\n * - Pure schema's in \"@xiwebdesign/xicms-core/schema\".\n */\n\n// Provider & config\nexport { XiCMSProvider } from \"./XiCMSProvider\";\nexport { useSiteConfig } from \"./config\";\n\n// Theming & design-primitieven (maatwerk zonder core te forken).\n// - `defineTheme` maakt een eigen Astryx-thema (tokens + component-overrides) → geef door als\n// XiCMSProvider `astryxTheme`-prop.\n// - De `ui`-primitieven (Card/Stack/Grid/Heading/Text/Btn…) zijn de bouwstenen waarop de ingebouwde\n// blokken draaien; gebruik ze in eigen blokken voor een consistent maar te herstijlen uiterlijk.\nexport { defineTheme, useTheme } from \"@astryxdesign/core/theme\";\nexport type { DefinedTheme } from \"@astryxdesign/core/theme\";\n// Framework-router-integratie: geef `next/link` door als XiCMSProvider `linkComponent`-prop\n// (soepele client-nav + prefetch op alle Astryx-knoppen/links). `useLinkComponent` voor eigen blokken.\nexport { LinkProvider, useLinkComponent } from \"@astryxdesign/core/Link\";\nexport type { LinkComponentType } from \"@astryxdesign/core/Link\";\n// Beeldoptimalisatie: geef `next/image` door als XiCMSProvider `imageComponent`-prop. `Img` is de\n// wrapper die de blokken gebruiken; `useImageComponent` voor eigen blokken.\nexport { Img, ImageProvider, useImageComponent, InlineImageEditProvider } from \"./media/ImageContext\";\nexport type { ImageComponentType, ImgProps } from \"./media/ImageContext\";\nexport * from \"./blocks/ui\";\nexport {\n SiteSettingsProvider,\n useSiteSettings,\n useMergedSiteConfig,\n} from \"./settings/useSiteSettings\";\nexport { SiteFooter } from \"./components/site/SiteFooter\";\nexport { EditorProvider, useEditor } from \"./editor/EditorProvider\";\nexport {\n definePattern,\n instantiatePattern,\n collectPatternTypes,\n builtinPatterns,\n type Pattern,\n type PatternBlock,\n} from \"./patterns\";\nexport { builtinThemePresets, type ThemePreset } from \"./theme/presets\";\nexport { defineSiteConfig } from \"./schema/siteConfig\";\nexport type { SiteConfig, SiteMode } from \"./schema/siteConfig\";\n// 5.0: Field-IR (primo-port), symbolen en custom blocks.\nexport { FieldSchema, FieldsSchema, fieldsToZod, fieldsDefaults, isFieldVisible, isRichTextKey } from \"./schema/fields\";\nexport type { Field, FieldHints, ShowIf } from \"./schema/fields\";\nexport { SymbolSchema } from \"./schema/symbols\";\nexport type { Symbol, StoredSymbol } from \"./schema/symbols\";\nexport { CustomBlockSchema } from \"./schema/customBlocks\";\nexport type { CustomBlock, CustomBlock as CustomBlockData } from \"./schema/customBlocks\";\nexport { customBlockToDefinition } from \"./blocks/customTemplate/definition\";\nexport { interpretTemplate, scopeCss } from \"./blocks/customTemplate/interpret\";\n// 5.0: localisatie — overlay-model (primo's locale-per-waarde, additief vertaald).\nexport {\n siteLocales,\n parseLocaleSlugs,\n localizedPath,\n localizePage,\n localizeBlocks,\n pruneTranslations,\n TranslationsSchema,\n} from \"./i18n/overlay\";\nexport type { Translations, LocaleConfig } from \"./i18n/overlay\";\nexport type { ThemeTokens, NavItem, SiteSettings, FormsSender } from \"./schema/settings\";\nexport type { Seo } from \"./schema/seo\";\nexport type { Page, PageStatus } from \"./schema/pages\";\nexport type { FormDefinition, FormField } from \"./schema/forms\";\n\n// Auth\nexport { AuthProvider, useAuth } from \"./auth/AuthProvider\";\nexport { LoginForm } from \"./auth/LoginForm\";\nexport {\n roleForSite,\n canEdit,\n canManageSite,\n isSuperadmin,\n type Role,\n type XiClaims,\n} from \"./auth/roles\";\n\n// De legacy inline-laag (ContentProvider/useContent + EditableText/EditableRichText/EditableImage,\n// het v1 platte `cms/content`-model) is in 5.0 VERWIJDERD, zoals bij de deprecatie aangekondigd.\n// Inline bewerken loopt via het block-model: markeer tekstvelden met `data-xicms-edit` in de Render.\nexport type { NewsArticle, MediaItem, MediaVariant } from \"./content/types\";\n\nexport { EditBar } from \"./components/EditBar\";\nexport { ResponsiveImage } from \"./components/ResponsiveImage\";\nexport { PageView } from \"./components/PageView\";\nexport { NewsList, NewsArticleView, useNews } from \"./components/News\";\n\n// Block-systeem (runtime: registry + renderer; editors zitten in /admin)\nexport {\n defineBlock,\n createRegistry,\n mergeRegistry,\n validateBlocks,\n buildBlockAddOptions,\n type BlockDefinition,\n type BlockRegistry,\n type BlockRenderProps,\n type BlockEditorProps,\n type BlockCategory,\n} from \"./blocks/registry\";\nexport { BlockRenderer } from \"./blocks/BlockRenderer\";\nexport { RegistryProvider, useRegistry } from \"./blocks/context\";\nexport { builtinBlocks, ConsentEmbed } from \"./blocks/builtins\";\nexport { PageRenderer } from \"./render/PageRenderer\";\nexport { PublishedPage } from \"./render/PublishedPage\";\n\n// Module-systeem (XiCMS 3.0): modules bundelen blocks + instellingen; per site aan/uit + te stylen.\nexport {\n defineModule,\n resolveModules,\n isModuleActive,\n ModulesProvider,\n useModules,\n useModuleActive,\n useModuleSettings,\n applyBlockOverrides,\n moduleIdForBlockType,\n builtinModules,\n validateModuleContract,\n assertModuleContract,\n useConsent,\n ConsentBanner,\n ConsentGate,\n ConsentReopenLink,\n type ConsentState,\n type ConsentSettings,\n type ConsentCategory,\n type ModuleDefinition,\n type ModuleSiteSetting,\n type ModulesSiteConfig,\n type Capability,\n type ResolvedModules,\n type BlockOverride,\n type BlockOverrides,\n} from \"./modules\";\n\n// Demo-lock\nexport { DemoLock } from \"./lock/DemoLock\";\n\n// Demo-bewerkmodus (lokaal-only): seed registreren + de live (lokaal-bewerkte) pagina ophalen\nexport {\n registerSeed,\n resolveDemoPage,\n loadDemoDraft,\n demoIdForPath,\n registerDemoNews,\n registerDemoForm,\n registerDemoMedia,\n DEMO_EVENT,\n} from \"./demo/demoStore\";\nexport { DemoStudio } from \"./demo/DemoStudio\";\n\n// Firebase (client)\nexport {\n getFirebaseApp,\n getFirebaseAuth,\n getDb,\n getBucket,\n isFirebaseConfigured,\n} from \"./firebase/client\";\nexport { initAppCheck } from \"./firebase/appcheck\";\n"],"mappings":"AAQA,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAO9B,SAAS,aAAa,gBAAgB;AAItC,SAAS,cAAc,wBAAwB;AAI/C,SAAS,KAAK,eAAe,mBAAmB,+BAA+B;AAE/E,cAAc;AACd;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB,iBAAiB;AAC1C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP,SAAS,2BAA6C;AACtD,SAAS,wBAAwB;AAGjC,SAAS,aAAa,cAAc,aAAa,gBAAgB,gBAAgB,qBAAqB;AAEtG,SAAS,oBAAoB;AAE7B,SAAS,yBAAyB;AAElC,SAAS,+BAA+B;AACxC,SAAS,mBAAmB,gBAAgB;AAE5C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAQP,SAAS,cAAc,eAAe;AACtC,SAAS,iBAAiB;AAC1B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAOP,SAAS,eAAe;AACxB,SAAS,uBAAuB;AAChC,SAAS,gBAAgB;AACzB,SAAS,UAAU,iBAAiB,eAAe;AAGnD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAMK;AACP,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB,mBAAmB;AAC9C,SAAS,eAAe,oBAAoB;AAC5C,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAG9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAWK;AAGP,SAAS,gBAAgB;AAGzB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAG3B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,oBAAoB;","names":[]}
@@ -17,6 +17,7 @@ import { teamBlock } from "../blocks/builtins/Team";
17
17
  import { agendaBlock } from "../blocks/builtins/Agenda";
18
18
  import { searchBlock } from "../blocks/builtins/Search";
19
19
  import { featureBlock, countersBlock, logosBlock, timelineBlock } from "../blocks/builtins/Sections";
20
+ import { symbolRefBlock } from "../blocks/builtins/SymbolRef";
20
21
  import { videoBlock } from "../blocks/builtins/Video";
21
22
  import { bannerBlock } from "../blocks/builtins/Banner";
22
23
  import { contactBlock, socialBlock } from "../blocks/builtins/Contact";
@@ -51,14 +52,14 @@ import {
51
52
  downloadsWidget,
52
53
  countdownWidget
53
54
  } from "../blocks/builtins/Widgets";
54
- const CORE_VERSION = "4.17.1";
55
+ const CORE_VERSION = "5.0.0";
55
56
  const contentModule = defineModule({
56
57
  id: "content",
57
58
  version: CORE_VERSION,
58
59
  label: "Basisinhoud",
59
60
  description: "Kern-bouwstenen: hero, tekst, afbeelding, CTA, kolommen, zijbalk, witruimte.",
60
61
  core: true,
61
- blocks: [heroBlock, richTextBlock, imageBlock, ctaBlock, columnsBlock, withSidebarBlock, spacerBlock, buttonsBlock, quoteBlock, dividerBlock, ctaWidget]
62
+ blocks: [heroBlock, richTextBlock, imageBlock, ctaBlock, columnsBlock, withSidebarBlock, spacerBlock, buttonsBlock, quoteBlock, dividerBlock, ctaWidget, symbolRefBlock]
62
63
  });
63
64
  const galleryModule = defineModule({
64
65
  id: "gallery",