@xiwebdesign/xicms-core 6.5.0 → 7.1.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.
- package/dist/SiteChrome.d.ts +12 -0
- package/dist/SiteChrome.js +24 -0
- package/dist/SiteChrome.js.map +1 -0
- package/dist/XiCMSProvider.d.ts +16 -8
- package/dist/XiCMSProvider.js +90 -61
- package/dist/XiCMSProvider.js.map +1 -1
- package/dist/admin/AdminApp.d.ts +1 -1
- package/dist/admin/AdminApp.js +81 -35
- package/dist/admin/AdminApp.js.map +1 -1
- package/dist/admin/AdminHelp.d.ts +8 -1
- package/dist/admin/AdminHelp.js +2 -2
- package/dist/admin/AdminHelp.js.map +1 -1
- package/dist/admin/CoreVersion.d.ts +13 -0
- package/dist/admin/CoreVersion.js +38 -0
- package/dist/admin/CoreVersion.js.map +1 -0
- package/dist/admin/NewsEditor.js +9 -9
- package/dist/admin/SuperadminPanel.js +5 -5
- package/dist/admin/blockEditors/GenericEditor.d.ts +2 -2
- package/dist/admin/blockEditors/GenericEditor.js +12 -11
- package/dist/admin/blockEditors/GenericEditor.js.map +1 -1
- package/dist/admin/blockEditors/StyleEditor.d.ts +1 -1
- package/dist/admin/blockEditors/StyleEditor.js +2 -2
- package/dist/admin/blockEditors/SymbolRefEditor.d.ts +1 -1
- package/dist/admin/blockEditors/SymbolRefEditor.js +5 -5
- package/dist/admin/blockEditors/index.d.ts +1 -1
- package/dist/admin/blockEditors/index.js +10 -10
- package/dist/admin/customBlocks/CustomBlocksPanel.js +7 -7
- package/dist/admin/editors/RichTextEditor.js +8 -7
- package/dist/admin/editors/RichTextEditor.js.map +1 -1
- package/dist/admin/editors/fontSizeExtension.js +1 -1
- package/dist/admin/editors/fontSizeExtension.js.map +1 -1
- package/dist/admin/forms/FormsPanel.js +9 -9
- package/dist/admin/index.d.ts +16 -16
- package/dist/admin/index.js +16 -16
- package/dist/admin/lib/mediaUsage.js +1 -1
- package/dist/admin/lib/pagesClient.d.ts +1 -1
- package/dist/admin/lib/pagesClient.js +11 -7
- package/dist/admin/lib/pagesClient.js.map +1 -1
- package/dist/admin/lib/sanitizeDraft.d.ts +9 -0
- package/dist/admin/lib/sanitizeDraft.js +28 -0
- package/dist/admin/lib/sanitizeDraft.js.map +1 -0
- package/dist/admin/lib/symbolsClient.d.ts +1 -1
- package/dist/admin/lib/symbolsClient.js +3 -3
- package/dist/admin/lib/upload.js +3 -3
- package/dist/admin/lib/useNestedDialog.d.ts +15 -0
- package/dist/admin/lib/useNestedDialog.js +23 -0
- package/dist/admin/lib/useNestedDialog.js.map +1 -0
- package/dist/admin/lib/zodFields.d.ts +4 -18
- package/dist/admin/lib/zodFields.js +54 -35
- package/dist/admin/lib/zodFields.js.map +1 -1
- package/dist/admin/media/MediaManager.js +7 -7
- package/dist/admin/media/MediaPicker.js +7 -7
- package/dist/admin/media/MediaPicker.js.map +1 -1
- package/dist/admin/pages/PageEditor.d.ts +1 -1
- package/dist/admin/pages/PageEditor.js +13 -13
- package/dist/admin/pages/PagesPanel.js +30 -30
- package/dist/admin/pages/PagesPanel.js.map +1 -1
- package/dist/admin/panelRegistry.js +7 -7
- package/dist/admin/patterns/PatternInserter.d.ts +1 -1
- package/dist/admin/patterns/PatternInserter.js +5 -5
- package/dist/admin/patterns/PatternInserter.js.map +1 -1
- package/dist/admin/settings/MailSettings.js +5 -5
- package/dist/admin/settings/MailTemplates.d.ts +1 -1
- package/dist/admin/settings/MailTemplates.js +5 -5
- package/dist/admin/settings/SettingsPanel.js +66 -20
- package/dist/admin/settings/SettingsPanel.js.map +1 -1
- package/dist/admin/settings/SnapshotsCard.js +5 -5
- package/dist/admin/settings/moduleSettingsForm.d.ts +1 -1
- package/dist/admin/settings/moduleSettingsForm.js +4 -4
- package/dist/admin/settings/moduleSettingsForm.js.map +1 -1
- package/dist/admin/shop/CategoriesTab.js +8 -8
- package/dist/admin/shop/ConnectionsTab.js +3 -3
- package/dist/admin/shop/DiscountsTab.js +8 -8
- package/dist/admin/shop/OrdersTab.js +10 -10
- package/dist/admin/shop/OrdersTab.js.map +1 -1
- package/dist/admin/shop/ProductsTab.js +10 -10
- package/dist/admin/shop/ShopPanel.js +9 -9
- package/dist/admin/shop/ShopSettingsTab.js +4 -4
- package/dist/admin/shop/index.d.ts +2 -2
- package/dist/admin/shop/index.js +2 -2
- package/dist/admin/shop/lib.js +2 -2
- package/dist/admin/stats/StatsPanel.js +2 -2
- package/dist/admin/ui/ArrayEditor.js +1 -1
- package/dist/admin/ui/PanelIcon.d.ts +3 -0
- package/dist/admin/ui/PanelIcon.js +34 -0
- package/dist/admin/ui/PanelIcon.js.map +1 -0
- package/dist/admin/ui/dialog.d.ts +21 -6
- package/dist/admin/ui/dialog.js +55 -34
- package/dist/admin/ui/dialog.js.map +1 -1
- package/dist/admin/ui/index.d.ts +7 -7
- package/dist/admin/ui/index.js +7 -7
- package/dist/admin/ui/primitives.js +1 -1
- package/dist/admin/ui/tabs.js +1 -1
- package/dist/admin/visual/TranslationPanel.d.ts +1 -1
- package/dist/admin/visual/TranslationPanel.js +3 -3
- package/dist/admin/visual/VisualEditor.js +47 -25
- package/dist/admin/visual/VisualEditor.js.map +1 -1
- package/dist/admin.css +2 -1
- package/dist/agentFiles/catalog.d.ts +2 -2
- package/dist/agentFiles/catalog.js +6 -5
- package/dist/agentFiles/catalog.js.map +1 -1
- package/dist/agentFiles/files.d.ts +5 -5
- package/dist/agentFiles/files.js +17 -17
- package/dist/agentFiles/files.js.map +1 -1
- package/dist/all.d.ts +4 -4
- package/dist/all.js +6 -6
- package/dist/auth/AuthProvider.d.ts +2 -2
- package/dist/auth/AuthProvider.js +51 -28
- package/dist/auth/AuthProvider.js.map +1 -1
- package/dist/auth/LoginForm.js +1 -1
- package/dist/auth/roles.js +4 -1
- package/dist/auth/roles.js.map +1 -1
- package/dist/blocks/BlockRenderer.d.ts +1 -1
- package/dist/blocks/BlockRenderer.js +3 -3
- package/dist/blocks/blockStyle.d.ts +1 -1
- package/dist/blocks/builtins/Accordion.d.ts +1 -1
- package/dist/blocks/builtins/Accordion.js +13 -6
- package/dist/blocks/builtins/Accordion.js.map +1 -1
- package/dist/blocks/builtins/Agenda.d.ts +1 -1
- package/dist/blocks/builtins/Agenda.js +5 -5
- package/dist/blocks/builtins/Banner.d.ts +1 -1
- package/dist/blocks/builtins/Banner.js +2 -2
- package/dist/blocks/builtins/BeforeAfter.d.ts +1 -1
- package/dist/blocks/builtins/BeforeAfter.js +4 -4
- package/dist/blocks/builtins/BeforeAfter.js.map +1 -1
- package/dist/blocks/builtins/Booking.d.ts +1 -1
- package/dist/blocks/builtins/Booking.js +5 -5
- package/dist/blocks/builtins/Breadcrumbs.d.ts +1 -1
- package/dist/blocks/builtins/Breadcrumbs.js +3 -3
- package/dist/blocks/builtins/Cards.d.ts +1 -1
- package/dist/blocks/builtins/Cards.js +5 -5
- package/dist/blocks/builtins/Cards.js.map +1 -1
- package/dist/blocks/builtins/Columns.d.ts +1 -1
- package/dist/blocks/builtins/Columns.js +4 -4
- package/dist/blocks/builtins/Contact.d.ts +3 -3
- package/dist/blocks/builtins/Contact.js +4 -4
- package/dist/blocks/builtins/Countdown.d.ts +1 -1
- package/dist/blocks/builtins/Countdown.js +4 -4
- package/dist/blocks/builtins/Countdown.js.map +1 -1
- package/dist/blocks/builtins/Cta.d.ts +1 -1
- package/dist/blocks/builtins/Cta.js +3 -3
- package/dist/blocks/builtins/Downloads.d.ts +1 -1
- package/dist/blocks/builtins/Downloads.js +4 -4
- package/dist/blocks/builtins/Elements.d.ts +3 -3
- package/dist/blocks/builtins/Elements.js +3 -3
- package/dist/blocks/builtins/Embed.d.ts +1 -1
- package/dist/blocks/builtins/Embed.js +3 -3
- package/dist/blocks/builtins/Faq.d.ts +1 -1
- package/dist/blocks/builtins/Faq.js +14 -6
- package/dist/blocks/builtins/Faq.js.map +1 -1
- package/dist/blocks/builtins/FormBlock.d.ts +1 -1
- package/dist/blocks/builtins/FormBlock.js +28 -18
- package/dist/blocks/builtins/FormBlock.js.map +1 -1
- package/dist/blocks/builtins/Gallery.d.ts +2 -2
- package/dist/blocks/builtins/Gallery.js +5 -5
- package/dist/blocks/builtins/Hero.d.ts +1 -1
- package/dist/blocks/builtins/Hero.js +4 -4
- package/dist/blocks/builtins/ImageBlock.d.ts +1 -1
- package/dist/blocks/builtins/ImageBlock.js +3 -3
- package/dist/blocks/builtins/Jobs.d.ts +2 -2
- package/dist/blocks/builtins/Jobs.js +5 -5
- package/dist/blocks/builtins/Layout.d.ts +2 -2
- package/dist/blocks/builtins/Layout.js +4 -4
- package/dist/blocks/builtins/MapBlock.d.ts +1 -1
- package/dist/blocks/builtins/MapBlock.js +3 -3
- package/dist/blocks/builtins/NewsListBlock.d.ts +1 -1
- package/dist/blocks/builtins/NewsListBlock.js +4 -4
- package/dist/blocks/builtins/Newsletter.d.ts +1 -1
- package/dist/blocks/builtins/Newsletter.js +7 -7
- package/dist/blocks/builtins/Newsletter.js.map +1 -1
- package/dist/blocks/builtins/OpenNowBadge.d.ts +1 -1
- package/dist/blocks/builtins/OpenNowBadge.js +8 -3
- package/dist/blocks/builtins/OpenNowBadge.js.map +1 -1
- package/dist/blocks/builtins/OpeningHours.d.ts +1 -1
- package/dist/blocks/builtins/OpeningHours.js +6 -6
- package/dist/blocks/builtins/PdfBlock.d.ts +1 -1
- package/dist/blocks/builtins/PdfBlock.js +3 -3
- package/dist/blocks/builtins/Portfolio.d.ts +1 -1
- package/dist/blocks/builtins/Portfolio.js +5 -5
- package/dist/blocks/builtins/Pricing.d.ts +2 -2
- package/dist/blocks/builtins/Pricing.js +5 -5
- package/dist/blocks/builtins/Pricing.js.map +1 -1
- package/dist/blocks/builtins/RichTextBlock.d.ts +1 -1
- package/dist/blocks/builtins/RichTextBlock.js +2 -2
- package/dist/blocks/builtins/RichTextBlock.js.map +1 -1
- package/dist/blocks/builtins/Search.d.ts +1 -1
- package/dist/blocks/builtins/Search.js +9 -7
- package/dist/blocks/builtins/Search.js.map +1 -1
- package/dist/blocks/builtins/Sections.d.ts +4 -4
- package/dist/blocks/builtins/Sections.js +4 -4
- package/dist/blocks/builtins/Slider.d.ts +1 -1
- package/dist/blocks/builtins/Slider.js +3 -3
- package/dist/blocks/builtins/Spacer.d.ts +1 -1
- package/dist/blocks/builtins/Spacer.js +2 -2
- package/dist/blocks/builtins/SymbolRef.d.ts +1 -1
- package/dist/blocks/builtins/SymbolRef.js +31 -17
- package/dist/blocks/builtins/SymbolRef.js.map +1 -1
- package/dist/blocks/builtins/Team.d.ts +1 -1
- package/dist/blocks/builtins/Team.js +4 -4
- package/dist/blocks/builtins/Testimonials.d.ts +2 -2
- package/dist/blocks/builtins/Testimonials.js +4 -4
- package/dist/blocks/builtins/Video.d.ts +2 -2
- package/dist/blocks/builtins/Video.js +4 -4
- package/dist/blocks/builtins/Video.js.map +1 -1
- package/dist/blocks/builtins/WhatsappChat.d.ts +1 -1
- package/dist/blocks/builtins/WhatsappChat.js +2 -2
- package/dist/blocks/builtins/Widgets.d.ts +12 -12
- package/dist/blocks/builtins/Widgets.js +19 -19
- package/dist/blocks/builtins/Widgets.js.map +1 -1
- package/dist/blocks/builtins/consentEmbed.js +2 -2
- package/dist/blocks/builtins/index.d.ts +40 -40
- package/dist/blocks/builtins/index.js +40 -40
- package/dist/blocks/builtins/lib/submitForm.js +5 -3
- package/dist/blocks/builtins/lib/submitForm.js.map +1 -1
- package/dist/blocks/context.d.ts +1 -1
- package/dist/blocks/customTemplate/definition.d.ts +3 -3
- package/dist/blocks/customTemplate/definition.js +6 -6
- package/dist/blocks/customTemplate/definition.js.map +1 -1
- package/dist/blocks/customTemplate/interpret.js +1 -1
- package/dist/blocks/index.d.ts +5 -5
- package/dist/blocks/index.js +5 -5
- package/dist/blocks/registry.d.ts +17 -7
- package/dist/blocks/registry.js +2 -1
- package/dist/blocks/registry.js.map +1 -1
- package/dist/components/EditBar.js +3 -3
- package/dist/components/FeedbackWidget.js +4 -4
- package/dist/components/News.d.ts +1 -1
- package/dist/components/News.js +50 -37
- package/dist/components/News.js.map +1 -1
- package/dist/components/PageView.js +11 -8
- package/dist/components/PageView.js.map +1 -1
- package/dist/components/ResponsiveImage.d.ts +1 -1
- package/dist/components/site/SiteFooter.d.ts +1 -1
- package/dist/components/site/SiteFooter.js +2 -2
- package/dist/config.d.ts +1 -1
- package/dist/demo/DemoStudio.js +3 -3
- package/dist/demo/demoStore.d.ts +3 -3
- package/dist/demo/index.d.ts +2 -2
- package/dist/demo/index.js +2 -2
- package/dist/editor/EditorProvider.js +1 -1
- package/dist/firebase/admin.d.ts +0 -2
- package/dist/firebase/admin.js +0 -6
- package/dist/firebase/admin.js.map +1 -1
- package/dist/firebase/appcheck.d.ts +1 -1
- package/dist/firebase/appcheck.js +5 -3
- package/dist/firebase/appcheck.js.map +1 -1
- package/dist/firebase/client.d.ts +2 -1
- package/dist/firebase/client.js +2 -14
- package/dist/firebase/client.js.map +1 -1
- package/dist/firebase/config.d.ts +31 -0
- package/dist/firebase/config.js +39 -0
- package/dist/firebase/config.js.map +1 -0
- package/dist/firebase/feedback.js +5 -3
- package/dist/firebase/feedback.js.map +1 -1
- package/dist/i18n/overlay.d.ts +2 -2
- package/dist/i18n/overlay.js +6 -4
- package/dist/i18n/overlay.js.map +1 -1
- package/dist/index.d.ts +46 -44
- package/dist/index.js +39 -33
- package/dist/index.js.map +1 -1
- package/dist/lock/DemoLock.js +1 -1
- package/dist/modules/builtins.d.ts +1 -1
- package/dist/modules/builtins.js +53 -55
- package/dist/modules/builtins.js.map +1 -1
- package/dist/modules/consent/ConsentBanner.js +1 -1
- package/dist/modules/consent/useConsent.js +1 -1
- package/dist/modules/context.d.ts +1 -1
- package/dist/modules/contract.d.ts +1 -1
- package/dist/modules/defineModule.d.ts +1 -1
- package/dist/modules/index.d.ts +9 -9
- package/dist/modules/index.js +8 -8
- package/dist/modules/overrides.d.ts +1 -1
- package/dist/modules/registry.d.ts +2 -7
- package/dist/modules/registry.js +2 -1
- package/dist/modules/registry.js.map +1 -1
- package/dist/modules/shop/blocks/Cart.d.ts +1 -1
- package/dist/modules/shop/blocks/Cart.js +6 -6
- package/dist/modules/shop/blocks/Checkout.d.ts +1 -1
- package/dist/modules/shop/blocks/Checkout.js +6 -6
- package/dist/modules/shop/blocks/Donation.d.ts +1 -1
- package/dist/modules/shop/blocks/Donation.js +5 -5
- package/dist/modules/shop/blocks/OrderStatus.d.ts +1 -1
- package/dist/modules/shop/blocks/OrderStatus.js +5 -5
- package/dist/modules/shop/blocks/ProductDetail.d.ts +1 -1
- package/dist/modules/shop/blocks/ProductDetail.js +8 -8
- package/dist/modules/shop/blocks/ProductGrid.d.ts +3 -3
- package/dist/modules/shop/blocks/ProductGrid.js +7 -7
- package/dist/modules/shop/blocks/ShopCategories.d.ts +1 -1
- package/dist/modules/shop/blocks/ShopCategories.js +6 -6
- package/dist/modules/shop/index.d.ts +5 -5
- package/dist/modules/shop/index.js +5 -5
- package/dist/modules/shop/lib.d.ts +2 -2
- package/dist/modules/shop/lib.js +18 -13
- package/dist/modules/shop/lib.js.map +1 -1
- package/dist/modules/shop/module.d.ts +1 -1
- package/dist/modules/shop/module.js +9 -9
- package/dist/modules/shop/settings.d.ts +18 -50
- package/dist/modules/shop/settings.js +16 -16
- package/dist/modules/shop/settings.js.map +1 -1
- package/dist/modules/shop/strings.js +1 -1
- package/dist/modules/shop/types.d.ts +1 -1
- package/dist/modules/types.d.ts +2 -2
- package/dist/patterns/builtins.d.ts +1 -1
- package/dist/patterns/builtins.js +1 -1
- package/dist/patterns/index.d.ts +2 -2
- package/dist/patterns/index.js +2 -2
- package/dist/render/PageRenderer.d.ts +2 -2
- package/dist/render/PageRenderer.js +1 -1
- package/dist/render/PublishedPage.d.ts +1 -1
- package/dist/render/PublishedPage.js +2 -2
- package/dist/schema/blocks.d.ts +6793 -15095
- package/dist/schema/blocks.js +335 -355
- package/dist/schema/blocks.js.map +1 -1
- package/dist/schema/customBlocks.d.ts +10 -29
- package/dist/schema/customBlocks.js +14 -13
- package/dist/schema/customBlocks.js.map +1 -1
- package/dist/schema/fields.d.ts +10 -16
- package/dist/schema/fields.js +37 -37
- package/dist/schema/fields.js.map +1 -1
- package/dist/schema/forms.d.ts +62 -111
- package/dist/schema/forms.js +17 -17
- package/dist/schema/forms.js.map +1 -1
- package/dist/schema/index.d.ts +7 -7
- package/dist/schema/index.js +7 -7
- package/dist/schema/mail.d.ts +39 -87
- package/dist/schema/mail.js +4 -4
- package/dist/schema/mail.js.map +1 -1
- package/dist/schema/pages.d.ts +152 -674
- package/dist/schema/pages.js +26 -15
- package/dist/schema/pages.js.map +1 -1
- package/dist/schema/seo.d.ts +9 -27
- package/dist/schema/seo.js +7 -7
- package/dist/schema/seo.js.map +1 -1
- package/dist/schema/settings.d.ts +233 -1074
- package/dist/schema/settings.js +71 -56
- package/dist/schema/settings.js.map +1 -1
- package/dist/schema/shop.d.ts +470 -1214
- package/dist/schema/shop.js +124 -124
- package/dist/schema/shop.js.map +1 -1
- package/dist/schema/siteConfig.d.ts +78 -597
- package/dist/schema/siteConfig.js +17 -17
- package/dist/schema/siteConfig.js.map +1 -1
- package/dist/schema/symbols.d.ts +34 -191
- package/dist/schema/symbols.js +8 -8
- package/dist/schema/symbols.js.map +1 -1
- package/dist/server/auth.d.ts +17 -0
- package/dist/server/auth.js +11 -0
- package/dist/server/auth.js.map +1 -0
- package/dist/server/bundle.d.ts +15 -6
- package/dist/server/bundle.js +5 -1
- package/dist/server/bundle.js.map +1 -1
- package/dist/server/draft.d.ts +16 -0
- package/dist/server/draft.js +12 -0
- package/dist/server/draft.js.map +1 -0
- package/dist/server/env.js +8 -8
- package/dist/server/env.js.map +1 -1
- package/dist/server/index.d.ts +11 -9
- package/dist/server/index.js +13 -10
- package/dist/server/index.js.map +1 -1
- package/dist/server/pages.d.ts +11 -4
- package/dist/server/pages.js +43 -15
- package/dist/server/pages.js.map +1 -1
- package/dist/server/revalidate.js +11 -2
- package/dist/server/revalidate.js.map +1 -1
- package/dist/server/seo.d.ts +3 -3
- package/dist/server/seo.js +1 -1
- package/dist/server/shop.d.ts +3 -3
- package/dist/server/shop.js +6 -3
- package/dist/server/shop.js.map +1 -1
- package/dist/server/version.d.ts +16 -0
- package/dist/server/version.js +17 -0
- package/dist/server/version.js.map +1 -0
- package/dist/settings/useSiteSettings.d.ts +2 -2
- package/dist/settings/useSiteSettings.js +48 -28
- package/dist/settings/useSiteSettings.js.map +1 -1
- package/dist/styles.css +30 -4
- package/dist/theme/presets.d.ts +1 -1
- package/dist/version.d.ts +8 -0
- package/dist/version.js +16 -0
- package/dist/version.js.map +1 -0
- package/package.json +35 -34
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* De zwevende site-chrome: demo-balk, bewerkbalk, feedbackknop, demo-slot en cookiebanner.
|
|
3
|
+
*
|
|
4
|
+
* Render dit in de layout van je PUBLIEKE routes (`app/(site)/layout.tsx`), niet in de root-layout.
|
|
5
|
+
* Het zat hiervoor in `XiCMSProvider` en verscheen daardoor overal — ook over /beheer heen, waar
|
|
6
|
+
* een cookiebanner en een "Zet live"-balk bovenop het CMS lagen en de demo-balk met de beheerbalk
|
|
7
|
+
* om dezelfde plek vocht. De provider levert nu alleen nog context; wat je ziet, plaatst de site.
|
|
8
|
+
*
|
|
9
|
+
* Volgorde is bewust: DemoStudio bovenaan (hij nestelt zich in de bovenrand), de rest eronder als
|
|
10
|
+
* overlays.
|
|
11
|
+
*/
|
|
12
|
+
export declare function SiteChrome(): import("react").JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useSiteConfig } from "./config.js";
|
|
4
|
+
import { useModules } from "./modules/context.js";
|
|
5
|
+
import { EditBar } from "./components/EditBar.js";
|
|
6
|
+
import { FeedbackWidget } from "./components/FeedbackWidget.js";
|
|
7
|
+
import { DemoLock } from "./lock/DemoLock.js";
|
|
8
|
+
import { DemoStudio } from "./demo/DemoStudio.js";
|
|
9
|
+
import { ConsentBanner } from "./modules/consent/ConsentBanner.js";
|
|
10
|
+
function SiteChrome() {
|
|
11
|
+
const config = useSiteConfig();
|
|
12
|
+
const modules = useModules();
|
|
13
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
14
|
+
/* @__PURE__ */ jsx(DemoStudio, {}),
|
|
15
|
+
/* @__PURE__ */ jsx(EditBar, {}),
|
|
16
|
+
/* @__PURE__ */ jsx(FeedbackWidget, { siteId: config.siteId }),
|
|
17
|
+
/* @__PURE__ */ jsx(DemoLock, {}),
|
|
18
|
+
modules.activeIds.has("consent") && /* @__PURE__ */ jsx(ConsentBanner, { settings: modules.settings.consent })
|
|
19
|
+
] });
|
|
20
|
+
}
|
|
21
|
+
export {
|
|
22
|
+
SiteChrome
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=SiteChrome.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/SiteChrome.tsx"],"sourcesContent":["\"use client\";\n\nimport { useSiteConfig } from \"./config\";\nimport { useModules } from \"./modules/context\";\nimport { EditBar } from \"./components/EditBar\";\nimport { FeedbackWidget } from \"./components/FeedbackWidget\";\nimport { DemoLock } from \"./lock/DemoLock\";\nimport { DemoStudio } from \"./demo/DemoStudio\";\nimport { ConsentBanner, type ConsentSettings } from \"./modules/consent/ConsentBanner\";\n\n/**\n * De zwevende site-chrome: demo-balk, bewerkbalk, feedbackknop, demo-slot en cookiebanner.\n *\n * Render dit in de layout van je PUBLIEKE routes (`app/(site)/layout.tsx`), niet in de root-layout.\n * Het zat hiervoor in `XiCMSProvider` en verscheen daardoor overal — ook over /beheer heen, waar\n * een cookiebanner en een \"Zet live\"-balk bovenop het CMS lagen en de demo-balk met de beheerbalk\n * om dezelfde plek vocht. De provider levert nu alleen nog context; wat je ziet, plaatst de site.\n *\n * Volgorde is bewust: DemoStudio bovenaan (hij nestelt zich in de bovenrand), de rest eronder als\n * overlays.\n */\nexport function SiteChrome() {\n const config = useSiteConfig();\n const modules = useModules();\n return (\n <>\n <DemoStudio />\n <EditBar />\n <FeedbackWidget siteId={config.siteId} />\n <DemoLock />\n {modules.activeIds.has(\"consent\") && (\n <ConsentBanner settings={modules.settings.consent as ConsentSettings} />\n )}\n </>\n );\n}\n"],"mappings":";AAyBI,mBACE,KADF;AAvBJ,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB;AAC3B,SAAS,eAAe;AACxB,SAAS,sBAAsB;AAC/B,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAC3B,SAAS,qBAA2C;AAa7C,SAAS,aAAa;AAC3B,QAAM,SAAS,cAAc;AAC7B,QAAM,UAAU,WAAW;AAC3B,SACE,iCACE;AAAA,wBAAC,cAAW;AAAA,IACZ,oBAAC,WAAQ;AAAA,IACT,oBAAC,kBAAe,QAAQ,OAAO,QAAQ;AAAA,IACvC,oBAAC,YAAS;AAAA,IACT,QAAQ,UAAU,IAAI,SAAS,KAC9B,oBAAC,iBAAc,UAAU,QAAQ,SAAS,SAA4B;AAAA,KAE1E;AAEJ;","names":[]}
|
package/dist/XiCMSProvider.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
|
-
import { type BlockDefinition } from "./blocks/registry";
|
|
3
|
-
import { type CustomBlock as CustomBlockData } from "./schema/customBlocks";
|
|
4
|
-
import { type BlockOverrides } from "./modules/overrides";
|
|
5
|
-
import type { ModuleDefinition } from "./modules/types";
|
|
6
|
-
import { type PublicSiteSettings } from "./schema/settings";
|
|
2
|
+
import { type BlockDefinition } from "./blocks/registry.js";
|
|
3
|
+
import { type CustomBlock as CustomBlockData } from "./schema/customBlocks.js";
|
|
4
|
+
import { type BlockOverrides } from "./modules/overrides.js";
|
|
5
|
+
import type { ModuleDefinition } from "./modules/types.js";
|
|
6
|
+
import { type PublicSiteSettings } from "./schema/settings.js";
|
|
7
7
|
import { type DefinedTheme } from "@astryxdesign/core/theme";
|
|
8
8
|
import { type LinkComponentType } from "@astryxdesign/core/Link";
|
|
9
|
-
import { type ImageComponentType } from "./media/ImageContext";
|
|
10
|
-
import { type SiteConfig } from "./schema/siteConfig";
|
|
9
|
+
import { type ImageComponentType } from "./media/ImageContext.js";
|
|
10
|
+
import { type SiteConfig } from "./schema/siteConfig.js";
|
|
11
11
|
interface ProviderProps {
|
|
12
12
|
config: SiteConfig;
|
|
13
13
|
/** Losse klant-blokken (via `defineBlock`) buiten een module om. Altijd actief. */
|
|
@@ -61,9 +61,17 @@ interface ProviderProps {
|
|
|
61
61
|
* - auth + content (Firebase, env-gedreven; werkt ook zonder Firebase);
|
|
62
62
|
* - de block-registry (ingebouwde + klant-blokken) voor de page-renderer;
|
|
63
63
|
* - de themavariabelen als CSS custom properties;
|
|
64
|
-
* - App Check (alleen als geconfigureerd)
|
|
64
|
+
* - App Check (alleen als geconfigureerd).
|
|
65
|
+
*
|
|
66
|
+
* De ZICHTBARE site-chrome (bewerkbalk, cookiebanner, demo) staat in `<SiteChrome />` en hoort in
|
|
67
|
+
* de layout van je publieke routes — niet hier, anders verschijnt hij ook over /beheer.
|
|
65
68
|
*/
|
|
66
69
|
export declare function XiCMSProvider({ config, blocks, modules, overrides, astryxTheme, linkComponent, imageComponent, customBlocksData, settingsData, children }: ProviderProps): import("react").JSX.Element;
|
|
70
|
+
/** Theme-tokens van de live site — voor UI die buiten `.xicms-root` rendert (de editor). */
|
|
71
|
+
export declare function useThemeVars(): {
|
|
72
|
+
vars: Record<string, string>;
|
|
73
|
+
darkAuto: boolean;
|
|
74
|
+
};
|
|
67
75
|
/**
|
|
68
76
|
* Is deze (hex-)kleur donker? Bepaalt de Astryx-thememodus voor sites met een vaste donkere
|
|
69
77
|
* achtergrond (bv. presets donker-modern/luxe-donker, `dark.auto: false`): zonder deze afleiding
|
package/dist/XiCMSProvider.js
CHANGED
|
@@ -1,35 +1,28 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useEffect, useMemo, useState } from "react";
|
|
4
|
-
import { ConfigProvider } from "./config";
|
|
5
|
-
import { AuthProvider, useAuth } from "./auth/AuthProvider";
|
|
6
|
-
import { canEdit } from "./auth/roles";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import { ConsentBanner } from "./modules/consent/ConsentBanner";
|
|
21
|
-
import { EditorProvider } from "./editor/EditorProvider";
|
|
22
|
-
import { SiteSettingsProvider, useSiteSettings, useSiteSettingsLiveSync } from "./settings/useSiteSettings";
|
|
23
|
-
import { mergeThemeTokens } from "./schema/settings";
|
|
24
|
-
import { initAppCheck } from "./firebase/appcheck";
|
|
25
|
-
import { DemoStudio } from "./demo/DemoStudio";
|
|
26
|
-
import { setDemoActive } from "./demo/demoStore";
|
|
3
|
+
import { createContext, useContext, useEffect, useMemo, useState } from "react";
|
|
4
|
+
import { ConfigProvider } from "./config.js";
|
|
5
|
+
import { AuthProvider, useAuth } from "./auth/AuthProvider.js";
|
|
6
|
+
import { canEdit } from "./auth/roles.js";
|
|
7
|
+
import { RegistryProvider } from "./blocks/context.js";
|
|
8
|
+
import { createRegistry, mergeRegistry } from "./blocks/registry.js";
|
|
9
|
+
import { CustomBlockSchema } from "./schema/customBlocks.js";
|
|
10
|
+
import { customBlockToDefinition } from "./blocks/customTemplate/definition.js";
|
|
11
|
+
import { resolveModules } from "./modules/registry.js";
|
|
12
|
+
import { ModulesProvider } from "./modules/context.js";
|
|
13
|
+
import { applyBlockOverrides } from "./modules/overrides.js";
|
|
14
|
+
import { builtinModules } from "./modules/builtins.js";
|
|
15
|
+
import { EditorProvider } from "./editor/EditorProvider.js";
|
|
16
|
+
import { SiteSettingsProvider, useSiteSettings, useSiteSettingsLiveSync } from "./settings/useSiteSettings.js";
|
|
17
|
+
import { mergeThemeTokens } from "./schema/settings.js";
|
|
18
|
+
import { initAppCheck } from "./firebase/appcheck.js";
|
|
19
|
+
import { setDemoActive } from "./demo/demoStore.js";
|
|
27
20
|
import { Theme } from "@astryxdesign/core/theme";
|
|
28
21
|
import { neutralTheme } from "@astryxdesign/theme-neutral/built";
|
|
29
22
|
import { LinkProvider } from "@astryxdesign/core/Link";
|
|
30
|
-
import { ImageProvider } from "./media/ImageContext";
|
|
31
|
-
import { validateSiteConfig } from "./schema/siteConfig";
|
|
32
|
-
import { validateModuleContract } from "./modules/contract";
|
|
23
|
+
import { ImageProvider } from "./media/ImageContext.js";
|
|
24
|
+
import { validateSiteConfig } from "./schema/siteConfig.js";
|
|
25
|
+
import { validateModuleContract } from "./modules/contract.js";
|
|
33
26
|
const NO_BLOCKS = [];
|
|
34
27
|
const NO_MODULES = [];
|
|
35
28
|
const warned = /* @__PURE__ */ new Set();
|
|
@@ -40,8 +33,23 @@ function warnOnce(message) {
|
|
|
40
33
|
}
|
|
41
34
|
function XiCMSProvider({ config, blocks = NO_BLOCKS, modules = NO_MODULES, overrides, astryxTheme, linkComponent, imageComponent, customBlocksData, settingsData, children }) {
|
|
42
35
|
useEffect(() => {
|
|
43
|
-
|
|
36
|
+
if (!process.env.NEXT_PUBLIC_FIREBASE_APPCHECK_KEY) return;
|
|
37
|
+
void initAppCheck();
|
|
44
38
|
}, []);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (process.env.NODE_ENV === "production") return;
|
|
41
|
+
if (!process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID) return;
|
|
42
|
+
if (settingsData === void 0) {
|
|
43
|
+
warnOnce(
|
|
44
|
+
"[xicms] `settingsData` ontbreekt op XiCMSProvider. Elke bezoeker doet daardoor z\xE9lf een Firestore-read voor de site-instellingen en downloadt de Firebase-SDK. Lees ze server-side in je layout met `getPublicSiteSettings(siteId)` en geef ze door \u2014 zie template/app/layout.tsx."
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
if (customBlocksData === void 0) {
|
|
48
|
+
warnOnce(
|
|
49
|
+
"[xicms] `customBlocksData` ontbreekt op XiCMSProvider. Custom blocks worden dan pas na hydratie zichtbaar (SEO-gat + flits). Lees ze server-side met `getSiteCustomBlocks(siteId)`."
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}, [settingsData, customBlocksData]);
|
|
45
53
|
useEffect(() => {
|
|
46
54
|
if (process.env.NODE_ENV === "production") return;
|
|
47
55
|
const configIssues = validateSiteConfig(config);
|
|
@@ -59,9 +67,17 @@ function XiCMSProvider({ config, blocks = NO_BLOCKS, modules = NO_MODULES, overr
|
|
|
59
67
|
}, [config, modules]);
|
|
60
68
|
return /* @__PURE__ */ jsx(ConfigProvider, { config, children: /* @__PURE__ */ jsx(SiteSettingsProvider, { siteId: config.siteId, initial: settingsData, children: /* @__PURE__ */ jsx(ModuleLayer, { config, blocks, modules, overrides, astryxTheme, linkComponent, imageComponent, customBlocksData, children }) }) });
|
|
61
69
|
}
|
|
70
|
+
const ThemeVarsCtx = createContext({ vars: {}, darkAuto: false });
|
|
71
|
+
function useThemeVars() {
|
|
72
|
+
return useContext(ThemeVarsCtx);
|
|
73
|
+
}
|
|
74
|
+
function themeDarkMode(theme) {
|
|
75
|
+
return theme.dark?.mode ?? (theme.dark?.auto ? "auto" : "light");
|
|
76
|
+
}
|
|
62
77
|
function themeCssVars(theme) {
|
|
63
|
-
const
|
|
64
|
-
const
|
|
78
|
+
const donkerModus = themeDarkMode(theme);
|
|
79
|
+
const auto = donkerModus === "auto";
|
|
80
|
+
const ld = (light, dark) => donkerModus === "auto" ? `light-dark(${light}, ${dark})` : donkerModus === "dark" ? dark : light;
|
|
65
81
|
const cssVars = {
|
|
66
82
|
"--xicms-primary": theme.dark?.primary ? ld(theme.primary, theme.dark.primary) : theme.primary,
|
|
67
83
|
"--xicms-accent": theme.accent ?? theme.primary,
|
|
@@ -151,34 +167,34 @@ function ModuleLayer({
|
|
|
151
167
|
[resolved.blocks, customDefs, blocks, overrides]
|
|
152
168
|
);
|
|
153
169
|
return /* @__PURE__ */ jsx(ModulesProvider, { value: resolved, children: /* @__PURE__ */ jsx(RegistryProvider, { registry, children: /* @__PURE__ */ jsxs(AuthProvider, { siteId: config.siteId, demo: Boolean(config.demoEditing), children: [
|
|
154
|
-
/* @__PURE__ */ jsx(
|
|
170
|
+
/* @__PURE__ */ jsx(PreviewDraftSync, {}),
|
|
155
171
|
/* @__PURE__ */ jsx(CustomBlocksSync, { siteId: config.siteId, onData: setCustomBlocks }),
|
|
156
172
|
/* @__PURE__ */ jsx(SiteSettingsSync, { siteId: config.siteId }),
|
|
157
|
-
/* @__PURE__ */ jsxs(EditorProvider, { children: [
|
|
173
|
+
/* @__PURE__ */ jsx(ThemeVarsCtx.Provider, { value: { vars: cssVars, darkAuto: themeDarkMode(theme) === "auto" }, children: /* @__PURE__ */ jsxs(EditorProvider, { children: [
|
|
158
174
|
theme.fontUrl && /* @__PURE__ */ jsx("link", { rel: "stylesheet", href: theme.fontUrl }),
|
|
159
|
-
/* @__PURE__ */ jsx(Theme, { theme: astryxTheme ?? neutralTheme, mode: theme
|
|
175
|
+
/* @__PURE__ */ jsx(Theme, { theme: astryxTheme ?? neutralTheme, mode: themeDarkMode(theme) === "auto" ? "system" : themeDarkMode(theme) === "dark" || isDarkColor(theme.background) ? "dark" : "light", children: /* @__PURE__ */ jsx(LinkProvider, { component: linkComponent ?? "a", children: /* @__PURE__ */ jsx(ImageProvider, { component: imageComponent, children: /* @__PURE__ */ jsx(
|
|
160
176
|
"div",
|
|
161
177
|
{
|
|
162
178
|
className: "xicms-root",
|
|
163
|
-
"data-dark": theme
|
|
179
|
+
"data-dark": themeDarkMode(theme) === "light" ? void 0 : themeDarkMode(theme),
|
|
164
180
|
style: cssVars,
|
|
165
|
-
children
|
|
166
|
-
/* @__PURE__ */ jsx(DemoStudio, {}),
|
|
167
|
-
children,
|
|
168
|
-
/* @__PURE__ */ jsx(EditBar, {}),
|
|
169
|
-
/* @__PURE__ */ jsx(FeedbackWidget, { siteId: config.siteId }),
|
|
170
|
-
/* @__PURE__ */ jsx(DemoLock, {}),
|
|
171
|
-
resolved.activeIds.has("consent") && /* @__PURE__ */ jsx(ConsentBanner, { settings: resolved.settings.consent })
|
|
172
|
-
]
|
|
181
|
+
children
|
|
173
182
|
}
|
|
174
183
|
) }) }) })
|
|
175
|
-
] })
|
|
184
|
+
] }) })
|
|
176
185
|
] }) }) });
|
|
177
186
|
}
|
|
178
|
-
function
|
|
187
|
+
function PreviewDraftSync() {
|
|
179
188
|
const { role } = useAuth();
|
|
180
189
|
useEffect(() => {
|
|
181
|
-
|
|
190
|
+
const gewenst = canEdit(role);
|
|
191
|
+
const gemarkeerd = document.cookie.includes("xicms-draft=1");
|
|
192
|
+
if (gewenst === gemarkeerd) return;
|
|
193
|
+
void fetch(`/api/draft?aan=${gewenst ? "1" : "0"}`, { method: "POST" }).then((r) => {
|
|
194
|
+
if (!r.ok) return;
|
|
195
|
+
document.cookie = gewenst ? "xicms-draft=1; path=/; samesite=lax" : "xicms-draft=; path=/; max-age=0";
|
|
196
|
+
}).catch(() => {
|
|
197
|
+
});
|
|
182
198
|
}, [role]);
|
|
183
199
|
return null;
|
|
184
200
|
}
|
|
@@ -192,26 +208,39 @@ function CustomBlocksSync({ siteId, onData }) {
|
|
|
192
208
|
const editing = canEdit(role);
|
|
193
209
|
useEffect(() => {
|
|
194
210
|
if (!editing) return;
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
211
|
+
let unsub;
|
|
212
|
+
let afgebroken = false;
|
|
213
|
+
void (async () => {
|
|
214
|
+
const [{ getDb }, { collection, onSnapshot }] = await Promise.all([
|
|
215
|
+
import("./firebase/client.js"),
|
|
216
|
+
import("firebase/firestore")
|
|
217
|
+
]);
|
|
218
|
+
const db = getDb();
|
|
219
|
+
if (!db || afgebroken) return;
|
|
220
|
+
unsub = onSnapshot(
|
|
221
|
+
collection(db, "sites", siteId, "customBlocks"),
|
|
222
|
+
(snap) => {
|
|
223
|
+
const defs = [];
|
|
224
|
+
snap.forEach((d) => {
|
|
225
|
+
const res = CustomBlockSchema.safeParse({ ...d.data(), type: d.data().type ?? d.id });
|
|
226
|
+
if (res.success) defs.push(res.data);
|
|
227
|
+
});
|
|
228
|
+
onData(defs);
|
|
229
|
+
},
|
|
230
|
+
() => void 0
|
|
231
|
+
// leesfout → SSR-set blijft staan
|
|
232
|
+
);
|
|
233
|
+
})();
|
|
234
|
+
return () => {
|
|
235
|
+
afgebroken = true;
|
|
236
|
+
unsub?.();
|
|
237
|
+
};
|
|
210
238
|
}, [editing, siteId, onData]);
|
|
211
239
|
return null;
|
|
212
240
|
}
|
|
213
241
|
export {
|
|
214
242
|
XiCMSProvider,
|
|
215
|
-
isDarkColor
|
|
243
|
+
isDarkColor,
|
|
244
|
+
useThemeVars
|
|
216
245
|
};
|
|
217
246
|
//# sourceMappingURL=XiCMSProvider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/XiCMSProvider.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport { ConfigProvider } from \"./config\";\nimport { AuthProvider, useAuth } from \"./auth/AuthProvider\";\nimport { canEdit } from \"./auth/roles\";\nimport { EditBar } from \"./components/EditBar\";\nimport { FeedbackWidget } from \"./components/FeedbackWidget\";\nimport { DemoLock } from \"./lock/DemoLock\";\nimport { RegistryProvider } from \"./blocks/context\";\nimport { getDb } from \"./firebase/client\";\nimport { collection, onSnapshot } from \"firebase/firestore\";\nimport { createRegistry, mergeRegistry, type BlockDefinition } from \"./blocks/registry\";\nimport { CustomBlockSchema, type CustomBlock as CustomBlockData } from \"./schema/customBlocks\";\nimport { customBlockToDefinition } from \"./blocks/customTemplate/definition\";\nimport { resolveModules } from \"./modules/registry\";\nimport { ModulesProvider } from \"./modules/context\";\nimport { applyBlockOverrides, type BlockOverrides } from \"./modules/overrides\";\nimport { builtinModules } from \"./modules/builtins\";\nimport type { ModuleDefinition, ModulesSiteConfig } from \"./modules/types\";\nimport { ConsentBanner, type ConsentSettings } from \"./modules/consent/ConsentBanner\";\nimport { EditorProvider } from \"./editor/EditorProvider\";\nimport { SiteSettingsProvider, useSiteSettings, useSiteSettingsLiveSync } from \"./settings/useSiteSettings\";\nimport { mergeThemeTokens, type ThemeTokens, type PublicSiteSettings } from \"./schema/settings\";\nimport { initAppCheck } from \"./firebase/appcheck\";\nimport { DemoStudio } from \"./demo/DemoStudio\";\nimport { setDemoActive } from \"./demo/demoStore\";\nimport { Theme, type DefinedTheme } from \"@astryxdesign/core/theme\";\nimport { neutralTheme } from \"@astryxdesign/theme-neutral/built\";\nimport { LinkProvider, type LinkComponentType } from \"@astryxdesign/core/Link\";\nimport { ImageProvider, type ImageComponentType } from \"./media/ImageContext\";\nimport { validateSiteConfig, type SiteConfig } from \"./schema/siteConfig\";\nimport { validateModuleContract } from \"./modules/contract\";\n\ninterface ProviderProps {\n config: SiteConfig;\n /** Losse klant-blokken (via `defineBlock`) buiten een module om. Altijd actief. */\n blocks?: BlockDefinition[];\n /**\n * Klant-modules (via `defineModule`) bovenop de ingebouwde. Worden gemerged op `id` (klant wint)\n * en respecteren `config.modules` voor activatie.\n */\n modules?: ModuleDefinition[];\n /**\n * Per-site presentatie-overrides per block-type (`{ gallery: { Render: MijnGalerij } }`). Vervangt\n * alleen het uiterlijk; schema/editor/logica blijven van core. De krachtigste maatwerk-naad.\n */\n overrides?: BlockOverrides;\n /**\n * SSR-startset van custom blocks (5.0): geef het resultaat van `getSiteCustomBlocks(siteId)`\n * (server) door zodat runtime-gedefinieerde blokken al in de server-HTML zitten. Zonder deze\n * prop laadt de provider ze alsnog client-side (werkend, maar pas na hydratie zichtbaar).\n */\n customBlocksData?: CustomBlockData[];\n /**\n * SSR-startset van de publieke site-instellingen: geef het resultaat van\n * `getPublicSiteSettings(siteId)` (server) door zodat klant-thema/nav/footer al in de\n * server-HTML zitten (geen theme-flits bij eerste paint) én publiek geen client-read meer\n * doet — de ISR-gecachte layout ververst de settings per revalidate. Zonder deze prop laadt\n * de provider ze alsnog client-side (werkend, maar met mogelijke flits + 1 read per bezoeker).\n */\n settingsData?: PublicSiteSettings;\n /**\n * Astryx-basistheme voor de hele site (radius-/spacing-/neutralen-karakter). Standaard `neutral`.\n * Een site kan een ander pakket kiezen (`@astryxdesign/theme-butter`, `-stone`, …) of een eigen\n * `defineTheme(...)` doorgeven voor component-overrides — zónder core te forken.\n */\n astryxTheme?: DefinedTheme;\n /**\n * Framework-link-component (bv. Next `Link`) voor soepele client-navigatie + prefetch. Astryx-\n * componenten met een `href` (knoppen/links/tabs) gebruiken 'm dan i.p.v. een rauwe `<a>` (= volledige\n * page-reload). Core importeert `next/link` niet zelf (optionele peer) — geef 'm hier door vanuit de site.\n */\n linkComponent?: LinkComponentType;\n /**\n * Framework-beeldcomponent (bv. Next `Image`) voor automatische beeldoptimalisatie (responsive\n * srcset, AVIF/WebP, geen layout-shift). Core importeert `next/image` niet zelf — geef 'm hier door.\n */\n imageComponent?: ImageComponentType;\n children: ReactNode;\n}\n\n// Stabiele lege defaults: een `= []`-defaultparameter maakt bij ELKE render een nieuwe\n// array-referentie en laat memo's/effects met `modules`/`blocks` in de deps onnodig hervuren.\nconst NO_BLOCKS: BlockDefinition[] = [];\nconst NO_MODULES: ModuleDefinition[] = [];\n\n// Dev-waarschuwingen één keer per boodschap (React strict-mode dubbelt effects; zonder dedupe\n// verschijnt dezelfde config-waarschuwing telkens opnieuw in de console).\nconst warned = new Set<string>();\nfunction warnOnce(message: string) {\n if (warned.has(message)) return;\n warned.add(message);\n console.warn(message);\n}\n\n/**\n * Wikkel de hele site in deze provider (in `app/layout.tsx`). Hij zet:\n * - de SiteConfig-context (siteId, theme, mode) + live publieke settings (footer/nav/modules);\n * - auth + content (Firebase, env-gedreven; werkt ook zonder Firebase);\n * - de block-registry (ingebouwde + klant-blokken) voor de page-renderer;\n * - de themavariabelen als CSS custom properties;\n * - App Check (alleen als geconfigureerd) en de EditBar/DemoLock.\n */\nexport function XiCMSProvider({ config, blocks = NO_BLOCKS, modules = NO_MODULES, overrides, astryxTheme, linkComponent, imageComponent, customBlocksData, settingsData, children }: ProviderProps) {\n useEffect(() => {\n initAppCheck();\n }, []);\n\n // Dev-vangnet voor (agent-)geschreven configs: meld config- en module-contractfouten meteen in\n // de console i.p.v. een subtiel kapotte site. In productie geen werk — en er wordt nooit gegooid.\n useEffect(() => {\n if (process.env.NODE_ENV === \"production\") return;\n const configIssues = validateSiteConfig(config);\n if (configIssues.length > 0) {\n warnOnce(`[xicms] site.config.ts bevat problemen:\\n- ${configIssues.join(\"\\n- \")}`);\n }\n if (modules.length > 0) {\n const contractIssues = validateModuleContract(modules);\n if (contractIssues.length > 0) {\n warnOnce(`[xicms] klant-modules voldoen niet aan het module-contract:\\n- ${contractIssues.join(\"\\n- \")}`);\n }\n }\n }, [config, modules]);\n\n return (\n <ConfigProvider config={config}>\n <SiteSettingsProvider siteId={config.siteId} initial={settingsData}>\n <ModuleLayer config={config} blocks={blocks} modules={modules} overrides={overrides} astryxTheme={astryxTheme} linkComponent={linkComponent} imageComponent={imageComponent} customBlocksData={customBlocksData}>\n {children}\n </ModuleLayer>\n </SiteSettingsProvider>\n </ConfigProvider>\n );\n}\n\n/**\n * Theme-tokens → CSS custom properties. Puur; wordt in `ModuleLayer` op het LIVE-gemergde thema\n * toegepast (SiteConfig + `settings/public.theme`), zodat huisstijl-wijzigingen uit /beheer direct\n * op de site verschijnen — net als module-instellingen.\n */\nfunction themeCssVars(theme: ThemeTokens): Record<string, string> {\n // Dark-auto via light-dark(): deze variabelen staan INLINE op `.xicms-root`, en inline wint\n // altijd van het `@media (prefers-color-scheme: dark)`-blok in styles.css. Alleen dat blok kan\n // een inline lichte waarde dus nooit overrulen — de tokenwaarde zelf moet meeschakelen.\n // (styles.css zet `color-scheme: light dark` op `[data-dark=\"auto\"]`, vereist voor light-dark().)\n const auto = Boolean(theme.dark?.auto);\n const ld = (light: string, dark: string) => (auto ? `light-dark(${light}, ${dark})` : light);\n const cssVars: Record<string, string> = {\n \"--xicms-primary\": theme.dark?.primary ? ld(theme.primary, theme.dark.primary) : theme.primary,\n \"--xicms-accent\": theme.accent ?? theme.primary,\n \"--xicms-bg\": ld(theme.background ?? \"#ffffff\", theme.dark?.background ?? \"#0f172a\"),\n \"--xicms-fg\": ld(theme.foreground ?? \"#0f172a\", theme.dark?.foreground ?? \"#e2e8f0\"),\n };\n if (theme.fontFamily) cssVars[\"--xicms-font\"] = theme.fontFamily;\n // Optionele schalen → CSS-variabelen (alleen gezet als opgegeven; styles.css heeft defaults).\n for (const [k, v] of Object.entries(theme.spacing ?? {})) if (v) cssVars[`--xicms-spacing-${k}`] = v;\n if (theme.radius?.sm) cssVars[\"--xicms-radius-sm\"] = theme.radius.sm;\n if (theme.radius?.md) cssVars[\"--xicms-radius\"] = theme.radius.md;\n if (theme.radius?.lg) cssVars[\"--xicms-radius-lg\"] = theme.radius.lg;\n if (theme.container?.maxWidth) cssVars[\"--xicms-container-max\"] = theme.container.maxWidth;\n if (theme.container?.padding) cssVars[\"--xicms-container-pad\"] = theme.container.padding;\n if (theme.dark?.background) cssVars[\"--xicms-bg-dark\"] = theme.dark.background;\n if (theme.dark?.foreground) cssVars[\"--xicms-fg-dark\"] = theme.dark.foreground;\n if (theme.dark?.primary) cssVars[\"--xicms-primary-dark\"] = theme.dark.primary;\n\n // Astryx-tokens op XiCMS-waarden mappen, zodat de Astryx-componenten elke site z'n eigen merk\n // (kleur/typografie/radius) volgen. Inline op `.xicms-root` → wint over de theme.css-defaults.\n cssVars[\"--color-accent\"] = \"var(--xicms-primary)\";\n // Tekst óp de accentkleur: wit op een donkere merkkleur, donker op een lichte (geel/pastel) —\n // hardcoded wit maakte knop- en bannertekst onleesbaar op lichte primaire kleuren.\n const onAccent = isDarkColor(theme.primary) ? \"#ffffff\" : \"#0f172a\";\n cssVars[\"--color-on-accent\"] = onAccent;\n cssVars[\"--xicms-on-primary\"] = onAccent;\n cssVars[\"--color-text-accent\"] = \"var(--xicms-primary)\";\n cssVars[\"--radius-element\"] = \"var(--xicms-radius-sm, 8px)\";\n cssVars[\"--radius-container\"] = \"var(--xicms-radius, 14px)\";\n cssVars[\"--radius-page\"] = \"var(--xicms-radius-lg, 24px)\";\n // Volledige paletmapping — ALLEEN als de site een eigen achtergrond/tekst kiest. Zo verschilt niet\n // enkel het accent maar de hele sfeer (kaarten, borders, secundaire tekst) per site; een minimale\n // config blijft op de gepolijste neutrale basis (incl. automatische dark-mode via light-dark()).\n if (theme.background) {\n cssVars[\"--color-background-body\"] = \"var(--xicms-bg)\";\n cssVars[\"--color-background-surface\"] = \"color-mix(in srgb, var(--xicms-fg) 4%, var(--xicms-bg))\";\n cssVars[\"--color-background-card\"] = \"color-mix(in srgb, var(--xicms-fg) 3%, var(--xicms-bg))\";\n cssVars[\"--color-background-popover\"] = \"var(--xicms-bg)\";\n cssVars[\"--color-background-muted\"] = \"color-mix(in srgb, var(--xicms-fg) 6%, var(--xicms-bg))\";\n // Ook de XiCMS-oppervlaktetokens meeschakelen: hun defaults in styles.css zijn licht (#fff/zwart-\n // rgba) en het dark-blok vuurt alleen bij `data-dark=\"auto\"`. Zonder deze mapping tonen presets\n // met een vaste donkere achtergrond (donker-modern, luxe-donker) witte kaarten en zwarte borders.\n cssVars[\"--xicms-surface\"] = \"color-mix(in srgb, var(--xicms-fg) 3%, var(--xicms-bg))\";\n cssVars[\"--xicms-muted\"] = \"color-mix(in srgb, var(--xicms-fg) 5%, var(--xicms-bg))\";\n }\n if (theme.foreground) {\n cssVars[\"--color-text-primary\"] = \"var(--xicms-fg)\";\n cssVars[\"--color-text-secondary\"] = \"color-mix(in srgb, var(--xicms-fg) 65%, transparent)\";\n cssVars[\"--color-neutral\"] = \"var(--xicms-fg)\";\n cssVars[\"--color-border\"] = \"color-mix(in srgb, var(--xicms-fg) 14%, transparent)\";\n cssVars[\"--xicms-border\"] = \"color-mix(in srgb, var(--xicms-fg) 12%, transparent)\";\n cssVars[\"--xicms-border-strong\"] = \"color-mix(in srgb, var(--xicms-fg) 22%, transparent)\";\n }\n if (theme.headingFont) cssVars[\"--xicms-font-heading\"] = theme.headingFont;\n if (theme.fontFamily) {\n cssVars[\"--font-family-body\"] = \"var(--xicms-font)\";\n // Koppen volgen een apart display/serif-font als dat is opgegeven, anders het body-font.\n cssVars[\"--font-family-heading\"] = theme.headingFont ? \"var(--xicms-font-heading)\" : \"var(--xicms-font)\";\n } else if (theme.headingFont) {\n cssVars[\"--font-family-heading\"] = \"var(--xicms-font-heading)\";\n }\n\n return cssVars;\n}\n\n/**\n * Is deze (hex-)kleur donker? Bepaalt de Astryx-thememodus voor sites met een vaste donkere\n * achtergrond (bv. presets donker-modern/luxe-donker, `dark.auto: false`): zonder deze afleiding\n * bleef Astryx op \"light\" staan en tekenden zijn componenten lichte kaarten op een donkere pagina.\n * Puur en exporteerbaar voor tests; niet-hex waarden gelden als licht (veilige default).\n */\nexport function isDarkColor(color?: string): boolean {\n const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(color?.trim() ?? \"\");\n if (!m) return false;\n let hex = m[1];\n if (hex.length === 3) hex = hex.replace(/./g, (c) => c + c);\n const [r, g, b] = [0, 2, 4].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255);\n return 0.2126 * r + 0.7152 * g + 0.0722 * b < 0.45;\n}\n\n/**\n * Binnenlaag: leest de live publieke settings en resolvet daarmee de modules (settings/public.modules\n * legt zich over SiteConfig.modules) én het thema (settings/public.theme over SiteConfig.theme).\n * Zo werken module-aan/uit, -instellingen én huisstijl die de klant in /beheer zet direct door.\n */\nfunction ModuleLayer({\n config,\n blocks = NO_BLOCKS,\n modules = NO_MODULES,\n overrides,\n customBlocksData,\n astryxTheme,\n linkComponent,\n imageComponent,\n children,\n}: ProviderProps) {\n const { settings } = useSiteSettings();\n\n // LIVE thema: wijzigingen uit /beheer (settings/public.theme) winnen per token van SiteConfig.\n const theme = useMemo(() => mergeThemeTokens(config.theme, settings.theme), [config.theme, settings.theme]);\n const cssVars = useMemo(() => themeCssVars(theme), [theme]);\n\n // Demo-bewerkmodus globaal markeren zodat de (Firebase-)dataclients lokaal-only werken.\n // In een effect (niet tijdens render): render-pure + veilig onder concurrent rendering. De\n // demoStore-default is `false`, dus vóór het effect gedraagt alles zich als niet-demo.\n useEffect(() => {\n setDemoActive(Boolean(config.demoEditing));\n }, [config.demoEditing]);\n\n const resolved = useMemo(\n () =>\n resolveModules([...builtinModules, ...modules], {\n modules: config.modules,\n firestoreModules: settings.modules as ModulesSiteConfig | undefined,\n }),\n [config.modules, modules, settings.modules],\n );\n\n // Custom blocks (5.0): runtime-gedefinieerde bloktypes uit sites/{siteId}/customBlocks.\n // Publieke bezoekers krijgen UITSLUITEND de SSR-startset (customBlocksData, server-side gelezen) —\n // géén Firestore-listener per bezoeker (kosten/verbinding). Alleen ingelogde editors krijgen een\n // live sync (CustomBlocksSync, binnen AuthProvider) zodat een nieuw blok uit /beheer of een\n // agent-push zonder redeploy in het toevoeg-menu en op de pagina verschijnt.\n const [customBlocks, setCustomBlocks] = useState<CustomBlockData[]>(customBlocksData ?? []);\n const customDefs = useMemo(() => customBlocks.map(customBlockToDefinition), [customBlocks]);\n\n const registry = useMemo(\n () => applyBlockOverrides(mergeRegistry(mergeRegistry(createRegistry(resolved.blocks), customDefs), blocks), overrides),\n [resolved.blocks, customDefs, blocks, overrides],\n );\n\n return (\n <ModulesProvider value={resolved}>\n <RegistryProvider registry={registry}>\n <AuthProvider siteId={config.siteId} demo={Boolean(config.demoEditing)}>\n <PreviewCookieSync />\n <CustomBlocksSync siteId={config.siteId} onData={setCustomBlocks} />\n <SiteSettingsSync siteId={config.siteId} />\n <EditorProvider>\n {/* React 19 hijst <link rel=\"stylesheet\"> automatisch naar <head> → lettertype laadt. */}\n {theme.fontUrl && <link rel=\"stylesheet\" href={theme.fontUrl} />}\n {/* Astryx-thema (Neutral basis) — de XiCMS-token-mapping op `.xicms-root` legt elke\n site z'n eigen merk eroverheen. */}\n <Theme theme={astryxTheme ?? neutralTheme} mode={theme.dark?.auto ? \"system\" : isDarkColor(theme.background) ? \"dark\" : \"light\"}>\n {/* Framework-router voor Astryx-links/knoppen (soepele client-nav + prefetch);\n zonder `linkComponent` valt het terug op een gewone `<a>` (huidig gedrag). */}\n <LinkProvider component={linkComponent ?? \"a\"}>\n <ImageProvider component={imageComponent}>\n <div\n className=\"xicms-root\"\n data-dark={theme.dark?.auto ? \"auto\" : undefined}\n style={cssVars as React.CSSProperties}\n >\n <DemoStudio />\n {children}\n <EditBar />\n <FeedbackWidget siteId={config.siteId} />\n <DemoLock />\n {resolved.activeIds.has(\"consent\") && (\n <ConsentBanner settings={resolved.settings.consent as ConsentSettings} />\n )}\n </div>\n </ImageProvider>\n </LinkProvider>\n </Theme>\n </EditorProvider>\n </AuthProvider>\n </RegistryProvider>\n </ModulesProvider>\n );\n}\n\n/**\n * Live sync van custom blocks — ALLEEN voor ingelogde editors. Publieke bezoekers krijgen de\n * SSR-startset (customBlocksData) en géén Firestore-listener: dat scheelt een collection-read +\n * open verbinding per bezoeker, conform het getDoc-voor-publiek-patroon van useSiteSettings/News.\n */\n/**\n * Live sync van de publieke site-instellingen — ALLEEN voor ingelogde editors (zelfde patroon als\n * CustomBlocksSync). Zo ziet een editor een /beheer-wijziging (footer/nav/thema) meteen op de site,\n * terwijl publiek op de SSR-seed (settingsData) of de eenmalige getDoc blijft draaien.\n */\n/**\n * Zet een niet-gevoelige cookie zodra een editor is ingelogd, zodat de server-side pagina-route\n * de gecommitte content-bundel + ISR-cache kan overslaan (server/pages.ts, `opts.skipBundle`) en\n * deze browser altijd de nieuwste GEPUBLICEERDE stand ziet — een publicatie in /beheer komt\n * anders pas ~5-15 min later mee via de gedebouncede deploy-worker. Draagt geen rechten: er wordt\n * nooit meer dan de al-publieke, gepubliceerde content mee getoond, dus vervalsen van de cookie\n * levert hoogstens een verse blik op iets dat toch al openbaar is.\n */\nfunction PreviewCookieSync() {\n const { role } = useAuth();\n useEffect(() => {\n document.cookie = canEdit(role)\n ? \"xicms-preview=1; path=/; max-age=43200; samesite=lax\"\n : \"xicms-preview=; path=/; max-age=0\";\n }, [role]);\n return null;\n}\n\nfunction SiteSettingsSync({ siteId }: { siteId: string }) {\n const { role } = useAuth();\n useSiteSettingsLiveSync(siteId, canEdit(role));\n return null;\n}\n\nfunction CustomBlocksSync({ siteId, onData }: { siteId: string; onData: (defs: CustomBlockData[]) => void }) {\n const { role } = useAuth();\n const editing = canEdit(role);\n useEffect(() => {\n if (!editing) return;\n const db = getDb();\n if (!db) return;\n return onSnapshot(\n collection(db, \"sites\", siteId, \"customBlocks\"),\n (snap) => {\n const defs: CustomBlockData[] = [];\n snap.forEach((d) => {\n const res = CustomBlockSchema.safeParse({ ...(d.data() as Record<string, unknown>), type: (d.data() as { type?: string }).type ?? d.id });\n if (res.success) defs.push(res.data);\n });\n onData(defs);\n },\n () => undefined, // leesfout → SSR-set blijft staan\n );\n }, [editing, siteId, onData]);\n return null;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/XiCMSProvider.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext, useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport { ConfigProvider } from \"./config\";\nimport { AuthProvider, useAuth } from \"./auth/AuthProvider\";\nimport { canEdit } from \"./auth/roles\";\nimport { RegistryProvider } from \"./blocks/context\";\nimport { createRegistry, mergeRegistry, type BlockDefinition } from \"./blocks/registry\";\nimport { CustomBlockSchema, type CustomBlock as CustomBlockData } from \"./schema/customBlocks\";\nimport { customBlockToDefinition } from \"./blocks/customTemplate/definition\";\nimport { resolveModules } from \"./modules/registry\";\nimport { ModulesProvider } from \"./modules/context\";\nimport { applyBlockOverrides, type BlockOverrides } from \"./modules/overrides\";\nimport { builtinModules } from \"./modules/builtins\";\nimport type { ModuleDefinition, ModulesSiteConfig } from \"./modules/types\";\nimport { EditorProvider } from \"./editor/EditorProvider\";\nimport { SiteSettingsProvider, useSiteSettings, useSiteSettingsLiveSync } from \"./settings/useSiteSettings\";\nimport { mergeThemeTokens, type ThemeTokens, type PublicSiteSettings } from \"./schema/settings\";\nimport { initAppCheck } from \"./firebase/appcheck\";\nimport { setDemoActive } from \"./demo/demoStore\";\nimport { Theme, type DefinedTheme } from \"@astryxdesign/core/theme\";\nimport { neutralTheme } from \"@astryxdesign/theme-neutral/built\";\nimport { LinkProvider, type LinkComponentType } from \"@astryxdesign/core/Link\";\nimport { ImageProvider, type ImageComponentType } from \"./media/ImageContext\";\nimport { validateSiteConfig, type SiteConfig } from \"./schema/siteConfig\";\nimport { validateModuleContract } from \"./modules/contract\";\n\ninterface ProviderProps {\n config: SiteConfig;\n /** Losse klant-blokken (via `defineBlock`) buiten een module om. Altijd actief. */\n blocks?: BlockDefinition[];\n /**\n * Klant-modules (via `defineModule`) bovenop de ingebouwde. Worden gemerged op `id` (klant wint)\n * en respecteren `config.modules` voor activatie.\n */\n modules?: ModuleDefinition[];\n /**\n * Per-site presentatie-overrides per block-type (`{ gallery: { Render: MijnGalerij } }`). Vervangt\n * alleen het uiterlijk; schema/editor/logica blijven van core. De krachtigste maatwerk-naad.\n */\n overrides?: BlockOverrides;\n /**\n * SSR-startset van custom blocks (5.0): geef het resultaat van `getSiteCustomBlocks(siteId)`\n * (server) door zodat runtime-gedefinieerde blokken al in de server-HTML zitten. Zonder deze\n * prop laadt de provider ze alsnog client-side (werkend, maar pas na hydratie zichtbaar).\n */\n customBlocksData?: CustomBlockData[];\n /**\n * SSR-startset van de publieke site-instellingen: geef het resultaat van\n * `getPublicSiteSettings(siteId)` (server) door zodat klant-thema/nav/footer al in de\n * server-HTML zitten (geen theme-flits bij eerste paint) én publiek geen client-read meer\n * doet — de ISR-gecachte layout ververst de settings per revalidate. Zonder deze prop laadt\n * de provider ze alsnog client-side (werkend, maar met mogelijke flits + 1 read per bezoeker).\n */\n settingsData?: PublicSiteSettings;\n /**\n * Astryx-basistheme voor de hele site (radius-/spacing-/neutralen-karakter). Standaard `neutral`.\n * Een site kan een ander pakket kiezen (`@astryxdesign/theme-butter`, `-stone`, …) of een eigen\n * `defineTheme(...)` doorgeven voor component-overrides — zónder core te forken.\n */\n astryxTheme?: DefinedTheme;\n /**\n * Framework-link-component (bv. Next `Link`) voor soepele client-navigatie + prefetch. Astryx-\n * componenten met een `href` (knoppen/links/tabs) gebruiken 'm dan i.p.v. een rauwe `<a>` (= volledige\n * page-reload). Core importeert `next/link` niet zelf (optionele peer) — geef 'm hier door vanuit de site.\n */\n linkComponent?: LinkComponentType;\n /**\n * Framework-beeldcomponent (bv. Next `Image`) voor automatische beeldoptimalisatie (responsive\n * srcset, AVIF/WebP, geen layout-shift). Core importeert `next/image` niet zelf — geef 'm hier door.\n */\n imageComponent?: ImageComponentType;\n children: ReactNode;\n}\n\n// Stabiele lege defaults: een `= []`-defaultparameter maakt bij ELKE render een nieuwe\n// array-referentie en laat memo's/effects met `modules`/`blocks` in de deps onnodig hervuren.\nconst NO_BLOCKS: BlockDefinition[] = [];\nconst NO_MODULES: ModuleDefinition[] = [];\n\n// Dev-waarschuwingen één keer per boodschap (React strict-mode dubbelt effects; zonder dedupe\n// verschijnt dezelfde config-waarschuwing telkens opnieuw in de console).\nconst warned = new Set<string>();\nfunction warnOnce(message: string) {\n if (warned.has(message)) return;\n warned.add(message);\n console.warn(message);\n}\n\n/**\n * Wikkel de hele site in deze provider (in `app/layout.tsx`). Hij zet:\n * - de SiteConfig-context (siteId, theme, mode) + live publieke settings (footer/nav/modules);\n * - auth + content (Firebase, env-gedreven; werkt ook zonder Firebase);\n * - de block-registry (ingebouwde + klant-blokken) voor de page-renderer;\n * - de themavariabelen als CSS custom properties;\n * - App Check (alleen als geconfigureerd).\n *\n * De ZICHTBARE site-chrome (bewerkbalk, cookiebanner, demo) staat in `<SiteChrome />` en hoort in\n * de layout van je publieke routes — niet hier, anders verschijnt hij ook over /beheer.\n */\nexport function XiCMSProvider({ config, blocks = NO_BLOCKS, modules = NO_MODULES, overrides, astryxTheme, linkComponent, imageComponent, customBlocksData, settingsData, children }: ProviderProps) {\n useEffect(() => {\n // App Check hoort bij het praten mét Firebase; een bezoeker doet dat niet. Alleen aanroepen\n // als er een sleutel is, en de module zelf laadt zijn SDK dynamisch.\n if (!process.env.NEXT_PUBLIC_FIREBASE_APPCHECK_KEY) return;\n void initAppCheck();\n }, []);\n\n // Dev-vangnet: ontbrekende SSR-seeds. Zonder `settingsData` haalt élke bezoeker de publieke\n // settings zelf uit Firestore — één read per bezoeker, én het downloaden van de Firebase-SDK\n // (~680 KB) die anders nooit nodig is. Dat faalt volkomen stil: de site ziet er goed uit.\n // De referentiesite groenhof liep hier maandenlang op, dus: melden zodra het misgaat.\n useEffect(() => {\n if (process.env.NODE_ENV === \"production\") return;\n if (!process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID) return; // geen Firebase → geen client-read\n if (settingsData === undefined) {\n warnOnce(\n \"[xicms] `settingsData` ontbreekt op XiCMSProvider. Elke bezoeker doet daardoor zélf een \" +\n \"Firestore-read voor de site-instellingen en downloadt de Firebase-SDK. Lees ze server-side \" +\n \"in je layout met `getPublicSiteSettings(siteId)` en geef ze door — zie template/app/layout.tsx.\",\n );\n }\n if (customBlocksData === undefined) {\n warnOnce(\n \"[xicms] `customBlocksData` ontbreekt op XiCMSProvider. Custom blocks worden dan pas na \" +\n \"hydratie zichtbaar (SEO-gat + flits). Lees ze server-side met `getSiteCustomBlocks(siteId)`.\",\n );\n }\n }, [settingsData, customBlocksData]);\n\n // Dev-vangnet voor (agent-)geschreven configs: meld config- en module-contractfouten meteen in\n // de console i.p.v. een subtiel kapotte site. In productie geen werk — en er wordt nooit gegooid.\n useEffect(() => {\n if (process.env.NODE_ENV === \"production\") return;\n const configIssues = validateSiteConfig(config);\n if (configIssues.length > 0) {\n warnOnce(`[xicms] site.config.ts bevat problemen:\\n- ${configIssues.join(\"\\n- \")}`);\n }\n if (modules.length > 0) {\n const contractIssues = validateModuleContract(modules);\n if (contractIssues.length > 0) {\n warnOnce(`[xicms] klant-modules voldoen niet aan het module-contract:\\n- ${contractIssues.join(\"\\n- \")}`);\n }\n }\n }, [config, modules]);\n\n return (\n <ConfigProvider config={config}>\n <SiteSettingsProvider siteId={config.siteId} initial={settingsData}>\n <ModuleLayer config={config} blocks={blocks} modules={modules} overrides={overrides} astryxTheme={astryxTheme} linkComponent={linkComponent} imageComponent={imageComponent} customBlocksData={customBlocksData}>\n {children}\n </ModuleLayer>\n </SiteSettingsProvider>\n </ConfigProvider>\n );\n}\n\n/**\n * De berekende theme-tokens, beschikbaar BUITEN `.xicms-root`.\n *\n * De visuele editor rendert als overlay naast die div (EditorProvider staat erboven in de boom),\n * dus zijn canvas erfde de merk-tokens niet: een groene primaire kleur werd daar de globale\n * indigo-fallback, en knoptekst kon zelfs samenvallen met de knopachtergrond. Door dezelfde\n * `cssVars` via context te delen toont het canvas exact wat de bezoeker straks ziet — zonder de\n * mapping te dupliceren of de overlay-structuur te verbouwen.\n */\nconst ThemeVarsCtx = createContext<{ vars: Record<string, string>; darkAuto: boolean }>({ vars: {}, darkAuto: false });\n\n/** Theme-tokens van de live site — voor UI die buiten `.xicms-root` rendert (de editor). */\nexport function useThemeVars() {\n return useContext(ThemeVarsCtx);\n}\n\n/**\n * Theme-tokens → CSS custom properties. Puur; wordt in `ModuleLayer` op het LIVE-gemergde thema\n * toegepast (SiteConfig + `settings/public.theme`), zodat huisstijl-wijzigingen uit /beheer direct\n * op de site verschijnen — net als module-instellingen.\n */\n/**\n * De donkere modus in één plek bepaald, zodat de tokenwaarden en de `data-dark`/`color-scheme` op\n * `.xicms-root` nooit uit elkaar kunnen lopen. `mode` wint; zonder `mode` valt hij terug op de\n * oude boolean, zodat bestaande site-configs (auto: true/false) ongewijzigd blijven werken.\n */\nfunction themeDarkMode(theme: ThemeTokens): \"light\" | \"dark\" | \"auto\" {\n return theme.dark?.mode ?? (theme.dark?.auto ? \"auto\" : \"light\");\n}\n\nfunction themeCssVars(theme: ThemeTokens): Record<string, string> {\n // Dark-auto via light-dark(): deze variabelen staan INLINE op `.xicms-root`, en inline wint\n // altijd van het `@media (prefers-color-scheme: dark)`-blok in styles.css. Alleen dat blok kan\n // een inline lichte waarde dus nooit overrulen — de tokenwaarde zelf moet meeschakelen.\n // (styles.css zet `color-scheme: light dark` op `[data-dark=\"auto\"]`, vereist voor light-dark().)\n // Driestand. `mode` wint; zonder `mode` valt hij terug op de oude boolean, zodat bestaande\n // site-configs (auto: true/false) ongewijzigd blijven werken.\n const donkerModus = themeDarkMode(theme);\n const auto = donkerModus === \"auto\";\n // Bij \"auto\" schakelt de tokenwaarde zélf mee via light-dark(); bij een vaste stand kiezen we hier\n // al. Dat moet op tokenniveau en niet via een @media-blok, want deze variabelen staan INLINE op\n // `.xicms-root` en inline wint altijd van een media-query in styles.css.\n const ld = (light: string, dark: string) =>\n donkerModus === \"auto\" ? `light-dark(${light}, ${dark})` : donkerModus === \"dark\" ? dark : light;\n const cssVars: Record<string, string> = {\n \"--xicms-primary\": theme.dark?.primary ? ld(theme.primary, theme.dark.primary) : theme.primary,\n \"--xicms-accent\": theme.accent ?? theme.primary,\n \"--xicms-bg\": ld(theme.background ?? \"#ffffff\", theme.dark?.background ?? \"#0f172a\"),\n \"--xicms-fg\": ld(theme.foreground ?? \"#0f172a\", theme.dark?.foreground ?? \"#e2e8f0\"),\n };\n if (theme.fontFamily) cssVars[\"--xicms-font\"] = theme.fontFamily;\n // Optionele schalen → CSS-variabelen (alleen gezet als opgegeven; styles.css heeft defaults).\n for (const [k, v] of Object.entries(theme.spacing ?? {})) if (v) cssVars[`--xicms-spacing-${k}`] = v;\n if (theme.radius?.sm) cssVars[\"--xicms-radius-sm\"] = theme.radius.sm;\n if (theme.radius?.md) cssVars[\"--xicms-radius\"] = theme.radius.md;\n if (theme.radius?.lg) cssVars[\"--xicms-radius-lg\"] = theme.radius.lg;\n if (theme.container?.maxWidth) cssVars[\"--xicms-container-max\"] = theme.container.maxWidth;\n if (theme.container?.padding) cssVars[\"--xicms-container-pad\"] = theme.container.padding;\n if (theme.dark?.background) cssVars[\"--xicms-bg-dark\"] = theme.dark.background;\n if (theme.dark?.foreground) cssVars[\"--xicms-fg-dark\"] = theme.dark.foreground;\n if (theme.dark?.primary) cssVars[\"--xicms-primary-dark\"] = theme.dark.primary;\n\n // Astryx-tokens op XiCMS-waarden mappen, zodat de Astryx-componenten elke site z'n eigen merk\n // (kleur/typografie/radius) volgen. Inline op `.xicms-root` → wint over de theme.css-defaults.\n cssVars[\"--color-accent\"] = \"var(--xicms-primary)\";\n // Tekst óp de accentkleur: wit op een donkere merkkleur, donker op een lichte (geel/pastel) —\n // hardcoded wit maakte knop- en bannertekst onleesbaar op lichte primaire kleuren.\n const onAccent = isDarkColor(theme.primary) ? \"#ffffff\" : \"#0f172a\";\n cssVars[\"--color-on-accent\"] = onAccent;\n cssVars[\"--xicms-on-primary\"] = onAccent;\n cssVars[\"--color-text-accent\"] = \"var(--xicms-primary)\";\n cssVars[\"--radius-element\"] = \"var(--xicms-radius-sm, 8px)\";\n cssVars[\"--radius-container\"] = \"var(--xicms-radius, 14px)\";\n cssVars[\"--radius-page\"] = \"var(--xicms-radius-lg, 24px)\";\n // Volledige paletmapping — ALLEEN als de site een eigen achtergrond/tekst kiest. Zo verschilt niet\n // enkel het accent maar de hele sfeer (kaarten, borders, secundaire tekst) per site; een minimale\n // config blijft op de gepolijste neutrale basis (incl. automatische dark-mode via light-dark()).\n if (theme.background) {\n cssVars[\"--color-background-body\"] = \"var(--xicms-bg)\";\n cssVars[\"--color-background-surface\"] = \"color-mix(in srgb, var(--xicms-fg) 4%, var(--xicms-bg))\";\n cssVars[\"--color-background-card\"] = \"color-mix(in srgb, var(--xicms-fg) 3%, var(--xicms-bg))\";\n cssVars[\"--color-background-popover\"] = \"var(--xicms-bg)\";\n cssVars[\"--color-background-muted\"] = \"color-mix(in srgb, var(--xicms-fg) 6%, var(--xicms-bg))\";\n // Ook de XiCMS-oppervlaktetokens meeschakelen: hun defaults in styles.css zijn licht (#fff/zwart-\n // rgba) en het dark-blok vuurt alleen bij `data-dark=\"auto\"`. Zonder deze mapping tonen presets\n // met een vaste donkere achtergrond (donker-modern, luxe-donker) witte kaarten en zwarte borders.\n cssVars[\"--xicms-surface\"] = \"color-mix(in srgb, var(--xicms-fg) 3%, var(--xicms-bg))\";\n cssVars[\"--xicms-muted\"] = \"color-mix(in srgb, var(--xicms-fg) 5%, var(--xicms-bg))\";\n }\n if (theme.foreground) {\n cssVars[\"--color-text-primary\"] = \"var(--xicms-fg)\";\n cssVars[\"--color-text-secondary\"] = \"color-mix(in srgb, var(--xicms-fg) 65%, transparent)\";\n cssVars[\"--color-neutral\"] = \"var(--xicms-fg)\";\n cssVars[\"--color-border\"] = \"color-mix(in srgb, var(--xicms-fg) 14%, transparent)\";\n cssVars[\"--xicms-border\"] = \"color-mix(in srgb, var(--xicms-fg) 12%, transparent)\";\n cssVars[\"--xicms-border-strong\"] = \"color-mix(in srgb, var(--xicms-fg) 22%, transparent)\";\n }\n if (theme.headingFont) cssVars[\"--xicms-font-heading\"] = theme.headingFont;\n if (theme.fontFamily) {\n cssVars[\"--font-family-body\"] = \"var(--xicms-font)\";\n // Koppen volgen een apart display/serif-font als dat is opgegeven, anders het body-font.\n cssVars[\"--font-family-heading\"] = theme.headingFont ? \"var(--xicms-font-heading)\" : \"var(--xicms-font)\";\n } else if (theme.headingFont) {\n cssVars[\"--font-family-heading\"] = \"var(--xicms-font-heading)\";\n }\n\n return cssVars;\n}\n\n/**\n * Is deze (hex-)kleur donker? Bepaalt de Astryx-thememodus voor sites met een vaste donkere\n * achtergrond (bv. presets donker-modern/luxe-donker, `dark.auto: false`): zonder deze afleiding\n * bleef Astryx op \"light\" staan en tekenden zijn componenten lichte kaarten op een donkere pagina.\n * Puur en exporteerbaar voor tests; niet-hex waarden gelden als licht (veilige default).\n */\nexport function isDarkColor(color?: string): boolean {\n const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(color?.trim() ?? \"\");\n if (!m) return false;\n let hex = m[1];\n if (hex.length === 3) hex = hex.replace(/./g, (c) => c + c);\n const [r, g, b] = [0, 2, 4].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255);\n return 0.2126 * r + 0.7152 * g + 0.0722 * b < 0.45;\n}\n\n/**\n * Binnenlaag: leest de live publieke settings en resolvet daarmee de modules (settings/public.modules\n * legt zich over SiteConfig.modules) én het thema (settings/public.theme over SiteConfig.theme).\n * Zo werken module-aan/uit, -instellingen én huisstijl die de klant in /beheer zet direct door.\n */\nfunction ModuleLayer({\n config,\n blocks = NO_BLOCKS,\n modules = NO_MODULES,\n overrides,\n customBlocksData,\n astryxTheme,\n linkComponent,\n imageComponent,\n children,\n}: ProviderProps) {\n const { settings } = useSiteSettings();\n\n // LIVE thema: wijzigingen uit /beheer (settings/public.theme) winnen per token van SiteConfig.\n const theme = useMemo(() => mergeThemeTokens(config.theme, settings.theme), [config.theme, settings.theme]);\n const cssVars = useMemo(() => themeCssVars(theme), [theme]);\n\n // Demo-bewerkmodus globaal markeren zodat de (Firebase-)dataclients lokaal-only werken.\n // In een effect (niet tijdens render): render-pure + veilig onder concurrent rendering. De\n // demoStore-default is `false`, dus vóór het effect gedraagt alles zich als niet-demo.\n useEffect(() => {\n setDemoActive(Boolean(config.demoEditing));\n }, [config.demoEditing]);\n\n const resolved = useMemo(\n () =>\n resolveModules([...builtinModules, ...modules], {\n modules: config.modules,\n firestoreModules: settings.modules as ModulesSiteConfig | undefined,\n }),\n [config.modules, modules, settings.modules],\n );\n\n // Custom blocks (5.0): runtime-gedefinieerde bloktypes uit sites/{siteId}/customBlocks.\n // Publieke bezoekers krijgen UITSLUITEND de SSR-startset (customBlocksData, server-side gelezen) —\n // géén Firestore-listener per bezoeker (kosten/verbinding). Alleen ingelogde editors krijgen een\n // live sync (CustomBlocksSync, binnen AuthProvider) zodat een nieuw blok uit /beheer of een\n // agent-push zonder redeploy in het toevoeg-menu en op de pagina verschijnt.\n const [customBlocks, setCustomBlocks] = useState<CustomBlockData[]>(customBlocksData ?? []);\n const customDefs = useMemo(() => customBlocks.map(customBlockToDefinition), [customBlocks]);\n\n const registry = useMemo(\n () => applyBlockOverrides(mergeRegistry(mergeRegistry(createRegistry(resolved.blocks), customDefs), blocks), overrides),\n [resolved.blocks, customDefs, blocks, overrides],\n );\n\n return (\n <ModulesProvider value={resolved}>\n <RegistryProvider registry={registry}>\n <AuthProvider siteId={config.siteId} demo={Boolean(config.demoEditing)}>\n <PreviewDraftSync />\n <CustomBlocksSync siteId={config.siteId} onData={setCustomBlocks} />\n <SiteSettingsSync siteId={config.siteId} />\n <ThemeVarsCtx.Provider value={{ vars: cssVars, darkAuto: themeDarkMode(theme) === \"auto\" }}>\n <EditorProvider>\n {/* React 19 hijst <link rel=\"stylesheet\"> automatisch naar <head> → lettertype laadt. */}\n {theme.fontUrl && <link rel=\"stylesheet\" href={theme.fontUrl} />}\n {/* Astryx-thema (Neutral basis) — de XiCMS-token-mapping op `.xicms-root` legt elke\n site z'n eigen merk eroverheen. */}\n <Theme theme={astryxTheme ?? neutralTheme} mode={themeDarkMode(theme) === \"auto\" ? \"system\" : themeDarkMode(theme) === \"dark\" || isDarkColor(theme.background) ? \"dark\" : \"light\"}>\n {/* Framework-router voor Astryx-links/knoppen (soepele client-nav + prefetch);\n zonder `linkComponent` valt het terug op een gewone `<a>` (huidig gedrag). */}\n <LinkProvider component={linkComponent ?? \"a\"}>\n <ImageProvider component={imageComponent}>\n <div\n className=\"xicms-root\"\n // Stuurt `color-scheme` (styles.css): \"auto\" = light dark, \"dark\" = dark.\n data-dark={themeDarkMode(theme) === \"light\" ? undefined : themeDarkMode(theme)}\n style={cssVars as React.CSSProperties}\n >\n {/* De zichtbare site-chrome (demo-balk, bewerkbalk, feedback, cookiebanner) is\n BEWUST geen onderdeel meer van de provider: die hoort bij het site-oppervlak\n en werd zo ook over /beheer heen gerenderd — een cookiebanner en een\n \"Zet live\"-balk bovenop het CMS. Sites renderen nu `<SiteChrome />` in hun\n eigen (site)-layout; zie ./SiteChrome.tsx. */}\n {children}\n </div>\n </ImageProvider>\n </LinkProvider>\n </Theme>\n </EditorProvider>\n </ThemeVarsCtx.Provider>\n </AuthProvider>\n </RegistryProvider>\n </ModulesProvider>\n );\n}\n\n/**\n * Live sync van custom blocks — ALLEEN voor ingelogde editors. Publieke bezoekers krijgen de\n * SSR-startset (customBlocksData) en géén Firestore-listener: dat scheelt een collection-read +\n * open verbinding per bezoeker, conform het getDoc-voor-publiek-patroon van useSiteSettings/News.\n */\n/**\n * Live sync van de publieke site-instellingen — ALLEEN voor ingelogde editors (zelfde patroon als\n * CustomBlocksSync). Zo ziet een editor een /beheer-wijziging (footer/nav/thema) meteen op de site,\n * terwijl publiek op de SSR-seed (settingsData) of de eenmalige getDoc blijft draaien.\n */\n/**\n * Zet Next's Draft Mode aan zodra een editor is ingelogd, zodat de pagina-route de gecommitte\n * content-bundel + de ISR-cache overslaat (server/pages.ts, `opts.skipBundle`) en deze browser\n * altijd de nieuwste GEPUBLICEERDE stand ziet — een publicatie in /beheer komt anders pas via het\n * ISR-vangnet mee.\n *\n * WAAROM EEN FETCH EN GEEN `document.cookie` ZOALS HIERVOOR: de vorige opzet zette zelf een\n * `xicms-preview`-cookie, die een proxy vertaalde naar `?preview=1`. Dat werkte niet: een route\n * die `searchParams` in zijn signatuur heeft merkt Next áltijd als dynamisch — ongeacht of de\n * proxy ooit herschrijft. Gemeten op groenhof: `ƒ (Dynamic)` met\n * `Cache-Control: private, no-cache, no-store` voor élke bezoeker. De cache was dus voor iedereen\n * stuk om een knop te bedienen die alleen de beheerder gebruikt.\n *\n * Draft Mode lost precies dát op: het zet de ondertekende `__prerender_bypass`-cookie die Next\n * VÓÓR de cache controleert, buiten de route om. Gemeten met dezelfde opzet: publiek houdt\n * `● (SSG)` met `s-maxage=300`, terwijl het request mét cookie `private, no-cache, no-store`\n * krijgt en vers rendert.\n *\n * Draagt geen rechten — net als de oude cookie. Er wordt nooit meer getoond dan de al-publieke,\n * gepubliceerde content, dus zelf `/api/draft` aanroepen levert hoogstens een verse blik op iets\n * dat toch al openbaar is. Wat het wél kost is een ongecachte render per request; wil je dat\n * dichttimmeren, laat de route dan een Firebase-ID-token verifiëren voor hij `enable()` doet.\n *\n * Faalt stil en onschadelijk als de site `/api/draft` niet heeft (zie template/): dan blijft de\n * beheerder gewoon op de gecachte stand, precies zoals een site zonder preview.\n */\nfunction PreviewDraftSync() {\n const { role } = useAuth();\n useEffect(() => {\n const gewenst = canEdit(role);\n // Alleen aanroepen als de stand écht moet veranderen. Zonder deze vergelijking zou élke\n // publieke bezoeker bij élke paginaweergave een POST doen om preview \"uit\" te zetten die al\n // uit stond — een serverless-aanroep per bezoeker, precies de kosten die deze hele omzetting\n // moet vermijden.\n //\n // De marker is een SESSIE-cookie, net als Next's `__prerender_bypass`: die laatste is httpOnly\n // en dus onleesbaar voor deze code, dus we houden er zelf een spiegel van bij. Omdat beide\n // met het browservenster verdwijnen lopen ze niet uit de pas — een marker die de cookie\n // overleeft zou preview stilletjes uitgeschakeld laten.\n const gemarkeerd = document.cookie.includes(\"xicms-draft=1\");\n if (gewenst === gemarkeerd) return;\n void fetch(`/api/draft?aan=${gewenst ? \"1\" : \"0\"}`, { method: \"POST\" })\n .then((r) => {\n if (!r.ok) return; // site zonder /api/draft: laat de marker met rust, dan blijft dit stil.\n document.cookie = gewenst ? \"xicms-draft=1; path=/; samesite=lax\" : \"xicms-draft=; path=/; max-age=0\";\n })\n .catch(() => {});\n }, [role]);\n return null;\n}\n\nfunction SiteSettingsSync({ siteId }: { siteId: string }) {\n const { role } = useAuth();\n useSiteSettingsLiveSync(siteId, canEdit(role));\n return null;\n}\n\nfunction CustomBlocksSync({ siteId, onData }: { siteId: string; onData: (defs: CustomBlockData[]) => void }) {\n const { role } = useAuth();\n const editing = canEdit(role);\n useEffect(() => {\n // Alleen editors luisteren mee (kosten + verbinding), en de SDK laadt pas dán.\n if (!editing) return;\n let unsub: (() => void) | undefined;\n let afgebroken = false;\n void (async () => {\n const [{ getDb }, { collection, onSnapshot }] = await Promise.all([\n import(\"./firebase/client\"),\n import(\"firebase/firestore\"),\n ]);\n const db = getDb();\n if (!db || afgebroken) return;\n unsub = onSnapshot(\n collection(db, \"sites\", siteId, \"customBlocks\"),\n (snap) => {\n const defs: CustomBlockData[] = [];\n snap.forEach((d) => {\n const res = CustomBlockSchema.safeParse({ ...(d.data() as Record<string, unknown>), type: (d.data() as { type?: string }).type ?? d.id });\n if (res.success) defs.push(res.data);\n });\n onData(defs);\n },\n () => undefined, // leesfout → SSR-set blijft staan\n );\n })();\n return () => {\n afgebroken = true;\n unsub?.();\n };\n }, [editing, siteId, onData]);\n return null;\n}\n"],"mappings":"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","names":[]}
|
package/dist/admin/AdminApp.d.ts
CHANGED
package/dist/admin/AdminApp.js
CHANGED
|
@@ -1,58 +1,104 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { useAuth } from "../auth/AuthProvider.js";
|
|
5
|
+
import { LoginForm } from "../auth/LoginForm.js";
|
|
6
|
+
import { useSiteConfig } from "../config.js";
|
|
7
|
+
import { useModules } from "../modules/context.js";
|
|
8
|
+
import { canEdit, canManageSite } from "../auth/roles.js";
|
|
9
|
+
import { Tabs, TabsContent } from "./ui/tabs.js";
|
|
10
|
+
import * as TabsPrimitive from "@radix-ui/react-tabs";
|
|
11
|
+
import { ToastProvider } from "./ui/toast.js";
|
|
12
|
+
import { ConfirmHost } from "./ui/ConfirmDialog.js";
|
|
13
|
+
import { Button } from "./ui/primitives.js";
|
|
14
|
+
import { PanelIcon } from "./ui/PanelIcon.js";
|
|
15
|
+
import { builtinPanels } from "./panelRegistry.js";
|
|
16
|
+
import { AdminHelp } from "./AdminHelp.js";
|
|
17
|
+
import { CoreVersion } from "./CoreVersion.js";
|
|
14
18
|
function roleAllows(role, min) {
|
|
15
19
|
return min === "siteadmin" ? canManageSite(role) : canEdit(role);
|
|
16
20
|
}
|
|
21
|
+
function Melding({ children }) {
|
|
22
|
+
return /* @__PURE__ */ jsx("div", { className: "grid min-h-screen place-items-center p-6", children: /* @__PURE__ */ jsx("div", { className: "w-full max-w-md rounded-xl border border-slate-200 bg-white p-6 text-sm shadow-sm", children }) });
|
|
23
|
+
}
|
|
17
24
|
function AdminApp({ extraPanels = [] }) {
|
|
18
25
|
const { user, role, loading, configured, signOut } = useAuth();
|
|
19
26
|
const { name, siteId } = useSiteConfig();
|
|
20
27
|
const { activeIds } = useModules();
|
|
21
28
|
const panels = [...builtinPanels, ...extraPanels].filter((p) => activeIds.has(p.moduleId) && roleAllows(role, p.minRole)).sort((a, b) => a.order - b.order);
|
|
22
29
|
const firstTab = panels[0]?.moduleId;
|
|
23
|
-
|
|
30
|
+
const [actief, setActief] = useState(firstTab);
|
|
31
|
+
const actievePanel = panels.find((p) => p.moduleId === (actief ?? firstTab));
|
|
32
|
+
return /* @__PURE__ */ jsx("div", { className: "xicms-admin", children: /* @__PURE__ */ jsx(ToastProvider, { children: /* @__PURE__ */ jsx(ConfirmHost, { children: !configured ? /* @__PURE__ */ jsxs(Melding, { children: [
|
|
24
33
|
"Firebase is nog niet geconfigureerd. Vul de ",
|
|
25
34
|
/* @__PURE__ */ jsx("code", { children: "NEXT_PUBLIC_FIREBASE_*" }),
|
|
26
35
|
"-variabelen in om het beheer aan te zetten."
|
|
27
|
-
] }) : loading ? /* @__PURE__ */ jsx("
|
|
36
|
+
] }) : loading ? /* @__PURE__ */ jsx(Melding, { children: /* @__PURE__ */ jsx("span", { className: "text-slate-500", children: "Bezig met laden\u2026" }) }) : !user ? /* @__PURE__ */ jsx("div", { className: "grid min-h-screen place-items-center p-6", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-sm", children: [
|
|
37
|
+
/* @__PURE__ */ jsxs("p", { className: "mb-4 text-center text-sm text-slate-500", children: [
|
|
38
|
+
"Beheer \xB7 ",
|
|
39
|
+
name
|
|
40
|
+
] }),
|
|
41
|
+
/* @__PURE__ */ jsx(LoginForm, {})
|
|
42
|
+
] }) }) : !canEdit(role) ? /* @__PURE__ */ jsxs(Melding, { children: [
|
|
28
43
|
"Je bent ingelogd als ",
|
|
29
44
|
/* @__PURE__ */ jsx("strong", { children: user.email }),
|
|
30
45
|
", maar hebt geen beheerrechten voor deze site.",
|
|
31
46
|
/* @__PURE__ */ jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "sm", onClick: () => void signOut(), children: "Uitloggen" }) })
|
|
32
|
-
] }) : /* @__PURE__ */
|
|
33
|
-
/* @__PURE__ */ jsxs(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
] }) : panels.length === 0 ? /* @__PURE__ */ jsx(Melding, { children: "Geen actieve beheer-modules voor deze site." }) : /* @__PURE__ */ jsxs(Tabs, { value: actief ?? firstTab, onValueChange: setActief, orientation: "vertical", className: "min-h-screen md:grid md:grid-cols-[248px_1fr]", children: [
|
|
48
|
+
/* @__PURE__ */ jsxs(
|
|
49
|
+
"div",
|
|
50
|
+
{
|
|
51
|
+
className: "flex flex-col gap-4 border-b border-slate-200 p-4 md:sticky md:top-0 md:h-screen md:border-r md:border-b-0",
|
|
52
|
+
style: { background: "var(--admin-sidebar)" },
|
|
53
|
+
children: [
|
|
54
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 px-2 pt-1", children: [
|
|
55
|
+
/* @__PURE__ */ jsx("p", { className: "truncate text-sm font-semibold", children: name }),
|
|
56
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-slate-500", children: "Beheer" })
|
|
57
|
+
] }),
|
|
58
|
+
/* @__PURE__ */ jsx(TabsPrimitive.List, { "aria-label": "Beheer-secties", className: "-mx-1 flex gap-1 overflow-x-auto md:flex-col md:overflow-visible", children: panels.map((p) => /* @__PURE__ */ jsxs(
|
|
59
|
+
TabsPrimitive.Trigger,
|
|
60
|
+
{
|
|
61
|
+
value: p.moduleId,
|
|
62
|
+
className: "flex shrink-0 items-center gap-2.5 rounded-lg px-3 py-2 text-sm font-medium text-slate-600 hover:bg-slate-200 hover:text-slate-900 focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:outline-none data-[state=active]:bg-slate-100 data-[state=active]:text-slate-900 data-[state=active]:shadow-[inset_2px_0_0_0_var(--color-brand-500)]",
|
|
63
|
+
children: [
|
|
64
|
+
/* @__PURE__ */ jsx(PanelIcon, { id: p.moduleId }),
|
|
65
|
+
p.label
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
p.moduleId
|
|
69
|
+
)) }),
|
|
70
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-auto hidden min-w-0 border-t border-slate-200 pt-3 md:block", children: [
|
|
71
|
+
/* @__PURE__ */ jsx("p", { className: "truncate text-xs text-slate-500", children: user.email }),
|
|
72
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-slate-400", children: role }),
|
|
73
|
+
/* @__PURE__ */ jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsx(CoreVersion, {}) }),
|
|
74
|
+
/* @__PURE__ */ jsx(
|
|
75
|
+
"button",
|
|
76
|
+
{
|
|
77
|
+
className: "mt-2 rounded text-xs text-slate-500 underline hover:text-slate-900 focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:outline-none",
|
|
78
|
+
onClick: () => void signOut(),
|
|
79
|
+
children: "Uitloggen"
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
] })
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
),
|
|
86
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
87
|
+
/* @__PURE__ */ jsxs("header", { className: "sticky top-0 z-10 flex items-center justify-between gap-4 border-b border-slate-200 px-4 py-3 md:px-8", style: { background: "var(--admin-canvas)" }, children: [
|
|
88
|
+
/* @__PURE__ */ jsx("h1", { className: "truncate text-base font-semibold", children: actievePanel?.label ?? "Beheer" }),
|
|
89
|
+
/* @__PURE__ */ jsx(
|
|
90
|
+
"a",
|
|
91
|
+
{
|
|
92
|
+
className: "inline-flex h-8 shrink-0 items-center rounded-lg border border-slate-200 px-3 text-sm hover:bg-slate-100 focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:outline-none",
|
|
93
|
+
href: "/",
|
|
94
|
+
children: "Bekijk site \u2197"
|
|
95
|
+
}
|
|
96
|
+
)
|
|
46
97
|
] }),
|
|
47
|
-
/* @__PURE__ */ jsxs("div", { className: "
|
|
48
|
-
/* @__PURE__ */ jsx(
|
|
49
|
-
/* @__PURE__ */ jsx(
|
|
98
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-6 p-4 md:p-8", children: [
|
|
99
|
+
panels.map((p) => /* @__PURE__ */ jsx(TabsContent, { value: p.moduleId, className: "pt-0", children: /* @__PURE__ */ jsx(p.Panel, { siteId }) }, p.moduleId)),
|
|
100
|
+
/* @__PURE__ */ jsx(AdminHelp, {})
|
|
50
101
|
] })
|
|
51
|
-
] }),
|
|
52
|
-
/* @__PURE__ */ jsx(AdminHelp, {}),
|
|
53
|
-
panels.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500", children: "Geen actieve beheer-modules voor deze site." }) : /* @__PURE__ */ jsxs(Tabs, { defaultValue: firstTab, children: [
|
|
54
|
-
/* @__PURE__ */ jsx(TabsList, { children: panels.map((p) => /* @__PURE__ */ jsx(TabsTrigger, { value: p.moduleId, children: p.label }, p.moduleId)) }),
|
|
55
|
-
panels.map((p) => /* @__PURE__ */ jsx(TabsContent, { value: p.moduleId, children: /* @__PURE__ */ jsx(p.Panel, { siteId }) }, p.moduleId))
|
|
56
102
|
] })
|
|
57
103
|
] }) }) }) });
|
|
58
104
|
}
|