@xiwebdesign/xicms-core 7.31.0 → 8.16.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/XiCMSProvider.js +23 -7
- package/dist/XiCMSProvider.js.map +1 -1
- package/dist/admin/AdminApp.js +175 -93
- package/dist/admin/AdminApp.js.map +1 -1
- package/dist/admin/AdminHelp.d.ts +1 -1
- package/dist/admin/AdminHelp.js +44 -36
- package/dist/admin/AdminHelp.js.map +1 -1
- package/dist/admin/CoreVersion.d.ts +6 -3
- package/dist/admin/CoreVersion.js +60 -24
- package/dist/admin/CoreVersion.js.map +1 -1
- package/dist/admin/NewsEditor.d.ts +7 -0
- package/dist/admin/NewsEditor.js +117 -75
- package/dist/admin/NewsEditor.js.map +1 -1
- package/dist/admin/SuperadminPanel.js +1 -1
- package/dist/admin/SuperadminPanel.js.map +1 -1
- package/dist/admin/ZoekPalet.d.ts +15 -0
- package/dist/admin/ZoekPalet.js +123 -0
- package/dist/admin/ZoekPalet.js.map +1 -0
- package/dist/admin/blockEditors/GenericEditor.js +36 -18
- package/dist/admin/blockEditors/GenericEditor.js.map +1 -1
- package/dist/admin/blockEditors/StyleEditor.js +37 -3
- package/dist/admin/blockEditors/StyleEditor.js.map +1 -1
- package/dist/admin/blockEditors/SymbolRefEditor.js +44 -2
- package/dist/admin/blockEditors/SymbolRefEditor.js.map +1 -1
- package/dist/admin/blockEditors/index.js +154 -73
- package/dist/admin/blockEditors/index.js.map +1 -1
- package/dist/admin/customBlocks/CustomBlocksPanel.js +18 -7
- package/dist/admin/customBlocks/CustomBlocksPanel.js.map +1 -1
- package/dist/admin/dashboard/DashboardPanel.js +26 -16
- package/dist/admin/dashboard/DashboardPanel.js.map +1 -1
- package/dist/admin/editors/RichTextEditor.d.ts +4 -3
- package/dist/admin/editors/RichTextEditor.js +19 -60
- package/dist/admin/editors/RichTextEditor.js.map +1 -1
- package/dist/admin/editors/fontSizeExtension.js +7 -1
- package/dist/admin/editors/fontSizeExtension.js.map +1 -1
- package/dist/admin/editors/slashMenu.d.ts +18 -0
- package/dist/admin/editors/slashMenu.js +34 -0
- package/dist/admin/editors/slashMenu.js.map +1 -0
- package/dist/admin/editors/useRijkeTekst.d.ts +48 -0
- package/dist/admin/editors/useRijkeTekst.js +310 -0
- package/dist/admin/editors/useRijkeTekst.js.map +1 -0
- package/dist/admin/forms/FormsPanel.d.ts +11 -2
- package/dist/admin/forms/FormsPanel.js +218 -65
- package/dist/admin/forms/FormsPanel.js.map +1 -1
- package/dist/admin/lib/blokInfo.d.ts +17 -0
- package/dist/admin/lib/blokInfo.js +80 -0
- package/dist/admin/lib/blokInfo.js.map +1 -0
- package/dist/admin/lib/foutNaarMens.d.ts +1 -0
- package/dist/admin/lib/foutNaarMens.js +22 -0
- package/dist/admin/lib/foutNaarMens.js.map +1 -0
- package/dist/admin/lib/gewisteVelden.d.ts +13 -0
- package/dist/admin/lib/gewisteVelden.js +31 -0
- package/dist/admin/lib/gewisteVelden.js.map +1 -0
- package/dist/admin/lib/heroHulp.d.ts +11 -0
- package/dist/admin/lib/heroHulp.js +18 -0
- package/dist/admin/lib/heroHulp.js.map +1 -0
- package/dist/admin/lib/kleur.js +2 -3
- package/dist/admin/lib/kleur.js.map +1 -1
- package/dist/admin/lib/leesbaarheid.d.ts +34 -0
- package/dist/admin/lib/leesbaarheid.js +82 -0
- package/dist/admin/lib/leesbaarheid.js.map +1 -0
- package/dist/admin/lib/lengteAdvies.d.ts +1 -0
- package/dist/admin/lib/lengteAdvies.js +16 -0
- package/dist/admin/lib/lengteAdvies.js.map +1 -0
- package/dist/admin/lib/mediaLijst.d.ts +26 -0
- package/dist/admin/lib/mediaLijst.js +42 -0
- package/dist/admin/lib/mediaLijst.js.map +1 -0
- package/dist/admin/lib/mediaUsage.d.ts +12 -1
- package/dist/admin/lib/mediaUsage.js +43 -33
- package/dist/admin/lib/mediaUsage.js.map +1 -1
- package/dist/admin/lib/menuHulp.d.ts +16 -0
- package/dist/admin/lib/menuHulp.js +41 -0
- package/dist/admin/lib/menuHulp.js.map +1 -0
- package/dist/admin/lib/onopgeslagen.d.ts +10 -0
- package/dist/admin/lib/onopgeslagen.js +35 -0
- package/dist/admin/lib/onopgeslagen.js.map +1 -0
- package/dist/admin/lib/pagesClient.d.ts +55 -2
- package/dist/admin/lib/pagesClient.js +126 -28
- package/dist/admin/lib/pagesClient.js.map +1 -1
- package/dist/admin/lib/paginaGebruik.d.ts +56 -0
- package/dist/admin/lib/paginaGebruik.js +109 -0
- package/dist/admin/lib/paginaGebruik.js.map +1 -0
- package/dist/admin/lib/publicatieCheck.d.ts +25 -0
- package/dist/admin/lib/publicatieCheck.js +114 -0
- package/dist/admin/lib/publicatieCheck.js.map +1 -0
- package/dist/admin/lib/scrollNaarDetail.d.ts +6 -0
- package/dist/admin/lib/scrollNaarDetail.js +20 -0
- package/dist/admin/lib/scrollNaarDetail.js.map +1 -0
- package/dist/admin/lib/symbolsClient.d.ts +10 -0
- package/dist/admin/lib/symbolsClient.js +14 -1
- package/dist/admin/lib/symbolsClient.js.map +1 -1
- package/dist/admin/lib/tekstVeld.d.ts +8 -0
- package/dist/admin/lib/tekstVeld.js +10 -0
- package/dist/admin/lib/tekstVeld.js.map +1 -0
- package/dist/admin/lib/useIsSuperadmin.d.ts +2 -0
- package/dist/admin/lib/useIsSuperadmin.js +13 -0
- package/dist/admin/lib/useIsSuperadmin.js.map +1 -0
- package/dist/admin/lib/veldTaal.d.ts +14 -0
- package/dist/admin/lib/veldTaal.js +248 -0
- package/dist/admin/lib/veldTaal.js.map +1 -0
- package/dist/admin/lib/versieVergelijk.d.ts +17 -0
- package/dist/admin/lib/versieVergelijk.js +24 -0
- package/dist/admin/lib/versieVergelijk.js.map +1 -0
- package/dist/admin/lib/zodFields.js +22 -4
- package/dist/admin/lib/zodFields.js.map +1 -1
- package/dist/admin/lib/zodFout.d.ts +9 -0
- package/dist/admin/lib/zodFout.js +63 -0
- package/dist/admin/lib/zodFout.js.map +1 -0
- package/dist/admin/media/MediaManager.js +162 -32
- package/dist/admin/media/MediaManager.js.map +1 -1
- package/dist/admin/media/MediaPicker.d.ts +3 -0
- package/dist/admin/media/MediaPicker.js +84 -31
- package/dist/admin/media/MediaPicker.js.map +1 -1
- package/dist/admin/menu/MenuPanel.js +144 -83
- package/dist/admin/menu/MenuPanel.js.map +1 -1
- package/dist/admin/navContext.d.ts +3 -0
- package/dist/admin/navContext.js +13 -1
- package/dist/admin/navContext.js.map +1 -1
- package/dist/admin/pages/PageEditor.js +146 -30
- package/dist/admin/pages/PageEditor.js.map +1 -1
- package/dist/admin/pages/PagesPanel.js +215 -61
- package/dist/admin/pages/PagesPanel.js.map +1 -1
- package/dist/admin/pages/StarterKiezer.d.ts +12 -0
- package/dist/admin/pages/StarterKiezer.js +113 -0
- package/dist/admin/pages/StarterKiezer.js.map +1 -0
- package/dist/admin/panelRegistry.d.ts +1 -1
- package/dist/admin/panelRegistry.js +2 -1
- package/dist/admin/panelRegistry.js.map +1 -1
- package/dist/admin/patterns/PatternInserter.js +1 -1
- package/dist/admin/patterns/PatternInserter.js.map +1 -1
- package/dist/admin/settings/BedrijfInstellingen.d.ts +20 -0
- package/dist/admin/settings/BedrijfInstellingen.js +159 -0
- package/dist/admin/settings/BedrijfInstellingen.js.map +1 -0
- package/dist/admin/settings/MailTemplates.js +5 -4
- package/dist/admin/settings/MailTemplates.js.map +1 -1
- package/dist/admin/settings/SettingsPanel.js +120 -78
- package/dist/admin/settings/SettingsPanel.js.map +1 -1
- package/dist/admin/settings/SnapshotsCard.js +4 -4
- package/dist/admin/settings/SnapshotsCard.js.map +1 -1
- package/dist/admin/settings/VorigeTerugzetten.d.ts +15 -0
- package/dist/admin/settings/VorigeTerugzetten.js +89 -0
- package/dist/admin/settings/VorigeTerugzetten.js.map +1 -0
- package/dist/admin/shop/CategoriesTab.js +6 -4
- package/dist/admin/shop/CategoriesTab.js.map +1 -1
- package/dist/admin/shop/DiscountsTab.js +4 -2
- package/dist/admin/shop/DiscountsTab.js.map +1 -1
- package/dist/admin/shop/OrdersTab.js +57 -19
- package/dist/admin/shop/OrdersTab.js.map +1 -1
- package/dist/admin/shop/ProductPaneel.js +2 -1
- package/dist/admin/shop/ProductPaneel.js.map +1 -1
- package/dist/admin/shop/ProductsTab.js +40 -19
- package/dist/admin/shop/ProductsTab.js.map +1 -1
- package/dist/admin/shop/ShopPanel.js +13 -1
- package/dist/admin/shop/ShopPanel.js.map +1 -1
- package/dist/admin/shop/ShopSettingsTab.js +56 -17
- package/dist/admin/shop/ShopSettingsTab.js.map +1 -1
- package/dist/admin/shop/productClient.js +7 -3
- package/dist/admin/shop/productClient.js.map +1 -1
- package/dist/admin/stats/NietGevonden.d.ts +10 -0
- package/dist/admin/stats/NietGevonden.js +78 -0
- package/dist/admin/stats/NietGevonden.js.map +1 -0
- package/dist/admin/stats/StatsPanel.js +6 -1
- package/dist/admin/stats/StatsPanel.js.map +1 -1
- package/dist/admin/stats/lib.d.ts +2 -0
- package/dist/admin/stats/lib.js.map +1 -1
- package/dist/admin/ui/ConfirmDialog.js +10 -1
- package/dist/admin/ui/ConfirmDialog.js.map +1 -1
- package/dist/admin/ui/Icon.d.ts +34 -0
- package/dist/admin/ui/Icon.js +44 -0
- package/dist/admin/ui/Icon.js.map +1 -0
- package/dist/admin/ui/ImageField.d.ts +15 -0
- package/dist/admin/ui/ImageField.js +67 -0
- package/dist/admin/ui/ImageField.js.map +1 -0
- package/dist/admin/ui/KleurVeld.d.ts +25 -0
- package/dist/admin/ui/KleurVeld.js +76 -0
- package/dist/admin/ui/KleurVeld.js.map +1 -0
- package/dist/admin/ui/LaadStaat.d.ts +21 -0
- package/dist/admin/ui/LaadStaat.js +43 -0
- package/dist/admin/ui/LaadStaat.js.map +1 -0
- package/dist/admin/ui/LeesbaarheidPaneel.d.ts +10 -0
- package/dist/admin/ui/LeesbaarheidPaneel.js +68 -0
- package/dist/admin/ui/LeesbaarheidPaneel.js.map +1 -0
- package/dist/admin/ui/LinkDialog.d.ts +22 -0
- package/dist/admin/ui/LinkDialog.js +131 -0
- package/dist/admin/ui/LinkDialog.js.map +1 -0
- package/dist/admin/ui/LinkVeld.d.ts +14 -0
- package/dist/admin/ui/LinkVeld.js +49 -0
- package/dist/admin/ui/LinkVeld.js.map +1 -0
- package/dist/admin/ui/PreviewLinkResultaat.d.ts +14 -0
- package/dist/admin/ui/PreviewLinkResultaat.js +52 -0
- package/dist/admin/ui/PreviewLinkResultaat.js.map +1 -0
- package/dist/admin/ui/charts.js +5 -5
- package/dist/admin/ui/charts.js.map +1 -1
- package/dist/admin/ui/primitives.d.ts +16 -6
- package/dist/admin/ui/primitives.js +98 -26
- package/dist/admin/ui/primitives.js.map +1 -1
- package/dist/admin/ui/select.js +5 -2
- package/dist/admin/ui/select.js.map +1 -1
- package/dist/admin/ui/switch.d.ts +3 -1
- package/dist/admin/ui/switch.js +6 -3
- package/dist/admin/ui/switch.js.map +1 -1
- package/dist/admin/ui/toast.d.ts +2 -1
- package/dist/admin/ui/toast.js +17 -11
- package/dist/admin/ui/toast.js.map +1 -1
- package/dist/admin/visual/BlokKiezer.d.ts +34 -0
- package/dist/admin/visual/BlokKiezer.js +225 -0
- package/dist/admin/visual/BlokKiezer.js.map +1 -0
- package/dist/admin/visual/InlineGereedschap.d.ts +52 -0
- package/dist/admin/visual/InlineGereedschap.js +356 -0
- package/dist/admin/visual/InlineGereedschap.js.map +1 -0
- package/dist/admin/visual/InlineRijkeTekst.d.ts +23 -0
- package/dist/admin/visual/InlineRijkeTekst.js +152 -0
- package/dist/admin/visual/InlineRijkeTekst.js.map +1 -0
- package/dist/admin/visual/VisualEditor.js +273 -125
- package/dist/admin/visual/VisualEditor.js.map +1 -1
- package/dist/admin.css +1 -1
- package/dist/auth/AuthProvider.js +1 -0
- package/dist/auth/AuthProvider.js.map +1 -1
- package/dist/bedrijf/bedrijf.d.ts +44 -0
- package/dist/bedrijf/bedrijf.js +125 -0
- package/dist/bedrijf/bedrijf.js.map +1 -0
- package/dist/blocks/BlockRenderer.js +11 -1
- package/dist/blocks/BlockRenderer.js.map +1 -1
- package/dist/blocks/blockStyle.d.ts +7 -0
- package/dist/blocks/blockStyle.js +16 -3
- package/dist/blocks/blockStyle.js.map +1 -1
- package/dist/blocks/builtinSchemas.js +6 -0
- package/dist/blocks/builtinSchemas.js.map +1 -1
- package/dist/blocks/builtins/AgendaRender.d.ts +22 -0
- package/dist/blocks/builtins/AgendaRender.js +69 -9
- package/dist/blocks/builtins/AgendaRender.js.map +1 -1
- package/dist/blocks/builtins/Availability.d.ts +1 -0
- package/dist/blocks/builtins/Availability.js +23 -0
- package/dist/blocks/builtins/Availability.js.map +1 -0
- package/dist/blocks/builtins/AvailabilityRender.d.ts +12 -0
- package/dist/blocks/builtins/AvailabilityRender.js +105 -0
- package/dist/blocks/builtins/AvailabilityRender.js.map +1 -0
- package/dist/blocks/builtins/BeforeAfterRender.js +4 -3
- package/dist/blocks/builtins/BeforeAfterRender.js.map +1 -1
- package/dist/blocks/builtins/Booking.js +1 -1
- package/dist/blocks/builtins/Booking.js.map +1 -1
- package/dist/blocks/builtins/BreadcrumbsRender.d.ts +4 -3
- package/dist/blocks/builtins/BreadcrumbsRender.js +14 -8
- package/dist/blocks/builtins/BreadcrumbsRender.js.map +1 -1
- package/dist/blocks/builtins/ColumnsRender.d.ts +1 -1
- package/dist/blocks/builtins/ColumnsRender.js +3 -1
- package/dist/blocks/builtins/ColumnsRender.js.map +1 -1
- package/dist/blocks/builtins/Contact.js +1 -1
- package/dist/blocks/builtins/Contact.js.map +1 -1
- package/dist/blocks/builtins/ContactRender.d.ts +1 -1
- package/dist/blocks/builtins/ContactRender.js +37 -8
- package/dist/blocks/builtins/ContactRender.js.map +1 -1
- package/dist/blocks/builtins/Cta.js +1 -1
- package/dist/blocks/builtins/Cta.js.map +1 -1
- package/dist/blocks/builtins/CtaRender.d.ts +1 -1
- package/dist/blocks/builtins/CtaRender.js +5 -4
- package/dist/blocks/builtins/CtaRender.js.map +1 -1
- package/dist/blocks/builtins/Embed.js +1 -1
- package/dist/blocks/builtins/Embed.js.map +1 -1
- package/dist/blocks/builtins/FormBlock.js +1 -0
- package/dist/blocks/builtins/FormBlock.js.map +1 -1
- package/dist/blocks/builtins/FormBlockRender.d.ts +6 -0
- package/dist/blocks/builtins/FormBlockRender.js +88 -16
- package/dist/blocks/builtins/FormBlockRender.js.map +1 -1
- package/dist/blocks/builtins/GalleryRender.js +3 -2
- package/dist/blocks/builtins/GalleryRender.js.map +1 -1
- package/dist/blocks/builtins/Hero.js +1 -1
- package/dist/blocks/builtins/Hero.js.map +1 -1
- package/dist/blocks/builtins/HeroRender.js +7 -3
- package/dist/blocks/builtins/HeroRender.js.map +1 -1
- package/dist/blocks/builtins/OpenNowBadge.d.ts +4 -2
- package/dist/blocks/builtins/OpenNowBadge.js +6 -6
- package/dist/blocks/builtins/OpenNowBadge.js.map +1 -1
- package/dist/blocks/builtins/OpeningHoursRender.d.ts +8 -2
- package/dist/blocks/builtins/OpeningHoursRender.js +27 -6
- package/dist/blocks/builtins/OpeningHoursRender.js.map +1 -1
- package/dist/blocks/builtins/PriceList.d.ts +1 -0
- package/dist/blocks/builtins/PriceList.js +25 -0
- package/dist/blocks/builtins/PriceList.js.map +1 -0
- package/dist/blocks/builtins/PriceListRender.d.ts +17 -0
- package/dist/blocks/builtins/PriceListRender.js +87 -0
- package/dist/blocks/builtins/PriceListRender.js.map +1 -0
- package/dist/blocks/builtins/RichTextBlockRender.js +6 -1
- package/dist/blocks/builtins/RichTextBlockRender.js.map +1 -1
- package/dist/blocks/builtins/SectionHeading.d.ts +1 -0
- package/dist/blocks/builtins/SectionHeading.js +14 -0
- package/dist/blocks/builtins/SectionHeading.js.map +1 -0
- package/dist/blocks/builtins/SectionHeadingRender.d.ts +7 -0
- package/dist/blocks/builtins/SectionHeadingRender.js +14 -0
- package/dist/blocks/builtins/SectionHeadingRender.js.map +1 -0
- package/dist/blocks/builtins/SliderRender.js +3 -2
- package/dist/blocks/builtins/SliderRender.js.map +1 -1
- package/dist/blocks/builtins/SymbolRef.js +1 -1
- package/dist/blocks/builtins/SymbolRef.js.map +1 -1
- package/dist/blocks/builtins/TeamRender.js +6 -1
- package/dist/blocks/builtins/TeamRender.js.map +1 -1
- package/dist/blocks/builtins/Testimonials.js +3 -1
- package/dist/blocks/builtins/Testimonials.js.map +1 -1
- package/dist/blocks/builtins/TestimonialsRender.js +4 -0
- package/dist/blocks/builtins/TestimonialsRender.js.map +1 -1
- package/dist/blocks/builtins/WhatsappChatRender.d.ts +1 -1
- package/dist/blocks/builtins/WhatsappChatRender.js +3 -1
- package/dist/blocks/builtins/WhatsappChatRender.js.map +1 -1
- package/dist/blocks/builtins/Widgets.js +2 -2
- package/dist/blocks/builtins/Widgets.js.map +1 -1
- package/dist/blocks/builtins/WidgetsRender.js +3 -1
- package/dist/blocks/builtins/WidgetsRender.js.map +1 -1
- package/dist/blocks/builtins/consentEmbed.js +26 -9
- package/dist/blocks/builtins/consentEmbed.js.map +1 -1
- package/dist/blocks/builtins/index.d.ts +3 -0
- package/dist/blocks/builtins/index.js +6 -0
- package/dist/blocks/builtins/index.js.map +1 -1
- package/dist/blocks/builtins/lib/autoComplete.d.ts +7 -0
- package/dist/blocks/builtins/lib/autoComplete.js +20 -0
- package/dist/blocks/builtins/lib/autoComplete.js.map +1 -0
- package/dist/blocks/builtins/lib/bookingUrl.d.ts +2 -2
- package/dist/blocks/builtins/lib/bookingUrl.js +1 -1
- package/dist/blocks/builtins/lib/bookingUrl.js.map +1 -1
- package/dist/blocks/builtins/lib/ical.d.ts +24 -0
- package/dist/blocks/builtins/lib/ical.js +82 -0
- package/dist/blocks/builtins/lib/ical.js.map +1 -0
- package/dist/blocks/builtins/lib/vandaag.d.ts +8 -0
- package/dist/blocks/builtins/lib/vandaag.js +22 -0
- package/dist/blocks/builtins/lib/vandaag.js.map +1 -0
- package/dist/blocks/registry.d.ts +6 -0
- package/dist/blocks/registry.js.map +1 -1
- package/dist/blocks/ui/index.js +1 -0
- package/dist/blocks/ui/index.js.map +1 -1
- package/dist/components/EditBar.js +2 -4
- package/dist/components/EditBar.js.map +1 -1
- package/dist/components/News.js +26 -18
- package/dist/components/News.js.map +1 -1
- package/dist/components/PageView.d.ts +7 -1
- package/dist/components/PageView.js +17 -0
- package/dist/components/PageView.js.map +1 -1
- package/dist/components/ResponsiveImage.js +18 -20
- package/dist/components/ResponsiveImage.js.map +1 -1
- package/dist/components/onderOffset.d.ts +13 -0
- package/dist/components/onderOffset.js +74 -0
- package/dist/components/onderOffset.js.map +1 -0
- package/dist/components/site/Bedrijfsnummers.d.ts +9 -0
- package/dist/components/site/Bedrijfsnummers.js +12 -0
- package/dist/components/site/Bedrijfsnummers.js.map +1 -0
- package/dist/components/site/SiteFooter.d.ts +6 -1
- package/dist/components/site/SiteFooter.js +62 -9
- package/dist/components/site/SiteFooter.js.map +1 -1
- package/dist/components/site/SiteHeader.d.ts +15 -0
- package/dist/components/site/SiteHeader.js +70 -0
- package/dist/components/site/SiteHeader.js.map +1 -0
- package/dist/components/site/SiteNav.d.ts +2 -0
- package/dist/components/site/SiteNav.js +29 -5
- package/dist/components/site/SiteNav.js.map +1 -1
- package/dist/demo/DemoStudio.js +2 -2
- package/dist/demo/DemoStudio.js.map +1 -1
- package/dist/demo/demoStore.d.ts +13 -0
- package/dist/demo/demoStore.js +36 -0
- package/dist/demo/demoStore.js.map +1 -1
- package/dist/editor/EditorProvider.js +15 -4
- package/dist/editor/EditorProvider.js.map +1 -1
- package/dist/firebase/functionsClient.js +5 -1
- package/dist/firebase/functionsClient.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +20 -1
- package/dist/index.js.map +1 -1
- package/dist/media/ImageContext.d.ts +17 -0
- package/dist/media/ImageContext.js +65 -20
- package/dist/media/ImageContext.js.map +1 -1
- package/dist/media/altInHtml.d.ts +9 -0
- package/dist/media/altInHtml.js +17 -0
- package/dist/media/altInHtml.js.map +1 -0
- package/dist/media/srcset.d.ts +12 -0
- package/dist/media/srcset.js +13 -0
- package/dist/media/srcset.js.map +1 -0
- package/dist/modules/builtins.d.ts +1 -0
- package/dist/modules/builtins.js +22 -9
- package/dist/modules/builtins.js.map +1 -1
- package/dist/modules/consent/ConsentBanner.d.ts +5 -0
- package/dist/modules/consent/ConsentBanner.js +8 -7
- package/dist/modules/consent/ConsentBanner.js.map +1 -1
- package/dist/modules/consent/standaard.d.ts +12 -0
- package/dist/modules/consent/standaard.js +10 -0
- package/dist/modules/consent/standaard.js.map +1 -0
- package/dist/modules/consent/useConsent.d.ts +4 -0
- package/dist/modules/consent/useConsent.js +30 -1
- package/dist/modules/consent/useConsent.js.map +1 -1
- package/dist/modules/shop/blocks/Cart.js +5 -3
- package/dist/modules/shop/blocks/Cart.js.map +1 -1
- package/dist/modules/shop/blocks/Checkout.js +56 -35
- package/dist/modules/shop/blocks/Checkout.js.map +1 -1
- package/dist/modules/shop/blocks/Donation.js +4 -4
- package/dist/modules/shop/blocks/Donation.js.map +1 -1
- package/dist/modules/shop/blocks/ProductDetail.js +19 -3
- package/dist/modules/shop/blocks/ProductDetail.js.map +1 -1
- package/dist/modules/shop/blocks/ProductGrid.d.ts +3 -1
- package/dist/modules/shop/blocks/ProductGrid.js +8 -4
- package/dist/modules/shop/blocks/ProductGrid.js.map +1 -1
- package/dist/modules/shop/blocks/ShopCategories.js +4 -3
- package/dist/modules/shop/blocks/ShopCategories.js.map +1 -1
- package/dist/modules/shop/lib.d.ts +4 -0
- package/dist/modules/shop/lib.js +14 -0
- package/dist/modules/shop/lib.js.map +1 -1
- package/dist/modules/shop/settings.d.ts +3 -0
- package/dist/modules/shop/settings.js +14 -0
- package/dist/modules/shop/settings.js.map +1 -1
- package/dist/modules/shop/strings.d.ts +4 -0
- package/dist/modules/shop/strings.js +8 -0
- package/dist/modules/shop/strings.js.map +1 -1
- package/dist/next/envCheck.d.ts +42 -0
- package/dist/next/envCheck.js +106 -0
- package/dist/next/envCheck.js.map +1 -0
- package/dist/next/index.cjs +185 -2
- package/dist/next/index.d.ts +2 -0
- package/dist/next/index.js +8 -1
- package/dist/next/index.js.map +1 -1
- package/dist/next/securityHeaders.d.ts +36 -0
- package/dist/next/securityHeaders.js +74 -0
- package/dist/next/securityHeaders.js.map +1 -0
- package/dist/patterns/builtins.d.ts +7 -0
- package/dist/patterns/builtins.js +138 -3
- package/dist/patterns/builtins.js.map +1 -1
- package/dist/releaseNotes.js +148 -0
- package/dist/releaseNotes.js.map +1 -1
- package/dist/render/PublishedPage.d.ts +2 -1
- package/dist/render/PublishedPage.js +10 -4
- package/dist/render/PublishedPage.js.map +1 -1
- package/dist/schema/blocks.d.ts +473 -0
- package/dist/schema/blocks.js +105 -5
- package/dist/schema/blocks.js.map +1 -1
- package/dist/schema/business.d.ts +118 -0
- package/dist/schema/business.js +75 -0
- package/dist/schema/business.js.map +1 -0
- package/dist/schema/fields.d.ts +2 -1
- package/dist/schema/fields.js.map +1 -1
- package/dist/schema/forms.d.ts +18 -0
- package/dist/schema/forms.js +18 -3
- package/dist/schema/forms.js.map +1 -1
- package/dist/schema/mail.d.ts +10 -0
- package/dist/schema/mail.js +7 -0
- package/dist/schema/mail.js.map +1 -1
- package/dist/schema/settings.d.ts +103 -0
- package/dist/schema/settings.js +24 -3
- package/dist/schema/settings.js.map +1 -1
- package/dist/schema/shop.d.ts +2 -0
- package/dist/schema/shop.js +4 -0
- package/dist/schema/shop.js.map +1 -1
- package/dist/schema/shopGeld.d.ts +1 -0
- package/dist/schema/shopGeld.js +1 -0
- package/dist/schema/shopGeld.js.map +1 -1
- package/dist/schema/siteConfig.d.ts +69 -1
- package/dist/schema/siteConfig.js +7 -2
- package/dist/schema/siteConfig.js.map +1 -1
- package/dist/server/blockData.d.ts +1 -1
- package/dist/server/blockData.js +74 -18
- package/dist/server/blockData.js.map +1 -1
- package/dist/server/cspRapport.d.ts +20 -0
- package/dist/server/cspRapport.js +56 -0
- package/dist/server/cspRapport.js.map +1 -0
- package/dist/server/fonts.d.ts +3 -0
- package/dist/server/fonts.js +39 -0
- package/dist/server/fonts.js.map +1 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +8 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/sanitize.js +2 -0
- package/dist/server/sanitize.js.map +1 -1
- package/dist/settings/useSiteSettings.js +4 -1
- package/dist/settings/useSiteSettings.js.map +1 -1
- package/dist/starters/starters.d.ts +69 -0
- package/dist/starters/starters.js +171 -0
- package/dist/starters/starters.js.map +1 -0
- package/dist/styles.css +1181 -212
- package/dist/theme/color.d.ts +10 -0
- package/dist/theme/color.js +17 -1
- package/dist/theme/color.js.map +1 -1
- package/dist/theme/fontFallback.d.ts +23 -0
- package/dist/theme/fontFallback.js +58 -0
- package/dist/theme/fontFallback.js.map +1 -0
- package/dist/theme/fonts.d.ts +11 -0
- package/dist/theme/fonts.js +16 -0
- package/dist/theme/fonts.js.map +1 -0
- package/dist/version.js +1 -1
- package/package.json +5 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/blocks/builtins/OpeningHoursRender.tsx"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../../src/blocks/builtins/OpeningHoursRender.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport { jsonLdHtml } from \"./jsonld\";\nimport type { OpeningHoursBlockSchema } from \"../../schema/blocks\";\nimport type { BlockRenderProps } from \"../registry\";\nimport { Heading } from \"../ui\";\nimport { OpenNowBadge } from \"./OpenNowBadge\";\nimport { openingHoursSpecJsonLd } from \"./lib/openingHours\";\nimport { useMergedSiteConfig } from \"../../settings/useSiteSettings\";\nimport { afwijkingDatumTekst, komendeAfwijkingen } from \"../../bedrijf/bedrijf\";\n\ntype OpeningHours = z.infer<typeof OpeningHoursBlockSchema>;\n\n/**\n * Openingstijden-tabel; de optionele \"Nu geopend\"-badge is een client-eiland.\n *\n * 8.13: zonder eigen regels toont het blok de tijden uit het bedrijfsprofiel (Instellingen →\n * Bedrijf) — één keer invullen, overal hetzelfde. Afwijkende dagen uit het profiel (feestdagen,\n * vakantie) die binnenkort vallen, staan eronder, en tellen mee voor \"nu geopend\".\n */\nexport function OpeningHoursRender({ block, mode }: BlockRenderProps<OpeningHours>) {\n const business = useMergedSiteConfig().business;\n const eigen = (block.rows ?? []).filter((r) => r.day.trim() || r.hours.trim());\n const uitProfiel = eigen.length === 0;\n const rows = uitProfiel ? (business?.hours ?? []) : block.rows ?? [];\n const afwijkingen = komendeAfwijkingen(business?.exceptions);\n // Komt de tijd uit het profiel, dan staat de JSON-LD al in de layout (bedrijfJsonLd).\n const spec = block.jsonLd && !uitProfiel ? openingHoursSpecJsonLd(rows) : [];\n if (rows.length === 0 && afwijkingen.length === 0) {\n return mode === \"preview\" ? (\n <p className=\"xicms-ve__hint\">Openingstijden: vul ze één keer in bij Instellingen → Bedrijf, of geef dit blok eigen regels.</p>\n ) : null;\n }\n return (\n <section className=\"xicms-hours\">\n {block.heading && <Heading level={2} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n {block.showStatus && <OpenNowBadge rows={rows} afwijkingen={business?.exceptions} />}\n <table className=\"xicms-hours-table\">\n <tbody>\n {rows.map((r, i) => (\n <tr key={i}>\n <th scope=\"row\" data-xicms-edit={uitProfiel ? undefined : `rows.${i}.day`}>{r.day}</th>\n <td data-xicms-edit={uitProfiel ? undefined : `rows.${i}.hours`}>{r.hours}</td>\n </tr>\n ))}\n </tbody>\n </table>\n {uitProfiel && business?.hoursNote && <p className=\"xicms-hours__noot\">{business.hoursNote}</p>}\n {afwijkingen.length > 0 && (\n <div className=\"xicms-hours__afwijkend\" role=\"note\">\n <strong>Aangepaste openingstijden</strong>\n <ul>\n {afwijkingen.map((a, i) => (\n <li key={i}>\n <span>{afwijkingDatumTekst(a)}{a.label ? ` (${a.label})` : \"\"}</span>\n <span>{a.hours}</span>\n </li>\n ))}\n </ul>\n </div>\n )}\n {spec.length > 0 && (\n <script\n type=\"application/ld+json\"\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{\n // Zelfde @id als contact-/layout-JSON-LD → Google voegt de drie samen tot één bedrijf.\n __html: jsonLdHtml({ \"@context\": \"https://schema.org\", \"@type\": \"LocalBusiness\", \"@id\": \"#business\", openingHoursSpecification: spec }),\n }}\n />\n )}\n </section>\n );\n}\n"],"mappings":";AA+BM,cAUM,YAVN;AA5BN,SAAS,kBAAkB;AAG3B,SAAS,eAAe;AACxB,SAAS,oBAAoB;AAC7B,SAAS,8BAA8B;AACvC,SAAS,2BAA2B;AACpC,SAAS,qBAAqB,0BAA0B;AAWjD,SAAS,mBAAmB,EAAE,OAAO,KAAK,GAAmC;AAClF,QAAM,WAAW,oBAAoB,EAAE;AACvC,QAAM,SAAS,MAAM,QAAQ,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,IAAI,KAAK,KAAK,EAAE,MAAM,KAAK,CAAC;AAC7E,QAAM,aAAa,MAAM,WAAW;AACpC,QAAM,OAAO,aAAc,UAAU,SAAS,CAAC,IAAK,MAAM,QAAQ,CAAC;AACnE,QAAM,cAAc,mBAAmB,UAAU,UAAU;AAE3D,QAAM,OAAO,MAAM,UAAU,CAAC,aAAa,uBAAuB,IAAI,IAAI,CAAC;AAC3E,MAAI,KAAK,WAAW,KAAK,YAAY,WAAW,GAAG;AACjD,WAAO,SAAS,YACd,oBAAC,OAAE,WAAU,kBAAiB,sHAA6F,IACzH;AAAA,EACN;AACA,SACE,qBAAC,aAAQ,WAAU,eAChB;AAAA,UAAM,WAAW,oBAAC,WAAQ,OAAO,GAAG,mBAAgB,WAAW,gBAAM,SAAQ;AAAA,IAC7E,MAAM,cAAc,oBAAC,gBAAa,MAAY,aAAa,UAAU,YAAY;AAAA,IAClF,oBAAC,WAAM,WAAU,qBACf,8BAAC,WACE,eAAK,IAAI,CAAC,GAAG,MACZ,qBAAC,QACC;AAAA,0BAAC,QAAG,OAAM,OAAM,mBAAiB,aAAa,SAAY,QAAQ,CAAC,QAAS,YAAE,KAAI;AAAA,MAClF,oBAAC,QAAG,mBAAiB,aAAa,SAAY,QAAQ,CAAC,UAAW,YAAE,OAAM;AAAA,SAFnE,CAGT,CACD,GACH,GACF;AAAA,IACC,cAAc,UAAU,aAAa,oBAAC,OAAE,WAAU,qBAAqB,mBAAS,WAAU;AAAA,IAC1F,YAAY,SAAS,KACpB,qBAAC,SAAI,WAAU,0BAAyB,MAAK,QAC3C;AAAA,0BAAC,YAAO,uCAAyB;AAAA,MACjC,oBAAC,QACE,sBAAY,IAAI,CAAC,GAAG,MACnB,qBAAC,QACC;AAAA,6BAAC,UAAM;AAAA,8BAAoB,CAAC;AAAA,UAAG,EAAE,QAAQ,KAAK,EAAE,KAAK,MAAM;AAAA,WAAG;AAAA,QAC9D,oBAAC,UAAM,YAAE,OAAM;AAAA,WAFR,CAGT,CACD,GACH;AAAA,OACF;AAAA,IAED,KAAK,SAAS,KACb;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QAEL,yBAAyB;AAAA;AAAA,UAEvB,QAAQ,WAAW,EAAE,YAAY,sBAAsB,SAAS,iBAAiB,OAAO,aAAa,2BAA2B,KAAK,CAAC;AAAA,QACxI;AAAA;AAAA,IACF;AAAA,KAEJ;AAEJ;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const priceListBlock: import("../index.js").BlockDefinition<import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import dynamic from "next/dynamic";
|
|
2
|
+
import { defineBlock } from "../registry.js";
|
|
3
|
+
const priceListBlock = defineBlock({
|
|
4
|
+
type: "priceList",
|
|
5
|
+
Render: dynamic(() => import("./PriceListRender.js").then((m) => m.PriceListRender)),
|
|
6
|
+
label: "Prijslijst / menukaart",
|
|
7
|
+
icon: "\u{1F9FE}",
|
|
8
|
+
defaults: () => ({
|
|
9
|
+
heading: "Prijzen",
|
|
10
|
+
variant: "lijst",
|
|
11
|
+
sections: [
|
|
12
|
+
{
|
|
13
|
+
title: "Behandelingen",
|
|
14
|
+
items: [
|
|
15
|
+
{ name: "Dienst \xE9\xE9n", description: "Korte omschrijving.", price: "\u20AC 25", duration: "30 min" },
|
|
16
|
+
{ name: "Dienst twee", description: "Korte omschrijving.", price: "\u20AC 40", duration: "45 min" }
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
})
|
|
21
|
+
});
|
|
22
|
+
export {
|
|
23
|
+
priceListBlock
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=PriceList.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/blocks/builtins/PriceList.tsx"],"sourcesContent":["import dynamic from \"next/dynamic\";\nimport { defineBlock } from \"../registry\";\n\nexport const priceListBlock = defineBlock({\n type: \"priceList\",\n Render: dynamic(() => import(\"./PriceListRender\").then((m) => m.PriceListRender)),\n label: \"Prijslijst / menukaart\",\n icon: \"🧾\",\n defaults: () => ({\n heading: \"Prijzen\",\n variant: \"lijst\",\n sections: [\n {\n title: \"Behandelingen\",\n items: [\n { name: \"Dienst één\", description: \"Korte omschrijving.\", price: \"€ 25\", duration: \"30 min\" },\n { name: \"Dienst twee\", description: \"Korte omschrijving.\", price: \"€ 40\", duration: \"45 min\" },\n ],\n },\n ],\n }),\n});\n"],"mappings":"AAAA,OAAO,aAAa;AACpB,SAAS,mBAAmB;AAErB,MAAM,iBAAiB,YAAY;AAAA,EACxC,MAAM;AAAA,EACN,QAAQ,QAAQ,MAAM,OAAO,mBAAmB,EAAE,KAAK,CAAC,MAAM,EAAE,eAAe,CAAC;AAAA,EAChF,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO;AAAA,IACf,SAAS;AAAA,IACT,SAAS;AAAA,IACT,UAAU;AAAA,MACR;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,UACL,EAAE,MAAM,oBAAc,aAAa,uBAAuB,OAAO,aAAQ,UAAU,SAAS;AAAA,UAC5F,EAAE,MAAM,eAAe,aAAa,uBAAuB,OAAO,aAAQ,UAAU,SAAS;AAAA,QAC/F;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;","names":[]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import type { PriceListBlockSchema } from "../../schema/blocks.js";
|
|
3
|
+
import type { BlockRenderProps } from "../registry.js";
|
|
4
|
+
type PriceList = z.infer<typeof PriceListBlockSchema>;
|
|
5
|
+
/** "€ 27,50" / "27.50" / "vanaf € 12" → 27.5 / 12; geen getal → undefined (dan geen prijs in de JSON-LD). */
|
|
6
|
+
export declare function prijsGetal(prijs: string | undefined): number | undefined;
|
|
7
|
+
/** schema.org: een horecamenu wordt Menu → MenuSection → MenuItem; al het andere een OfferCatalog. */
|
|
8
|
+
export declare function prijslijstJsonLd(b: PriceList): Record<string, unknown>;
|
|
9
|
+
/**
|
|
10
|
+
* Prijslijst / menukaart (8.13). Drie weergaven op dezelfde gegevens:
|
|
11
|
+
* - lijst: naam … prijs op één regel, omschrijving en duur eronder (kapper, praktijk);
|
|
12
|
+
* - menu: gecentreerde kaart in de koppenletter (restaurant, café);
|
|
13
|
+
* - kolommen: de secties naast elkaar (uitgebreide kaart of tarieflijst).
|
|
14
|
+
* Elke tekst heeft een veldhaak, dus alles is op de pagina zelf te bewerken (ook regels toevoegen).
|
|
15
|
+
*/
|
|
16
|
+
export declare function PriceListRender({ block, mode }: BlockRenderProps<PriceList>): import("react").JSX.Element | null;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Heading } from "../ui/index.js";
|
|
4
|
+
import { jsonLdHtml } from "./jsonld.js";
|
|
5
|
+
function prijsGetal(prijs) {
|
|
6
|
+
const m = /(\d+(?:[.,]\d{1,2})?)/.exec((prijs ?? "").replace(/\s/g, ""));
|
|
7
|
+
if (!m) return void 0;
|
|
8
|
+
const n = Number(m[1].replace(",", "."));
|
|
9
|
+
return Number.isFinite(n) ? n : void 0;
|
|
10
|
+
}
|
|
11
|
+
function prijslijstJsonLd(b) {
|
|
12
|
+
const aanbod = (prijs) => {
|
|
13
|
+
const n = prijsGetal(prijs);
|
|
14
|
+
return n === void 0 ? void 0 : { "@type": "Offer", price: n.toFixed(2), priceCurrency: "EUR" };
|
|
15
|
+
};
|
|
16
|
+
if (b.variant === "menu") {
|
|
17
|
+
return {
|
|
18
|
+
"@context": "https://schema.org",
|
|
19
|
+
"@type": "Menu",
|
|
20
|
+
...b.heading ? { name: b.heading } : {},
|
|
21
|
+
hasMenuSection: (b.sections ?? []).map((s) => ({
|
|
22
|
+
"@type": "MenuSection",
|
|
23
|
+
name: s.title,
|
|
24
|
+
hasMenuItem: (s.items ?? []).filter((i) => i.name.trim()).map((i) => ({
|
|
25
|
+
"@type": "MenuItem",
|
|
26
|
+
name: i.name,
|
|
27
|
+
...i.description ? { description: i.description } : {},
|
|
28
|
+
...aanbod(i.price) ? { offers: aanbod(i.price) } : {}
|
|
29
|
+
}))
|
|
30
|
+
}))
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
"@context": "https://schema.org",
|
|
35
|
+
"@type": "OfferCatalog",
|
|
36
|
+
...b.heading ? { name: b.heading } : {},
|
|
37
|
+
itemListElement: (b.sections ?? []).map((s) => ({
|
|
38
|
+
"@type": "OfferCatalog",
|
|
39
|
+
name: s.title,
|
|
40
|
+
itemListElement: (s.items ?? []).filter((i) => i.name.trim()).map((i) => ({
|
|
41
|
+
"@type": "Offer",
|
|
42
|
+
itemOffered: { "@type": "Service", name: i.name, ...i.description ? { description: i.description } : {} },
|
|
43
|
+
...prijsGetal(i.price) !== void 0 ? { price: prijsGetal(i.price).toFixed(2), priceCurrency: "EUR" } : {}
|
|
44
|
+
}))
|
|
45
|
+
}))
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function PriceListRender({ block, mode }) {
|
|
49
|
+
const secties = block.sections ?? [];
|
|
50
|
+
if (secties.length === 0 && mode !== "preview") return null;
|
|
51
|
+
const variant = block.variant ?? "lijst";
|
|
52
|
+
return /* @__PURE__ */ jsxs("section", { className: "xicms-prijslijst", "data-variant": variant, children: [
|
|
53
|
+
(block.heading || block.intro) && /* @__PURE__ */ jsxs("header", { className: "xicms-prijslijst__kop", children: [
|
|
54
|
+
block.heading && /* @__PURE__ */ jsx(Heading, { level: 2, "data-xicms-edit": "heading", children: block.heading }),
|
|
55
|
+
block.intro && /* @__PURE__ */ jsx("p", { className: "xicms-prijslijst__intro", "data-xicms-edit": "intro", children: block.intro })
|
|
56
|
+
] }),
|
|
57
|
+
/* @__PURE__ */ jsx("div", { className: "xicms-prijslijst__secties", children: secties.map((s, si) => /* @__PURE__ */ jsxs("div", { className: "xicms-prijslijst__sectie", children: [
|
|
58
|
+
s.title && /* @__PURE__ */ jsx("h3", { className: "xicms-prijslijst__sectietitel", "data-xicms-edit": `sections.${si}.title`, children: s.title }),
|
|
59
|
+
s.note && /* @__PURE__ */ jsx("p", { className: "xicms-prijslijst__noot", "data-xicms-edit": `sections.${si}.note`, children: s.note }),
|
|
60
|
+
/* @__PURE__ */ jsx("ul", { className: "xicms-prijslijst__regels", children: (s.items ?? []).map((it, ii) => {
|
|
61
|
+
const pad = `sections.${si}.items.${ii}`;
|
|
62
|
+
const tags = (it.tags ?? "").split(",").map((t) => t.trim()).filter(Boolean);
|
|
63
|
+
return /* @__PURE__ */ jsxs("li", { className: `xicms-prijslijst__regel${it.featured ? " is-uitgelicht" : ""}`, children: [
|
|
64
|
+
/* @__PURE__ */ jsxs("div", { className: "xicms-prijslijst__lijn", children: [
|
|
65
|
+
/* @__PURE__ */ jsx("span", { className: "xicms-prijslijst__naam", "data-xicms-edit": `${pad}.name`, children: it.name }),
|
|
66
|
+
/* @__PURE__ */ jsx("span", { className: "xicms-prijslijst__puntjes", "aria-hidden": true }),
|
|
67
|
+
it.price && /* @__PURE__ */ jsx("span", { className: "xicms-prijslijst__prijs", "data-xicms-edit": `${pad}.price`, children: it.price })
|
|
68
|
+
] }),
|
|
69
|
+
(it.description || it.duration || tags.length > 0) && /* @__PURE__ */ jsxs("div", { className: "xicms-prijslijst__details", children: [
|
|
70
|
+
it.description && /* @__PURE__ */ jsx("span", { "data-xicms-edit": `${pad}.description`, children: it.description }),
|
|
71
|
+
it.duration && /* @__PURE__ */ jsx("span", { className: "xicms-prijslijst__duur", "data-xicms-edit": `${pad}.duration`, children: it.duration }),
|
|
72
|
+
tags.map((t) => /* @__PURE__ */ jsx("span", { className: "xicms-prijslijst__tag", children: t }, t))
|
|
73
|
+
] })
|
|
74
|
+
] }, ii);
|
|
75
|
+
}) })
|
|
76
|
+
] }, si)) }),
|
|
77
|
+
block.footnote && /* @__PURE__ */ jsx("p", { className: "xicms-prijslijst__voetnoot", "data-xicms-edit": "footnote", children: block.footnote }),
|
|
78
|
+
block.jsonLd && // eslint-disable-next-line react/no-danger
|
|
79
|
+
/* @__PURE__ */ jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: { __html: jsonLdHtml(prijslijstJsonLd(block)) } })
|
|
80
|
+
] });
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
PriceListRender,
|
|
84
|
+
prijsGetal,
|
|
85
|
+
prijslijstJsonLd
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=PriceListRender.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/blocks/builtins/PriceListRender.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport type { PriceListBlockSchema } from \"../../schema/blocks\";\nimport type { BlockRenderProps } from \"../registry\";\nimport { Heading } from \"../ui\";\nimport { jsonLdHtml } from \"./jsonld\";\n\ntype PriceList = z.infer<typeof PriceListBlockSchema>;\n\n/** \"€ 27,50\" / \"27.50\" / \"vanaf € 12\" → 27.5 / 12; geen getal → undefined (dan geen prijs in de JSON-LD). */\nexport function prijsGetal(prijs: string | undefined): number | undefined {\n const m = /(\\d+(?:[.,]\\d{1,2})?)/.exec((prijs ?? \"\").replace(/\\s/g, \"\"));\n if (!m) return undefined;\n const n = Number(m[1].replace(\",\", \".\"));\n return Number.isFinite(n) ? n : undefined;\n}\n\n/** schema.org: een horecamenu wordt Menu → MenuSection → MenuItem; al het andere een OfferCatalog. */\nexport function prijslijstJsonLd(b: PriceList): Record<string, unknown> {\n const aanbod = (prijs: string | undefined) => {\n const n = prijsGetal(prijs);\n return n === undefined ? undefined : { \"@type\": \"Offer\", price: n.toFixed(2), priceCurrency: \"EUR\" };\n };\n if (b.variant === \"menu\") {\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"Menu\",\n ...(b.heading ? { name: b.heading } : {}),\n hasMenuSection: (b.sections ?? []).map((s) => ({\n \"@type\": \"MenuSection\",\n name: s.title,\n hasMenuItem: (s.items ?? []).filter((i) => i.name.trim()).map((i) => ({\n \"@type\": \"MenuItem\",\n name: i.name,\n ...(i.description ? { description: i.description } : {}),\n ...(aanbod(i.price) ? { offers: aanbod(i.price) } : {}),\n })),\n })),\n };\n }\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"OfferCatalog\",\n ...(b.heading ? { name: b.heading } : {}),\n itemListElement: (b.sections ?? []).map((s) => ({\n \"@type\": \"OfferCatalog\",\n name: s.title,\n itemListElement: (s.items ?? []).filter((i) => i.name.trim()).map((i) => ({\n \"@type\": \"Offer\",\n itemOffered: { \"@type\": \"Service\", name: i.name, ...(i.description ? { description: i.description } : {}) },\n ...(prijsGetal(i.price) !== undefined ? { price: prijsGetal(i.price)!.toFixed(2), priceCurrency: \"EUR\" } : {}),\n })),\n })),\n };\n}\n\n/**\n * Prijslijst / menukaart (8.13). Drie weergaven op dezelfde gegevens:\n * - lijst: naam … prijs op één regel, omschrijving en duur eronder (kapper, praktijk);\n * - menu: gecentreerde kaart in de koppenletter (restaurant, café);\n * - kolommen: de secties naast elkaar (uitgebreide kaart of tarieflijst).\n * Elke tekst heeft een veldhaak, dus alles is op de pagina zelf te bewerken (ook regels toevoegen).\n */\nexport function PriceListRender({ block, mode }: BlockRenderProps<PriceList>) {\n const secties = block.sections ?? [];\n if (secties.length === 0 && mode !== \"preview\") return null;\n const variant = block.variant ?? \"lijst\";\n return (\n <section className=\"xicms-prijslijst\" data-variant={variant}>\n {(block.heading || block.intro) && (\n <header className=\"xicms-prijslijst__kop\">\n {block.heading && <Heading level={2} data-xicms-edit=\"heading\">{block.heading}</Heading>}\n {block.intro && <p className=\"xicms-prijslijst__intro\" data-xicms-edit=\"intro\">{block.intro}</p>}\n </header>\n )}\n <div className=\"xicms-prijslijst__secties\">\n {secties.map((s, si) => (\n <div key={si} className=\"xicms-prijslijst__sectie\">\n {s.title && <h3 className=\"xicms-prijslijst__sectietitel\" data-xicms-edit={`sections.${si}.title`}>{s.title}</h3>}\n {s.note && <p className=\"xicms-prijslijst__noot\" data-xicms-edit={`sections.${si}.note`}>{s.note}</p>}\n <ul className=\"xicms-prijslijst__regels\">\n {(s.items ?? []).map((it, ii) => {\n const pad = `sections.${si}.items.${ii}`;\n const tags = (it.tags ?? \"\").split(\",\").map((t) => t.trim()).filter(Boolean);\n return (\n <li key={ii} className={`xicms-prijslijst__regel${it.featured ? \" is-uitgelicht\" : \"\"}`}>\n <div className=\"xicms-prijslijst__lijn\">\n <span className=\"xicms-prijslijst__naam\" data-xicms-edit={`${pad}.name`}>{it.name}</span>\n <span className=\"xicms-prijslijst__puntjes\" aria-hidden />\n {it.price && <span className=\"xicms-prijslijst__prijs\" data-xicms-edit={`${pad}.price`}>{it.price}</span>}\n </div>\n {(it.description || it.duration || tags.length > 0) && (\n <div className=\"xicms-prijslijst__details\">\n {it.description && <span data-xicms-edit={`${pad}.description`}>{it.description}</span>}\n {it.duration && <span className=\"xicms-prijslijst__duur\" data-xicms-edit={`${pad}.duration`}>{it.duration}</span>}\n {tags.map((t) => (\n <span key={t} className=\"xicms-prijslijst__tag\">{t}</span>\n ))}\n </div>\n )}\n </li>\n );\n })}\n </ul>\n </div>\n ))}\n </div>\n {block.footnote && <p className=\"xicms-prijslijst__voetnoot\" data-xicms-edit=\"footnote\">{block.footnote}</p>}\n {block.jsonLd && (\n // eslint-disable-next-line react/no-danger\n <script type=\"application/ld+json\" dangerouslySetInnerHTML={{ __html: jsonLdHtml(prijslijstJsonLd(block)) }} />\n )}\n </section>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useBlockData } from "../context.js";
|
|
4
|
+
import { vulAltIn } from "../../media/altInHtml.js";
|
|
2
5
|
function RichTextRender({ block }) {
|
|
3
|
-
|
|
6
|
+
const media = useBlockData("media");
|
|
7
|
+
const html = media ? vulAltIn(block.html, (src) => media[src]?.alt) : block.html;
|
|
8
|
+
return /* @__PURE__ */ jsx("div", { className: "xicms-richtext", "data-xicms-edit": "html", dangerouslySetInnerHTML: { __html: html } });
|
|
4
9
|
}
|
|
5
10
|
export {
|
|
6
11
|
RichTextRender
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/blocks/builtins/RichTextBlockRender.tsx"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../../src/blocks/builtins/RichTextBlockRender.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport type { RichTextBlockSchema } from \"../../schema/blocks\";\nimport type { BlockRenderProps } from \"../registry\";\nimport { useBlockData } from \"../context\";\nimport { vulAltIn } from \"../../media/altInHtml\";\n\ntype RichText = z.infer<typeof RichTextBlockSchema>;\n\nexport function RichTextRender({ block }: BlockRenderProps<RichText>) {\n // Twee bronnen, twee saneringen — allebei vóór dit punt:\n // - GEPUBLICEERD: `publishPage` haalt de blokken door `sanitizeBlocks`, en de Firestore-rules\n // maken `pages` Functions-only. Wat hier binnenkomt is dus al server-side gesaneerd.\n // - WERKVERSIE: die schrijven editors rechtstreeks naar `drafts`, waar rules geen HTML kunnen\n // saneren. Daarom saneert de editor bij het INLEZEN (admin/lib/sanitizeDraft.ts).\n // Ga hier dus niet vanuit \"opslaan heeft het al gedaan\" — dat gold nooit voor werkversies.\n // `data-xicms-edit=\"html\"` geeft dit blok een haakje voor de rode wijzigings-highlight in de\n // visuele editor — zonder dit hook bleef een gewijzigd tekstblok (juist het bloktype dat een\n // klant het vaakst bewerkt) als enige zonder markering, terwijl andere tekstvelden wél rood\n // oplichtten.\n const media = useBlockData<Record<string, { alt?: string }>>(\"media\");\n const html = media ? vulAltIn(block.html, (src) => media[src]?.alt) : block.html;\n return <div className=\"xicms-richtext\" data-xicms-edit=\"html\" dangerouslySetInnerHTML={{ __html: html }} />;\n}\n"],"mappings":";AAuBS;AAlBT,SAAS,oBAAoB;AAC7B,SAAS,gBAAgB;AAIlB,SAAS,eAAe,EAAE,MAAM,GAA+B;AAWpE,QAAM,QAAQ,aAA+C,OAAO;AACpE,QAAM,OAAO,QAAQ,SAAS,MAAM,MAAM,CAAC,QAAQ,MAAM,GAAG,GAAG,GAAG,IAAI,MAAM;AAC5E,SAAO,oBAAC,SAAI,WAAU,kBAAiB,mBAAgB,QAAO,yBAAyB,EAAE,QAAQ,KAAK,GAAG;AAC3G;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const sectionHeadingBlock: import("../index.js").BlockDefinition<import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { defineBlock } from "../registry.js";
|
|
2
|
+
import { SectionHeadingRender } from "./SectionHeadingRender.js";
|
|
3
|
+
const sectionHeadingBlock = defineBlock({
|
|
4
|
+
type: "sectionHeading",
|
|
5
|
+
// Klein en altijd boven de vouw van een sectie: niet lazy, anders flitst de kop na.
|
|
6
|
+
Render: SectionHeadingRender,
|
|
7
|
+
label: "Sectiekop",
|
|
8
|
+
icon: "\u{1F524}",
|
|
9
|
+
defaults: () => ({ eyebrow: "", title: "Kop van deze sectie", intro: "", align: "center" })
|
|
10
|
+
});
|
|
11
|
+
export {
|
|
12
|
+
sectionHeadingBlock
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=SectionHeading.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/blocks/builtins/SectionHeading.tsx"],"sourcesContent":["import { defineBlock } from \"../registry\";\nimport { SectionHeadingRender } from \"./SectionHeadingRender\";\n\nexport const sectionHeadingBlock = defineBlock({\n type: \"sectionHeading\",\n // Klein en altijd boven de vouw van een sectie: niet lazy, anders flitst de kop na.\n Render: SectionHeadingRender,\n label: \"Sectiekop\",\n icon: \"🔤\",\n defaults: () => ({ eyebrow: \"\", title: \"Kop van deze sectie\", intro: \"\", align: \"center\" }),\n});\n"],"mappings":"AAAA,SAAS,mBAAmB;AAC5B,SAAS,4BAA4B;AAE9B,MAAM,sBAAsB,YAAY;AAAA,EAC7C,MAAM;AAAA;AAAA,EAEN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,SAAS,IAAI,OAAO,uBAAuB,OAAO,IAAI,OAAO,SAAS;AAC3F,CAAC;","names":[]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import type { SectionHeadingBlockSchema } from "../../schema/blocks.js";
|
|
3
|
+
import type { BlockRenderProps } from "../registry.js";
|
|
4
|
+
type SectieKop = z.infer<typeof SectionHeadingBlockSchema>;
|
|
5
|
+
/** Sectiekop (8.13): regeltje, kop en inleiding — overal dezelfde opbouw en uitlijning. */
|
|
6
|
+
export declare function SectionHeadingRender({ block }: BlockRenderProps<SectieKop>): import("react").JSX.Element | null;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Heading } from "../ui/index.js";
|
|
3
|
+
function SectionHeadingRender({ block }) {
|
|
4
|
+
if (!block.title && !block.eyebrow && !block.intro) return null;
|
|
5
|
+
return /* @__PURE__ */ jsxs("header", { className: "xicms-sectiekop", "data-align": block.align ?? "center", children: [
|
|
6
|
+
block.eyebrow && /* @__PURE__ */ jsx("p", { className: "xicms-sectiekop__regel", "data-xicms-edit": "eyebrow", children: block.eyebrow }),
|
|
7
|
+
block.title && /* @__PURE__ */ jsx(Heading, { level: 2, "data-xicms-edit": "title", children: block.title }),
|
|
8
|
+
block.intro && /* @__PURE__ */ jsx("p", { className: "xicms-sectiekop__intro", "data-xicms-edit": "intro", children: block.intro })
|
|
9
|
+
] });
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
SectionHeadingRender
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=SectionHeadingRender.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/blocks/builtins/SectionHeadingRender.tsx"],"sourcesContent":["import type { z } from \"zod\";\nimport type { SectionHeadingBlockSchema } from \"../../schema/blocks\";\nimport type { BlockRenderProps } from \"../registry\";\nimport { Heading } from \"../ui\";\n\ntype SectieKop = z.infer<typeof SectionHeadingBlockSchema>;\n\n/** Sectiekop (8.13): regeltje, kop en inleiding — overal dezelfde opbouw en uitlijning. */\nexport function SectionHeadingRender({ block }: BlockRenderProps<SectieKop>) {\n if (!block.title && !block.eyebrow && !block.intro) return null;\n return (\n <header className=\"xicms-sectiekop\" data-align={block.align ?? \"center\"}>\n {block.eyebrow && <p className=\"xicms-sectiekop__regel\" data-xicms-edit=\"eyebrow\">{block.eyebrow}</p>}\n {block.title && <Heading level={2} data-xicms-edit=\"title\">{block.title}</Heading>}\n {block.intro && <p className=\"xicms-sectiekop__intro\" data-xicms-edit=\"intro\">{block.intro}</p>}\n </header>\n );\n}\n"],"mappings":"AAWI,SACoB,KADpB;AARJ,SAAS,eAAe;AAKjB,SAAS,qBAAqB,EAAE,MAAM,GAAgC;AAC3E,MAAI,CAAC,MAAM,SAAS,CAAC,MAAM,WAAW,CAAC,MAAM,MAAO,QAAO;AAC3D,SACE,qBAAC,YAAO,WAAU,mBAAkB,cAAY,MAAM,SAAS,UAC5D;AAAA,UAAM,WAAW,oBAAC,OAAE,WAAU,0BAAyB,mBAAgB,WAAW,gBAAM,SAAQ;AAAA,IAChG,MAAM,SAAS,oBAAC,WAAQ,OAAO,GAAG,mBAAgB,SAAS,gBAAM,OAAM;AAAA,IACvE,MAAM,SAAS,oBAAC,OAAE,WAAU,0BAAyB,mBAAgB,SAAS,gBAAM,OAAM;AAAA,KAC7F;AAEJ;","names":[]}
|
|
@@ -17,7 +17,8 @@ function SliderRender({ block, mode }) {
|
|
|
17
17
|
}, [count]);
|
|
18
18
|
useEffect(() => {
|
|
19
19
|
if (!block.autoplay || paused || userPaused || count <= 1 || prefersReducedMotion()) return;
|
|
20
|
-
const
|
|
20
|
+
const sec = Number.isFinite(block.interval) && block.interval >= 1 ? block.interval : 5;
|
|
21
|
+
const id = setInterval(() => setIndex((i) => (i + 1) % count), sec * 1e3);
|
|
21
22
|
return () => clearInterval(id);
|
|
22
23
|
}, [block.autoplay, block.interval, paused, userPaused, count]);
|
|
23
24
|
if (count === 0) {
|
|
@@ -50,7 +51,7 @@ function SliderRender({ block, mode }) {
|
|
|
50
51
|
"section",
|
|
51
52
|
{
|
|
52
53
|
className: "xicms-slider",
|
|
53
|
-
style: { ["--xicms-slider-ratio"]: block.aspectRatio.replace("/", " / ") },
|
|
54
|
+
style: { ["--xicms-slider-ratio"]: (block.aspectRatio ?? "16/9").replace("/", " / ") },
|
|
54
55
|
onMouseEnter: () => setPaused(true),
|
|
55
56
|
onMouseLeave: () => setPaused(false),
|
|
56
57
|
onFocus: () => setPaused(true),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/blocks/builtins/SliderRender.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport type { z } from \"zod\";\nimport type { SliderBlockSchema } from \"../../schema/blocks\";\nimport type { BlockRenderProps } from \"../registry\";\nimport { Img } from \"../../media/ImageContext\";\n\ntype Slider = z.infer<typeof SliderBlockSchema>;\n\nfunction prefersReducedMotion(): boolean {\n return typeof window !== \"undefined\" && window.matchMedia?.(\"(prefers-reduced-motion: reduce)\").matches;\n}\n\n/** Beeld-/contentcarrousel. Client-side; autoplay respecteert reduced-motion en pauzeert bij hover. */\nexport function SliderRender({ block, mode }: BlockRenderProps<Slider>) {\n // `_i` = ORIGINELE index (slides gefilterd): inline caption-edits schrijven naar het juiste item.\n const slides = (block.slides ?? []).map((s, i) => ({ ...s, _i: i })).filter((s) => s.imageUrl || s.caption);\n const [index, setIndex] = useState(0);\n const [paused, setPaused] = useState(false);\n // Expliciete stopknop voor autoplay: hover-/focus-pauze helpt touch- en screenreadergebruikers\n // niet, dus WCAG (2.2.2, bewegende content) vraagt een echte pauzeknop.\n const [userPaused, setUserPaused] = useState(false);\n const swipeStart = useRef<number | null>(null);\n const count = slides.length;\n\n // Clamp de index als het aantal slides krimpt (bv. tijdens bewerken in preview), anders blijft\n // de carrousel op een lege positie hangen tot de bezoeker interacteert.\n useEffect(() => {\n setIndex((i) => (count === 0 ? 0 : Math.min(i, count - 1)));\n }, [count]);\n\n useEffect(() => {\n if (!block.autoplay || paused || userPaused || count <= 1 || prefersReducedMotion()) return;\n const id = setInterval(() => setIndex((i) => (i + 1) % count), block.interval * 1000);\n return () => clearInterval(id);\n }, [block.autoplay, block.interval, paused, userPaused, count]);\n\n if (count === 0) {\n // In de editor was een verse slider ONZICHTBAAR (default-slide is leeg → weggefilterd → null):\n // de klant zag \"er gebeurt niets\" na toevoegen. Toon in preview een duidelijke lege staat;\n // publiek blijft het blok gewoon verborgen.\n if (mode === \"preview\") {\n return (\n <div className=\"xicms-slider xicms-slider--empty\">\n 🎠 Carrousel — voeg in het zijpaneel slides met een afbeelding of tekst toe.\n </div>\n );\n }\n return null;\n }\n const go = (i: number) => setIndex(((i % count) + count) % count);\n\n // Swipe (pointer events: touch én muis-sleep) + pijltjestoetsen wanneer de carrousel focus heeft.\n const onPointerDown = (e: React.PointerEvent) => {\n swipeStart.current = e.clientX;\n };\n const onPointerUp = (e: React.PointerEvent) => {\n if (swipeStart.current === null || count < 2) return;\n const dx = e.clientX - swipeStart.current;\n swipeStart.current = null;\n if (dx > 40) go(index - 1);\n else if (dx < -40) go(index + 1);\n };\n const onKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"ArrowLeft\") {\n e.preventDefault();\n go(index - 1);\n } else if (e.key === \"ArrowRight\") {\n e.preventDefault();\n go(index + 1);\n }\n };\n\n return (\n <section\n className=\"xicms-slider\"\n style={{ [\"--xicms-slider-ratio\" as string]: block.aspectRatio.replace(\"/\", \" / \") }}\n onMouseEnter={() => setPaused(true)}\n onMouseLeave={() => setPaused(false)}\n onFocus={() => setPaused(true)}\n onBlur={() => setPaused(false)}\n onKeyDown={onKeyDown}\n tabIndex={0}\n role=\"region\"\n aria-roledescription=\"carousel\"\n aria-label=\"Carrousel\"\n >\n <div\n className=\"xicms-slider__viewport\"\n onPointerDown={onPointerDown}\n onPointerUp={onPointerUp}\n onPointerCancel={() => { swipeStart.current = null; }}\n onPointerLeave={() => { swipeStart.current = null; }}\n style={{ touchAction: \"pan-y\" }}\n >\n <div className=\"xicms-slider__track\" style={{ transform: `translateX(-${index * 100}%)` }}>\n {slides.map((s, i) => {\n const img = s.imageUrl ? (\n <Img className=\"xicms-slider__image\" src={s.imageUrl} alt={s.alt ?? \"\"} width={1800} height={800} sizes=\"100vw\" priority={i === 0} />\n ) : null;\n return (\n /* inert haalt links in verborgen slides ook uit de tabvolgorde — aria-hidden\n mét bereikbare focusables is een WCAG-schending (4.1.2). */\n <div\n key={i}\n className=\"xicms-slider__slide\"\n role=\"group\"\n aria-roledescription=\"slide\"\n aria-label={`${i + 1} / ${count}`}\n aria-hidden={i !== index}\n inert={i !== index || undefined}\n >\n {s.href ? <a href={s.href}>{img}</a> : img}\n {s.caption && <div className=\"xicms-slider__caption\" data-xicms-edit={`slides.${s._i}.caption`}>{s.caption}</div>}\n </div>\n );\n })}\n </div>\n\n {block.showArrows && count > 1 && (\n <>\n <button type=\"button\" className=\"xicms-slider__arrow xicms-slider__arrow--prev\" aria-label=\"Vorige\" onClick={() => go(index - 1)}>‹</button>\n <button type=\"button\" className=\"xicms-slider__arrow xicms-slider__arrow--next\" aria-label=\"Volgende\" onClick={() => go(index + 1)}>›</button>\n </>\n )}\n {/* Geen reduced-motion-check hier: die zou server en client verschillend laten renderen. */}\n {block.autoplay && count > 1 && (\n <button\n type=\"button\"\n className=\"xicms-slider__pause\"\n aria-pressed={userPaused}\n aria-label={userPaused ? \"Diavoorstelling afspelen\" : \"Diavoorstelling pauzeren\"}\n onClick={() => setUserPaused((v) => !v)}\n >\n {userPaused ? \"▶\" : \"⏸\"}\n </button>\n )}\n </div>\n\n {/* Dots als gewone knoppen (geen tablist: er zijn geen tabpanels om aan te koppelen). */}\n {block.showDots && count > 1 && (\n <div className=\"xicms-slider__dots\" role=\"group\" aria-label=\"Kies slide\">\n {slides.map((_, i) => (\n <button\n key={i}\n type=\"button\"\n aria-current={i === index || undefined}\n aria-label={`Naar slide ${i + 1}`}\n className={`xicms-slider__dot${i === index ? \" xicms-slider__dot--active\" : \"\"}`}\n onClick={() => go(i)}\n />\n ))}\n </div>\n )}\n </section>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/blocks/builtins/SliderRender.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport type { z } from \"zod\";\nimport type { SliderBlockSchema } from \"../../schema/blocks\";\nimport type { BlockRenderProps } from \"../registry\";\nimport { Img } from \"../../media/ImageContext\";\n\ntype Slider = z.infer<typeof SliderBlockSchema>;\n\nfunction prefersReducedMotion(): boolean {\n return typeof window !== \"undefined\" && window.matchMedia?.(\"(prefers-reduced-motion: reduce)\").matches;\n}\n\n/** Beeld-/contentcarrousel. Client-side; autoplay respecteert reduced-motion en pauzeert bij hover. */\nexport function SliderRender({ block, mode }: BlockRenderProps<Slider>) {\n // `_i` = ORIGINELE index (slides gefilterd): inline caption-edits schrijven naar het juiste item.\n const slides = (block.slides ?? []).map((s, i) => ({ ...s, _i: i })).filter((s) => s.imageUrl || s.caption);\n const [index, setIndex] = useState(0);\n const [paused, setPaused] = useState(false);\n // Expliciete stopknop voor autoplay: hover-/focus-pauze helpt touch- en screenreadergebruikers\n // niet, dus WCAG (2.2.2, bewegende content) vraagt een echte pauzeknop.\n const [userPaused, setUserPaused] = useState(false);\n const swipeStart = useRef<number | null>(null);\n const count = slides.length;\n\n // Clamp de index als het aantal slides krimpt (bv. tijdens bewerken in preview), anders blijft\n // de carrousel op een lege positie hangen tot de bezoeker interacteert.\n useEffect(() => {\n setIndex((i) => (count === 0 ? 0 : Math.min(i, count - 1)));\n }, [count]);\n\n useEffect(() => {\n if (!block.autoplay || paused || userPaused || count <= 1 || prefersReducedMotion()) return;\n // Ontbrekend of onzinnig interval (oude data) gaf setInterval(NaN): ~0 ms, de slider raasde (8.1).\n const sec = Number.isFinite(block.interval) && block.interval >= 1 ? block.interval : 5;\n const id = setInterval(() => setIndex((i) => (i + 1) % count), sec * 1000);\n return () => clearInterval(id);\n }, [block.autoplay, block.interval, paused, userPaused, count]);\n\n if (count === 0) {\n // In de editor was een verse slider ONZICHTBAAR (default-slide is leeg → weggefilterd → null):\n // de klant zag \"er gebeurt niets\" na toevoegen. Toon in preview een duidelijke lege staat;\n // publiek blijft het blok gewoon verborgen.\n if (mode === \"preview\") {\n return (\n <div className=\"xicms-slider xicms-slider--empty\">\n 🎠 Carrousel — voeg in het zijpaneel slides met een afbeelding of tekst toe.\n </div>\n );\n }\n return null;\n }\n const go = (i: number) => setIndex(((i % count) + count) % count);\n\n // Swipe (pointer events: touch én muis-sleep) + pijltjestoetsen wanneer de carrousel focus heeft.\n const onPointerDown = (e: React.PointerEvent) => {\n swipeStart.current = e.clientX;\n };\n const onPointerUp = (e: React.PointerEvent) => {\n if (swipeStart.current === null || count < 2) return;\n const dx = e.clientX - swipeStart.current;\n swipeStart.current = null;\n if (dx > 40) go(index - 1);\n else if (dx < -40) go(index + 1);\n };\n const onKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"ArrowLeft\") {\n e.preventDefault();\n go(index - 1);\n } else if (e.key === \"ArrowRight\") {\n e.preventDefault();\n go(index + 1);\n }\n };\n\n return (\n <section\n className=\"xicms-slider\"\n style={{ [\"--xicms-slider-ratio\" as string]: (block.aspectRatio ?? \"16/9\").replace(\"/\", \" / \") }}\n onMouseEnter={() => setPaused(true)}\n onMouseLeave={() => setPaused(false)}\n onFocus={() => setPaused(true)}\n onBlur={() => setPaused(false)}\n onKeyDown={onKeyDown}\n tabIndex={0}\n role=\"region\"\n aria-roledescription=\"carousel\"\n aria-label=\"Carrousel\"\n >\n <div\n className=\"xicms-slider__viewport\"\n onPointerDown={onPointerDown}\n onPointerUp={onPointerUp}\n onPointerCancel={() => { swipeStart.current = null; }}\n onPointerLeave={() => { swipeStart.current = null; }}\n style={{ touchAction: \"pan-y\" }}\n >\n <div className=\"xicms-slider__track\" style={{ transform: `translateX(-${index * 100}%)` }}>\n {slides.map((s, i) => {\n const img = s.imageUrl ? (\n <Img className=\"xicms-slider__image\" src={s.imageUrl} alt={s.alt ?? \"\"} width={1800} height={800} sizes=\"100vw\" priority={i === 0} />\n ) : null;\n return (\n /* inert haalt links in verborgen slides ook uit de tabvolgorde — aria-hidden\n mét bereikbare focusables is een WCAG-schending (4.1.2). */\n <div\n key={i}\n className=\"xicms-slider__slide\"\n role=\"group\"\n aria-roledescription=\"slide\"\n aria-label={`${i + 1} / ${count}`}\n aria-hidden={i !== index}\n inert={i !== index || undefined}\n >\n {s.href ? <a href={s.href}>{img}</a> : img}\n {s.caption && <div className=\"xicms-slider__caption\" data-xicms-edit={`slides.${s._i}.caption`}>{s.caption}</div>}\n </div>\n );\n })}\n </div>\n\n {block.showArrows && count > 1 && (\n <>\n <button type=\"button\" className=\"xicms-slider__arrow xicms-slider__arrow--prev\" aria-label=\"Vorige\" onClick={() => go(index - 1)}>‹</button>\n <button type=\"button\" className=\"xicms-slider__arrow xicms-slider__arrow--next\" aria-label=\"Volgende\" onClick={() => go(index + 1)}>›</button>\n </>\n )}\n {/* Geen reduced-motion-check hier: die zou server en client verschillend laten renderen. */}\n {block.autoplay && count > 1 && (\n <button\n type=\"button\"\n className=\"xicms-slider__pause\"\n aria-pressed={userPaused}\n aria-label={userPaused ? \"Diavoorstelling afspelen\" : \"Diavoorstelling pauzeren\"}\n onClick={() => setUserPaused((v) => !v)}\n >\n {userPaused ? \"▶\" : \"⏸\"}\n </button>\n )}\n </div>\n\n {/* Dots als gewone knoppen (geen tablist: er zijn geen tabpanels om aan te koppelen). */}\n {block.showDots && count > 1 && (\n <div className=\"xicms-slider__dots\" role=\"group\" aria-label=\"Kies slide\">\n {slides.map((_, i) => (\n <button\n key={i}\n type=\"button\"\n aria-current={i === index || undefined}\n aria-label={`Naar slide ${i + 1}`}\n className={`xicms-slider__dot${i === index ? \" xicms-slider__dot--active\" : \"\"}`}\n onClick={() => go(i)}\n />\n ))}\n </div>\n )}\n </section>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -3,7 +3,7 @@ import { defineBlock } from "../registry.js";
|
|
|
3
3
|
const symbolRefBlock = defineBlock({
|
|
4
4
|
type: "symbolRef",
|
|
5
5
|
Render: dynamic(() => import("./SymbolRefRender.js").then((m) => m.SymbolRefRender)),
|
|
6
|
-
label: "
|
|
6
|
+
label: "Gedeeld blok",
|
|
7
7
|
icon: "\u{1F9E9}",
|
|
8
8
|
defaults: () => ({ symbolId: "" })
|
|
9
9
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/blocks/builtins/SymbolRef.tsx"],"sourcesContent":["import dynamic from \"next/dynamic\";\nimport { defineBlock } from \"../registry\";\n\nexport const symbolRefBlock = defineBlock({\n type: \"symbolRef\",\n Render: dynamic(() => import(\"./SymbolRefRender\").then((m) => m.SymbolRefRender)),\n label: \"
|
|
1
|
+
{"version":3,"sources":["../../../src/blocks/builtins/SymbolRef.tsx"],"sourcesContent":["import dynamic from \"next/dynamic\";\nimport { defineBlock } from \"../registry\";\n\nexport const symbolRefBlock = defineBlock({\n type: \"symbolRef\",\n Render: dynamic(() => import(\"./SymbolRefRender\").then((m) => m.SymbolRefRender)),\n label: \"Gedeeld blok\",\n icon: \"🧩\",\n defaults: () => ({ symbolId: \"\" }),\n});\n"],"mappings":"AAAA,OAAO,aAAa;AACpB,SAAS,mBAAmB;AAErB,MAAM,iBAAiB,YAAY;AAAA,EACxC,MAAM;AAAA,EACN,QAAQ,QAAQ,MAAM,OAAO,mBAAmB,EAAE,KAAK,CAAC,MAAM,EAAE,eAAe,CAAC;AAAA,EAChF,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO,EAAE,UAAU,GAAG;AAClC,CAAC;","names":[]}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { VStack, HStack, Grid, Card, Heading, Text, Avatar } from "../ui/index.js";
|
|
4
4
|
import { jsonLdHtml } from "./jsonld.js";
|
|
5
|
+
import { useVariantVoor } from "../../media/ImageContext.js";
|
|
5
6
|
function personJsonLd(members) {
|
|
6
7
|
return {
|
|
7
8
|
"@context": "https://schema.org",
|
|
@@ -28,7 +29,7 @@ function TeamRender({ block }) {
|
|
|
28
29
|
const grid = (list) => /* @__PURE__ */ jsx(Grid, { columns: { minWidth: 220, max: 4 }, gap: 4, children: list.map((m) => {
|
|
29
30
|
const i = m._i;
|
|
30
31
|
return /* @__PURE__ */ jsx(Card, { padding: 4, height: "100%", children: /* @__PURE__ */ jsxs(VStack, { gap: 1, hAlign: "center", style: { textAlign: "center", height: "100%" }, children: [
|
|
31
|
-
/* @__PURE__ */ jsx(
|
|
32
|
+
/* @__PURE__ */ jsx(TeamFoto, { src: m.photoUrl, name: m.name }),
|
|
32
33
|
/* @__PURE__ */ jsx(Heading, { level: 3, "data-xicms-edit": `members.${i}.name`, children: m.name }),
|
|
33
34
|
m.role && /* @__PURE__ */ jsx(Text, { type: "label", "data-xicms-edit": `members.${i}.role`, style: { color: "var(--color-accent)" }, children: m.role }),
|
|
34
35
|
m.bio && /* @__PURE__ */ jsx(Text, { color: "secondary", "data-xicms-edit": `members.${i}.bio`, children: m.bio }),
|
|
@@ -52,6 +53,10 @@ function TeamRender({ block }) {
|
|
|
52
53
|
)
|
|
53
54
|
] });
|
|
54
55
|
}
|
|
56
|
+
function TeamFoto({ src, name }) {
|
|
57
|
+
const klein = useVariantVoor(src, 192);
|
|
58
|
+
return /* @__PURE__ */ jsx(Avatar, { src: klein, name, size: 96 });
|
|
59
|
+
}
|
|
55
60
|
export {
|
|
56
61
|
TeamRender
|
|
57
62
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/blocks/builtins/TeamRender.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport type { TeamBlockSchema } from \"../../schema/blocks\";\nimport type { BlockRenderProps } from \"../registry\";\nimport { VStack, HStack, Grid, Card, Heading, Text, Avatar } from \"../ui\";\nimport { jsonLdHtml } from \"./jsonld\";\n\ntype Team = z.infer<typeof TeamBlockSchema>;\n\nfunction personJsonLd(members: Team[\"members\"]): Record<string, unknown> {\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"ItemList\",\n itemListElement: members\n .filter((m) => m.name)\n .map((m, i) => ({\n \"@type\": \"ListItem\",\n position: i + 1,\n item: {\n \"@type\": \"Person\",\n name: m.name,\n ...(m.role ? { jobTitle: m.role } : {}),\n ...(m.email ? { email: m.email } : {}),\n ...(m.phone ? { telephone: m.phone } : {}),\n ...(m.photoUrl ? { image: m.photoUrl } : {}),\n ...(m.social?.length ? { sameAs: m.social.map((s) => s.href) } : {}),\n },\n })),\n };\n}\n\n/** Team-/medewerkersoverzicht als kaarten (Astryx), optioneel gegroepeerd per afdeling. */\nexport function TeamRender({ block }: BlockRenderProps<Team>) {\n // _i = index in de OORSPRONKELIJKE array — nodig voor de inline-edit-paden bij groepering.\n const members = (block.members ?? []).map((m, i) => ({ ...m, _i: i })).filter((m) => m.name);\n if (members.length === 0) return null;\n\n // Groepen in volgorde van eerste voorkomen; leden zonder afdeling achteraan onder één kop.\n const groups = block.groupByDepartment\n ? [...new Set(members.map((m) => m.department ?? \"\"))]\n .sort((a, b) => (a === \"\" ? 1 : b === \"\" ? -1 : 0))\n .map((dep) => ({ dep, members: members.filter((m) => (m.department ?? \"\") === dep) }))\n : [{ dep: \"\", members }];\n\n const grid = (list: typeof members) => (\n <Grid columns={{ minWidth: 220, max: 4 }} gap={4}>\n {list.map((m) => {\n const i = m._i;\n return (\n <Card key={i} padding={4} height=\"100%\">\n <VStack gap={1} hAlign=\"center\" style={{ textAlign: \"center\", height: \"100%\" }}>\n <
|
|
1
|
+
{"version":3,"sources":["../../../src/blocks/builtins/TeamRender.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport type { TeamBlockSchema } from \"../../schema/blocks\";\nimport type { BlockRenderProps } from \"../registry\";\nimport { VStack, HStack, Grid, Card, Heading, Text, Avatar } from \"../ui\";\nimport { jsonLdHtml } from \"./jsonld\";\nimport { useVariantVoor } from \"../../media/ImageContext\";\n\ntype Team = z.infer<typeof TeamBlockSchema>;\n\nfunction personJsonLd(members: Team[\"members\"]): Record<string, unknown> {\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"ItemList\",\n itemListElement: members\n .filter((m) => m.name)\n .map((m, i) => ({\n \"@type\": \"ListItem\",\n position: i + 1,\n item: {\n \"@type\": \"Person\",\n name: m.name,\n ...(m.role ? { jobTitle: m.role } : {}),\n ...(m.email ? { email: m.email } : {}),\n ...(m.phone ? { telephone: m.phone } : {}),\n ...(m.photoUrl ? { image: m.photoUrl } : {}),\n ...(m.social?.length ? { sameAs: m.social.map((s) => s.href) } : {}),\n },\n })),\n };\n}\n\n/** Team-/medewerkersoverzicht als kaarten (Astryx), optioneel gegroepeerd per afdeling. */\nexport function TeamRender({ block }: BlockRenderProps<Team>) {\n // _i = index in de OORSPRONKELIJKE array — nodig voor de inline-edit-paden bij groepering.\n const members = (block.members ?? []).map((m, i) => ({ ...m, _i: i })).filter((m) => m.name);\n if (members.length === 0) return null;\n\n // Groepen in volgorde van eerste voorkomen; leden zonder afdeling achteraan onder één kop.\n const groups = block.groupByDepartment\n ? [...new Set(members.map((m) => m.department ?? \"\"))]\n .sort((a, b) => (a === \"\" ? 1 : b === \"\" ? -1 : 0))\n .map((dep) => ({ dep, members: members.filter((m) => (m.department ?? \"\") === dep) }))\n : [{ dep: \"\", members }];\n\n const grid = (list: typeof members) => (\n <Grid columns={{ minWidth: 220, max: 4 }} gap={4}>\n {list.map((m) => {\n const i = m._i;\n return (\n <Card key={i} padding={4} height=\"100%\">\n <VStack gap={1} hAlign=\"center\" style={{ textAlign: \"center\", height: \"100%\" }}>\n <TeamFoto src={m.photoUrl} name={m.name} />\n <Heading level={3} data-xicms-edit={`members.${i}.name`}>{m.name}</Heading>\n {m.role && <Text type=\"label\" data-xicms-edit={`members.${i}.role`} style={{ color: \"var(--color-accent)\" }}>{m.role}</Text>}\n {m.bio && <Text color=\"secondary\" data-xicms-edit={`members.${i}.bio`}>{m.bio}</Text>}\n {m.email && (\n <a href={`mailto:${m.email}`} style={{ color: \"var(--color-accent)\" }}>\n <Text type=\"supporting\" data-xicms-edit={`members.${i}.email`}>{m.email}</Text>\n </a>\n )}\n {m.phone && <Text type=\"supporting\" color=\"secondary\" data-xicms-edit={`members.${i}.phone`}>{m.phone}</Text>}\n {m.social && m.social.length > 0 && (\n <HStack gap={2} hAlign=\"center\" as=\"ul\" style={{ listStyle: \"none\", margin: 0, padding: 0, flexWrap: \"wrap\" }}>\n {m.social.map((s, j) => (\n <li key={j}>\n <a href={s.href} rel=\"noopener noreferrer\" target=\"_blank\" style={{ color: \"var(--color-accent)\" }}>\n <Text type=\"supporting\" data-xicms-edit={`members.${i}.social.${j}.platform`}>{s.platform}</Text>\n </a>\n </li>\n ))}\n </HStack>\n )}\n </VStack>\n </Card>\n );\n })}\n </Grid>\n );\n\n return (\n <VStack gap={4} as=\"section\" className=\"xicms-team\">\n {block.heading && (\n <Heading level={2} justify=\"center\" data-xicms-edit=\"heading\" style={{ textAlign: \"center\" }}>{block.heading}</Heading>\n )}\n {groups.map(({ dep, members: list }) => (\n <VStack key={dep || \"_overig\"} gap={3}>\n {block.groupByDepartment && groups.length > 1 && (\n <Heading level={3} justify=\"center\" style={{ textAlign: \"center\" }}>\n {dep || \"Overig\"}\n </Heading>\n )}\n {grid(list)}\n </VStack>\n ))}\n {block.jsonLd && (\n <script\n type=\"application/ld+json\"\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{ __html: jsonLdHtml(personJsonLd(members)) }}\n />\n )}\n </VStack>\n );\n}\n\n/** Avatar van 96px laadt de kleinste variant van ≥ 192px (2x) i.p.v. de volle foto (8.3). */\nfunction TeamFoto({ src, name }: { src?: string; name: string }) {\n const klein = useVariantVoor(src, 192);\n return <Avatar src={klein} name={name} size={96} />;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -8,7 +8,9 @@ const testimonialsBlock = defineBlock({
|
|
|
8
8
|
defaults: () => ({
|
|
9
9
|
heading: "Wat klanten zeggen",
|
|
10
10
|
items: [{ quote: "Top geholpen!", author: "Tevreden klant", rating: 5 }],
|
|
11
|
-
|
|
11
|
+
// 8.12: uit. Reviews op je eigen site (over je eigen bedrijf) toont Google al jaren niet als
|
|
12
|
+
// sterren; aan stond er zo bij een nieuw blok een verzonnen review in de gestructureerde data.
|
|
13
|
+
jsonLd: false
|
|
12
14
|
})
|
|
13
15
|
});
|
|
14
16
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/blocks/builtins/Testimonials.tsx"],"sourcesContent":["import dynamic from \"next/dynamic\";\nimport { defineBlock } from \"../registry\";\n\nexport const testimonialsBlock = defineBlock({\n type: \"testimonials\",\n Render: dynamic(() => import(\"./TestimonialsRender\").then((m) => m.TestimonialsRender)),\n label: \"Reviews\",\n icon: \"⭐\",\n defaults: () => ({\n heading: \"Wat klanten zeggen\",\n items: [{ quote: \"Top geholpen!\", author: \"Tevreden klant\", rating: 5 }],\n jsonLd:
|
|
1
|
+
{"version":3,"sources":["../../../src/blocks/builtins/Testimonials.tsx"],"sourcesContent":["import dynamic from \"next/dynamic\";\nimport { defineBlock } from \"../registry\";\n\nexport const testimonialsBlock = defineBlock({\n type: \"testimonials\",\n Render: dynamic(() => import(\"./TestimonialsRender\").then((m) => m.TestimonialsRender)),\n label: \"Reviews\",\n icon: \"⭐\",\n defaults: () => ({\n heading: \"Wat klanten zeggen\",\n items: [{ quote: \"Top geholpen!\", author: \"Tevreden klant\", rating: 5 }],\n // 8.12: uit. Reviews op je eigen site (over je eigen bedrijf) toont Google al jaren niet als\n // sterren; aan stond er zo bij een nieuw blok een verzonnen review in de gestructureerde data.\n jsonLd: false,\n }),\n});\n"],"mappings":"AAAA,OAAO,aAAa;AACpB,SAAS,mBAAmB;AAErB,MAAM,oBAAoB,YAAY;AAAA,EAC3C,MAAM;AAAA,EACN,QAAQ,QAAQ,MAAM,OAAO,sBAAsB,EAAE,KAAK,CAAC,MAAM,EAAE,kBAAkB,CAAC;AAAA,EACtF,OAAO;AAAA,EACP,MAAM;AAAA,EACN,UAAU,OAAO;AAAA,IACf,SAAS;AAAA,IACT,OAAO,CAAC,EAAE,OAAO,iBAAiB,QAAQ,kBAAkB,QAAQ,EAAE,CAAC;AAAA;AAAA;AAAA,IAGvE,QAAQ;AAAA,EACV;AACF,CAAC;","names":[]}
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { VStack, HStack, Grid, Card, Heading, Text, Avatar } from "../ui/index.js";
|
|
4
4
|
import { jsonLdHtml } from "./jsonld.js";
|
|
5
|
+
import { Btn } from "../ui/index.js";
|
|
6
|
+
import { useMergedSiteConfig } from "../../settings/useSiteSettings.js";
|
|
5
7
|
function aggregateRatingJsonLd(items) {
|
|
6
8
|
const rated = items.filter((it) => typeof it.rating === "number");
|
|
7
9
|
if (rated.length === 0) return null;
|
|
@@ -29,6 +31,7 @@ function reviewJsonLd(items) {
|
|
|
29
31
|
};
|
|
30
32
|
}
|
|
31
33
|
function TestimonialsRender({ block }) {
|
|
34
|
+
const reviewUrl = useMergedSiteConfig().business?.reviewUrl;
|
|
32
35
|
const items = (block.items ?? []).map((it, i) => ({ ...it, _i: i })).filter((i) => i.quote);
|
|
33
36
|
if (items.length === 0) return null;
|
|
34
37
|
const cols = block.layout === "list" ? { minWidth: 320, max: 1 } : { minWidth: 280, max: 3 };
|
|
@@ -55,6 +58,7 @@ function TestimonialsRender({ block }) {
|
|
|
55
58
|
] })
|
|
56
59
|
] }) }, i);
|
|
57
60
|
}) }),
|
|
61
|
+
block.reviewKnop !== false && reviewUrl && /* @__PURE__ */ jsx(HStack, { hAlign: "center", children: /* @__PURE__ */ jsx(Btn, { label: "Laat een review achter", href: reviewUrl, variant: "outline", size: "md", target: "_blank" }) }),
|
|
58
62
|
block.jsonLd && /* @__PURE__ */ jsx(
|
|
59
63
|
"script",
|
|
60
64
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/blocks/builtins/TestimonialsRender.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport type { TestimonialsBlockSchema } from \"../../schema/blocks\";\nimport type { BlockRenderProps } from \"../registry\";\nimport { VStack, HStack, Grid, Card, Heading, Text, Avatar } from \"../ui\";\nimport { jsonLdHtml } from \"./jsonld\";\n\ntype Testimonials = z.infer<typeof TestimonialsBlockSchema>;\n\n/** Gemiddelde beoordeling over de items met een rating — voor de sterren-snippet in Google. */\nexport function aggregateRatingJsonLd(items: Testimonials[\"items\"]): Record<string, unknown> | null {\n const rated = items.filter((it) => typeof it.rating === \"number\");\n if (rated.length === 0) return null;\n const avg = rated.reduce((sum, it) => sum + (it.rating as number), 0) / rated.length;\n return {\n \"@type\": \"AggregateRating\",\n ratingValue: Math.round(avg * 10) / 10,\n reviewCount: rated.length,\n bestRating: 5,\n };\n}\n\nexport function reviewJsonLd(items: Testimonials[\"items\"]): Record<string, unknown> {\n const aggregate = aggregateRatingJsonLd(items);\n // Reviews/AggregateRating zijn voor rich results alleen geldig aan een \"ding\" (bedrijf/product);\n // een losse ItemList negeert Google. We hangen ze aan dezelfde #business-entiteit als de\n // contact-/openingstijden-JSON-LD, zodat alles samenvloeit tot één LocalBusiness.\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"LocalBusiness\",\n \"@id\": \"#business\",\n ...(aggregate ? { aggregateRating: aggregate } : {}),\n review: items\n .filter((it) => it.quote && it.author)\n .map((it) => ({\n \"@type\": \"Review\",\n reviewBody: it.quote,\n author: { \"@type\": \"Person\", name: it.author },\n ...(it.rating\n ? { reviewRating: { \"@type\": \"Rating\", ratingValue: it.rating, bestRating: 5 } }\n : {}),\n })),\n };\n}\n\n/** Klantquotes / reviews als kaarten (Astryx). */\nexport function TestimonialsRender({ block }: BlockRenderProps<Testimonials>) {\n // _i = index in de OORSPRONKELIJKE array — inline-edit-paden (items.N.quote) moeten daarheen wijzen.\n const items = (block.items ?? []).map((it, i) => ({ ...it, _i: i })).filter((i) => i.quote);\n if (items.length === 0) return null;\n const cols = block.layout === \"list\" ? { minWidth: 320, max: 1 as const } : { minWidth: 280, max: 3 as const };\n return (\n <VStack gap={4} as=\"section\" className=\"xicms-testimonials\">\n {block.heading && (\n <Heading level={2} justify=\"center\" data-xicms-edit=\"heading\" style={{ textAlign: \"center\" }}>{block.heading}</Heading>\n )}\n <Grid columns={cols} gap={4}>\n {items.map((it) => {\n const i = it._i;\n return (\n <Card key={i} padding={4} height=\"100%\" className=\"xicms-testimonials__card\">\n <VStack gap={2} style={{ height: \"100%\" }}>\n {typeof it.rating === \"number\" && (\n <Text className=\"xicms-testimonials__rating\" style={{ color: \"var(--xicms-star, #f59e0b)\", letterSpacing: \"0.1em\" }} aria-label={`${it.rating} van 5 sterren`}>\n {\"★\".repeat(it.rating)}\n <span style={{ opacity: 0.25 }}>{\"★\".repeat(5 - it.rating)}</span>\n </Text>\n )}\n <Text type=\"large\" className=\"xicms-testimonials__quote\" style={{ flex: 1 }}>“<span data-xicms-edit={`items.${i}.quote`}>{it.quote}</span>”</Text>\n <HStack gap={1.5} vAlign=\"center\">\n {it.avatarUrl && <Avatar src={it.avatarUrl} name={it.author} size={40} />}\n <VStack gap={0}>\n <Text weight=\"bold\" className=\"xicms-testimonials__author\" data-xicms-edit={`items.${i}.author`}>{it.author}</Text>\n {it.role && <Text type=\"supporting\" color=\"secondary\" className=\"xicms-testimonials__role\" data-xicms-edit={`items.${i}.role`}>{it.role}</Text>}\n </VStack>\n </HStack>\n </VStack>\n </Card>\n );\n })}\n </Grid>\n {block.jsonLd && (\n <script\n type=\"application/ld+json\"\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{ __html: jsonLdHtml(reviewJsonLd(items)) }}\n />\n )}\n </VStack>\n );\n}\n"],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../../../src/blocks/builtins/TestimonialsRender.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport type { TestimonialsBlockSchema } from \"../../schema/blocks\";\nimport type { BlockRenderProps } from \"../registry\";\nimport { VStack, HStack, Grid, Card, Heading, Text, Avatar } from \"../ui\";\nimport { jsonLdHtml } from \"./jsonld\";\nimport { Btn } from \"../ui\";\nimport { useMergedSiteConfig } from \"../../settings/useSiteSettings\";\n\ntype Testimonials = z.infer<typeof TestimonialsBlockSchema>;\n\n/** Gemiddelde beoordeling over de items met een rating — voor de sterren-snippet in Google. */\nexport function aggregateRatingJsonLd(items: Testimonials[\"items\"]): Record<string, unknown> | null {\n const rated = items.filter((it) => typeof it.rating === \"number\");\n if (rated.length === 0) return null;\n const avg = rated.reduce((sum, it) => sum + (it.rating as number), 0) / rated.length;\n return {\n \"@type\": \"AggregateRating\",\n ratingValue: Math.round(avg * 10) / 10,\n reviewCount: rated.length,\n bestRating: 5,\n };\n}\n\nexport function reviewJsonLd(items: Testimonials[\"items\"]): Record<string, unknown> {\n const aggregate = aggregateRatingJsonLd(items);\n // Reviews/AggregateRating zijn voor rich results alleen geldig aan een \"ding\" (bedrijf/product);\n // een losse ItemList negeert Google. We hangen ze aan dezelfde #business-entiteit als de\n // contact-/openingstijden-JSON-LD, zodat alles samenvloeit tot één LocalBusiness.\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"LocalBusiness\",\n \"@id\": \"#business\",\n ...(aggregate ? { aggregateRating: aggregate } : {}),\n review: items\n .filter((it) => it.quote && it.author)\n .map((it) => ({\n \"@type\": \"Review\",\n reviewBody: it.quote,\n author: { \"@type\": \"Person\", name: it.author },\n ...(it.rating\n ? { reviewRating: { \"@type\": \"Rating\", ratingValue: it.rating, bestRating: 5 } }\n : {}),\n })),\n };\n}\n\n/** Klantquotes / reviews als kaarten (Astryx). */\nexport function TestimonialsRender({ block }: BlockRenderProps<Testimonials>) {\n // Hook vóór de vroege return (vaste hook-volgorde).\n const reviewUrl = useMergedSiteConfig().business?.reviewUrl;\n // _i = index in de OORSPRONKELIJKE array — inline-edit-paden (items.N.quote) moeten daarheen wijzen.\n const items = (block.items ?? []).map((it, i) => ({ ...it, _i: i })).filter((i) => i.quote);\n if (items.length === 0) return null;\n const cols = block.layout === \"list\" ? { minWidth: 320, max: 1 as const } : { minWidth: 280, max: 3 as const };\n return (\n <VStack gap={4} as=\"section\" className=\"xicms-testimonials\">\n {block.heading && (\n <Heading level={2} justify=\"center\" data-xicms-edit=\"heading\" style={{ textAlign: \"center\" }}>{block.heading}</Heading>\n )}\n <Grid columns={cols} gap={4}>\n {items.map((it) => {\n const i = it._i;\n return (\n <Card key={i} padding={4} height=\"100%\" className=\"xicms-testimonials__card\">\n <VStack gap={2} style={{ height: \"100%\" }}>\n {typeof it.rating === \"number\" && (\n <Text className=\"xicms-testimonials__rating\" style={{ color: \"var(--xicms-star, #f59e0b)\", letterSpacing: \"0.1em\" }} aria-label={`${it.rating} van 5 sterren`}>\n {\"★\".repeat(it.rating)}\n <span style={{ opacity: 0.25 }}>{\"★\".repeat(5 - it.rating)}</span>\n </Text>\n )}\n <Text type=\"large\" className=\"xicms-testimonials__quote\" style={{ flex: 1 }}>“<span data-xicms-edit={`items.${i}.quote`}>{it.quote}</span>”</Text>\n <HStack gap={1.5} vAlign=\"center\">\n {it.avatarUrl && <Avatar src={it.avatarUrl} name={it.author} size={40} />}\n <VStack gap={0}>\n <Text weight=\"bold\" className=\"xicms-testimonials__author\" data-xicms-edit={`items.${i}.author`}>{it.author}</Text>\n {it.role && <Text type=\"supporting\" color=\"secondary\" className=\"xicms-testimonials__role\" data-xicms-edit={`items.${i}.role`}>{it.role}</Text>}\n </VStack>\n </HStack>\n </VStack>\n </Card>\n );\n })}\n </Grid>\n {/* 8.13: de link waar klanten een review achterlaten (Instellingen → Bedrijf). Echte reviews\n op Google tellen; die op je eigen site toont Google niet als sterren. */}\n {block.reviewKnop !== false && reviewUrl && (\n <HStack hAlign=\"center\">\n <Btn label=\"Laat een review achter\" href={reviewUrl} variant=\"outline\" size=\"md\" target=\"_blank\" />\n </HStack>\n )}\n {block.jsonLd && (\n <script\n type=\"application/ld+json\"\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{ __html: jsonLdHtml(reviewJsonLd(items)) }}\n />\n )}\n </VStack>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -7,7 +7,7 @@ type WhatsappChat = z.infer<typeof WhatsappChatBlockSchema>;
|
|
|
7
7
|
* ("06-12345678") heeft geen landcode — die zomaar strippen levert een verkeerd nummer op, dus
|
|
8
8
|
* dan liever geen link (de editor-preview vraagt om internationale notatie).
|
|
9
9
|
*/
|
|
10
|
-
export declare function waLink(phone: string, text?: string): string | null;
|
|
10
|
+
export declare function waLink(phone: string | undefined, text?: string): string | null;
|
|
11
11
|
/**
|
|
12
12
|
* Zwevende WhatsApp-knop — dé laagdrempelige contactknop voor lokale bedrijven. Gewone link
|
|
13
13
|
* (geen embed/scripts), dus geen consent nodig. In de editor-preview inline weergegeven zodat
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useOnderOffset } from "../../components/onderOffset.js";
|
|
3
4
|
function waLink(phone, text) {
|
|
4
|
-
const trimmed = phone.trim().replace(/\(0\)/g, "");
|
|
5
|
+
const trimmed = (phone ?? "").trim().replace(/\(0\)/g, "");
|
|
5
6
|
const digits = trimmed.replace(/\D/g, "");
|
|
6
7
|
const intl = trimmed.startsWith("+") ? digits : digits.startsWith("00") ? digits.slice(2) : digits.startsWith("0") ? null : digits;
|
|
7
8
|
if (!intl || intl.length < 8 || intl.length > 15) return null;
|
|
@@ -9,6 +10,7 @@ function waLink(phone, text) {
|
|
|
9
10
|
}
|
|
10
11
|
function WhatsappChatRender({ block, mode }) {
|
|
11
12
|
const href = waLink(block.phone, block.prefilledText);
|
|
13
|
+
useOnderOffset(Boolean(href) && mode !== "preview");
|
|
12
14
|
if (!href) {
|
|
13
15
|
return mode === "preview" ? /* @__PURE__ */ jsx("p", { className: "xicms-ve__hint", children: "\u{1F4AC} WhatsApp-knop: vul een internationaal telefoonnummer in (bv. +31 6 12345678)." }) : null;
|
|
14
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/blocks/builtins/WhatsappChatRender.tsx"],"sourcesContent":["\"use client\";\n\nimport type { z } from \"zod\";\nimport type { WhatsappChatBlockSchema } from \"../../schema/blocks\";\nimport type { BlockRenderProps } from \"../registry\";\n\ntype WhatsappChat = z.infer<typeof WhatsappChatBlockSchema>;\n\n/**\n * wa.me accepteert alleen cijfers (internationaal, zonder + of spaties). Een nationaal nummer\n * (\"06-12345678\") heeft geen landcode — die zomaar strippen levert een verkeerd nummer op, dus\n * dan liever geen link (de editor-preview vraagt om internationale notatie).\n */\nexport function waLink(phone: string, text?: string): string | null {\n // \"(0)\" in \"+31 (0)6 12345678\" is een schrijfconventie, geen kiescijfer — eerst strippen,\n // anders belandt die valse nul midden in het wa.me-nummer.\n const trimmed = phone.trim().replace(/\\(0\\)/g, \"\");\n const digits = trimmed.replace(/\\D/g, \"\");\n const intl = trimmed.startsWith(\"+\")\n ? digits\n : digits.startsWith(\"00\")\n ? digits.slice(2)\n : digits.startsWith(\"0\")\n ? null\n : digits;\n if (!intl || intl.length < 8 || intl.length > 15) return null;\n return `https://wa.me/${intl}${text ? `?text=${encodeURIComponent(text)}` : \"\"}`;\n}\n\n/**\n * Zwevende WhatsApp-knop — dé laagdrempelige contactknop voor lokale bedrijven. Gewone link\n * (geen embed/scripts), dus geen consent nodig. In de editor-preview inline weergegeven zodat\n * hij het canvas niet overlapt.\n */\nexport function WhatsappChatRender({ block, mode }: BlockRenderProps<WhatsappChat>) {\n const href = waLink(block.phone, block.prefilledText);\n if (!href) {\n return mode === \"preview\" ? <p className=\"xicms-ve__hint\">💬 WhatsApp-knop: vul een internationaal telefoonnummer in (bv. +31 6 12345678).</p> : null;\n }\n const icon = (\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.9\" aria-hidden>\n <path d=\"M12 4.2a7.8 7.8 0 0 0-6.7 11.8L4.4 19.6l3.7-.9A7.8 7.8 0 1 0 12 4.2z\" />\n <path d=\"M9.3 8.9c.7 2.4 2.6 4.4 5 5l1-1.2 2 1.2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n return (\n <a\n className=\"xicms-whatsapp\"\n data-position={block.position}\n data-preview={mode === \"preview\" ? \"1\" : undefined}\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={block.label || \"Chat via WhatsApp\"}\n >\n {icon}\n {block.label && <span className=\"xicms-whatsapp__label\" data-xicms-edit=\"label\">{block.label}</span>}\n </a>\n );\n}\n"],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../../../src/blocks/builtins/WhatsappChatRender.tsx"],"sourcesContent":["\"use client\";\n\nimport { useOnderOffset } from \"../../components/onderOffset\";\nimport type { z } from \"zod\";\nimport type { WhatsappChatBlockSchema } from \"../../schema/blocks\";\nimport type { BlockRenderProps } from \"../registry\";\n\ntype WhatsappChat = z.infer<typeof WhatsappChatBlockSchema>;\n\n/**\n * wa.me accepteert alleen cijfers (internationaal, zonder + of spaties). Een nationaal nummer\n * (\"06-12345678\") heeft geen landcode — die zomaar strippen levert een verkeerd nummer op, dus\n * dan liever geen link (de editor-preview vraagt om internationale notatie).\n */\nexport function waLink(phone: string | undefined, text?: string): string | null {\n // \"(0)\" in \"+31 (0)6 12345678\" is een schrijfconventie, geen kiescijfer — eerst strippen,\n // anders belandt die valse nul midden in het wa.me-nummer.\n const trimmed = (phone ?? \"\").trim().replace(/\\(0\\)/g, \"\");\n const digits = trimmed.replace(/\\D/g, \"\");\n const intl = trimmed.startsWith(\"+\")\n ? digits\n : digits.startsWith(\"00\")\n ? digits.slice(2)\n : digits.startsWith(\"0\")\n ? null\n : digits;\n if (!intl || intl.length < 8 || intl.length > 15) return null;\n return `https://wa.me/${intl}${text ? `?text=${encodeURIComponent(text)}` : \"\"}`;\n}\n\n/**\n * Zwevende WhatsApp-knop — dé laagdrempelige contactknop voor lokale bedrijven. Gewone link\n * (geen embed/scripts), dus geen consent nodig. In de editor-preview inline weergegeven zodat\n * hij het canvas niet overlapt.\n */\nexport function WhatsappChatRender({ block, mode }: BlockRenderProps<WhatsappChat>) {\n const href = waLink(block.phone, block.prefilledText);\n // 8.16: boven een vaste balk onderaan (belbalk, demobalk), niet eroverheen.\n useOnderOffset(Boolean(href) && mode !== \"preview\");\n if (!href) {\n return mode === \"preview\" ? <p className=\"xicms-ve__hint\">💬 WhatsApp-knop: vul een internationaal telefoonnummer in (bv. +31 6 12345678).</p> : null;\n }\n const icon = (\n <svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.9\" aria-hidden>\n <path d=\"M12 4.2a7.8 7.8 0 0 0-6.7 11.8L4.4 19.6l3.7-.9A7.8 7.8 0 1 0 12 4.2z\" />\n <path d=\"M9.3 8.9c.7 2.4 2.6 4.4 5 5l1-1.2 2 1.2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n return (\n <a\n className=\"xicms-whatsapp\"\n data-position={block.position}\n data-preview={mode === \"preview\" ? \"1\" : undefined}\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={block.label || \"Chat via WhatsApp\"}\n >\n {icon}\n {block.label && <span className=\"xicms-whatsapp__label\" data-xicms-edit=\"label\">{block.label}</span>}\n </a>\n );\n}\n"],"mappings":";AAwCgC,cAG5B,YAH4B;AAtChC,SAAS,sBAAsB;AAYxB,SAAS,OAAO,OAA2B,MAA8B;AAG9E,QAAM,WAAW,SAAS,IAAI,KAAK,EAAE,QAAQ,UAAU,EAAE;AACzD,QAAM,SAAS,QAAQ,QAAQ,OAAO,EAAE;AACxC,QAAM,OAAO,QAAQ,WAAW,GAAG,IAC/B,SACA,OAAO,WAAW,IAAI,IACpB,OAAO,MAAM,CAAC,IACd,OAAO,WAAW,GAAG,IACnB,OACA;AACR,MAAI,CAAC,QAAQ,KAAK,SAAS,KAAK,KAAK,SAAS,GAAI,QAAO;AACzD,SAAO,iBAAiB,IAAI,GAAG,OAAO,SAAS,mBAAmB,IAAI,CAAC,KAAK,EAAE;AAChF;AAOO,SAAS,mBAAmB,EAAE,OAAO,KAAK,GAAmC;AAClF,QAAM,OAAO,OAAO,MAAM,OAAO,MAAM,aAAa;AAEpD,iBAAe,QAAQ,IAAI,KAAK,SAAS,SAAS;AAClD,MAAI,CAAC,MAAM;AACT,WAAO,SAAS,YAAY,oBAAC,OAAE,WAAU,kBAAiB,qGAAgF,IAAO;AAAA,EACnJ;AACA,QAAM,OACJ,qBAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAW,MAC7G;AAAA,wBAAC,UAAK,GAAE,wEAAuE;AAAA,IAC/E,oBAAC,UAAK,GAAE,2CAA0C,eAAc,SAAQ,gBAAe,SAAQ;AAAA,KACjG;AAEF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,iBAAe,MAAM;AAAA,MACrB,gBAAc,SAAS,YAAY,MAAM;AAAA,MACzC;AAAA,MACA,QAAO;AAAA,MACP,KAAI;AAAA,MACJ,cAAY,MAAM,SAAS;AAAA,MAE1B;AAAA;AAAA,QACA,MAAM,SAAS,oBAAC,UAAK,WAAU,yBAAwB,mBAAgB,SAAS,gBAAM,OAAM;AAAA;AAAA;AAAA,EAC/F;AAEJ;","names":[]}
|