@xiwebdesign/xicms-core 6.4.7 → 7.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.
- 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 +83 -58
- package/dist/XiCMSProvider.js.map +1 -1
- package/dist/admin/AdminApp.d.ts +1 -1
- package/dist/admin/AdminApp.js +79 -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/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 +20 -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 +45 -44
- package/dist/index.js +35 -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 +218 -1074
- package/dist/schema/settings.js +55 -55
- 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 +73 -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 +10 -8
- package/dist/server/index.js +12 -9
- package/dist/server/index.js.map +1 -1
- package/dist/server/pages.d.ts +14 -7
- package/dist/server/pages.js +183 -17
- package/dist/server/pages.js.map +1 -1
- package/dist/server/revalidate.d.ts +6 -0
- package/dist/server/revalidate.js +40 -0
- package/dist/server/revalidate.js.map +1 -0
- 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/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 +4 -1
- package/dist/theme/presets.d.ts +1 -1
- package/package.json +35 -34
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/admin/visual/VisualEditor.tsx"],"sourcesContent":["\"use client\";\n\n// De admin-stijlen (Tailwind, scoped onder .xicms-admin) horen bij dit lazy-geladen chunk, zodat\n// publieke bezoekers ze nooit downloaden — alleen wanneer een editor de pagina-editor opent.\nimport \"@xiwebdesign/xicms-core/admin.css\";\nimport { useCallback, useEffect, useMemo, useRef, useState, type ComponentType } from \"react\";\nimport { useSiteConfig } from \"../../config\";\nimport { useRegistry } from \"../../blocks/context\";\nimport { introspectToFields } from \"../lib/zodFields\";\nimport { BlockErrorBoundary } from \"../../blocks/BlockErrorBoundary\";\nimport { InlineImageEditProvider } from \"../../media/ImageContext\";\nimport { MediaPickerDialog } from \"../media/MediaPicker\";\nimport { EmptyState } from \"@astryxdesign/core/EmptyState\";\nimport { buildBlockAddOptions } from \"../../blocks/registry\";\nimport DOMPurify from \"dompurify\";\nimport { createPage, getDraftByPath, saveDraft, publishPage, subscribeDraft, subscribeVersions, restoreVersion, type DraftPage } from \"../lib/pagesClient\";\nimport { isDemoActive } from \"../../demo/demoStore\";\nimport { builtinBlockEditors, GenericEditor, type BlockEditorProps } from \"../blockEditors\";\nimport { StyleEditor } from \"../blockEditors/StyleEditor\";\nimport { siteLocales, parseLocaleSlugs, localizeBlocks } from \"../../i18n/overlay\";\nimport { TranslationPanel } from \"./TranslationPanel\";\nimport { reorderBlocks } from \"./reorder\";\nimport { PatternInserter } from \"../patterns/PatternInserter\";\nimport type { BlockStyle } from \"../../schema/blocks\";\nimport { Button, Field, Input, Textarea } from \"../ui/primitives\";\nimport { Select } from \"../ui/select\";\nimport { ToastProvider, useToast } from \"../ui/toast\";\nimport { ConfirmHost, useConfirm } from \"../ui/ConfirmDialog\";\n\ntype Block = Record<string, unknown> & { _key: string; _type: string };\ntype Status = \"loading\" | \"none\" | \"idle\" | \"saving\" | \"saved\" | \"error\";\n\n/**\n * Inline bewerken is sinds 5.0 volledig generiek: élk blok markeert zijn tekstvelden met\n * `data-xicms-edit=\"veldpad\"` (de builtin-Renders doen dat), plus de rich-text-haak\n * `.xicms-richtext`. De oude hardgecodeerde per-type selector-map (`INLINE_FIELDS`) is vervallen.\n * In development waarschuwt `warnInlineCoverage` wanneer een tekstveld uit het schema géén\n * DOM-haak heeft — zo blijven Renders eerlijk t.o.v. hun schema.\n */\nconst GLOBAL_INLINE = [\n { selector: \".xicms-richtext\", field: \"html\", html: true as const },\n { selector: \"[data-xicms-edit]\", field: \"\", html: false as const, fromData: true as const },\n];\n\n/** Dev-vangnet (5.0): meld tekstvelden zonder inline-haak — één keer per bloktype. */\nconst inlineCoverageWarned = new Set<string>();\nfunction warnInlineCoverage(type: string, def: { schema: Parameters<typeof introspectToFields>[0]; fields?: Parameters<typeof introspectToFields>[1] } | undefined, host: HTMLElement) {\n if (process.env.NODE_ENV === \"production\" || !def || inlineCoverageWarned.has(type)) return;\n inlineCoverageWarned.add(type);\n const missing = introspectToFields(def.schema, def.fields)\n .filter((f) => f.type === \"text\" || f.type === \"textarea\")\n .map((f) => f.key)\n .filter((key) => !host.querySelector(`[data-xicms-edit=\"${key}\"], [data-xicms-edit$=\".${key}\"]`));\n if (missing.length > 0) {\n console.warn(\n `[xicms] blok \"${type}\": tekstveld(en) zonder inline-haak: ${missing.join(\", \")} — voeg data-xicms-edit=\"<veld>\" toe aan de Render zodat ze direct op de pagina bewerkbaar zijn.`,\n );\n }\n}\n\n/* Lees/schrijf een waarde op een gepunt pad (bv. \"items.0.title\") — zodat ook lijst-items inline\n bewerkt kunnen worden. setPath kloont onderweg (immutable) zodat React de wijziging detecteert. */\nfunction getPath(obj: unknown, path: string): unknown {\n return path.split(\".\").reduce<unknown>((o, k) => (o == null ? undefined : (o as Record<string, unknown>)[k]), obj);\n}\nfunction setPath<T>(obj: T, path: string, value: unknown): T {\n const keys = path.split(\".\");\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const clone = (v: unknown): any => (Array.isArray(v) ? [...v] : v && typeof v === \"object\" ? { ...(v as object) } : v);\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\nfunction newKey() {\n return (globalThis.crypto?.randomUUID?.() ?? `b${Date.now()}${Math.random()}`).slice(0, 12);\n}\n\n/** JSON.stringify met gesorteerde sleutels — voor betrouwbare inhoudsvergelijking (conflictdetectie):\n * Firestore kan velden in een andere volgorde teruggeven dan wij ze lokaal opbouwden. */\nfunction stableStringify(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(stableStringify).join(\",\")}]`;\n if (value && typeof value === \"object\") {\n const entries = Object.entries(value as Record<string, unknown>)\n .filter(([, v]) => v !== undefined)\n .sort(([a], [b]) => (a < b ? -1 : 1));\n return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).join(\",\")}}`;\n }\n return JSON.stringify(value) ?? \"null\";\n}\n\n/**\n * Visuele/inline pagina-editor: opent als overlay over de live pagina, laadt de werkversie van de\n * huidige route, en laat de editor blokken op een live canvas selecteren, herordenen, dupliceren,\n * verwijderen en toevoegen — met autosave en publiceren. De zware code laadt pas bij openen\n * (lazy, via EditorProvider), dus bezoekers downloaden hem nooit.\n */\nexport default function VisualEditor({ onClose }: { onClose: () => void }) {\n return (\n <div className=\"xicms-admin xicms-ve\">\n <ToastProvider>\n <ConfirmHost>\n <VisualEditorInner onClose={onClose} />\n </ConfirmHost>\n </ToastProvider>\n </div>\n );\n}\n\nfunction VisualEditorInner({ onClose }: { onClose: () => void }) {\n const config = useSiteConfig();\n const { siteId, name } = config;\n const registry = useRegistry();\n const { toast } = useToast();\n const confirm = useConfirm();\n\n // Meertalig (5.0): een taalprefix in de URL (/de/over-ons) hoort niet bij het canonieke\n // pagina-pad — de editor opent dan de pagina zélf, met de betreffende taal actief.\n const localeCfg = useMemo(() => siteLocales(config), [config]);\n const { path, urlLocale } = useMemo(() => {\n const raw = typeof window !== \"undefined\" ? window.location.pathname || \"/\" : \"/\";\n const { locale, slugs } = parseLocaleSlugs(raw.split(\"/\").filter(Boolean), localeCfg);\n const p = \"/\" + slugs.join(\"/\");\n return { path: p === \"/\" ? \"/\" : p.replace(/\\/$/, \"\"), urlLocale: locale };\n }, [localeCfg]);\n const [locale, setLocale] = useState(urlLocale);\n const isTranslating = locale !== localeCfg.defaultLocale;\n const [draft, setDraft] = useState<DraftPage | null>(null);\n const [status, setStatus] = useState<Status>(\"loading\");\n const [selectedKey, setSelectedKey] = useState<string | null>(null);\n const [publishing, setPublishing] = useState(false);\n const [imgPicker, setImgPicker] = useState<{ key: string; field: string } | null>(null);\n const firstSave = useRef(true);\n const canvasRef = useRef<HTMLDivElement>(null);\n const [conflict, setConflict] = useState(false);\n\n // Drag-and-drop herordenen: dragIndex = het gesleepte blok, dropIndex = invoegpunt (0..length).\n // draggingRef pauzeert de inline-bind MutationObserver tijdens het slepen (re-bind-ruis).\n const [dragIndex, setDragIndex] = useState<number | null>(null);\n const [dropIndex, setDropIndex] = useState<number | null>(null);\n const draggingRef = useRef(false);\n const endDrag = useCallback(() => {\n draggingRef.current = false;\n setDragIndex(null);\n setDropIndex(null);\n }, []);\n\n // Altijd de laatste draft + \"zijn er niet-opgeslagen wijzigingen\" bij de hand houden, zodat we\n // bij sluiten/wegnavigeren nog kunnen flushen (de debounce zou de laatste 700ms anders weggooien).\n const draftRef = useRef<DraftPage | null>(null);\n const dirtyRef = useRef(false);\n // Inhoud (stable-stringified) van de laatst succesvol opgeslagen payload — voor conflictdetectie.\n const lastSavedRef = useRef<string | null>(null);\n useEffect(() => {\n draftRef.current = draft;\n }, [draft]);\n\n // ── Undo/redo ──────────────────────────────────────────────────────────────\n // History over draft-snapshots. Tekstedits (per toetsaanslag) worden ge-coalesced: binnen één\n // typ-burst (<800ms) staat het pre-burst-snapshot al op de stack, dus niet opnieuw pushen —\n // Ctrl+Z springt dan per burst terug i.p.v. per letter. `histVersion` forceert re-render van\n // de knop-states (de stacks leven in een ref).\n const historyRef = useRef<{ past: DraftPage[]; future: DraftPage[]; lastPush: number }>({ past: [], future: [], lastPush: 0 });\n const [, setHistVersion] = useState(0);\n\n const pushHistory = useCallback((prev: DraftPage, coalesce: boolean) => {\n const h = historyRef.current;\n const now = Date.now();\n if (!(coalesce && now - h.lastPush < 800 && h.past.length > 0)) {\n h.past.push(prev);\n if (h.past.length > 100) h.past.shift();\n }\n h.lastPush = now;\n h.future = [];\n setHistVersion((v) => v + 1);\n }, []);\n\n /** Enige route waarlangs de draft muteert: bewaart eerst een undo-snapshot. */\n const mutateDraft = useCallback(\n (updater: (d: DraftPage) => DraftPage, opts?: { coalesce?: boolean }) => {\n const d = draftRef.current;\n if (!d) return;\n const next = updater(d);\n if (next === d) return;\n pushHistory(d, opts?.coalesce ?? false);\n draftRef.current = next;\n // Dirty HIER markeren (synchroon met de mutatie), niet pas in het debounced autosave-effect:\n // een inline edit (blur) direct gevolgd door \"Sluiten\" in dezelfde gesture zou anders\n // flushSave() zien met dirtyRef=false → laatste wijziging verloren.\n dirtyRef.current = true;\n setDraft(next);\n },\n [pushHistory],\n );\n\n const undo = useCallback(() => {\n const h = historyRef.current;\n const d = draftRef.current;\n const prev = h.past.pop();\n if (!prev || !d) return;\n h.future.push(d);\n h.lastPush = 0;\n draftRef.current = prev;\n dirtyRef.current = true; // undo is óók een wijziging die opgeslagen moet worden\n setDraft(prev);\n setHistVersion((v) => v + 1);\n }, []);\n\n const redo = useCallback(() => {\n const h = historyRef.current;\n const d = draftRef.current;\n const next = h.future.pop();\n if (!next || !d) return;\n h.past.push(d);\n h.lastPush = 0;\n draftRef.current = next;\n dirtyRef.current = true; // redo is óók een wijziging die opgeslagen moet worden\n setDraft(next);\n setHistVersion((v) => v + 1);\n }, []);\n\n const draftPayload = (d: DraftPage) => ({\n blocks: d.blocks,\n title: d.title,\n slug: d.slug,\n path: d.path,\n seo: d.seo,\n // Alleen meesturen wanneer aanwezig: `undefined` weigert de Firestore-client.\n ...(d.translations ? { translations: d.translations } : {}),\n });\n\n // Schrijf eventuele pending wijziging direct weg (gebruikt bij Sluiten, tab-wissel en retry).\n const flushSave = useCallback(async () => {\n // Een veld dat pas op blur committeert (bv. het JSON-redmiddel in GenericEditor) moet die\n // commit eerst nog uitvoeren. Op desktop vuurt blur al vóór de click van deze knop, maar op\n // mobiel Safari is die volgorde niet gegarandeerd (het toetsenbord-sluiten kan blur vertragen\n // tot ná de klik) — expliciet blur() forceert de commit synchroon, ongeacht platform.\n (document.activeElement as HTMLElement | null)?.blur();\n const d = draftRef.current;\n if (!d || !dirtyRef.current) return;\n const payload = draftPayload(d);\n await saveDraft(siteId, d.id, payload);\n lastSavedRef.current = stableStringify(payload);\n // Alleen \"schoon\" markeren als er intussen niets nieuws is getypt (anders zou een trage\n // write nieuwere wijzigingen als opgeslagen bestempelen).\n if (draftRef.current === d) {\n dirtyRef.current = false;\n setStatus(\"saved\");\n }\n }, [siteId]);\n\n const handleClose = useCallback(() => {\n void flushSave().finally(() => onClose());\n }, [flushSave, onClose]);\n\n useEffect(() => {\n let active = true;\n getDraftByPath(siteId, path)\n .then((d) => {\n if (!active) return;\n if (d) {\n setDraft(d);\n lastSavedRef.current = stableStringify(draftPayload(d));\n setStatus(\"idle\");\n } else {\n setStatus(\"none\");\n }\n })\n .catch(() => active && setStatus(\"none\"));\n return () => {\n active = false;\n };\n }, [siteId, path]);\n\n /** Bootstrap vanuit de \"Geen werkversie\"-toestand: maak de pagina hier direct aan (geen omweg\n * via /beheer → Pagina's — dat was een doodloop voor niet-technische klanten). */\n const handleCreatePage = useCallback(async () => {\n setStatus(\"loading\");\n try {\n const segment = path.split(\"/\").filter(Boolean).pop() ?? \"\";\n const title = segment ? segment.replace(/[-_]+/g, \" \").replace(/^\\w/, (c) => c.toUpperCase()) : \"Home\";\n await createPage(siteId, { title, slug: segment || \"home\", path });\n const d = await getDraftByPath(siteId, path);\n if (d) {\n setDraft(d);\n lastSavedRef.current = stableStringify(draftPayload(d));\n setStatus(\"idle\");\n toast({ title: \"Pagina aangemaakt\", description: \"Voeg je eerste blok toe en publiceer wanneer je klaar bent.\", tone: \"success\" });\n } else {\n setStatus(\"none\");\n }\n } catch (e) {\n setStatus(\"none\");\n toast({ title: \"Pagina aanmaken mislukt\", description: (e as Error)?.message, tone: \"error\" });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [siteId, path, toast]);\n\n // ── Conflictdetectie ───────────────────────────────────────────────────────\n // Luister naar de draft in Firestore. Een server-snapshot die afwijkt van zowel onze laatst\n // opgeslagen payload als onze huidige lokale staat, betekent: iemand anders (tab/collega)\n // heeft deze pagina gewijzigd. Waarschuw i.p.v. elkaars werk stil te overschrijven.\n const draftId = draft?.id;\n useEffect(() => {\n if (!draftId) return;\n return subscribeDraft(siteId, draftId, (remote, meta) => {\n if (!meta.fromServer || !remote) return;\n const remotePayload = stableStringify(draftPayload(remote));\n const local = draftRef.current;\n const localPayload = local ? stableStringify(draftPayload(local)) : null;\n if (remotePayload !== lastSavedRef.current && remotePayload !== localPayload) setConflict(true);\n });\n }, [siteId, draftId]);\n\n const blocks = (draft?.blocks ?? []) as Block[];\n // Canvas in een niet-default taal: toon de vertaal-overlay over de canonieke blokken.\n const overlay = draft?.translations?.[locale];\n const displayBlocks = useMemo(\n () => (isTranslating ? (localizeBlocks(blocks, overlay) as Block[]) : blocks),\n [blocks, isTranslating, overlay],\n );\n\n // Schrijf een inline (in-canvas) tekstwijziging terug naar het juiste blokveld (canoniek).\n const commitInline = useCallback(\n (key: string, field: string, value: string) => {\n mutateDraft(\n (d) => {\n const bl = d.blocks as Block[];\n const idx = bl.findIndex((x) => x._key === key);\n if (idx < 0 || getPath(bl[idx], field) === value) return d;\n const next = [...bl];\n next[idx] = setPath(next[idx], field, value);\n return { ...d, blocks: next };\n },\n { coalesce: true },\n );\n },\n [mutateDraft],\n );\n\n // Schrijf een vertaling naar de taal-overlay; leeg = sleutel weg (terugvallen op origineel).\n const setTranslation = useCallback(\n (tkey: string, value: string) => {\n mutateDraft(\n (d) => {\n const overlay = { ...(d.translations?.[locale] ?? {}) };\n if (value.trim() === \"\" || value === undefined) delete overlay[tkey];\n else overlay[tkey] = value;\n return { ...d, translations: { ...(d.translations ?? {}), [locale]: overlay } };\n },\n { coalesce: true },\n );\n },\n [mutateDraft, locale],\n );\n\n // ── Inline opmaak-toolbar (WYSIWYG op het canvas) ─────────────────────────\n // Zwevende mini-toolbar boven een gefocust rich-text-veld: vet/schuin/onderstrepen/link +\n // groter-kleiner via kop-niveaus (H2/H3/normaal — semantisch i.p.v. losse font-sizes).\n // document.execCommand is deprecated-maar-universeel en precies goed voor contentEditable;\n // de output gaat bij commit door DOMPurify én server-side door de allowlist-sanitizer.\n const [fmtBar, setFmtBar] = useState<{ top: number; left: number } | null>(null);\n const fmtElRef = useRef<HTMLElement | null>(null);\n const positionFmtBar = useCallback((el: HTMLElement) => {\n const r = el.getBoundingClientRect();\n setFmtBar({\n top: Math.max(56, r.top - 44),\n left: Math.min(Math.max(8, r.left), Math.max(8, window.innerWidth - 300)),\n });\n }, []);\n useEffect(() => {\n if (!fmtBar) return;\n const onScroll = () => {\n const el = fmtElRef.current;\n if (el) positionFmtBar(el);\n };\n window.addEventListener(\"scroll\", onScroll, { capture: true, passive: true });\n return () => window.removeEventListener(\"scroll\", onScroll, { capture: true });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [fmtBar !== null, positionFmtBar]);\n\n // Inline canvas-edits: in de default-taal naar het blokveld, in een andere taal naar de overlay.\n const commitText = useCallback(\n (key: string, field: string, value: string) => {\n if (isTranslating) setTranslation(`${key}.${field}`, value);\n else commitInline(key, field, value);\n },\n [isTranslating, setTranslation, commitInline],\n );\n\n // Maak de tekstvelden van het GESELECTEERDE blok ter plekke bewerkbaar (contentEditable) en synct\n // op blur terug — zo bewerk je tekst inline op het canvas i.p.v. via de zijbalk. We binden via een\n // MutationObserver én her-binden zodra React de DOM-node vervangt (re-render), met een dataset-flag\n // zodat we nooit dubbele listeners zetten.\n useEffect(() => {\n if (!selectedKey) return;\n const host = canvasRef.current?.querySelector<HTMLElement>(`[data-ve-content=\"${selectedKey}\"]`);\n if (!host) return;\n const type = blocks.find((b) => b._key === selectedKey)?._type ?? \"\";\n const specs = [...GLOBAL_INLINE];\n warnInlineCoverage(String(type), registry.get(String(type)), host);\n\n const bound = new Set<HTMLElement>();\n const bind = (el: HTMLElement, field: string, html: boolean) => {\n if (el.dataset.veInline === \"1\") return;\n el.dataset.veInline = \"1\";\n el.setAttribute(\"contenteditable\", \"true\");\n el.setAttribute(\"spellcheck\", \"true\");\n el.classList.add(\"xicms-ve-inline\");\n // Inline HTML wordt vóór commit gesanitized (DOMPurify) — zelfde belofte als het TipTap-pad;\n // de server sanitized nogmaals bij publiceren. Geplakte Word-/Docs-rommel blijft zo buiten.\n el.addEventListener(\"blur\", () => commitText(selectedKey, field, html ? DOMPurify.sanitize(el.innerHTML) : (el.textContent ?? \"\")));\n if (html) {\n // Opmaak-toolbar tonen zolang dit rich-text-veld focus heeft.\n el.addEventListener(\"focus\", () => {\n fmtElRef.current = el;\n positionFmtBar(el);\n });\n el.addEventListener(\"blur\", () => {\n fmtElRef.current = null;\n setFmtBar(null);\n });\n }\n el.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Escape\") el.blur();\n else if (!html && e.key === \"Enter\") { e.preventDefault(); el.blur(); }\n });\n bound.add(el);\n };\n const apply = () => {\n for (const m of specs) {\n host.querySelectorAll<HTMLElement>(m.selector).forEach((el) =>\n bind(el, \"fromData\" in m && m.fromData ? (el.dataset.xicmsEdit as string) : m.field, !!m.html),\n );\n }\n };\n\n apply();\n // Her-bind na elke re-render die de tekstnodes vervangt (niet tijdens slepen: dan muteert de\n // DOM continu door de drop-indicatoren en zou her-binden alleen maar ruis geven).\n const obs = new MutationObserver(() => {\n if (!draggingRef.current) apply();\n });\n obs.observe(host, { childList: true, subtree: true });\n return () => {\n obs.disconnect();\n bound.forEach((el) => {\n el.removeAttribute(\"contenteditable\");\n el.classList.remove(\"xicms-ve-inline\");\n delete el.dataset.veInline;\n });\n };\n }, [selectedKey, blocks, commitText, positionFmtBar]);\n\n // Autosave naar de draft (publiceren blijft een aparte, bewuste stap).\n // Debounce 700ms ná de laatste wijziging, met een MAX-WAIT van 3s: de debounce herstart bij elke\n // toetsaanslag, dus zonder max-wait zou iemand die blijft doortypen nooit tussentijds opslaan.\n const dirtySinceRef = useRef<number | null>(null);\n useEffect(() => {\n if (!draft) return;\n if (firstSave.current) {\n firstSave.current = false;\n return;\n }\n // Bij een openstaand conflict PAUZEREN we autosave: de banner wegklikken en doorwerken\n // overschreef anders stil de wijzigingen van de collega/andere tab (destructief-by-default).\n // De klant kiest eerst expliciet \"Nieuwste laden\" of \"Mijn versie behouden\".\n if (conflict) return;\n dirtyRef.current = true;\n dirtySinceRef.current ??= Date.now();\n setStatus(\"saving\");\n const waited = Date.now() - dirtySinceRef.current;\n const delay = Math.max(0, Math.min(700, 3000 - waited));\n const t = setTimeout(() => {\n dirtySinceRef.current = null;\n const payload = draftPayload(draft);\n void saveDraft(siteId, draft.id, payload)\n .then(() => {\n lastSavedRef.current = stableStringify(payload);\n // Alleen \"schoon\"/\"saved\" als dit nog de nieuwste versie is (zie flushSave).\n if (draftRef.current === draft) {\n dirtyRef.current = false;\n setStatus(\"saved\");\n }\n })\n .catch(() => setStatus(\"error\"));\n }, delay);\n return () => clearTimeout(t);\n }, [draft, siteId, conflict]);\n\n // Waarschuw bij het verlaten van de pagina met niet-opgeslagen wijzigingen; flush bij tab-wissel/\n // verbergen (visibilitychange) en bij unmount. Escape sluit de editor (na flush).\n useEffect(() => {\n const beforeUnload = (e: BeforeUnloadEvent) => {\n if (dirtyRef.current) {\n e.preventDefault();\n e.returnValue = \"\";\n }\n };\n const onVisibility = () => {\n // Tab-wissel/minimaliseren: beste moment om pending werk veilig te stellen.\n if (document.visibilityState === \"hidden\") void flushSave().catch(() => {});\n };\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n // Escape sluit alléén de editor als er niets \"boven\" de editor actief is: een open\n // dialog (mediakiezer, bevestiging — Radix rendert [role=dialog] buiten deze shell) of\n // een inline bewerking/invoerveld vangt zijn eigen Escape. Anders verdween bij het\n // sluiten van de mediakiezer meteen de hele editor.\n const t = e.target as HTMLElement | null;\n const inField = !!t && (t.isContentEditable || t.tagName === \"INPUT\" || t.tagName === \"TEXTAREA\" || t.tagName === \"SELECT\");\n const dialogOpen = document.querySelector('[role=\"dialog\"][data-state=\"open\"], [role=\"alertdialog\"][data-state=\"open\"]');\n if (!inField && !dialogOpen) handleClose();\n return;\n }\n // Undo/redo op canvas-niveau. In invoervelden/contentEditable laten we de native\n // tekst-undo van de browser zijn werk doen (anders vecht Ctrl+Z met het veld zelf).\n const t = e.target as HTMLElement | null;\n const inField = !!t && (t.isContentEditable || t.tagName === \"INPUT\" || t.tagName === \"TEXTAREA\" || t.tagName === \"SELECT\");\n if ((e.metaKey || e.ctrlKey) && !inField && (e.key.toLowerCase() === \"z\" || e.key.toLowerCase() === \"y\")) {\n e.preventDefault();\n if (e.key.toLowerCase() === \"y\" || e.shiftKey) redo();\n else undo();\n }\n };\n window.addEventListener(\"beforeunload\", beforeUnload);\n document.addEventListener(\"visibilitychange\", onVisibility);\n window.addEventListener(\"keydown\", onKeyDown);\n return () => {\n window.removeEventListener(\"beforeunload\", beforeUnload);\n document.removeEventListener(\"visibilitychange\", onVisibility);\n window.removeEventListener(\"keydown\", onKeyDown);\n const d = draftRef.current;\n if (d && dirtyRef.current) {\n // Laatste redmiddel bij unmount; log een mislukking i.p.v. stil verliezen.\n void saveDraft(siteId, d.id, draftPayload(d)).catch((err) =>\n console.warn(\"[xicms] autosave bij sluiten mislukt:\", err),\n );\n }\n };\n }, [siteId, handleClose, flushSave, undo, redo]);\n\n function setBlocks(next: Block[], opts?: { coalesce?: boolean }) {\n mutateDraft((d) => ({ ...d, blocks: next }), opts);\n }\n function updateByKey(key: string, next: Record<string, unknown>) {\n // Zijpaneel-edits komen per toetsaanslag binnen → coalesce voor zinnige undo-stappen.\n setBlocks(blocks.map((b) => (b._key === key ? ({ ...(next as Block), _key: b._key, _type: b._type }) : b)), { coalesce: true });\n }\n function move(i: number, dir: -1 | 1) {\n const j = i + dir;\n if (j < 0 || j >= blocks.length) return;\n const copy = [...blocks];\n [copy[i], copy[j]] = [copy[j], copy[i]];\n setBlocks(copy);\n }\n function duplicate(i: number) {\n const copy = [...blocks];\n copy.splice(i + 1, 0, { ...blocks[i], _key: newKey() });\n setBlocks(copy);\n }\n /** Symbool loskoppelen (5.0): vervang de referentie door een kloon van de symboolblokken —\n * daarna beweegt dit exemplaar niet meer mee met het gedeelde symbool. */\n async function detachSymbol(i: number) {\n const blk = blocks[i] as { _type?: string; symbolId?: string; _key: string };\n if (blk._type !== \"symbolRef\" || !blk.symbolId) return;\n const ok = await confirm({\n title: \"Symbool loskoppelen?\",\n description: \"Dit blok wordt een losse kopie en beweegt niet meer mee met het gedeelde symbool.\",\n confirmLabel: \"Loskoppelen\",\n });\n if (!ok) return;\n const { getSymbolOnce } = await import(\"../lib/symbolsClient\");\n const sym = await getSymbolOnce(siteId, blk.symbolId);\n if (!sym) {\n toast({ title: \"Symbool niet gevonden\", tone: \"error\" });\n return;\n }\n const clones = sym.blocks.map((b) => ({ ...(b as Record<string, unknown>), _key: newKey() })) as Block[];\n const copy = [...blocks];\n copy.splice(i, 1, ...clones);\n setBlocks(copy);\n if (selectedKey === blk._key) setSelectedKey(null);\n toast({ title: \"Losgekoppeld\", description: \"Dit is nu een losse kopie.\", tone: \"success\" });\n }\n async function remove(i: number) {\n const ok = await confirm({ title: \"Blok verwijderen?\", confirmLabel: \"Verwijderen\", tone: \"danger\" });\n if (!ok) return;\n const removed = blocks[i];\n setBlocks(blocks.filter((_, idx) => idx !== i));\n if (selectedKey === removed._key) setSelectedKey(null);\n }\n function addBlock(type: string) {\n const def = registry.get(type);\n const base = def?.defaults?.() ?? {};\n const block = { _key: newKey(), _type: type, ...base } as Block;\n insertAfterSelected([block]);\n setSelectedKey(block._key);\n }\n function insertAfterSelected(newBlocks: Array<Record<string, unknown>>) {\n const sel = blocks.findIndex((b) => b._key === selectedKey);\n const copy = [...blocks];\n copy.splice(sel >= 0 ? sel + 1 : blocks.length, 0, ...(newBlocks as Block[]));\n setBlocks(copy);\n }\n\n async function onPublish() {\n // Zie flushSave: een veld dat pas op blur committeert (JSON-redmiddel) moet die commit eerst\n // nog doen — anders publiceert dit de stand van vóór de laatste bewerking.\n (document.activeElement as HTMLElement | null)?.blur();\n const d = draftRef.current;\n if (!d) return;\n // Openstaand conflict eerst oplossen: publiceren zou anders een stale merge live zetten.\n if (conflict) {\n toast({ title: \"Los eerst het conflict op\", description: \"Kies 'Nieuwste versie laden' of 'Mijn versie behouden' in de gele balk.\", tone: \"error\" });\n return;\n }\n const ok = await confirm({ title: \"Pagina publiceren?\", description: `De live site wordt bijgewerkt (${d.path}).`, confirmLabel: \"Publiceren\" });\n if (!ok) return;\n setPublishing(true);\n try {\n await saveDraft(siteId, d.id, draftPayload(d));\n await publishPage(siteId, d.id);\n toast({\n title: \"Gepubliceerd\",\n description: \"Zelf zie je de nieuwe tekst meteen. Voor overige bezoekers duurt het nog ongeveer 15 minuten.\",\n tone: \"success\",\n });\n } catch (e) {\n toast({ title: \"Publiceren mislukt\", description: (e as Error).message, tone: \"error\" });\n } finally {\n setPublishing(false);\n }\n }\n\n const addOptions = useMemo(() => buildBlockAddOptions(registry.values()), [registry]);\n\n const selectedIndex = blocks.findIndex((b) => b._key === selectedKey);\n const selected = selectedIndex >= 0 ? blocks[selectedIndex] : null;\n const canUndo = historyRef.current.past.length > 0;\n const canRedo = historyRef.current.future.length > 0;\n\n /** Laad de nieuwste (remote) versie in de editor — bij een gedetecteerd conflict. */\n const reloadRemote = useCallback(async () => {\n const remote = await getDraftByPath(siteId, path).catch(() => null);\n if (remote) {\n mutateDraft(() => remote);\n lastSavedRef.current = stableStringify(draftPayload(remote));\n dirtyRef.current = false;\n setStatus(\"idle\");\n }\n setConflict(false);\n }, [siteId, path, mutateDraft]);\n\n return (\n <div className=\"xicms-ve__shell\" role=\"dialog\" aria-modal=\"true\" aria-label={`Pagina bewerken: ${path}`}>\n <header className=\"xicms-ve__bar\">\n <strong className=\"xicms-ve__title\">Bewerken · {name}</strong>\n <span className=\"xicms-ve__path\">{path}</span>\n {localeCfg.locales.length > 1 && (\n <span className=\"xicms-ve__locale\" title=\"Taal — in een andere taal dan de standaard bewerk je vertalingen\">\n 🌐\n <Select\n value={locale}\n onValueChange={setLocale}\n options={localeCfg.locales.map((l) => ({ value: l, label: l === localeCfg.defaultLocale ? `${l} (standaard)` : l }))}\n />\n </span>\n )}\n <button type=\"button\" className=\"xicms-ve__histbtn\" disabled={!canUndo} onClick={undo} title=\"Ongedaan maken (Ctrl+Z)\" aria-label=\"Ongedaan maken (Ctrl+Z)\">↶</button>\n <button type=\"button\" className=\"xicms-ve__histbtn\" disabled={!canRedo} onClick={redo} title=\"Opnieuw (Ctrl+Shift+Z)\" aria-label=\"Opnieuw (Ctrl+Shift+Z)\">↷</button>\n <span className=\"xicms-ve__status\" aria-live=\"polite\">\n {status === \"saving\" ? \"Opslaan…\" : status === \"saved\" ? \"✓ Opgeslagen\" : status === \"error\" ? \"⚠ Niet opgeslagen\" : \"\"}\n </span>\n {status === \"error\" && (\n <Button size=\"sm\" variant=\"secondary\" onClick={() => void flushSave().catch(() => setStatus(\"error\"))}>\n Opnieuw opslaan\n </Button>\n )}\n <div className=\"xicms-ve__bar-actions\">\n <Button size=\"sm\" disabled={publishing || !draft} onClick={onPublish}>\n {publishing ? \"Bezig…\" : \"Publiceren\"}\n </Button>\n <Button size=\"sm\" variant=\"secondary\" onClick={handleClose}>Sluiten</Button>\n </div>\n </header>\n\n {conflict && (\n <div className=\"xicms-ve__conflict\" role=\"alert\">\n <span>⚠ Deze pagina is intussen ergens anders gewijzigd (andere tab of collega). Doorwerken kan die wijzigingen overschrijven.</span>\n <Button size=\"sm\" onClick={() => void reloadRemote()}>Nieuwste versie laden</Button>\n <Button size=\"sm\" variant=\"secondary\" onClick={() => setConflict(false)}>Mijn versie behouden</Button>\n </div>\n )}\n\n <div className=\"xicms-ve__body\">\n <main className=\"xicms-ve__canvas\">\n {status === \"loading\" && <p className=\"xicms-ve__hint\">Laden…</p>}\n {status === \"none\" && (\n <div className=\"xicms-ve__empty\">\n <EmptyState\n icon=\"📄\"\n title=\"Geen werkversie gevonden\"\n description={`Voor deze pagina (${path}) bestaat nog geen werkversie. Maak hem hier direct aan, of ga naar /beheer → Pagina's.`}\n />\n <p style={{ textAlign: \"center\", marginTop: \"1rem\" }}>\n <button type=\"button\" className=\"xicms-btn\" onClick={() => void handleCreatePage()}>\n + Deze pagina aanmaken\n </button>\n </p>\n </div>\n )}\n {draft && (\n <div className=\"container\" ref={canvasRef}>\n {blocks.length === 0 && (\n <EmptyState icon=\"🧱\" title=\"Nog geen blokken\" description=\"Voeg hieronder je eerste blok toe.\" />\n )}\n {displayBlocks.map((b, i) => {\n const def = registry.get(b._type);\n const Render = def?.Render;\n // Coerce via het schema zodat defaults zijn toegepast (zoals de live pagina via\n // validateBlocks doet). Ruwe drafts missen anders defaults (bv. hero.buttons) en\n // zouden de Render laten throwen. Lukt het parsen niet, val terug op het ruwe blok\n // (de error-boundary hieronder vangt een eventuele fout dan netjes op).\n const safe = (() => {\n const parsed = def?.schema?.safeParse(b);\n return parsed?.success ? (parsed.data as Block) : b;\n })();\n const dropClass = dropIndex === i ? \" is-drop-before\" : dropIndex === i + 1 ? \" is-drop-after\" : \"\";\n return (\n <div\n key={b._key}\n className={`xicms-ve-block${b._key === selectedKey ? \" is-selected\" : \"\"}${dragIndex === i ? \" is-dragging\" : \"\"}${dropClass}`}\n onDragOver={(e) => {\n if (dragIndex === null) return;\n e.preventDefault();\n e.dataTransfer.dropEffect = \"move\";\n const rect = e.currentTarget.getBoundingClientRect();\n setDropIndex(e.clientY < rect.top + rect.height / 2 ? i : i + 1);\n }}\n onDrop={(e) => {\n if (dragIndex === null || dropIndex === null) return;\n e.preventDefault();\n setBlocks(reorderBlocks(blocks, dragIndex, dropIndex));\n endDrag();\n }}\n >\n <div className=\"xicms-ve-block__toolbar\">\n {/* Sleep-greep: apart element (niet het hele blok) zodat slepen nooit botst met\n het inline contentEditable-bewerken; ↑/↓ blijven het toetsenbord-alternatief. */}\n <button\n type=\"button\"\n className=\"xicms-ve-block__drag\"\n draggable\n onDragStart={(e) => {\n draggingRef.current = true;\n setDragIndex(i);\n e.dataTransfer.effectAllowed = \"move\";\n e.dataTransfer.setData(\"text/plain\", String(i));\n const blockEl = e.currentTarget.closest(\".xicms-ve-block\");\n if (blockEl) e.dataTransfer.setDragImage(blockEl, 24, 24);\n }}\n onDragEnd={endDrag}\n aria-label={`Versleep ${def?.label ?? b._type}`}\n title=\"Slepen om te verplaatsen\"\n >\n ⋮⋮\n </button>\n <span className=\"xicms-ve-block__label\">{def?.label ?? b._type}</span>\n <button type=\"button\" onClick={() => setSelectedKey(b._key)} aria-label={`Bewerk ${def?.label ?? b._type}`} title=\"Bewerken\">✏️</button>\n <button type=\"button\" disabled={i === 0} onClick={() => move(i, -1)} aria-label=\"Omhoog\">↑</button>\n <button type=\"button\" disabled={i === blocks.length - 1} onClick={() => move(i, 1)} aria-label=\"Omlaag\">↓</button>\n {b._type === \"symbolRef\" && (\n <button type=\"button\" onClick={() => void detachSymbol(i)} aria-label=\"Symbool loskoppelen\" title=\"Loskoppelen (losse kopie)\">🔗✂</button>\n )}\n <button type=\"button\" onClick={() => duplicate(i)} aria-label=\"Dupliceren\">⎘</button>\n <button type=\"button\" onClick={() => void remove(i)} aria-label=\"Verwijderen\">🗑</button>\n </div>\n {/* Altijd renderen (geen conditie) → geen remount van de inhoud bij selecteren,\n anders verliest het inline-bewerken zijn contentEditable. Bij selectie zet de\n CSS deze overlay op pointer-events:none zodat je de tekst kunt bewerken. */}\n <button type=\"button\" className=\"xicms-ve-block__select\" aria-label={`Selecteer ${def?.label ?? b._type}`} onClick={() => setSelectedKey(b._key)} />\n <div className=\"xicms-ve-block__content\" data-ve-content={b._key}>\n {/* Net als BlockRenderer: elk blok in een per-blok error-boundary zodat één\n falend (maatwerk-)blok de hele editor niet blank maakt. mode=\"preview\". */}\n {Render ? (\n <BlockErrorBoundary mode=\"preview\" type={b._type} blockKey={b._key}>\n {/* Alleen het geselecteerde blok krijgt de inline beeld-vervangen-overlay. */}\n <InlineImageEditProvider onReplace={b._key === selectedKey ? (field) => setImgPicker({ key: b._key, field }) : null}>\n <Render block={safe} siteId={siteId} mode=\"preview\" />\n </InlineImageEditProvider>\n </BlockErrorBoundary>\n ) : (\n <p className=\"xicms-ve__hint\">Onbekend blok: {b._type}</p>\n )}\n </div>\n </div>\n );\n })}\n <div className=\"xicms-ve__inserter\">\n <span>Toevoegen{selected ? \" (na selectie)\" : \"\"}:</span>\n <div className=\"xicms-ve__inserter-select\">\n <Select value=\"\" placeholder=\"Kies een blok…\" onValueChange={(v) => v && addBlock(v)} options={addOptions} />\n </div>\n <PatternInserter onInsert={insertAfterSelected} />\n </div>\n </div>\n )}\n </main>\n\n <aside className=\"xicms-ve__panel\">\n {selected && isTranslating ? (\n <div className=\"grid gap-3\">\n <h3 className=\"text-sm font-semibold\">{registry.get(selected._type)?.label ?? selected._type} — vertaling ({locale})</h3>\n <TranslationPanel\n key={`${selected._key}:${locale}`}\n block={selected}\n siteId={siteId}\n registry={registry}\n locale={locale}\n overlay={overlay ?? {}}\n onTranslate={setTranslation}\n />\n </div>\n ) : selected ? (\n <div className=\"grid gap-3\">\n <div className=\"xicms-ve__panel-head\">\n {/* Kleur volgt de autosave-status (zelfde bron als de statustekst in de topbalk):\n blauw = nog niet-opgeslagen wijziging (of een mislukte save die opnieuw moet),\n grijs = alles staat al veilig. Directe visuele bevestiging i.p.v. alleen tekst. */}\n <button\n type=\"button\"\n className={`xicms-btn${status === \"saving\" || status === \"error\" ? \"\" : \" xicms-btn--ghost\"}`}\n onClick={() => void flushSave().catch(() => setStatus(\"error\"))}\n >\n {status === \"saving\" ? \"Opslaan…\" : status === \"error\" ? \"⚠ Opnieuw opslaan\" : \"✓ Opgeslagen\"}\n </button>\n <button type=\"button\" className=\"xicms-btn xicms-btn--ghost\" onClick={() => setSelectedKey(null)}>\n ✕ Sluiten\n </button>\n </div>\n <SelectedEditor key={selected._key} block={selected} siteId={siteId} registry={registry} onChange={(next) => updateByKey(selected._key, next)} />\n </div>\n ) : draft && isTranslating ? (\n <div className=\"grid gap-4\">\n <p className=\"xicms-ve__hint\">\n Je bewerkt de vertaling <strong>{locale}</strong>. Klik op een blok om zijn teksten te\n vertalen; lege velden vallen terug op de standaardtaal. Blokken toevoegen/verplaatsen\n doe je in de standaardtaal.\n </p>\n <PageTranslationSettings draft={draft} locale={locale} onTranslate={setTranslation} />\n </div>\n ) : draft ? (\n <div className=\"grid gap-4\">\n <p className=\"xicms-ve__hint\">Klik op een blok om het te bewerken.</p>\n <PageSettings draft={draft} onChange={(part) => mutateDraft((d) => ({ ...d, ...part }), { coalesce: true })} />\n {!isDemoActive() && (\n <VersionsPanel\n siteId={siteId}\n pageId={draft.id}\n onRestore={(restored) => {\n mutateDraft((d) => ({ ...d, ...restored }));\n toast({ title: \"Versie hersteld naar werkversie\", description: \"Publiceer om hem live te zetten.\", tone: \"success\" });\n }}\n />\n )}\n </div>\n ) : (\n <p className=\"xicms-ve__hint\">Klik op een blok om het te bewerken.</p>\n )}\n </aside>\n </div>\n\n {/* Inline afbeelding vervangen: opent de mediabibliotheek; alleen de URL van het veld wordt gezet. */}\n <MediaPickerDialog\n siteId={siteId}\n open={!!imgPicker}\n onOpenChange={(v) => { if (!v) setImgPicker(null); }}\n onSelect={(m) => {\n if (imgPicker) {\n commitInline(imgPicker.key, imgPicker.field, m.url);\n // Alt-tekst van de gekozen media meenemen (a11y/SEO): conventie url→alt / imageUrl→alt\n // op hetzelfde niveau. Bestaat het veld niet in het schema, dan stript Zod het bij\n // publiceren — nooit schadelijk, meestal precies goed (Image/Gallery/Cards/Slider).\n const altField = imgPicker.field.replace(/(^|\\.)((image)?[uU]rl)$/, \"$1alt\");\n if (altField !== imgPicker.field) commitInline(imgPicker.key, altField, m.alt ?? \"\");\n }\n setImgPicker(null);\n }}\n />\n\n {/* Zwevende opmaak-toolbar boven het gefocuste inline rich-text-veld. onMouseDown-preventDefault\n houdt focus + selectie in het veld, zodat execCommand op de selectie werkt. */}\n {fmtBar && (\n <div className=\"xicms-ve-fmtbar\" style={{ top: fmtBar.top, left: fmtBar.left }} role=\"toolbar\" aria-label=\"Tekstopmaak\">\n <FmtBtn label={<b>B</b>} title=\"Vet (Ctrl/Cmd+B)\" onRun={() => document.execCommand(\"bold\")} />\n <FmtBtn label={<i>I</i>} title=\"Cursief (Ctrl/Cmd+I)\" onRun={() => document.execCommand(\"italic\")} />\n <FmtBtn label={<u>U</u>} title=\"Onderstrepen (Ctrl/Cmd+U)\" onRun={() => document.execCommand(\"underline\")} />\n <FmtBtn\n label=\"🔗\"\n title=\"Link (selecteer eerst tekst; leeg = link verwijderen)\"\n onRun={() => {\n const url = window.prompt(\"Link-URL (leeg = link verwijderen)\", \"https://\");\n if (url === null) return;\n if (url === \"\" || url === \"https://\") document.execCommand(\"unlink\");\n else document.execCommand(\"createLink\", false, url);\n }}\n />\n <span className=\"xicms-ve-fmtbar__sep\" aria-hidden />\n <FmtBtn label=\"H2\" title=\"Grote kop\" onRun={() => document.execCommand(\"formatBlock\", false, \"<h2>\")} />\n <FmtBtn label=\"H3\" title=\"Kleine kop\" onRun={() => document.execCommand(\"formatBlock\", false, \"<h3>\")} />\n <FmtBtn label=\"¶\" title=\"Normale tekst\" onRun={() => document.execCommand(\"formatBlock\", false, \"<p>\")} />\n <span className=\"xicms-ve-fmtbar__sep\" aria-hidden />\n <FmtBtn label=\"•\" title=\"Opsomming\" onRun={() => document.execCommand(\"insertUnorderedList\")} />\n </div>\n )}\n </div>\n );\n}\n\n/** Toolbar-knop die de selectie/focus in het contentEditable-veld intact laat. */\nfunction FmtBtn({ label, title, onRun }: { label: React.ReactNode; title: string; onRun: () => void }) {\n return (\n <button\n type=\"button\"\n title={title}\n aria-label={title}\n onMouseDown={(e) => e.preventDefault()}\n onClick={onRun}\n >\n {label}\n </button>\n );\n}\n\n/**\n * Pagina-instellingen (titel + SEO) direct in de visuele editor — de klant hoeft niet meer naar\n * /beheer voor een titel- of meta-omschrijving-wijziging. Slug/pad blijven bewust in /beheer\n * (die raken URL-structuur en zijn niet iets om per ongeluk inline aan te passen).\n */\nfunction PageSettings({\n draft,\n onChange,\n}: {\n draft: DraftPage;\n onChange: (part: Partial<DraftPage>) => void;\n}) {\n const seo = draft.seo ?? {};\n return (\n <details className=\"xicms-ve__section\" open>\n <summary className=\"text-sm font-semibold\">Pagina-instellingen</summary>\n <div className=\"mt-2 grid gap-3\">\n <Field label=\"Paginatitel\">\n <Input value={draft.title ?? \"\"} onChange={(e) => onChange({ title: e.target.value })} />\n </Field>\n <Field label=\"SEO-titel\" hint=\"Leeg = paginatitel\">\n <Input value={seo.title ?? \"\"} onChange={(e) => onChange({ seo: { ...seo, title: e.target.value } })} />\n </Field>\n <Field label=\"SEO-omschrijving\" hint=\"Wordt getoond in zoekresultaten\">\n <Textarea rows={3} value={seo.description ?? \"\"} onChange={(e) => onChange({ seo: { ...seo, description: e.target.value } })} />\n </Field>\n </div>\n </details>\n );\n}\n\n/** Pagina-instellingen in vertaalmodus (5.0): titel + SEO als overlay-sleutels. */\nfunction PageTranslationSettings({\n draft,\n locale,\n onTranslate,\n}: {\n draft: DraftPage;\n locale: string;\n onTranslate: (key: string, value: string) => void;\n}) {\n const ov = draft.translations?.[locale] ?? {};\n return (\n <details className=\"xicms-ve__section\" open>\n <summary className=\"text-sm font-semibold\">Pagina-instellingen ({locale})</summary>\n <div className=\"mt-2 grid gap-3\">\n <Field label=\"Paginatitel\" hint={`Origineel: ${draft.title ?? \"\"}`}>\n <Input value={ov[\"title\"] ?? \"\"} placeholder={draft.title ?? \"\"} onChange={(e) => onTranslate(\"title\", e.target.value)} />\n </Field>\n <Field label=\"SEO-titel\">\n <Input value={ov[\"seo.title\"] ?? \"\"} placeholder={draft.seo?.title ?? \"\"} onChange={(e) => onTranslate(\"seo.title\", e.target.value)} />\n </Field>\n <Field label=\"SEO-omschrijving\">\n <Textarea rows={3} value={ov[\"seo.description\"] ?? \"\"} placeholder={draft.seo?.description ?? \"\"} onChange={(e) => onTranslate(\"seo.description\", e.target.value)} />\n </Field>\n </div>\n </details>\n );\n}\n\n/** Versiegeschiedenis in de visuele editor: herstellen zet een snapshot terug naar de WERKVERSIE. */\nfunction VersionsPanel({\n siteId,\n pageId,\n onRestore,\n}: {\n siteId: string;\n pageId: string;\n onRestore: (restored: Partial<DraftPage>) => void;\n}) {\n const [versions, setVersions] = useState<{ id: string; createdAt?: unknown; kind?: string; label?: string }[]>([]);\n const { toast } = useToast();\n const confirm = useConfirm();\n useEffect(() => subscribeVersions(siteId, pageId, setVersions), [siteId, pageId]);\n if (versions.length === 0) return null;\n\n const restore = async (versionId: string) => {\n const ok = await confirm({\n title: \"Versie herstellen?\",\n description: \"De snapshot vervangt je huidige werkversie (ongedaan te maken met Ctrl+Z). De live site verandert pas bij Publiceren.\",\n confirmLabel: \"Herstellen\",\n });\n if (!ok) return;\n try {\n const restored = await restoreVersion(siteId, pageId, versionId);\n onRestore(restored);\n } catch (e) {\n toast({ title: \"Herstellen mislukt\", description: (e as Error).message, tone: \"error\" });\n }\n };\n\n return (\n <details className=\"xicms-ve__section\">\n <summary className=\"text-sm font-semibold\">Versiegeschiedenis</summary>\n <ul className=\"mt-2 grid gap-1 text-sm\">\n {versions.slice(0, 10).map((v) => (\n <li key={v.id} className=\"flex items-center justify-between gap-2\">\n <span>\n {v.label ?? (v.kind === \"publish\" ? \"Gepubliceerd\" : v.kind ?? \"Snapshot\")}\n {formatVersionDate(v.createdAt) && <span className=\"text-slate-400\"> · {formatVersionDate(v.createdAt)}</span>}\n </span>\n <Button variant=\"ghost\" size=\"sm\" onClick={() => void restore(v.id)}>\n Herstellen\n </Button>\n </li>\n ))}\n </ul>\n </details>\n );\n}\n\nfunction formatVersionDate(createdAt: unknown): string {\n const date =\n createdAt && typeof (createdAt as { toDate?: () => Date }).toDate === \"function\"\n ? (createdAt as { toDate: () => Date }).toDate()\n : typeof createdAt === \"string\"\n ? new Date(createdAt)\n : null;\n return date && !Number.isNaN(date.getTime()) ? date.toLocaleString(\"nl-NL\", { dateStyle: \"short\", timeStyle: \"short\" }) : \"\";\n}\n\nfunction SelectedEditor({\n block,\n siteId,\n registry,\n onChange,\n}: {\n block: Block;\n siteId: string;\n registry: ReturnType<typeof useRegistry>;\n onChange: (next: Record<string, unknown>) => void;\n}) {\n const def = registry.get(block._type);\n const Editor: ComponentType<BlockEditorProps> =\n (def?.Editor as ComponentType<BlockEditorProps> | undefined) ?? builtinBlockEditors[block._type] ?? GenericEditor;\n return (\n <div className=\"grid gap-3\">\n <h3 className=\"text-sm font-semibold\">{def?.label ?? block._type}</h3>\n {/* Maatwerk-Editors kunnen falen → vang per-blok op zodat het paneel niet leeg wordt. */}\n <BlockErrorBoundary mode=\"preview\" type={block._type} blockKey={block._key}>\n <Editor block={block} siteId={siteId} onChange={onChange} />\n </BlockErrorBoundary>\n <StyleEditor\n value={block._style as BlockStyle | undefined}\n onChange={(style) => onChange({ ...block, _style: style })}\n />\n </div>\n );\n}\n"],"mappings":"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","names":["locale","overlay","t","inField"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/admin/visual/VisualEditor.tsx"],"sourcesContent":["\"use client\";\n\n// De admin-stijlen (Tailwind, scoped onder .xicms-admin) horen bij dit lazy-geladen chunk, zodat\n// publieke bezoekers ze nooit downloaden — alleen wanneer een editor de pagina-editor opent.\nimport \"@xiwebdesign/xicms-core/admin.css\";\nimport { useCallback, useEffect, useMemo, useRef, useState, type ComponentType } from \"react\";\nimport { useSiteConfig } from \"../../config\";\nimport { useRegistry } from \"../../blocks/context\";\nimport { introspectToFields } from \"../lib/zodFields\";\nimport { BlockErrorBoundary } from \"../../blocks/BlockErrorBoundary\";\nimport { InlineImageEditProvider } from \"../../media/ImageContext\";\nimport { MediaPickerDialog } from \"../media/MediaPicker\";\nimport { EmptyState } from \"@astryxdesign/core/EmptyState\";\nimport { useFocusTrap, useScrollLock } from \"@astryxdesign/core/hooks\";\nimport { useNestedDialogOpen } from \"../lib/useNestedDialog\";\nimport { useThemeVars } from \"../../XiCMSProvider\";\nimport { buildBlockAddOptions } from \"../../blocks/registry\";\nimport { safeParse } from \"zod/v4/core\";\nimport DOMPurify from \"dompurify\";\nimport { createPage, getDraftByPath, saveDraft, publishPage, subscribeDraft, subscribeVersions, restoreVersion, type DraftPage } from \"../lib/pagesClient\";\nimport { isDemoActive } from \"../../demo/demoStore\";\nimport { builtinBlockEditors, GenericEditor, type BlockEditorProps } from \"../blockEditors\";\nimport { StyleEditor } from \"../blockEditors/StyleEditor\";\nimport { siteLocales, parseLocaleSlugs, localizeBlocks } from \"../../i18n/overlay\";\nimport { TranslationPanel } from \"./TranslationPanel\";\nimport { reorderBlocks } from \"./reorder\";\nimport { PatternInserter } from \"../patterns/PatternInserter\";\nimport type { BlockStyle } from \"../../schema/blocks\";\nimport { Button, Field, Input, Textarea } from \"../ui/primitives\";\nimport { Select } from \"../ui/select\";\nimport { ToastProvider, useToast } from \"../ui/toast\";\nimport { ConfirmHost, useConfirm } from \"../ui/ConfirmDialog\";\n\ntype Block = Record<string, unknown> & { _key: string; _type: string };\ntype Status = \"loading\" | \"none\" | \"idle\" | \"saving\" | \"saved\" | \"error\";\n\n/**\n * Inline bewerken is sinds 5.0 volledig generiek: élk blok markeert zijn tekstvelden met\n * `data-xicms-edit=\"veldpad\"` (de builtin-Renders doen dat), plus de rich-text-haak\n * `.xicms-richtext`. De oude hardgecodeerde per-type selector-map (`INLINE_FIELDS`) is vervallen.\n * In development waarschuwt `warnInlineCoverage` wanneer een tekstveld uit het schema géén\n * DOM-haak heeft — zo blijven Renders eerlijk t.o.v. hun schema.\n */\nconst GLOBAL_INLINE = [\n // `field: \"html\"` is de AANNAME, geen wet: een element mag met `data-xicms-edit` zeggen welk veld\n // het werkelijk toont, en dat wint (zie de bind hieronder). Zonder die voorrang schreef élk\n // `.xicms-richtext`-element naar een veld dat letterlijk \"html\" heet — waar de FAQ zijn antwoord\n // in `items[].aHtml` bewaart en het accordeon in `items[].bodyHtml`. Inline bewerken van een\n // FAQ-antwoord landde daardoor op een niet-bestaand veld: de wijziging verdween stil en het blok\n // hield een zwerfveld over.\n { selector: \".xicms-richtext\", field: \"html\", html: true as const },\n { selector: \"[data-xicms-edit]\", field: \"\", html: false as const, fromData: true as const },\n];\n\n/** Dev-vangnet (5.0): meld tekstvelden zonder inline-haak — één keer per bloktype. */\nconst inlineCoverageWarned = new Set<string>();\nfunction warnInlineCoverage(type: string, def: { schema: Parameters<typeof introspectToFields>[0]; fields?: Parameters<typeof introspectToFields>[1] } | undefined, host: HTMLElement) {\n if (process.env.NODE_ENV === \"production\" || !def || inlineCoverageWarned.has(type)) return;\n inlineCoverageWarned.add(type);\n const missing = introspectToFields(def.schema, def.fields)\n .filter((f) => f.type === \"text\" || f.type === \"textarea\")\n .map((f) => f.key)\n .filter((key) => !host.querySelector(`[data-xicms-edit=\"${key}\"], [data-xicms-edit$=\".${key}\"]`));\n if (missing.length > 0) {\n console.warn(\n `[xicms] blok \"${type}\": tekstveld(en) zonder inline-haak: ${missing.join(\", \")} — voeg data-xicms-edit=\"<veld>\" toe aan de Render zodat ze direct op de pagina bewerkbaar zijn.`,\n );\n }\n}\n\n/* Lees/schrijf een waarde op een gepunt pad (bv. \"items.0.title\") — zodat ook lijst-items inline\n bewerkt kunnen worden. setPath kloont onderweg (immutable) zodat React de wijziging detecteert. */\nfunction getPath(obj: unknown, path: string): unknown {\n return path.split(\".\").reduce<unknown>((o, k) => (o == null ? undefined : (o as Record<string, unknown>)[k]), obj);\n}\nfunction setPath<T>(obj: T, path: string, value: unknown): T {\n const keys = path.split(\".\");\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const clone = (v: unknown): any => (Array.isArray(v) ? [...v] : v && typeof v === \"object\" ? { ...(v as object) } : v);\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\nfunction newKey() {\n return (globalThis.crypto?.randomUUID?.() ?? `b${Date.now()}${Math.random()}`).slice(0, 12);\n}\n\n/** JSON.stringify met gesorteerde sleutels — voor betrouwbare inhoudsvergelijking (conflictdetectie):\n * Firestore kan velden in een andere volgorde teruggeven dan wij ze lokaal opbouwden. */\nfunction stableStringify(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(stableStringify).join(\",\")}]`;\n if (value && typeof value === \"object\") {\n const entries = Object.entries(value as Record<string, unknown>)\n .filter(([, v]) => v !== undefined)\n .sort(([a], [b]) => (a < b ? -1 : 1));\n return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).join(\",\")}}`;\n }\n return JSON.stringify(value) ?? \"null\";\n}\n\n/**\n * Visuele/inline pagina-editor: opent als overlay over de live pagina, laadt de werkversie van de\n * huidige route, en laat de editor blokken op een live canvas selecteren, herordenen, dupliceren,\n * verwijderen en toevoegen — met autosave en publiceren. De zware code laadt pas bij openen\n * (lazy, via EditorProvider), dus bezoekers downloaden hem nooit.\n */\nexport default function VisualEditor({ onClose }: { onClose: () => void }) {\n return (\n <div className=\"xicms-admin xicms-ve\">\n <ToastProvider>\n <ConfirmHost>\n <VisualEditorInner onClose={onClose} />\n </ConfirmHost>\n </ToastProvider>\n </div>\n );\n}\n\nfunction VisualEditorInner({ onClose }: { onClose: () => void }) {\n const config = useSiteConfig();\n const { siteId, name } = config;\n const registry = useRegistry();\n const { toast } = useToast();\n const confirm = useConfirm();\n\n // Meertalig (5.0): een taalprefix in de URL (/de/over-ons) hoort niet bij het canonieke\n // pagina-pad — de editor opent dan de pagina zélf, met de betreffende taal actief.\n const localeCfg = useMemo(() => siteLocales(config), [config]);\n const { path, urlLocale } = useMemo(() => {\n const raw = typeof window !== \"undefined\" ? window.location.pathname || \"/\" : \"/\";\n const { locale, slugs } = parseLocaleSlugs(raw.split(\"/\").filter(Boolean), localeCfg);\n const p = \"/\" + slugs.join(\"/\");\n return { path: p === \"/\" ? \"/\" : p.replace(/\\/$/, \"\"), urlLocale: locale };\n }, [localeCfg]);\n const [locale, setLocale] = useState(urlLocale);\n const isTranslating = locale !== localeCfg.defaultLocale;\n const [draft, setDraft] = useState<DraftPage | null>(null);\n const [status, setStatus] = useState<Status>(\"loading\");\n const [selectedKey, setSelectedKey] = useState<string | null>(null);\n const [publishing, setPublishing] = useState(false);\n const [imgPicker, setImgPicker] = useState<{ key: string; field: string } | null>(null);\n const firstSave = useRef(true);\n const canvasRef = useRef<HTMLDivElement>(null);\n const [conflict, setConflict] = useState(false);\n\n // ── Modale discipline (WAI-ARIA dialog pattern) ───────────────────────────\n // De shell draagt `role=\"dialog\" aria-modal=\"true\"` en belooft daarmee aan hulpsoftware dat\n // alles erbuiten onbereikbaar is. Zonder trap klopte die belofte niet: met Tab liep je zó de\n // onderliggende pagina in, terwijl de schermlezer meldde dat die er niet was.\n //\n // Geen `onEscape` meegeven: Escape wordt hieronder al afgehandeld met logica die de trap niet\n // kent (niet sluiten terwijl je in een invoerveld staat of er een dialoog openstaat).\n // Het canvas is een VOORBEELD van de live pagina en moet dus dezelfde merk-tokens dragen.\n // De editor rendert buiten `.xicms-root`, dus die erven we hier expliciet via context.\n const { vars: themeVars, darkAuto } = useThemeVars();\n const nestedDialogOpen = useNestedDialogOpen();\n const { containerRef, focusFirst } = useFocusTrap<HTMLDivElement>({ isActive: !nestedDialogOpen });\n useScrollLock(true);\n\n // Focus de eerste bediening bij openen, en geef hem bij sluiten terug aan het element dat de\n // editor opende (\"Pagina bewerken\"). Zonder dat teruggeven valt de focus terug naar <body> en\n // begint een toetsenbordgebruiker weer bovenaan de pagina.\n useEffect(() => {\n const opener = document.activeElement as HTMLElement | null;\n focusFirst();\n return () => opener?.focus?.();\n }, [focusFirst]);\n\n // Drag-and-drop herordenen: dragIndex = het gesleepte blok, dropIndex = invoegpunt (0..length).\n // draggingRef pauzeert de inline-bind MutationObserver tijdens het slepen (re-bind-ruis).\n const [dragIndex, setDragIndex] = useState<number | null>(null);\n const [dropIndex, setDropIndex] = useState<number | null>(null);\n const draggingRef = useRef(false);\n const endDrag = useCallback(() => {\n draggingRef.current = false;\n setDragIndex(null);\n setDropIndex(null);\n }, []);\n\n // Altijd de laatste draft + \"zijn er niet-opgeslagen wijzigingen\" bij de hand houden, zodat we\n // bij sluiten/wegnavigeren nog kunnen flushen (de debounce zou de laatste 700ms anders weggooien).\n const draftRef = useRef<DraftPage | null>(null);\n const dirtyRef = useRef(false);\n // Inhoud (stable-stringified) van de laatst succesvol opgeslagen payload — voor conflictdetectie.\n const lastSavedRef = useRef<string | null>(null);\n useEffect(() => {\n draftRef.current = draft;\n }, [draft]);\n\n // ── Undo/redo ──────────────────────────────────────────────────────────────\n // History over draft-snapshots. Tekstedits (per toetsaanslag) worden ge-coalesced: binnen één\n // typ-burst (<800ms) staat het pre-burst-snapshot al op de stack, dus niet opnieuw pushen —\n // Ctrl+Z springt dan per burst terug i.p.v. per letter. `histVersion` forceert re-render van\n // de knop-states (de stacks leven in een ref).\n const historyRef = useRef<{ past: DraftPage[]; future: DraftPage[]; lastPush: number }>({ past: [], future: [], lastPush: 0 });\n const [, setHistVersion] = useState(0);\n\n const pushHistory = useCallback((prev: DraftPage, coalesce: boolean) => {\n const h = historyRef.current;\n const now = Date.now();\n if (!(coalesce && now - h.lastPush < 800 && h.past.length > 0)) {\n h.past.push(prev);\n if (h.past.length > 100) h.past.shift();\n }\n h.lastPush = now;\n h.future = [];\n setHistVersion((v) => v + 1);\n }, []);\n\n /** Enige route waarlangs de draft muteert: bewaart eerst een undo-snapshot. */\n const mutateDraft = useCallback(\n (updater: (d: DraftPage) => DraftPage, opts?: { coalesce?: boolean }) => {\n const d = draftRef.current;\n if (!d) return;\n const next = updater(d);\n if (next === d) return;\n pushHistory(d, opts?.coalesce ?? false);\n draftRef.current = next;\n // Dirty HIER markeren (synchroon met de mutatie), niet pas in het debounced autosave-effect:\n // een inline edit (blur) direct gevolgd door \"Sluiten\" in dezelfde gesture zou anders\n // flushSave() zien met dirtyRef=false → laatste wijziging verloren.\n dirtyRef.current = true;\n setDraft(next);\n },\n [pushHistory],\n );\n\n const undo = useCallback(() => {\n const h = historyRef.current;\n const d = draftRef.current;\n const prev = h.past.pop();\n if (!prev || !d) return;\n h.future.push(d);\n h.lastPush = 0;\n draftRef.current = prev;\n dirtyRef.current = true; // undo is óók een wijziging die opgeslagen moet worden\n setDraft(prev);\n setHistVersion((v) => v + 1);\n }, []);\n\n const redo = useCallback(() => {\n const h = historyRef.current;\n const d = draftRef.current;\n const next = h.future.pop();\n if (!next || !d) return;\n h.past.push(d);\n h.lastPush = 0;\n draftRef.current = next;\n dirtyRef.current = true; // redo is óók een wijziging die opgeslagen moet worden\n setDraft(next);\n setHistVersion((v) => v + 1);\n }, []);\n\n const draftPayload = (d: DraftPage) => ({\n blocks: d.blocks,\n title: d.title,\n slug: d.slug,\n path: d.path,\n seo: d.seo,\n // Alleen meesturen wanneer aanwezig: `undefined` weigert de Firestore-client.\n ...(d.translations ? { translations: d.translations } : {}),\n });\n\n // Schrijf eventuele pending wijziging direct weg (gebruikt bij Sluiten, tab-wissel en retry).\n const flushSave = useCallback(async () => {\n // Een veld dat pas op blur committeert (bv. het JSON-redmiddel in GenericEditor) moet die\n // commit eerst nog uitvoeren. Op desktop vuurt blur al vóór de click van deze knop, maar op\n // mobiel Safari is die volgorde niet gegarandeerd (het toetsenbord-sluiten kan blur vertragen\n // tot ná de klik) — expliciet blur() forceert de commit synchroon, ongeacht platform.\n (document.activeElement as HTMLElement | null)?.blur();\n const d = draftRef.current;\n if (!d || !dirtyRef.current) return;\n const payload = draftPayload(d);\n await saveDraft(siteId, d.id, payload);\n lastSavedRef.current = stableStringify(payload);\n // Alleen \"schoon\" markeren als er intussen niets nieuws is getypt (anders zou een trage\n // write nieuwere wijzigingen als opgeslagen bestempelen).\n if (draftRef.current === d) {\n dirtyRef.current = false;\n setStatus(\"saved\");\n }\n }, [siteId]);\n\n const handleClose = useCallback(() => {\n void flushSave().finally(() => onClose());\n }, [flushSave, onClose]);\n\n useEffect(() => {\n let active = true;\n getDraftByPath(siteId, path)\n .then((d) => {\n if (!active) return;\n if (d) {\n setDraft(d);\n lastSavedRef.current = stableStringify(draftPayload(d));\n setStatus(\"idle\");\n } else {\n setStatus(\"none\");\n }\n })\n .catch(() => active && setStatus(\"none\"));\n return () => {\n active = false;\n };\n }, [siteId, path]);\n\n /** Bootstrap vanuit de \"Geen werkversie\"-toestand: maak de pagina hier direct aan (geen omweg\n * via /beheer → Pagina's — dat was een doodloop voor niet-technische klanten). */\n const handleCreatePage = useCallback(async () => {\n setStatus(\"loading\");\n try {\n const segment = path.split(\"/\").filter(Boolean).pop() ?? \"\";\n const title = segment ? segment.replace(/[-_]+/g, \" \").replace(/^\\w/, (c) => c.toUpperCase()) : \"Home\";\n await createPage(siteId, { title, slug: segment || \"home\", path });\n const d = await getDraftByPath(siteId, path);\n if (d) {\n setDraft(d);\n lastSavedRef.current = stableStringify(draftPayload(d));\n setStatus(\"idle\");\n toast({ title: \"Pagina aangemaakt\", description: \"Voeg je eerste blok toe en publiceer wanneer je klaar bent.\", tone: \"success\" });\n } else {\n setStatus(\"none\");\n }\n } catch (e) {\n setStatus(\"none\");\n toast({ title: \"Pagina aanmaken mislukt\", description: (e as Error)?.message, tone: \"error\" });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [siteId, path, toast]);\n\n // ── Conflictdetectie ───────────────────────────────────────────────────────\n // Luister naar de draft in Firestore. Een server-snapshot die afwijkt van zowel onze laatst\n // opgeslagen payload als onze huidige lokale staat, betekent: iemand anders (tab/collega)\n // heeft deze pagina gewijzigd. Waarschuw i.p.v. elkaars werk stil te overschrijven.\n const draftId = draft?.id;\n useEffect(() => {\n if (!draftId) return;\n return subscribeDraft(siteId, draftId, (remote, meta) => {\n if (!meta.fromServer || !remote) return;\n const remotePayload = stableStringify(draftPayload(remote));\n const local = draftRef.current;\n const localPayload = local ? stableStringify(draftPayload(local)) : null;\n if (remotePayload !== lastSavedRef.current && remotePayload !== localPayload) setConflict(true);\n });\n }, [siteId, draftId]);\n\n const blocks = (draft?.blocks ?? []) as Block[];\n // Canvas in een niet-default taal: toon de vertaal-overlay over de canonieke blokken.\n const overlay = draft?.translations?.[locale];\n const displayBlocks = useMemo(\n () => (isTranslating ? (localizeBlocks(blocks, overlay) as Block[]) : blocks),\n [blocks, isTranslating, overlay],\n );\n\n // Schrijf een inline (in-canvas) tekstwijziging terug naar het juiste blokveld (canoniek).\n const commitInline = useCallback(\n (key: string, field: string, value: string) => {\n mutateDraft(\n (d) => {\n const bl = d.blocks as Block[];\n const idx = bl.findIndex((x) => x._key === key);\n if (idx < 0 || getPath(bl[idx], field) === value) return d;\n const next = [...bl];\n next[idx] = setPath(next[idx], field, value);\n return { ...d, blocks: next };\n },\n { coalesce: true },\n );\n },\n [mutateDraft],\n );\n\n // Schrijf een vertaling naar de taal-overlay; leeg = sleutel weg (terugvallen op origineel).\n const setTranslation = useCallback(\n (tkey: string, value: string) => {\n mutateDraft(\n (d) => {\n const overlay = { ...(d.translations?.[locale] ?? {}) };\n if (value.trim() === \"\" || value === undefined) delete overlay[tkey];\n else overlay[tkey] = value;\n return { ...d, translations: { ...(d.translations ?? {}), [locale]: overlay } };\n },\n { coalesce: true },\n );\n },\n [mutateDraft, locale],\n );\n\n // ── Inline opmaak-toolbar (WYSIWYG op het canvas) ─────────────────────────\n // Zwevende mini-toolbar boven een gefocust rich-text-veld: vet/schuin/onderstrepen/link +\n // groter-kleiner via kop-niveaus (H2/H3/normaal — semantisch i.p.v. losse font-sizes).\n // document.execCommand is deprecated-maar-universeel en precies goed voor contentEditable;\n // de output gaat bij commit door DOMPurify én server-side door de allowlist-sanitizer.\n const [fmtBar, setFmtBar] = useState<{ top: number; left: number } | null>(null);\n const fmtElRef = useRef<HTMLElement | null>(null);\n const positionFmtBar = useCallback((el: HTMLElement) => {\n const r = el.getBoundingClientRect();\n setFmtBar({\n top: Math.max(56, r.top - 44),\n left: Math.min(Math.max(8, r.left), Math.max(8, window.innerWidth - 300)),\n });\n }, []);\n useEffect(() => {\n if (!fmtBar) return;\n const onScroll = () => {\n const el = fmtElRef.current;\n if (el) positionFmtBar(el);\n };\n window.addEventListener(\"scroll\", onScroll, { capture: true, passive: true });\n return () => window.removeEventListener(\"scroll\", onScroll, { capture: true });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [fmtBar !== null, positionFmtBar]);\n\n // Inline canvas-edits: in de default-taal naar het blokveld, in een andere taal naar de overlay.\n const commitText = useCallback(\n (key: string, field: string, value: string) => {\n if (isTranslating) setTranslation(`${key}.${field}`, value);\n else commitInline(key, field, value);\n },\n [isTranslating, setTranslation, commitInline],\n );\n\n // Maak de tekstvelden van het GESELECTEERDE blok ter plekke bewerkbaar (contentEditable) en synct\n // op blur terug — zo bewerk je tekst inline op het canvas i.p.v. via de zijbalk. We binden via een\n // MutationObserver én her-binden zodra React de DOM-node vervangt (re-render), met een dataset-flag\n // zodat we nooit dubbele listeners zetten.\n useEffect(() => {\n if (!selectedKey) return;\n const host = canvasRef.current?.querySelector<HTMLElement>(`[data-ve-content=\"${selectedKey}\"]`);\n if (!host) return;\n const type = blocks.find((b) => b._key === selectedKey)?._type ?? \"\";\n const specs = [...GLOBAL_INLINE];\n warnInlineCoverage(String(type), registry.get(String(type)), host);\n\n const bound = new Set<HTMLElement>();\n const bind = (el: HTMLElement, field: string, html: boolean) => {\n if (el.dataset.veInline === \"1\") return;\n el.dataset.veInline = \"1\";\n el.setAttribute(\"contenteditable\", \"true\");\n el.setAttribute(\"spellcheck\", \"true\");\n el.classList.add(\"xicms-ve-inline\");\n // Inline HTML wordt vóór commit gesanitized (DOMPurify) — zelfde belofte als het TipTap-pad;\n // de server sanitized nogmaals bij publiceren. Geplakte Word-/Docs-rommel blijft zo buiten.\n el.addEventListener(\"blur\", () => commitText(selectedKey, field, html ? DOMPurify.sanitize(el.innerHTML) : (el.textContent ?? \"\")));\n if (html) {\n // Opmaak-toolbar tonen zolang dit rich-text-veld focus heeft.\n el.addEventListener(\"focus\", () => {\n fmtElRef.current = el;\n positionFmtBar(el);\n });\n el.addEventListener(\"blur\", () => {\n fmtElRef.current = null;\n setFmtBar(null);\n });\n }\n el.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Escape\") el.blur();\n else if (!html && e.key === \"Enter\") { e.preventDefault(); el.blur(); }\n });\n bound.add(el);\n };\n const apply = () => {\n for (const m of specs) {\n host.querySelectorAll<HTMLElement>(m.selector).forEach((el) =>\n // Een expliciete `data-xicms-edit` wint altijd; anders het veld van de matcher.\n bind(el, el.dataset.xicmsEdit ?? m.field, !!m.html),\n );\n }\n };\n\n apply();\n // Her-bind na elke re-render die de tekstnodes vervangt (niet tijdens slepen: dan muteert de\n // DOM continu door de drop-indicatoren en zou her-binden alleen maar ruis geven).\n const obs = new MutationObserver(() => {\n if (!draggingRef.current) apply();\n });\n obs.observe(host, { childList: true, subtree: true });\n return () => {\n obs.disconnect();\n bound.forEach((el) => {\n el.removeAttribute(\"contenteditable\");\n el.classList.remove(\"xicms-ve-inline\");\n delete el.dataset.veInline;\n });\n };\n }, [selectedKey, blocks, commitText, positionFmtBar]);\n\n // Autosave naar de draft (publiceren blijft een aparte, bewuste stap).\n // Debounce 700ms ná de laatste wijziging, met een MAX-WAIT van 3s: de debounce herstart bij elke\n // toetsaanslag, dus zonder max-wait zou iemand die blijft doortypen nooit tussentijds opslaan.\n const dirtySinceRef = useRef<number | null>(null);\n useEffect(() => {\n if (!draft) return;\n if (firstSave.current) {\n firstSave.current = false;\n return;\n }\n // Bij een openstaand conflict PAUZEREN we autosave: de banner wegklikken en doorwerken\n // overschreef anders stil de wijzigingen van de collega/andere tab (destructief-by-default).\n // De klant kiest eerst expliciet \"Nieuwste laden\" of \"Mijn versie behouden\".\n if (conflict) return;\n dirtyRef.current = true;\n dirtySinceRef.current ??= Date.now();\n setStatus(\"saving\");\n const waited = Date.now() - dirtySinceRef.current;\n const delay = Math.max(0, Math.min(700, 3000 - waited));\n const t = setTimeout(() => {\n dirtySinceRef.current = null;\n const payload = draftPayload(draft);\n void saveDraft(siteId, draft.id, payload)\n .then(() => {\n lastSavedRef.current = stableStringify(payload);\n // Alleen \"schoon\"/\"saved\" als dit nog de nieuwste versie is (zie flushSave).\n if (draftRef.current === draft) {\n dirtyRef.current = false;\n setStatus(\"saved\");\n }\n })\n .catch(() => setStatus(\"error\"));\n }, delay);\n return () => clearTimeout(t);\n }, [draft, siteId, conflict]);\n\n // Waarschuw bij het verlaten van de pagina met niet-opgeslagen wijzigingen; flush bij tab-wissel/\n // verbergen (visibilitychange) en bij unmount. Escape sluit de editor (na flush).\n useEffect(() => {\n const beforeUnload = (e: BeforeUnloadEvent) => {\n if (dirtyRef.current) {\n e.preventDefault();\n e.returnValue = \"\";\n }\n };\n const onVisibility = () => {\n // Tab-wissel/minimaliseren: beste moment om pending werk veilig te stellen.\n if (document.visibilityState === \"hidden\") void flushSave().catch(() => {});\n };\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n // Escape sluit alléén de editor als er niets \"boven\" de editor actief is: een open\n // dialog (mediakiezer, bevestiging — Radix rendert [role=dialog] buiten deze shell) of\n // een inline bewerking/invoerveld vangt zijn eigen Escape. Anders verdween bij het\n // sluiten van de mediakiezer meteen de hele editor.\n const t = e.target as HTMLElement | null;\n const inField = !!t && (t.isContentEditable || t.tagName === \"INPUT\" || t.tagName === \"TEXTAREA\" || t.tagName === \"SELECT\");\n // Zelfde herkenning als useNestedDialog: Astryx' dialoog is een natieve <dialog open>.\n const dialogOpen = document.querySelector('dialog[open], [role=\"dialog\"][data-state=\"open\"], [role=\"alertdialog\"][data-state=\"open\"]');\n if (!inField && !dialogOpen) handleClose();\n return;\n }\n // Undo/redo op canvas-niveau. In invoervelden/contentEditable laten we de native\n // tekst-undo van de browser zijn werk doen (anders vecht Ctrl+Z met het veld zelf).\n const t = e.target as HTMLElement | null;\n const inField = !!t && (t.isContentEditable || t.tagName === \"INPUT\" || t.tagName === \"TEXTAREA\" || t.tagName === \"SELECT\");\n if ((e.metaKey || e.ctrlKey) && !inField && (e.key.toLowerCase() === \"z\" || e.key.toLowerCase() === \"y\")) {\n e.preventDefault();\n if (e.key.toLowerCase() === \"y\" || e.shiftKey) redo();\n else undo();\n }\n };\n window.addEventListener(\"beforeunload\", beforeUnload);\n document.addEventListener(\"visibilitychange\", onVisibility);\n window.addEventListener(\"keydown\", onKeyDown);\n return () => {\n window.removeEventListener(\"beforeunload\", beforeUnload);\n document.removeEventListener(\"visibilitychange\", onVisibility);\n window.removeEventListener(\"keydown\", onKeyDown);\n const d = draftRef.current;\n if (d && dirtyRef.current) {\n // Laatste redmiddel bij unmount; log een mislukking i.p.v. stil verliezen.\n void saveDraft(siteId, d.id, draftPayload(d)).catch((err) =>\n console.warn(\"[xicms] autosave bij sluiten mislukt:\", err),\n );\n }\n };\n }, [siteId, handleClose, flushSave, undo, redo]);\n\n function setBlocks(next: Block[], opts?: { coalesce?: boolean }) {\n mutateDraft((d) => ({ ...d, blocks: next }), opts);\n }\n function updateByKey(key: string, next: Record<string, unknown>) {\n // Zijpaneel-edits komen per toetsaanslag binnen → coalesce voor zinnige undo-stappen.\n setBlocks(blocks.map((b) => (b._key === key ? ({ ...(next as Block), _key: b._key, _type: b._type }) : b)), { coalesce: true });\n }\n function move(i: number, dir: -1 | 1) {\n const j = i + dir;\n if (j < 0 || j >= blocks.length) return;\n const copy = [...blocks];\n [copy[i], copy[j]] = [copy[j], copy[i]];\n setBlocks(copy);\n }\n function duplicate(i: number) {\n const copy = [...blocks];\n copy.splice(i + 1, 0, { ...blocks[i], _key: newKey() });\n setBlocks(copy);\n }\n /** Symbool loskoppelen (5.0): vervang de referentie door een kloon van de symboolblokken —\n * daarna beweegt dit exemplaar niet meer mee met het gedeelde symbool. */\n async function detachSymbol(i: number) {\n const blk = blocks[i] as { _type?: string; symbolId?: string; _key: string };\n if (blk._type !== \"symbolRef\" || !blk.symbolId) return;\n const ok = await confirm({\n title: \"Symbool loskoppelen?\",\n description: \"Dit blok wordt een losse kopie en beweegt niet meer mee met het gedeelde symbool.\",\n confirmLabel: \"Loskoppelen\",\n });\n if (!ok) return;\n const { getSymbolOnce } = await import(\"../lib/symbolsClient\");\n const sym = await getSymbolOnce(siteId, blk.symbolId);\n if (!sym) {\n toast({ title: \"Symbool niet gevonden\", tone: \"error\" });\n return;\n }\n const clones = sym.blocks.map((b) => ({ ...(b as Record<string, unknown>), _key: newKey() })) as Block[];\n const copy = [...blocks];\n copy.splice(i, 1, ...clones);\n setBlocks(copy);\n if (selectedKey === blk._key) setSelectedKey(null);\n toast({ title: \"Losgekoppeld\", description: \"Dit is nu een losse kopie.\", tone: \"success\" });\n }\n async function remove(i: number) {\n const ok = await confirm({ title: \"Blok verwijderen?\", confirmLabel: \"Verwijderen\", tone: \"danger\" });\n if (!ok) return;\n const removed = blocks[i];\n setBlocks(blocks.filter((_, idx) => idx !== i));\n if (selectedKey === removed._key) setSelectedKey(null);\n }\n function addBlock(type: string) {\n const def = registry.get(type);\n const base = def?.defaults?.() ?? {};\n const block = { _key: newKey(), _type: type, ...base } as Block;\n insertAfterSelected([block]);\n setSelectedKey(block._key);\n }\n function insertAfterSelected(newBlocks: Array<Record<string, unknown>>) {\n const sel = blocks.findIndex((b) => b._key === selectedKey);\n const copy = [...blocks];\n copy.splice(sel >= 0 ? sel + 1 : blocks.length, 0, ...(newBlocks as Block[]));\n setBlocks(copy);\n }\n\n async function onPublish() {\n // Zie flushSave: een veld dat pas op blur committeert (JSON-redmiddel) moet die commit eerst\n // nog doen — anders publiceert dit de stand van vóór de laatste bewerking.\n (document.activeElement as HTMLElement | null)?.blur();\n const d = draftRef.current;\n if (!d) return;\n // Openstaand conflict eerst oplossen: publiceren zou anders een stale merge live zetten.\n if (conflict) {\n toast({ title: \"Los eerst het conflict op\", description: \"Kies 'Nieuwste versie laden' of 'Mijn versie behouden' in de gele balk.\", tone: \"error\" });\n return;\n }\n const ok = await confirm({ title: \"Pagina publiceren?\", description: `De live site wordt bijgewerkt (${d.path}).`, confirmLabel: \"Publiceren\" });\n if (!ok) return;\n setPublishing(true);\n try {\n await saveDraft(siteId, d.id, draftPayload(d));\n await publishPage(siteId, d.id);\n toast({\n title: \"Gepubliceerd\",\n description: \"Zelf zie je de nieuwe tekst meteen. Voor overige bezoekers duurt het nog ongeveer 15 minuten.\",\n tone: \"success\",\n });\n } catch (e) {\n toast({ title: \"Publiceren mislukt\", description: (e as Error).message, tone: \"error\" });\n } finally {\n setPublishing(false);\n }\n }\n\n const addOptions = useMemo(() => buildBlockAddOptions(registry.values()), [registry]);\n\n const selectedIndex = blocks.findIndex((b) => b._key === selectedKey);\n const selected = selectedIndex >= 0 ? blocks[selectedIndex] : null;\n const canUndo = historyRef.current.past.length > 0;\n const canRedo = historyRef.current.future.length > 0;\n\n /** Laad de nieuwste (remote) versie in de editor — bij een gedetecteerd conflict. */\n const reloadRemote = useCallback(async () => {\n const remote = await getDraftByPath(siteId, path).catch(() => null);\n if (remote) {\n mutateDraft(() => remote);\n lastSavedRef.current = stableStringify(draftPayload(remote));\n dirtyRef.current = false;\n setStatus(\"idle\");\n }\n setConflict(false);\n }, [siteId, path, mutateDraft]);\n\n return (\n <div ref={containerRef} className=\"xicms-ve__shell\" role=\"dialog\" aria-modal=\"true\" aria-label={`Pagina bewerken: ${path}`}>\n <header className=\"xicms-ve__bar\">\n <strong className=\"xicms-ve__title\">Bewerken · {name}</strong>\n <span className=\"xicms-ve__path\">{path}</span>\n {localeCfg.locales.length > 1 && (\n <span className=\"xicms-ve__locale\" title=\"Taal — in een andere taal dan de standaard bewerk je vertalingen\">\n 🌐\n <Select\n value={locale}\n onValueChange={setLocale}\n options={localeCfg.locales.map((l) => ({ value: l, label: l === localeCfg.defaultLocale ? `${l} (standaard)` : l }))}\n />\n </span>\n )}\n <button type=\"button\" className=\"xicms-ve__histbtn\" disabled={!canUndo} onClick={undo} title=\"Ongedaan maken (Ctrl+Z)\" aria-label=\"Ongedaan maken (Ctrl+Z)\">↶</button>\n <button type=\"button\" className=\"xicms-ve__histbtn\" disabled={!canRedo} onClick={redo} title=\"Opnieuw (Ctrl+Shift+Z)\" aria-label=\"Opnieuw (Ctrl+Shift+Z)\">↷</button>\n <span className=\"xicms-ve__status\" aria-live=\"polite\">\n {status === \"saving\" ? \"Opslaan…\" : status === \"saved\" ? \"✓ Opgeslagen\" : status === \"error\" ? \"⚠ Niet opgeslagen\" : \"\"}\n </span>\n {status === \"error\" && (\n <Button size=\"sm\" variant=\"secondary\" onClick={() => void flushSave().catch(() => setStatus(\"error\"))}>\n Opnieuw opslaan\n </Button>\n )}\n <div className=\"xicms-ve__bar-actions\">\n <Button size=\"sm\" disabled={publishing || !draft} onClick={onPublish}>\n {publishing ? \"Bezig…\" : \"Publiceren\"}\n </Button>\n <Button size=\"sm\" variant=\"secondary\" onClick={handleClose}>Sluiten</Button>\n </div>\n </header>\n\n {conflict && (\n <div className=\"xicms-ve__conflict\" role=\"alert\">\n <span>⚠ Deze pagina is intussen ergens anders gewijzigd (andere tab of collega). Doorwerken kan die wijzigingen overschrijven.</span>\n <Button size=\"sm\" onClick={() => void reloadRemote()}>Nieuwste versie laden</Button>\n <Button size=\"sm\" variant=\"secondary\" onClick={() => setConflict(false)}>Mijn versie behouden</Button>\n </div>\n )}\n\n <div className=\"xicms-ve__body\">\n <main className=\"xicms-ve__canvas xicms-root\" data-dark={darkAuto ? \"auto\" : undefined} style={themeVars as React.CSSProperties}>\n {status === \"loading\" && <p className=\"xicms-ve__hint\">Laden…</p>}\n {status === \"none\" && (\n <div className=\"xicms-ve__empty\">\n <EmptyState\n icon=\"📄\"\n title=\"Geen werkversie gevonden\"\n description={`Voor deze pagina (${path}) bestaat nog geen werkversie. Maak hem hier direct aan, of ga naar /beheer → Pagina's.`}\n />\n <p style={{ textAlign: \"center\", marginTop: \"1rem\" }}>\n <button type=\"button\" className=\"xicms-btn\" onClick={() => void handleCreatePage()}>\n + Deze pagina aanmaken\n </button>\n </p>\n </div>\n )}\n {draft && (\n <div className=\"container\" ref={canvasRef}>\n {blocks.length === 0 && (\n <EmptyState icon=\"🧱\" title=\"Nog geen blokken\" description=\"Voeg hieronder je eerste blok toe.\" />\n )}\n {displayBlocks.map((b, i) => {\n const def = registry.get(b._type);\n const Render = def?.Render;\n // Coerce via het schema zodat defaults zijn toegepast (zoals de live pagina via\n // validateBlocks doet). Ruwe drafts missen anders defaults (bv. hero.buttons) en\n // zouden de Render laten throwen. Lukt het parsen niet, val terug op het ruwe blok\n // (de error-boundary hieronder vangt een eventuele fout dan netjes op).\n const safe = (() => {\n const parsed = def?.schema ? safeParse(def.schema, b) : undefined;\n return parsed?.success ? (parsed.data as Block) : b;\n })();\n const dropClass = dropIndex === i ? \" is-drop-before\" : dropIndex === i + 1 ? \" is-drop-after\" : \"\";\n return (\n <div\n key={b._key}\n className={`xicms-ve-block${b._key === selectedKey ? \" is-selected\" : \"\"}${dragIndex === i ? \" is-dragging\" : \"\"}${dropClass}`}\n onDragOver={(e) => {\n if (dragIndex === null) return;\n e.preventDefault();\n e.dataTransfer.dropEffect = \"move\";\n const rect = e.currentTarget.getBoundingClientRect();\n setDropIndex(e.clientY < rect.top + rect.height / 2 ? i : i + 1);\n }}\n onDrop={(e) => {\n if (dragIndex === null || dropIndex === null) return;\n e.preventDefault();\n setBlocks(reorderBlocks(blocks, dragIndex, dropIndex));\n endDrag();\n }}\n >\n <div className=\"xicms-ve-block__toolbar\">\n {/* Sleep-greep: apart element (niet het hele blok) zodat slepen nooit botst met\n het inline contentEditable-bewerken; ↑/↓ blijven het toetsenbord-alternatief. */}\n <button\n type=\"button\"\n className=\"xicms-ve-block__drag\"\n draggable\n onDragStart={(e) => {\n draggingRef.current = true;\n setDragIndex(i);\n e.dataTransfer.effectAllowed = \"move\";\n e.dataTransfer.setData(\"text/plain\", String(i));\n const blockEl = e.currentTarget.closest(\".xicms-ve-block\");\n if (blockEl) e.dataTransfer.setDragImage(blockEl, 24, 24);\n }}\n onDragEnd={endDrag}\n aria-label={`Versleep ${def?.label ?? b._type}`}\n title=\"Slepen om te verplaatsen\"\n >\n ⋮⋮\n </button>\n <span className=\"xicms-ve-block__label\">{def?.label ?? b._type}</span>\n <button type=\"button\" onClick={() => setSelectedKey(b._key)} aria-label={`Bewerk ${def?.label ?? b._type}`} title=\"Bewerken\">✏️</button>\n <button type=\"button\" disabled={i === 0} onClick={() => move(i, -1)} aria-label=\"Omhoog\">↑</button>\n <button type=\"button\" disabled={i === blocks.length - 1} onClick={() => move(i, 1)} aria-label=\"Omlaag\">↓</button>\n {b._type === \"symbolRef\" && (\n <button type=\"button\" onClick={() => void detachSymbol(i)} aria-label=\"Symbool loskoppelen\" title=\"Loskoppelen (losse kopie)\">🔗✂</button>\n )}\n <button type=\"button\" onClick={() => duplicate(i)} aria-label=\"Dupliceren\">⎘</button>\n <button type=\"button\" onClick={() => void remove(i)} aria-label=\"Verwijderen\">🗑</button>\n </div>\n {/* Altijd renderen (geen conditie) → geen remount van de inhoud bij selecteren,\n anders verliest het inline-bewerken zijn contentEditable. Bij selectie zet de\n CSS deze overlay op pointer-events:none zodat je de tekst kunt bewerken. */}\n <button type=\"button\" className=\"xicms-ve-block__select\" aria-label={`Selecteer ${def?.label ?? b._type}`} onClick={() => setSelectedKey(b._key)} />\n <div className=\"xicms-ve-block__content\" data-ve-content={b._key}>\n {/* Net als BlockRenderer: elk blok in een per-blok error-boundary zodat één\n falend (maatwerk-)blok de hele editor niet blank maakt. mode=\"preview\". */}\n {Render ? (\n <BlockErrorBoundary mode=\"preview\" type={b._type} blockKey={b._key}>\n {/* Alleen het geselecteerde blok krijgt de inline beeld-vervangen-overlay. */}\n <InlineImageEditProvider onReplace={b._key === selectedKey ? (field) => setImgPicker({ key: b._key, field }) : null}>\n <Render block={safe} siteId={siteId} mode=\"preview\" />\n </InlineImageEditProvider>\n </BlockErrorBoundary>\n ) : (\n <p className=\"xicms-ve__hint\">Onbekend blok: {b._type}</p>\n )}\n </div>\n </div>\n );\n })}\n <div className=\"xicms-ve__inserter\">\n <span>Toevoegen{selected ? \" (na selectie)\" : \"\"}:</span>\n <div className=\"xicms-ve__inserter-select\">\n <Select value=\"\" placeholder=\"Kies een blok…\" onValueChange={(v) => v && addBlock(v)} options={addOptions} />\n </div>\n <PatternInserter onInsert={insertAfterSelected} />\n </div>\n </div>\n )}\n </main>\n\n <aside className=\"xicms-ve__panel\">\n {selected && isTranslating ? (\n <div className=\"grid gap-3\">\n <h3 className=\"text-sm font-semibold\">{registry.get(selected._type)?.label ?? selected._type} — vertaling ({locale})</h3>\n <TranslationPanel\n key={`${selected._key}:${locale}`}\n block={selected}\n siteId={siteId}\n registry={registry}\n locale={locale}\n overlay={overlay ?? {}}\n onTranslate={setTranslation}\n />\n </div>\n ) : selected ? (\n <div className=\"grid gap-3\">\n <div className=\"xicms-ve__panel-head\">\n {/* Kleur volgt de autosave-status (zelfde bron als de statustekst in de topbalk):\n blauw = nog niet-opgeslagen wijziging (of een mislukte save die opnieuw moet),\n grijs = alles staat al veilig. Directe visuele bevestiging i.p.v. alleen tekst. */}\n <button\n type=\"button\"\n className={`xicms-btn${status === \"saving\" || status === \"error\" ? \"\" : \" xicms-btn--ghost\"}`}\n onClick={() => void flushSave().catch(() => setStatus(\"error\"))}\n >\n {status === \"saving\" ? \"Opslaan…\" : status === \"error\" ? \"⚠ Opnieuw opslaan\" : \"✓ Opgeslagen\"}\n </button>\n <button type=\"button\" className=\"xicms-btn xicms-btn--ghost\" onClick={() => setSelectedKey(null)}>\n ✕ Sluiten\n </button>\n </div>\n <SelectedEditor key={selected._key} block={selected} siteId={siteId} registry={registry} onChange={(next) => updateByKey(selected._key, next)} />\n </div>\n ) : draft && isTranslating ? (\n <div className=\"grid gap-4\">\n <p className=\"xicms-ve__hint\">\n Je bewerkt de vertaling <strong>{locale}</strong>. Klik op een blok om zijn teksten te\n vertalen; lege velden vallen terug op de standaardtaal. Blokken toevoegen/verplaatsen\n doe je in de standaardtaal.\n </p>\n <PageTranslationSettings draft={draft} locale={locale} onTranslate={setTranslation} />\n </div>\n ) : draft ? (\n <div className=\"grid gap-4\">\n <p className=\"xicms-ve__hint\">Klik op een blok om het te bewerken.</p>\n <PageSettings draft={draft} onChange={(part) => mutateDraft((d) => ({ ...d, ...part }), { coalesce: true })} />\n {!isDemoActive() && (\n <VersionsPanel\n siteId={siteId}\n pageId={draft.id}\n onRestore={(restored) => {\n mutateDraft((d) => ({ ...d, ...restored }));\n toast({ title: \"Versie hersteld naar werkversie\", description: \"Publiceer om hem live te zetten.\", tone: \"success\" });\n }}\n />\n )}\n </div>\n ) : (\n <p className=\"xicms-ve__hint\">Klik op een blok om het te bewerken.</p>\n )}\n </aside>\n </div>\n\n {/* Inline afbeelding vervangen: opent de mediabibliotheek; alleen de URL van het veld wordt gezet. */}\n <MediaPickerDialog\n siteId={siteId}\n open={!!imgPicker}\n onOpenChange={(v) => { if (!v) setImgPicker(null); }}\n onSelect={(m) => {\n if (imgPicker) {\n commitInline(imgPicker.key, imgPicker.field, m.url);\n // Alt-tekst van de gekozen media meenemen (a11y/SEO): conventie url→alt / imageUrl→alt\n // op hetzelfde niveau. Bestaat het veld niet in het schema, dan stript Zod het bij\n // publiceren — nooit schadelijk, meestal precies goed (Image/Gallery/Cards/Slider).\n const altField = imgPicker.field.replace(/(^|\\.)((image)?[uU]rl)$/, \"$1alt\");\n if (altField !== imgPicker.field) commitInline(imgPicker.key, altField, m.alt ?? \"\");\n }\n setImgPicker(null);\n }}\n />\n\n {/* Zwevende opmaak-toolbar boven het gefocuste inline rich-text-veld. onMouseDown-preventDefault\n houdt focus + selectie in het veld, zodat execCommand op de selectie werkt. */}\n {fmtBar && (\n <div className=\"xicms-ve-fmtbar\" style={{ top: fmtBar.top, left: fmtBar.left }} role=\"toolbar\" aria-label=\"Tekstopmaak\">\n <FmtBtn label={<b>B</b>} title=\"Vet (Ctrl/Cmd+B)\" onRun={() => document.execCommand(\"bold\")} />\n <FmtBtn label={<i>I</i>} title=\"Cursief (Ctrl/Cmd+I)\" onRun={() => document.execCommand(\"italic\")} />\n <FmtBtn label={<u>U</u>} title=\"Onderstrepen (Ctrl/Cmd+U)\" onRun={() => document.execCommand(\"underline\")} />\n <FmtBtn\n label=\"🔗\"\n title=\"Link (selecteer eerst tekst; leeg = link verwijderen)\"\n onRun={() => {\n const url = window.prompt(\"Link-URL (leeg = link verwijderen)\", \"https://\");\n if (url === null) return;\n if (url === \"\" || url === \"https://\") document.execCommand(\"unlink\");\n else document.execCommand(\"createLink\", false, url);\n }}\n />\n <span className=\"xicms-ve-fmtbar__sep\" aria-hidden />\n <FmtBtn label=\"H2\" title=\"Grote kop\" onRun={() => document.execCommand(\"formatBlock\", false, \"<h2>\")} />\n <FmtBtn label=\"H3\" title=\"Kleine kop\" onRun={() => document.execCommand(\"formatBlock\", false, \"<h3>\")} />\n <FmtBtn label=\"¶\" title=\"Normale tekst\" onRun={() => document.execCommand(\"formatBlock\", false, \"<p>\")} />\n <span className=\"xicms-ve-fmtbar__sep\" aria-hidden />\n <FmtBtn label=\"•\" title=\"Opsomming\" onRun={() => document.execCommand(\"insertUnorderedList\")} />\n </div>\n )}\n </div>\n );\n}\n\n/** Toolbar-knop die de selectie/focus in het contentEditable-veld intact laat. */\nfunction FmtBtn({ label, title, onRun }: { label: React.ReactNode; title: string; onRun: () => void }) {\n return (\n <button\n type=\"button\"\n title={title}\n aria-label={title}\n onMouseDown={(e) => e.preventDefault()}\n onClick={onRun}\n >\n {label}\n </button>\n );\n}\n\n/**\n * Pagina-instellingen (titel + SEO) direct in de visuele editor — de klant hoeft niet meer naar\n * /beheer voor een titel- of meta-omschrijving-wijziging. Slug/pad blijven bewust in /beheer\n * (die raken URL-structuur en zijn niet iets om per ongeluk inline aan te passen).\n */\nfunction PageSettings({\n draft,\n onChange,\n}: {\n draft: DraftPage;\n onChange: (part: Partial<DraftPage>) => void;\n}) {\n const seo = draft.seo ?? {};\n return (\n <details className=\"xicms-ve__section\" open>\n <summary className=\"text-sm font-semibold\">Pagina-instellingen</summary>\n <div className=\"mt-2 grid gap-3\">\n <Field label=\"Paginatitel\">\n <Input value={draft.title ?? \"\"} onChange={(e) => onChange({ title: e.target.value })} />\n </Field>\n <Field label=\"SEO-titel\" hint=\"Leeg = paginatitel\">\n <Input value={seo.title ?? \"\"} onChange={(e) => onChange({ seo: { ...seo, title: e.target.value } })} />\n </Field>\n <Field label=\"SEO-omschrijving\" hint=\"Wordt getoond in zoekresultaten\">\n <Textarea rows={3} value={seo.description ?? \"\"} onChange={(e) => onChange({ seo: { ...seo, description: e.target.value } })} />\n </Field>\n </div>\n </details>\n );\n}\n\n/** Pagina-instellingen in vertaalmodus (5.0): titel + SEO als overlay-sleutels. */\nfunction PageTranslationSettings({\n draft,\n locale,\n onTranslate,\n}: {\n draft: DraftPage;\n locale: string;\n onTranslate: (key: string, value: string) => void;\n}) {\n const ov = draft.translations?.[locale] ?? {};\n return (\n <details className=\"xicms-ve__section\" open>\n <summary className=\"text-sm font-semibold\">Pagina-instellingen ({locale})</summary>\n <div className=\"mt-2 grid gap-3\">\n <Field label=\"Paginatitel\" hint={`Origineel: ${draft.title ?? \"\"}`}>\n <Input value={ov[\"title\"] ?? \"\"} placeholder={draft.title ?? \"\"} onChange={(e) => onTranslate(\"title\", e.target.value)} />\n </Field>\n <Field label=\"SEO-titel\">\n <Input value={ov[\"seo.title\"] ?? \"\"} placeholder={draft.seo?.title ?? \"\"} onChange={(e) => onTranslate(\"seo.title\", e.target.value)} />\n </Field>\n <Field label=\"SEO-omschrijving\">\n <Textarea rows={3} value={ov[\"seo.description\"] ?? \"\"} placeholder={draft.seo?.description ?? \"\"} onChange={(e) => onTranslate(\"seo.description\", e.target.value)} />\n </Field>\n </div>\n </details>\n );\n}\n\n/** Versiegeschiedenis in de visuele editor: herstellen zet een snapshot terug naar de WERKVERSIE. */\nfunction VersionsPanel({\n siteId,\n pageId,\n onRestore,\n}: {\n siteId: string;\n pageId: string;\n onRestore: (restored: Partial<DraftPage>) => void;\n}) {\n const [versions, setVersions] = useState<{ id: string; createdAt?: unknown; kind?: string; label?: string }[]>([]);\n const { toast } = useToast();\n const confirm = useConfirm();\n useEffect(() => subscribeVersions(siteId, pageId, setVersions), [siteId, pageId]);\n if (versions.length === 0) return null;\n\n const restore = async (versionId: string) => {\n const ok = await confirm({\n title: \"Versie herstellen?\",\n description: \"De snapshot vervangt je huidige werkversie (ongedaan te maken met Ctrl+Z). De live site verandert pas bij Publiceren.\",\n confirmLabel: \"Herstellen\",\n });\n if (!ok) return;\n try {\n const restored = await restoreVersion(siteId, pageId, versionId);\n onRestore(restored);\n } catch (e) {\n toast({ title: \"Herstellen mislukt\", description: (e as Error).message, tone: \"error\" });\n }\n };\n\n return (\n <details className=\"xicms-ve__section\">\n <summary className=\"text-sm font-semibold\">Versiegeschiedenis</summary>\n <ul className=\"mt-2 grid gap-1 text-sm\">\n {versions.slice(0, 10).map((v) => (\n <li key={v.id} className=\"flex items-center justify-between gap-2\">\n <span>\n {v.label ?? (v.kind === \"publish\" ? \"Gepubliceerd\" : v.kind ?? \"Snapshot\")}\n {formatVersionDate(v.createdAt) && <span className=\"text-slate-400\"> · {formatVersionDate(v.createdAt)}</span>}\n </span>\n <Button variant=\"ghost\" size=\"sm\" onClick={() => void restore(v.id)}>\n Herstellen\n </Button>\n </li>\n ))}\n </ul>\n </details>\n );\n}\n\nfunction formatVersionDate(createdAt: unknown): string {\n const date =\n createdAt && typeof (createdAt as { toDate?: () => Date }).toDate === \"function\"\n ? (createdAt as { toDate: () => Date }).toDate()\n : typeof createdAt === \"string\"\n ? new Date(createdAt)\n : null;\n return date && !Number.isNaN(date.getTime()) ? date.toLocaleString(\"nl-NL\", { dateStyle: \"short\", timeStyle: \"short\" }) : \"\";\n}\n\nfunction SelectedEditor({\n block,\n siteId,\n registry,\n onChange,\n}: {\n block: Block;\n siteId: string;\n registry: ReturnType<typeof useRegistry>;\n onChange: (next: Record<string, unknown>) => void;\n}) {\n const def = registry.get(block._type);\n const Editor: ComponentType<BlockEditorProps> =\n (def?.Editor as ComponentType<BlockEditorProps> | undefined) ?? builtinBlockEditors[block._type] ?? GenericEditor;\n return (\n <div className=\"grid gap-3\">\n <h3 className=\"text-sm font-semibold\">{def?.label ?? block._type}</h3>\n {/* Maatwerk-Editors kunnen falen → vang per-blok op zodat het paneel niet leeg wordt. */}\n <BlockErrorBoundary mode=\"preview\" type={block._type} blockKey={block._key}>\n <Editor block={block} siteId={siteId} onChange={onChange} />\n </BlockErrorBoundary>\n <StyleEditor\n value={block._style as BlockStyle | undefined}\n onChange={(style) => onChange({ ...block, _style: style })}\n />\n </div>\n );\n}\n"],"mappings":"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","names":["locale","overlay","t","inField"]}
|
package/dist/admin.css
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.xicms-admin .visible{visibility:visible}.xicms-admin .static{position:static}.xicms-admin .fixed{position:fixed}.xicms-admin .absolute{position:absolute}.xicms-admin .relative{position:relative}.xicms-admin .sticky{position:sticky}.xicms-admin .inset-0{inset:0}.xicms-admin .-right-2{right:-.5rem}.xicms-admin .-top-2{top:-.5rem}.xicms-admin .z-\[10010\]{z-index:10010}.xicms-admin .mb-1{margin-bottom:.25rem}.xicms-admin .mb-2{margin-bottom:.5rem}.xicms-admin .mb-3{margin-bottom:.75rem}.xicms-admin .ml-1{margin-left:.25rem}.xicms-admin .ml-auto{margin-left:auto}.xicms-admin .mr-1{margin-right:.25rem}.xicms-admin .mr-2{margin-right:.5rem}.xicms-admin .mt-0\.5{margin-top:.125rem}.xicms-admin .mt-1{margin-top:.25rem}.xicms-admin .mt-2{margin-top:.5rem}.xicms-admin .mt-3{margin-top:.75rem}.xicms-admin .mt-4{margin-top:1rem}.xicms-admin .mt-5{margin-top:1.25rem}.xicms-admin .mt-6{margin-top:1.5rem}.xicms-admin .\!block{display:block!important}.xicms-admin .block{display:block}.xicms-admin .inline{display:inline}.xicms-admin .flex{display:flex}.xicms-admin .inline-flex{display:inline-flex}.xicms-admin .table{display:table}.xicms-admin .grid{display:grid}.xicms-admin .hidden{display:none}.xicms-admin .aspect-square{aspect-ratio:1/1}.xicms-admin .h-10{height:2.5rem}.xicms-admin .h-14{height:3.5rem}.xicms-admin .h-16{height:4rem}.xicms-admin .h-28{height:7rem}.xicms-admin .h-32{height:8rem}.xicms-admin .h-5{height:1.25rem}.xicms-admin .h-6{height:1.5rem}.xicms-admin .h-8{height:2rem}.xicms-admin .h-9{height:2.25rem}.xicms-admin .h-\[70vh\]{height:70vh}.xicms-admin .h-fit{height:-moz-fit-content;height:fit-content}.xicms-admin .max-h-\[55vh\]{max-height:55vh}.xicms-admin .max-h-\[60vh\]{max-height:60vh}.xicms-admin .min-h-\[8rem\]{min-height:8rem}.xicms-admin .w-14{width:3.5rem}.xicms-admin .w-16{width:4rem}.xicms-admin .w-20{width:5rem}.xicms-admin .w-24{width:6rem}.xicms-admin .w-28{width:7rem}.xicms-admin .w-32{width:8rem}.xicms-admin .w-36{width:9rem}.xicms-admin .w-5{width:1.25rem}.xicms-admin .w-56{width:14rem}.xicms-admin .w-6{width:1.5rem}.xicms-admin .w-8{width:2rem}.xicms-admin .w-fit{width:-moz-fit-content;width:fit-content}.xicms-admin .w-full{width:100%}.xicms-admin .min-w-0{min-width:0}.xicms-admin .min-w-8{min-width:2rem}.xicms-admin .max-w-2xl{max-width:42rem}.xicms-admin .max-w-3xl{max-width:48rem}.xicms-admin .max-w-xl{max-width:36rem}.xicms-admin .max-w-xs{max-width:20rem}.xicms-admin .flex-1{flex:1 1 0%}.xicms-admin .shrink-0{flex-shrink:0}.xicms-admin .-translate-x-1\/2{--tw-translate-x:-50%}.xicms-admin .-translate-x-1\/2,.xicms-admin .transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.xicms-admin .cursor-pointer{cursor:pointer}.xicms-admin .resize{resize:both}.xicms-admin .list-decimal{list-style-type:decimal}.xicms-admin .list-disc{list-style-type:disc}.xicms-admin .grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.xicms-admin .grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.xicms-admin .grid-cols-\[120px_1fr\]{grid-template-columns:120px 1fr}.xicms-admin .flex-col{flex-direction:column}.xicms-admin .flex-wrap{flex-wrap:wrap}.xicms-admin .place-items-center{place-items:center}.xicms-admin .items-start{align-items:flex-start}.xicms-admin .items-end{align-items:flex-end}.xicms-admin .items-center{align-items:center}.xicms-admin .justify-end{justify-content:flex-end}.xicms-admin .justify-center{justify-content:center}.xicms-admin .justify-between{justify-content:space-between}.xicms-admin .gap-0\.5{gap:.125rem}.xicms-admin .gap-1{gap:.25rem}.xicms-admin .gap-1\.5{gap:.375rem}.xicms-admin .gap-2{gap:.5rem}.xicms-admin .gap-3{gap:.75rem}.xicms-admin .gap-4{gap:1rem}.xicms-admin .gap-6{gap:1.5rem}.xicms-admin .self-end{align-self:flex-end}.xicms-admin .self-center{align-self:center}.xicms-admin .overflow-auto{overflow:auto}.xicms-admin .overflow-hidden{overflow:hidden}.xicms-admin .overflow-x-auto{overflow-x:auto}.xicms-admin .overflow-y-auto{overflow-y:auto}.xicms-admin .truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.xicms-admin .whitespace-pre-wrap{white-space:pre-wrap}.xicms-admin .rounded{border-radius:.25rem}.xicms-admin .rounded-full{border-radius:9999px}.xicms-admin .rounded-lg{border-radius:.5rem}.xicms-admin .rounded-md{border-radius:.375rem}.xicms-admin .rounded-xl{border-radius:.75rem}.xicms-admin .rounded-b-lg{border-bottom-right-radius:.5rem;border-bottom-left-radius:.5rem}.xicms-admin .rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.xicms-admin .rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.xicms-admin .border{border-width:1px}.xicms-admin .border-b{border-bottom-width:1px}.xicms-admin .border-t{border-top-width:1px}.xicms-admin .border-t-0{border-top-width:0}.xicms-admin .border-amber-300{--tw-border-opacity:1;border-color:rgb(252 211 77/var(--tw-border-opacity,1))}.xicms-admin .border-brand-500{border-color:var(--xicms-primary,#4f46e5)}.xicms-admin .border-red-200{--tw-border-opacity:1;border-color:rgb(254 202 202/var(--tw-border-opacity,1))}.xicms-admin .border-slate-100{--tw-border-opacity:1;border-color:rgb(241 245 249/var(--tw-border-opacity,1))}.xicms-admin .border-slate-200{--tw-border-opacity:1;border-color:rgb(226 232 240/var(--tw-border-opacity,1))}.xicms-admin .border-slate-300{--tw-border-opacity:1;border-color:rgb(203 213 225/var(--tw-border-opacity,1))}.xicms-admin .bg-amber-50{--tw-bg-opacity:1;background-color:rgb(255 251 235/var(--tw-bg-opacity,1))}.xicms-admin .bg-black\/50{background-color:rgba(0,0,0,.5)}.xicms-admin .bg-brand-50{background-color:color-mix(in srgb,var(--xicms-primary,#4f46e5) 12%,#fff)}.xicms-admin .bg-brand-500{background-color:var(--xicms-primary,#4f46e5)}.xicms-admin .bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.xicms-admin .bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.xicms-admin .bg-slate-200{--tw-bg-opacity:1;background-color:rgb(226 232 240/var(--tw-bg-opacity,1))}.xicms-admin .bg-slate-50{--tw-bg-opacity:1;background-color:rgb(248 250 252/var(--tw-bg-opacity,1))}.xicms-admin .bg-slate-700{--tw-bg-opacity:1;background-color:rgb(51 65 85/var(--tw-bg-opacity,1))}.xicms-admin .bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.xicms-admin .object-cover{-o-object-fit:cover;object-fit:cover}.xicms-admin .p-0\.5{padding:.125rem}.xicms-admin .p-1{padding:.25rem}.xicms-admin .p-2{padding:.5rem}.xicms-admin .p-3{padding:.75rem}.xicms-admin .p-4{padding:1rem}.xicms-admin .p-5{padding:1.25rem}.xicms-admin .p-6{padding:1.5rem}.xicms-admin .px-1{padding-left:.25rem;padding-right:.25rem}.xicms-admin .px-2{padding-left:.5rem;padding-right:.5rem}.xicms-admin .px-3{padding-left:.75rem;padding-right:.75rem}.xicms-admin .px-4{padding-left:1rem;padding-right:1rem}.xicms-admin .py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.xicms-admin .py-1{padding-top:.25rem;padding-bottom:.25rem}.xicms-admin .py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.xicms-admin .py-2{padding-top:.5rem;padding-bottom:.5rem}.xicms-admin .py-3{padding-top:.75rem;padding-bottom:.75rem}.xicms-admin .py-8{padding-top:2rem;padding-bottom:2rem}.xicms-admin .pl-5{padding-left:1.25rem}.xicms-admin .pr-2{padding-right:.5rem}.xicms-admin .pt-4{padding-top:1rem}.xicms-admin .pt-5{padding-top:1.25rem}.xicms-admin .text-left{text-align:left}.xicms-admin .text-center{text-align:center}.xicms-admin .text-right{text-align:right}.xicms-admin .align-top{vertical-align:top}.xicms-admin .font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.xicms-admin .text-3xl{font-size:1.875rem;line-height:2.25rem}.xicms-admin .text-\[11px\]{font-size:11px}.xicms-admin .text-base{font-size:1rem;line-height:1.5rem}.xicms-admin .text-lg{font-size:1.125rem;line-height:1.75rem}.xicms-admin .text-sm{font-size:.875rem;line-height:1.25rem}.xicms-admin .text-xl{font-size:1.25rem;line-height:1.75rem}.xicms-admin .text-xs{font-size:.75rem;line-height:1rem}.xicms-admin .font-bold{font-weight:700}.xicms-admin .font-medium{font-weight:500}.xicms-admin .font-semibold{font-weight:600}.xicms-admin .uppercase{text-transform:uppercase}.xicms-admin .italic{font-style:italic}.xicms-admin .tracking-wide{letter-spacing:.025em}.xicms-admin .text-amber-600{--tw-text-opacity:1;color:rgb(217 119 6/var(--tw-text-opacity,1))}.xicms-admin .text-amber-700{--tw-text-opacity:1;color:rgb(180 83 9/var(--tw-text-opacity,1))}.xicms-admin .text-amber-800{--tw-text-opacity:1;color:rgb(146 64 14/var(--tw-text-opacity,1))}.xicms-admin .text-brand-700{color:color-mix(in srgb,var(--xicms-primary,#4f46e5) 82%,#000)}.xicms-admin .text-red-600{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity,1))}.xicms-admin .text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity,1))}.xicms-admin .text-slate-400{--tw-text-opacity:1;color:rgb(148 163 184/var(--tw-text-opacity,1))}.xicms-admin .text-slate-500{--tw-text-opacity:1;color:rgb(100 116 139/var(--tw-text-opacity,1))}.xicms-admin .text-slate-600{--tw-text-opacity:1;color:rgb(71 85 105/var(--tw-text-opacity,1))}.xicms-admin .text-slate-700{--tw-text-opacity:1;color:rgb(51 65 85/var(--tw-text-opacity,1))}.xicms-admin .text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.xicms-admin .underline{text-decoration-line:underline}.xicms-admin .line-through{text-decoration-line:line-through}.xicms-admin .opacity-70{opacity:.7}.xicms-admin .shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.xicms-admin .shadow-sm,.xicms-admin .shadow-xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.xicms-admin .shadow-xl{--tw-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color)}.xicms-admin .outline-none{outline:2px solid transparent;outline-offset:2px}.xicms-admin .outline{outline-style:solid}.xicms-admin .blur{--tw-blur:blur(8px)}.xicms-admin .blur,.xicms-admin .filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.xicms-admin .transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.xicms-admin .transition-\[filter\]{transition-property:filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.xicms-admin,.xicms-admin *,.xicms-admin :after,.xicms-admin :before{box-sizing:border-box}.xicms-admin{font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;color:#0f172a;line-height:1.5;-webkit-font-smoothing:antialiased;color-scheme:light;background:#fff;--color-background-body:#fff;--color-background-surface:#fff;--color-background-card:#fff;--color-background-muted:#f1f5f9;--color-text-primary:#0f172a;--color-text-secondary:#475569;--color-border:#e2e8f0;--color-accent:#4f46e5;--color-on-accent:#fff;--color-error:#dc2626}.xicms-admin figure,.xicms-admin h1,.xicms-admin h2,.xicms-admin h3,.xicms-admin p{margin:0}.xicms-admin button{font:inherit;cursor:pointer}.xicms-admin input,.xicms-admin select,.xicms-admin textarea{font:inherit;color:inherit}.xicms-admin .ProseMirror{min-height:8rem;outline:none}.xicms-admin .ProseMirror p{margin:0 0 .6rem}.xicms-admin .ProseMirror:focus{outline:none}@media (prefers-reduced-motion:reduce){.xicms-admin *,.xicms-admin :after,.xicms-admin :before,.xicms-ve *,.xicms-ve :after,.xicms-ve :before{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}}.xicms-admin .last\:border-0:last-child{border-width:0}.xicms-admin .hover\:border-brand-500:hover{border-color:var(--xicms-primary,#4f46e5)}.xicms-admin .hover\:bg-slate-100:hover{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.xicms-admin .hover\:bg-slate-50:hover{--tw-bg-opacity:1;background-color:rgb(248 250 252/var(--tw-bg-opacity,1))}.xicms-admin .hover\:text-slate-700:hover{--tw-text-opacity:1;color:rgb(51 65 85/var(--tw-text-opacity,1))}.xicms-admin .hover\:text-slate-900:hover{--tw-text-opacity:1;color:rgb(15 23 42/var(--tw-text-opacity,1))}.xicms-admin .hover\:underline:hover{text-decoration-line:underline}.xicms-admin .hover\:brightness-95:hover{--tw-brightness:brightness(.95);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.xicms-admin .focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.xicms-admin .focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.xicms-admin .focus\:ring-indigo-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(99 102 241/var(--tw-ring-opacity,1))}.xicms-admin .focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.xicms-admin .focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.xicms-admin .focus-visible\:ring-brand-500:focus-visible{--tw-ring-color:var(--xicms-primary,#4f46e5)}.xicms-admin .disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.xicms-admin .disabled\:opacity-50:disabled{opacity:.5}.xicms-admin :is(.group:hover .group-hover\:opacity-80){opacity:.8}.xicms-admin .data-\[state\=active\]\:border-b-2[data-state=active]{border-bottom-width:2px}.xicms-admin .data-\[state\=active\]\:border-brand-600[data-state=active]{border-color:var(--xicms-primary,#4f46e5)}.xicms-admin .data-\[state\=active\]\:text-brand-700[data-state=active]{color:color-mix(in srgb,var(--xicms-primary,#4f46e5) 82%,#000)}@media (min-width:640px){.xicms-admin .sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.xicms-admin .sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.xicms-admin .sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media (min-width:768px){.xicms-admin .md\:col-span-5{grid-column:span 5/span 5}.xicms-admin .md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.xicms-admin .md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.xicms-admin .md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.xicms-admin .md\:grid-cols-\[1fr_110px\]{grid-template-columns:1fr 110px}.xicms-admin .md\:grid-cols-\[1fr_130px_90px_110px_auto\]{grid-template-columns:1fr 130px 90px 110px auto}.xicms-admin .md\:grid-cols-\[1fr_1fr_140px_auto_auto\]{grid-template-columns:1fr 1fr 140px auto auto}.xicms-admin .md\:grid-cols-\[260px_1fr\]{grid-template-columns:260px 1fr}.xicms-admin .md\:grid-cols-\[280px_1fr\]{grid-template-columns:280px 1fr}.xicms-admin .md\:grid-cols-\[300px_1fr\]{grid-template-columns:300px 1fr}.xicms-admin .md\:grid-cols-\[340px_1fr\]{grid-template-columns:340px 1fr}}@media (min-width:1024px){.xicms-admin .lg\:col-span-2{grid-column:span 2/span 2}.xicms-admin .lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.xicms-admin .lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}
|
|
1
|
+
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-200:oklch(88.5% .062 18.334);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-600:oklch(66.6% .179 58.318);--color-amber-700:oklch(55.5% .163 48.998);--color-amber-800:oklch(47.3% .137 46.201);--color-indigo-500:oklch(58.5% .233 277.117);--color-slate-50:oklch(98.4% .003 247.858);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-700:oklch(37.2% .044 257.287);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--container-sm:24rem;--container-md:28rem;--container-3xl:48rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--ease-out:cubic-bezier(0, 0, .2, 1);--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--color-brand-50:#eef2ff;--color-brand-500:#4f46e5;--color-brand-600:#4f46e5;--color-brand-700:#3730a3}}@scope(.xicms-admin){@layer utilities{.visible{visibility:visible!important}.absolute{position:absolute!important}.fixed{position:fixed!important}.relative{position:relative!important}.static{position:static!important}.sticky{position:sticky!important}.-top-2{top:calc(var(--spacing) * -2)!important}.top-0{top:0!important}.-right-2{right:calc(var(--spacing) * -2)!important}.z-10{z-index:10!important}.container{width:100%!important}@media (min-width:40rem){.container{max-width:40rem!important}}@media (min-width:48rem){.container{max-width:48rem!important}}@media (min-width:64rem){.container{max-width:64rem!important}}@media (min-width:80rem){.container{max-width:80rem!important}}@media (min-width:96rem){.container{max-width:96rem!important}}.-mx-1{margin-inline:calc(var(--spacing) * -1)!important}.mt-0\.5{margin-top:calc(var(--spacing) * .5)!important}.mt-1{margin-top:var(--spacing)!important}.mt-2{margin-top:calc(var(--spacing) * 2)!important}.mt-3{margin-top:calc(var(--spacing) * 3)!important}.mt-4{margin-top:calc(var(--spacing) * 4)!important}.mt-5{margin-top:calc(var(--spacing) * 5)!important}.mt-6{margin-top:calc(var(--spacing) * 6)!important}.mt-auto{margin-top:auto!important}.mr-1{margin-right:var(--spacing)!important}.mr-2{margin-right:calc(var(--spacing) * 2)!important}.mb-1{margin-bottom:var(--spacing)!important}.mb-2{margin-bottom:calc(var(--spacing) * 2)!important}.mb-3{margin-bottom:calc(var(--spacing) * 3)!important}.mb-4{margin-bottom:calc(var(--spacing) * 4)!important}.ml-1{margin-left:var(--spacing)!important}.ml-auto{margin-left:auto!important}.block{display:block!important}.contents{display:contents!important}.flex{display:flex!important}.grid{display:grid!important}.hidden{display:none!important}.inline{display:inline!important}.inline-block{display:inline-block!important}.inline-flex{display:inline-flex!important}.table{display:table!important}.aspect-square{aspect-ratio:1!important}.h-5{height:calc(var(--spacing) * 5)!important}.h-6{height:calc(var(--spacing) * 6)!important}.h-8{height:calc(var(--spacing) * 8)!important}.h-9{height:calc(var(--spacing) * 9)!important}.h-10{height:calc(var(--spacing) * 10)!important}.h-14{height:calc(var(--spacing) * 14)!important}.h-16{height:calc(var(--spacing) * 16)!important}.h-28{height:calc(var(--spacing) * 28)!important}.h-32{height:calc(var(--spacing) * 32)!important}.h-\[70vh\]{height:70vh!important}.h-fit{height:fit-content!important}.max-h-\[55vh\]{max-height:55vh!important}.max-h-\[60vh\]{max-height:60vh!important}.min-h-\[8rem\]{min-height:8rem!important}.min-h-screen{min-height:100vh!important}.w-5{width:calc(var(--spacing) * 5)!important}.w-6{width:calc(var(--spacing) * 6)!important}.w-8{width:calc(var(--spacing) * 8)!important}.w-14{width:calc(var(--spacing) * 14)!important}.w-16{width:calc(var(--spacing) * 16)!important}.w-20{width:calc(var(--spacing) * 20)!important}.w-24{width:calc(var(--spacing) * 24)!important}.w-28{width:calc(var(--spacing) * 28)!important}.w-32{width:calc(var(--spacing) * 32)!important}.w-36{width:calc(var(--spacing) * 36)!important}.w-56{width:calc(var(--spacing) * 56)!important}.w-fit{width:fit-content!important}.w-full{width:100%!important}.max-w-3xl{max-width:var(--container-3xl)!important}.max-w-md{max-width:var(--container-md)!important}.max-w-sm{max-width:var(--container-sm)!important}.max-w-xs{max-width:var(--container-xs)!important}.min-w-0{min-width:0!important}.min-w-8{min-width:calc(var(--spacing) * 8)!important}.flex-1{flex:1!important}.shrink-0{flex-shrink:0!important}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1)!important;translate:var(--tw-translate-x) var(--tw-translate-y)!important}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)!important}.cursor-pointer{cursor:pointer!important}.resize{resize:both!important}.list-decimal{list-style-type:decimal!important}.list-disc{list-style-type:disc!important}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))!important}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))!important}.grid-cols-\[120px_1fr\]{grid-template-columns:120px 1fr!important}.flex-col{flex-direction:column!important}.flex-wrap{flex-wrap:wrap!important}.place-items-center{place-items:center!important}.items-center{align-items:center!important}.items-end{align-items:flex-end!important}.items-start{align-items:flex-start!important}.justify-between{justify-content:space-between!important}.justify-center{justify-content:center!important}.justify-end{justify-content:flex-end!important}.gap-0\.5{gap:calc(var(--spacing) * .5)!important}.gap-1{gap:var(--spacing)!important}.gap-1\.5{gap:calc(var(--spacing) * 1.5)!important}.gap-2{gap:calc(var(--spacing) * 2)!important}.gap-2\.5{gap:calc(var(--spacing) * 2.5)!important}.gap-3{gap:calc(var(--spacing) * 3)!important}.gap-4{gap:calc(var(--spacing) * 4)!important}.gap-6{gap:calc(var(--spacing) * 6)!important}.self-center{align-self:center!important}.self-end{align-self:flex-end!important}.truncate{text-overflow:ellipsis!important;white-space:nowrap!important;overflow:hidden!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-x-auto{overflow-x:auto!important}.overflow-y-auto{overflow-y:auto!important}.rounded{border-radius:.25rem!important}.rounded-full{border-radius:3.40282e38px!important}.rounded-lg{border-radius:var(--radius-lg)!important}.rounded-md{border-radius:var(--radius-md)!important}.rounded-xl{border-radius:var(--radius-xl)!important}.rounded-t{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-t-lg{border-top-left-radius:var(--radius-lg)!important;border-top-right-radius:var(--radius-lg)!important}.rounded-b-lg{border-bottom-right-radius:var(--radius-lg)!important;border-bottom-left-radius:var(--radius-lg)!important}.border{border-style:var(--tw-border-style)!important;border-width:1px!important}.border-t{border-top-style:var(--tw-border-style)!important;border-top-width:1px!important}.border-t-0{border-top-style:var(--tw-border-style)!important;border-top-width:0!important}.border-b{border-bottom-style:var(--tw-border-style)!important;border-bottom-width:1px!important}.border-amber-300{border-color:var(--color-amber-300)!important}.border-brand-500{border-color:var(--color-brand-500)!important}.border-red-200{border-color:var(--color-red-200)!important}.border-slate-100{border-color:var(--color-slate-100)!important}.border-slate-200{border-color:var(--color-slate-200)!important}.border-slate-300{border-color:var(--color-slate-300)!important}.bg-amber-50{background-color:var(--color-amber-50)!important}.bg-brand-50{background-color:var(--color-brand-50)!important}.bg-brand-500{background-color:var(--color-brand-500)!important}.bg-red-50{background-color:var(--color-red-50)!important}.bg-slate-50{background-color:var(--color-slate-50)!important}.bg-slate-100{background-color:var(--color-slate-100)!important}.bg-slate-200{background-color:var(--color-slate-200)!important}.bg-slate-700{background-color:var(--color-slate-700)!important}.bg-white{background-color:var(--color-white)!important}.object-cover{object-fit:cover!important}.p-0\.5{padding:calc(var(--spacing) * .5)!important}.p-1{padding:var(--spacing)!important}.p-2{padding:calc(var(--spacing) * 2)!important}.p-3{padding:calc(var(--spacing) * 3)!important}.p-4{padding:calc(var(--spacing) * 4)!important}.p-5{padding:calc(var(--spacing) * 5)!important}.p-6{padding:calc(var(--spacing) * 6)!important}.px-1{padding-inline:var(--spacing)!important}.px-2{padding-inline:calc(var(--spacing) * 2)!important}.px-3{padding-inline:calc(var(--spacing) * 3)!important}.px-4{padding-inline:calc(var(--spacing) * 4)!important}.py-0\.5{padding-block:calc(var(--spacing) * .5)!important}.py-1{padding-block:var(--spacing)!important}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)!important}.py-2{padding-block:calc(var(--spacing) * 2)!important}.py-3{padding-block:calc(var(--spacing) * 3)!important}.py-8{padding-block:calc(var(--spacing) * 8)!important}.py-16{padding-block:calc(var(--spacing) * 16)!important}.pt-0{padding-top:0!important}.pt-1{padding-top:var(--spacing)!important}.pt-3{padding-top:calc(var(--spacing) * 3)!important}.pt-4{padding-top:calc(var(--spacing) * 4)!important}.pt-5{padding-top:calc(var(--spacing) * 5)!important}.pr-2{padding-right:calc(var(--spacing) * 2)!important}.pl-5{padding-left:calc(var(--spacing) * 5)!important}.text-center{text-align:center!important}.text-left{text-align:left!important}.text-right{text-align:right!important}.align-top{vertical-align:top!important}.font-mono{font-family:var(--font-mono)!important}.text-3xl{font-size:var(--text-3xl)!important;line-height:var(--tw-leading,var(--text-3xl--line-height))!important}.text-base{font-size:var(--text-base)!important;line-height:var(--tw-leading,var(--text-base--line-height))!important}.text-lg{font-size:var(--text-lg)!important;line-height:var(--tw-leading,var(--text-lg--line-height))!important}.text-sm{font-size:var(--text-sm)!important;line-height:var(--tw-leading,var(--text-sm--line-height))!important}.text-xl{font-size:var(--text-xl)!important;line-height:var(--tw-leading,var(--text-xl--line-height))!important}.text-xs{font-size:var(--text-xs)!important;line-height:var(--tw-leading,var(--text-xs--line-height))!important}.text-\[11px\]{font-size:11px!important}.font-bold{--tw-font-weight:var(--font-weight-bold)!important;font-weight:var(--font-weight-bold)!important}.font-medium{--tw-font-weight:var(--font-weight-medium)!important;font-weight:var(--font-weight-medium)!important}.font-semibold{--tw-font-weight:var(--font-weight-semibold)!important;font-weight:var(--font-weight-semibold)!important}.tracking-wide{--tw-tracking:var(--tracking-wide)!important;letter-spacing:var(--tracking-wide)!important}.whitespace-pre-wrap{white-space:pre-wrap!important}.text-amber-600{color:var(--color-amber-600)!important}.text-amber-700{color:var(--color-amber-700)!important}.text-amber-800{color:var(--color-amber-800)!important}.text-brand-700{color:var(--color-brand-700)!important}.text-red-600{color:var(--color-red-600)!important}.text-red-700{color:var(--color-red-700)!important}.text-slate-400{color:var(--color-slate-400)!important}.text-slate-500{color:var(--color-slate-500)!important}.text-slate-600{color:var(--color-slate-600)!important}.text-slate-700{color:var(--color-slate-700)!important}.text-white{color:var(--color-white)!important}.uppercase{text-transform:uppercase!important}.italic{font-style:italic!important}.line-through{text-decoration-line:line-through!important}.underline{text-decoration-line:underline!important}.opacity-70{opacity:.7!important}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a)!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}.outline{outline-style:var(--tw-outline-style)!important;outline-width:1px!important}.blur{--tw-blur:blur(8px)!important;filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)!important}.grayscale{--tw-grayscale:grayscale(100%)!important;filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)!important}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)!important}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events!important;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function))!important;transition-duration:var(--tw-duration,var(--default-transition-duration))!important}.transition-\[filter\]{transition-property:filter!important;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function))!important;transition-duration:var(--tw-duration,var(--default-transition-duration))!important}.ease-out{--tw-ease:var(--ease-out)!important;transition-timing-function:var(--ease-out)!important}.outline-none{--tw-outline-style:none!important;outline-style:none!important}@media (hover:hover){.group-hover\:opacity-80:is(:where(.group):hover *){opacity:.8!important}}.last\:border-0:last-child{border-style:var(--tw-border-style)!important;border-width:0!important}@media (hover:hover){.hover\:border-brand-500:hover{border-color:var(--color-brand-500)!important}.hover\:bg-slate-50:hover{background-color:var(--color-slate-50)!important}.hover\:bg-slate-100:hover{background-color:var(--color-slate-100)!important}.hover\:bg-slate-200:hover{background-color:var(--color-slate-200)!important}.hover\:text-slate-700:hover{color:var(--color-slate-700)!important}.hover\:text-slate-900:hover{color:var(--color-slate-900)!important}.hover\:underline:hover{text-decoration-line:underline!important}.hover\:brightness-95:hover{--tw-brightness:brightness(95%)!important;filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)!important}}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor)!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}.focus\:ring-indigo-500:focus{--tw-ring-color:var(--color-indigo-500)!important}.focus\:outline-none:focus{--tw-outline-style:none!important;outline-style:none!important}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor)!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}.focus-visible\:ring-brand-500:focus-visible{--tw-ring-color:var(--color-brand-500)!important}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none!important;outline-style:none!important}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed!important}.disabled\:opacity-50:disabled{opacity:.5!important}.data-\[state\=active\]\:border-b-2[data-state=active]{border-bottom-style:var(--tw-border-style)!important;border-bottom-width:2px!important}.data-\[state\=active\]\:border-brand-600[data-state=active]{border-color:var(--color-brand-600)!important}.data-\[state\=active\]\:bg-slate-100[data-state=active]{background-color:var(--color-slate-100)!important}.data-\[state\=active\]\:text-brand-700[data-state=active]{color:var(--color-brand-700)!important}.data-\[state\=active\]\:text-slate-900[data-state=active]{color:var(--color-slate-900)!important}.data-\[state\=active\]\:shadow-\[inset_2px_0_0_0_var\(--color-brand-500\)\][data-state=active]{--tw-shadow:inset 2px 0 0 0 var(--tw-shadow-color,var(--color-brand-500))!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}@media (min-width:40rem){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))!important}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))!important}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))!important}}@media (min-width:48rem){.md\:sticky{position:sticky!important}.md\:top-0{top:0!important}.md\:col-span-5{grid-column:span 5/span 5!important}.md\:block{display:block!important}.md\:grid{display:grid!important}.md\:h-screen{height:100vh!important}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))!important}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))!important}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))!important}.md\:grid-cols-\[1fr_1fr_140px_auto_auto\]{grid-template-columns:1fr 1fr 140px auto auto!important}.md\:grid-cols-\[1fr_110px\]{grid-template-columns:1fr 110px!important}.md\:grid-cols-\[1fr_130px_90px_110px_auto\]{grid-template-columns:1fr 130px 90px 110px auto!important}.md\:grid-cols-\[248px_1fr\]{grid-template-columns:248px 1fr!important}.md\:grid-cols-\[260px_1fr\]{grid-template-columns:260px 1fr!important}.md\:grid-cols-\[280px_1fr\]{grid-template-columns:280px 1fr!important}.md\:grid-cols-\[300px_1fr\]{grid-template-columns:300px 1fr!important}.md\:grid-cols-\[340px_1fr\]{grid-template-columns:340px 1fr!important}.md\:flex-col{flex-direction:column!important}.md\:overflow-visible{overflow:visible!important}.md\:border-r{border-right-style:var(--tw-border-style)!important;border-right-width:1px!important}.md\:border-b-0{border-bottom-style:var(--tw-border-style)!important;border-bottom-width:0!important}.md\:p-8{padding:calc(var(--spacing) * 8)!important}.md\:px-8{padding-inline:calc(var(--spacing) * 8)!important}}@media (min-width:64rem){.lg\:col-span-2{grid-column:span 2/span 2!important}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))!important}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))!important}}}}.xicms-admin,.xicms-admin *,.xicms-admin :before,.xicms-admin :after{box-sizing:border-box}.xicms-admin{-webkit-font-smoothing:antialiased;color-scheme:light;--color-white:#fff;--color-slate-50:#faf9f6;--color-slate-100:#f3f1ec;--color-slate-200:#e5e2da;--color-slate-300:#d5d1c7;--color-slate-400:#a8a399;--color-slate-500:#6e6a62;--color-slate-600:#57534b;--color-slate-700:#403c36;--color-slate-900:#1b1a17;--color-brand:var(--xicms-primary,#4f46e5);--color-brand-500:var(--xicms-primary,#4f46e5);--color-brand-600:var(--xicms-primary,#4f46e5);--color-brand-700:var(--xicms-primary,#4f46e5);font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;line-height:1.5}@supports (color:color-mix(in lab, red, red)){.xicms-admin{--color-brand-700:color-mix(in srgb, var(--xicms-primary,#4f46e5) 78%, #1b1a17)}}.xicms-admin{--color-brand-50:var(--xicms-primary,#4f46e5)}@supports (color:color-mix(in lab, red, red)){.xicms-admin{--color-brand-50:color-mix(in srgb, var(--xicms-primary,#4f46e5) 10%, #fff)}}.xicms-admin{--admin-canvas:#f6f5f2;--admin-sidebar:#f0eee9;--color-background-body:var(--color-white);--color-background-surface:var(--color-white);--color-background-card:var(--color-white);--color-background-muted:var(--color-slate-100);--color-text-primary:var(--color-slate-900);--color-text-secondary:var(--color-slate-500);--color-border:var(--color-slate-200);--color-accent:var(--color-brand-500);--color-on-accent:#fff;--color-error:#dc2626;color:var(--color-text-primary);background:var(--admin-canvas)}@media (prefers-color-scheme:dark){.xicms-admin{color-scheme:dark;--color-white:#1e1d1a;--color-slate-50:#24231f;--color-slate-100:#2b2925;--color-slate-200:#37342f;--color-slate-300:#45413a;--color-slate-400:#7c776e;--color-slate-500:#9b958b;--color-slate-600:#b6b0a5;--color-slate-700:#d2ccc1;--color-slate-900:#ece9e3;--color-brand-700:var(--xicms-primary,#4f46e5)}@supports (color:color-mix(in lab, red, red)){.xicms-admin{--color-brand-700:color-mix(in srgb, var(--xicms-primary,#4f46e5) 70%, #ece9e3)}}.xicms-admin{--color-brand-50:var(--xicms-primary,#4f46e5)}@supports (color:color-mix(in lab, red, red)){.xicms-admin{--color-brand-50:color-mix(in srgb, var(--xicms-primary,#4f46e5) 22%, #1e1d1a)}}.xicms-admin{--admin-canvas:#141311;--admin-sidebar:#191815;--color-error:#f87171}}.xicms-admin h1,.xicms-admin h2,.xicms-admin h3,.xicms-admin p,.xicms-admin figure{margin:0}.xicms-admin button{font:inherit;cursor:pointer}.xicms-admin input,.xicms-admin textarea,.xicms-admin select{font:inherit;color:inherit}.xicms-admin .ProseMirror{outline:none;min-height:8rem}.xicms-admin .ProseMirror p{margin:0 0 .6rem}.xicms-admin .ProseMirror:focus{outline:none}@media (prefers-reduced-motion:reduce){.xicms-admin *,.xicms-admin :before,.xicms-admin :after,.xicms-ve *,.xicms-ve :before,.xicms-ve :after{transition-duration:.001ms!important;animation-duration:.001ms!important;animation-iteration-count:1!important}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Field } from "../schema/fields";
|
|
2
|
-
import type { CustomBlock } from "../schema/customBlocks";
|
|
1
|
+
import type { Field } from "../schema/fields.js";
|
|
2
|
+
import type { CustomBlock } from "../schema/customBlocks.js";
|
|
3
3
|
export interface CatalogEntry {
|
|
4
4
|
type: string;
|
|
5
5
|
fields: Field[];
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { BuiltinBlockSchema } from "../schema/blocks";
|
|
2
|
-
import { introspectToFields } from "../admin/lib/zodFields";
|
|
1
|
+
import { BuiltinBlockSchema } from "../schema/blocks.js";
|
|
2
|
+
import { introspectToFields } from "../admin/lib/zodFields.js";
|
|
3
3
|
function builtinBlockCatalog() {
|
|
4
|
-
const
|
|
4
|
+
const intern = (s) => s?._zod?.def;
|
|
5
|
+
const options = intern(BuiltinBlockSchema)?.options ?? [];
|
|
5
6
|
return options.map((schema) => {
|
|
6
|
-
const shape = schema
|
|
7
|
-
const type = shape?._type?.
|
|
7
|
+
const shape = intern(schema)?.shape;
|
|
8
|
+
const type = String(intern(shape?._type)?.values?.[0] ?? "");
|
|
8
9
|
return { type, fields: introspectToFields(schema), source: "builtin" };
|
|
9
10
|
}).filter((e) => e.type !== "").sort((a, b) => a.type.localeCompare(b.type));
|
|
10
11
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/agentFiles/catalog.ts"],"sourcesContent":["/**\n * Blok-catalogus + AGENTS.md-generator (5.0, primo-concept): bij `pull-site` wordt in de\n * site-map een AGENTS.md gegenereerd die een coding-agent vertelt hoe de bestanden werken en\n * welke bloktypes er bestaan — mét hun velden, afgeleid uit de Zod-schema's (Field-IR) en de\n * Field-IR van de custom blocks van de site. Zo hoeft een agent de engine-repo niet te kennen\n * om content te kunnen schrijven.\n */\nimport type { ZodTypeAny } from \"zod\";\nimport { BuiltinBlockSchema } from \"../schema/blocks\";\nimport { introspectToFields } from \"../admin/lib/zodFields\";\nimport type { Field } from \"../schema/fields\";\nimport type { CustomBlock } from \"../schema/customBlocks\";\n\nexport interface CatalogEntry {\n type: string;\n fields: Field[];\n /** \"builtin\" of \"custom\" (per site gedefinieerd). */\n source: \"builtin\" | \"custom\";\n}\n\n/** Catalogus van alle ingebouwde bloktypes, via de discriminated union (geen React-imports). */\nexport function builtinBlockCatalog(): CatalogEntry[] {\n
|
|
1
|
+
{"version":3,"sources":["../../src/agentFiles/catalog.ts"],"sourcesContent":["/**\n * Blok-catalogus + AGENTS.md-generator (5.0, primo-concept): bij `pull-site` wordt in de\n * site-map een AGENTS.md gegenereerd die een coding-agent vertelt hoe de bestanden werken en\n * welke bloktypes er bestaan — mét hun velden, afgeleid uit de Zod-schema's (Field-IR) en de\n * Field-IR van de custom blocks van de site. Zo hoeft een agent de engine-repo niet te kennen\n * om content te kunnen schrijven.\n */\nimport type { $ZodType as ZodTypeAny } from \"zod/v4/core\";\nimport { BuiltinBlockSchema } from \"../schema/blocks\";\nimport { introspectToFields } from \"../admin/lib/zodFields\";\nimport type { Field } from \"../schema/fields\";\nimport type { CustomBlock } from \"../schema/customBlocks\";\n\nexport interface CatalogEntry {\n type: string;\n fields: Field[];\n /** \"builtin\" of \"custom\" (per site gedefinieerd). */\n source: \"builtin\" | \"custom\";\n}\n\n/** Catalogus van alle ingebouwde bloktypes, via de discriminated union (geen React-imports). */\nexport function builtinBlockCatalog(): CatalogEntry[] {\n // `.options` en `.value` zijn getters van de classic-façade; `zod/mini` (waar core op draait)\n // legt alles onder `_zod.def` — een literal draagt daar zijn waarde in `values[0]`.\n const intern = (s: unknown) => (s as { _zod?: { def?: Record<string, unknown> } })?._zod?.def;\n const options = ((intern(BuiltinBlockSchema)?.options as ZodTypeAny[] | undefined) ?? []) as ZodTypeAny[];\n return options\n .map((schema) => {\n const shape = intern(schema)?.shape as Record<string, unknown> | undefined;\n const type = String((intern(shape?._type)?.values as string[] | undefined)?.[0] ?? \"\");\n return { type, fields: introspectToFields(schema), source: \"builtin\" as const };\n })\n .filter((e) => e.type !== \"\")\n .sort((a, b) => a.type.localeCompare(b.type));\n}\n\nexport function customBlockCatalog(defs: CustomBlock[]): CatalogEntry[] {\n return defs.map((d) => ({ type: d.type, fields: d.fields, source: \"custom\" as const }));\n}\n\nfunction fieldLine(f: Field, indent: string): string[] {\n const label = f.label && f.label !== f.key ? ` — ${f.label}` : \"\";\n const extra =\n f.type === \"select\" && \"options\" in f && Array.isArray((f as { options?: { value: string }[] }).options)\n ? ` (opties: ${((f as { options: { value: string }[] }).options).map((o) => o.value).join(\", \")})`\n : \"\";\n const lines = [`${indent}- \\`${f.key}\\` (${f.type})${label}${extra}`];\n if (f.type === \"group\" || f.type === \"repeater\") {\n for (const sub of f.fields) lines.push(...fieldLine(sub, indent + \" \"));\n }\n return lines;\n}\n\n/**\n * Genereert de AGENTS.md voor een gepullde site-map. `meta` beschrijft de site;\n * `catalog` is builtin + custom samen (zie builtinBlockCatalog/customBlockCatalog).\n */\nexport function generateAgentsMd(\n meta: { siteId: string; name?: string; locales?: string[]; defaultLocale?: string },\n catalog: CatalogEntry[],\n): string {\n const locales = meta.locales && meta.locales.length > 1 ? meta.locales : null;\n const lines: string[] = [\n \"<!-- GEGENEREERD door pull-site — niet met de hand bewerken; wordt bij elke pull overschreven. -->\",\n `# Agent-gids: site \"${meta.name ?? meta.siteId}\" (${meta.siteId})`,\n \"\",\n \"Deze map is een bewerkbare bestandsweergave van een XiCMS-site (werkversies/drafts).\",\n \"Werkwijze: bewerk de bestanden, en push met `npm run push-site -- \" + meta.siteId + \" <deze map>`.\",\n \"Push valideert alles vooraf (Zod) en weigert bij conflicten met tussentijdse wijzigingen\",\n \"in het beheer (zie `.xicms/manifest.json`); `--force` overschrijft bewust.\",\n \"\",\n \"## Structuur\",\n \"\",\n \"- `site.yaml` — site-instellingen (naam, thema, navigatie, talen).\",\n \"- `pages/<pad>.yaml` — één pagina per bestand (werkversie): `title`, `slug`, `path`, `seo`, `blocks`.\",\n \"- `symbols/<id>.yaml` — gedeelde secties; een pagina verwijst ernaar met een `symbolRef`-blok.\",\n \"- `custom-blocks/<type>/` — per site gedefinieerde bloktypes: `block.yaml` (velden als Field-IR),\",\n \" `template.html` (veilige mustache-subset) en `style.css` (automatisch gescoped).\",\n \"- `.xicms/manifest.json` — sync-administratie van pull/push; niet handmatig bewerken.\",\n \"\",\n \"## Conventies\",\n \"\",\n \"- Elk blok heeft `_type` (bloktype, zie catalogus) en een uniek `_key` (kort, stabiel).\",\n \"- Rich-text-velden heten `html` of eindigen op `Html` en bevatten beperkte HTML\",\n \" (p/strong/em/a/ul/ol/h2-h4 …); alle andere velden zijn platte tekst — die worden escaped.\",\n \"- Verwijder nooit `_key`s die je niet zelf toevoegde: vertalingen en versies verwijzen ernaar.\",\n ];\n if (locales) {\n lines.push(\n \"\",\n \"## Talen\",\n \"\",\n `- Talen: ${locales.join(\", \")} (default: ${meta.defaultLocale ?? locales[0]}).`,\n \"- Vertalingen zijn een overlay per pagina/symbool onder `translations`:\",\n ' `translations: { de: { \"<blokKey>.<veldpad>\": \"vertaalde tekst\", title: \"…\", \"seo.title\": \"…\" } }`.',\n \"- De blokkenstructuur is altijd de default-taal; overlays bevatten alléén tekst-strings.\",\n );\n }\n lines.push(\"\", \"## Blok-catalogus\", \"\");\n for (const entry of catalog) {\n lines.push(`### \\`${entry.type}\\`${entry.source === \"custom\" ? \" (custom block van deze site)\" : \"\"}`, \"\");\n const fields = entry.fields.filter((f) => f.type !== \"info\");\n if (fields.length === 0) lines.push(\"_Geen velden._\", \"\");\n else {\n for (const f of fields) lines.push(...fieldLine(f, \"\"));\n lines.push(\"\");\n }\n }\n return lines.join(\"\\n\");\n}\n"],"mappings":"AAQA,SAAS,0BAA0B;AACnC,SAAS,0BAA0B;AAY5B,SAAS,sBAAsC;AAGpD,QAAM,SAAS,CAAC,MAAgB,GAAoD,MAAM;AAC1F,QAAM,UAAY,OAAO,kBAAkB,GAAG,WAAwC,CAAC;AACvF,SAAO,QACJ,IAAI,CAAC,WAAW;AACf,UAAM,QAAQ,OAAO,MAAM,GAAG;AAC9B,UAAM,OAAO,OAAQ,OAAO,OAAO,KAAK,GAAG,SAAkC,CAAC,KAAK,EAAE;AACrF,WAAO,EAAE,MAAM,QAAQ,mBAAmB,MAAM,GAAG,QAAQ,UAAmB;AAAA,EAChF,CAAC,EACA,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,EAC3B,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAChD;AAEO,SAAS,mBAAmB,MAAqC;AACtE,SAAO,KAAK,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,EAAE,QAAQ,QAAQ,SAAkB,EAAE;AACxF;AAEA,SAAS,UAAU,GAAU,QAA0B;AACrD,QAAM,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAM,EAAE,KAAK,KAAK;AAC/D,QAAM,QACJ,EAAE,SAAS,YAAY,aAAa,KAAK,MAAM,QAAS,EAAwC,OAAO,IACnG,aAAe,EAAuC,QAAS,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI,CAAC,MAC7F;AACN,QAAM,QAAQ,CAAC,GAAG,MAAM,OAAO,EAAE,GAAG,OAAO,EAAE,IAAI,IAAI,KAAK,GAAG,KAAK,EAAE;AACpE,MAAI,EAAE,SAAS,WAAW,EAAE,SAAS,YAAY;AAC/C,eAAW,OAAO,EAAE,OAAQ,OAAM,KAAK,GAAG,UAAU,KAAK,SAAS,IAAI,CAAC;AAAA,EACzE;AACA,SAAO;AACT;AAMO,SAAS,iBACd,MACA,SACQ;AACR,QAAM,UAAU,KAAK,WAAW,KAAK,QAAQ,SAAS,IAAI,KAAK,UAAU;AACzE,QAAM,QAAkB;AAAA,IACtB;AAAA,IACA,uBAAuB,KAAK,QAAQ,KAAK,MAAM,MAAM,KAAK,MAAM;AAAA,IAChE;AAAA,IACA;AAAA,IACA,uEAAuE,KAAK,SAAS;AAAA,IACrF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,SAAS;AACX,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY,QAAQ,KAAK,IAAI,CAAC,cAAc,KAAK,iBAAiB,QAAQ,CAAC,CAAC;AAAA,MAC5E;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,QAAM,KAAK,IAAI,qBAAqB,EAAE;AACtC,aAAW,SAAS,SAAS;AAC3B,UAAM,KAAK,SAAS,MAAM,IAAI,KAAK,MAAM,WAAW,WAAW,kCAAkC,EAAE,IAAI,EAAE;AACzG,UAAM,SAAS,MAAM,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM;AAC3D,QAAI,OAAO,WAAW,EAAG,OAAM,KAAK,kBAAkB,EAAE;AAAA,SACnD;AACH,iBAAW,KAAK,OAAQ,OAAM,KAAK,GAAG,UAAU,GAAG,EAAE,CAAC;AACtD,YAAM,KAAK,EAAE;AAAA,IACf;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;","names":[]}
|