@designcrowd/library.brand-page 5.19.1-error-html2canvas-2 → 5.19.1-id-based-items-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/src/{CreatedOnBrandCrowd-de-de-DmKe7W8L.js → CreatedOnBrandCrowd-de-de-0PcGqy0N.js} +3 -3
- package/lib/src/{CreatedOnBrandCrowd-en-us-D2EeiNep.js → CreatedOnBrandCrowd-en-us-DB8wcFMI.js} +3 -3
- package/lib/src/{CreatedOnBrandCrowd-es-es-BqVwNY1D.js → CreatedOnBrandCrowd-es-es-DVWQ243C.js} +3 -3
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-C756a27-.js → CreatedOnBrandCrowd-fr-ca-D-M_L0Du.js} +3 -3
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-C756a27-.js → CreatedOnBrandCrowd-fr-fr-D-M_L0Du.js} +3 -3
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-FNHAnZUw.js → CreatedOnBrandCrowd-pt-br-CNpzknxU.js} +3 -3
- package/lib/src/{CreatedOnBrandCrowd-pt-br-FNHAnZUw.js → CreatedOnBrandCrowd-pt-pt-CNpzknxU.js} +3 -3
- package/lib/src/{CreatedOnDcom-de-de-8AZZFmDt.js → CreatedOnDcom-de-de-DMJoD5wE.js} +3 -3
- package/lib/src/{CreatedOnDcom-en-us-DizTP32i.js → CreatedOnDcom-en-us-B-F3Pmjv.js} +3 -3
- package/lib/src/{CreatedOnDcom-es-es-qnp9_n_A.js → CreatedOnDcom-es-es-DmLk-cA2.js} +3 -3
- package/lib/src/{CreatedOnDcom-fr-ca-jUs352uK.js → CreatedOnDcom-fr-ca-ntnsCzvA.js} +3 -3
- package/lib/src/{CreatedOnDcom-fr-fr-CTxXtHyk.js → CreatedOnDcom-fr-fr-DFcO0gHL.js} +3 -3
- package/lib/src/{CreatedOnDcom-pt-br-nQHj8P7d.js → CreatedOnDcom-pt-br-CtuJoVXW.js} +3 -3
- package/lib/src/{CreatedOnDcom-pt-pt-DJmVYQuL.js → CreatedOnDcom-pt-pt-B7shZVVn.js} +3 -3
- package/lib/src/brand-page/clients/brand-page.client.d.ts +9 -9
- package/lib/src/brand-page/components/image-gallery/masonry/MasonryGallery.mixin.d.ts +2 -1
- package/lib/src/brand-page/components/navigation/hamburger/HamburgerNavigation.mixin.d.ts +2 -4
- package/lib/src/brand-page/components/navigation/hamburger/HamburgerNavigation.mixin.js +0 -1
- package/lib/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.d.ts +2 -4
- package/lib/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.js +4 -5
- package/lib/src/brand-page/components/page/Page.mixin.d.ts +1 -1
- package/lib/src/brand-page/components/page/PageComponent.mixin.d.ts +1 -1
- package/lib/src/brand-page/components/payment/Payment.mixin.d.ts +3 -3
- package/lib/src/brand-page/components/payment/__fixtures__/request-payment.d.ts +13 -13
- package/lib/src/brand-page/components/payment/__fixtures__/support-me.d.ts +13 -13
- package/lib/src/brand-page/constants/sections/footer-display.constants.js +1 -1
- package/lib/src/brand-page/models/index.d.ts +13 -2
- package/lib/src/brand-page/models/index.js +0 -3
- package/lib/src/brand-page/models/payment.model.d.ts +1 -1
- package/lib/src/brand-page/utils/personalisation.util.js +14 -72
- package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.d.ts +19 -21
- package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.js +0 -1
- package/lib/src/brand-page-maker/components/admin-background-settings/AdminBackgroundSettings.mixin.d.ts +10 -16
- package/lib/src/brand-page-maker/components/admin-logo-settings/AdminLogoSettings.mixin.d.ts +3 -3
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +170 -181
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +0 -3
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.stories.js +0 -1
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.mixin.d.ts +12 -12
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.stories.js +2 -2
- package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-payment.js +7 -0
- package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +149 -148
- package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.d.ts +21 -21
- package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.js +1 -1
- package/lib/src/brand-page-maker/components/color-picker/components/ColorModeSelect.mixin.d.ts +2 -4
- package/lib/src/brand-page-maker/components/color-picker/components/ColorModeSelect.mixin.js +0 -1
- package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSlider.mixin.d.ts +2 -4
- package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSlider.mixin.js +0 -1
- package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSliderHandler.mixin.d.ts +2 -5
- package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSliderHandler.mixin.js +0 -1
- package/lib/src/brand-page-maker/components/color-picker/components/GradientTypeSelector.mixin.d.ts +2 -4
- package/lib/src/brand-page-maker/components/color-picker/components/GradientTypeSelector.mixin.js +0 -1
- package/lib/src/brand-page-maker/components/device/Device.mixin.d.ts +2 -4
- package/lib/src/brand-page-maker/components/device/Device.mixin.js +0 -1
- package/lib/src/brand-page-maker/components/navigation/Navigation.mixin.d.ts +2 -4
- package/lib/src/brand-page-maker/components/navigation/Navigation.mixin.js +0 -1
- package/lib/src/brand-page-maker/components/preview/Preview.mixin.d.ts +3 -3
- package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +11 -11
- package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +25 -27
- package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.js +0 -1
- package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +27 -27
- package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.js +1 -1
- package/lib/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.mixin.d.ts +12 -17
- package/lib/src/brand-page-maker/components/social-share/SocialShare.mixin.d.ts +12 -12
- package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +32 -30
- package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.js +5 -16
- package/lib/src/brand-page-maker/components/upgrade-to-premium-button/UpgradeToPremiumButton.mixin.d.ts +11 -11
- package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +1 -1
- package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.d.ts +1 -1
- package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +6 -6
- package/lib/src/brand-page-maker/composables/useEventTracker.d.ts +2 -2
- package/lib/src/brand-page-maker/constants/config-settings-constant.d.ts +6 -6
- package/lib/src/brand-page-maker/constants/config-settings-constant.js +1 -1
- package/lib/src/brand-page-maker/convertors/text-image-display-style.convertor.d.ts +1 -1
- package/lib/src/brand-page-maker/convertors/text-image-display-style.convertor.js +1 -1
- package/lib/src/brand-page-maker/models/content-settings.d.ts +1 -1
- package/lib/src/brand-page-maker/models/navigation-style-configs.js +1 -1
- package/lib/src/brand-page-maker/routing/brand-page-maker-router.d.ts +2 -1
- package/lib/src/brand-page-maker/stores/ai-checkpoint/ai-checkpoint-store.d.ts +378 -366
- package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.d.ts +4 -5
- package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.js +5 -8
- package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.d.ts +1 -3
- package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +3 -7
- package/lib/src/brand-page-maker/stores/history/history-store.d.ts +15 -15
- package/lib/src/brand-page-maker/stores/ui/ui-store.d.ts +0 -6
- package/lib/src/brand-page-maker/stores/ui/ui-store.js +0 -8
- package/lib/src/brand-page-maker/utils/content-settings.util.js +1 -1
- package/lib/src/brand-page-maker/utils/rich-text-editor.util.d.ts +1 -1
- package/lib/src/brand-page-maker/utils/rich-text-editor.util.js +4 -4
- package/lib/src/clients/brand-page-client.d.ts +15 -16
- package/lib/src/clients/design-template-client.d.ts +0 -3
- package/lib/src/clients/media-client.d.ts +2 -2
- package/lib/src/clients/models.d.ts +0 -2
- package/lib/src/composables/useSnapshot.js +18 -18
- package/lib/src/css/library.brand-page-brandCrowd.min.css +324 -342
- package/lib/src/css/library.brand-page-brandPage.min.css +324 -620
- package/lib/src/css/library.brand-page-designCom.min.css +324 -342
- package/lib/src/css/library.brand-page-preview.min.css +324 -598
- package/lib/src/index.d.ts +1 -1
- package/lib/src/index.mjs +15 -16
- package/lib/src/{lib-DityivZa.js → lib-BQmJBVbS.js} +33238 -36458
- package/lib/src/lib.js +1 -1
- package/lib/src/metadata-builder/builders/footer-builder.js +56 -91
- package/lib/src/metadata-builder/builders/item-id-utils.d.ts +41 -0
- package/lib/src/metadata-builder/builders/item-id-utils.js +68 -0
- package/lib/src/metadata-builder/builders/section-builders/image-gallery-builder.js +57 -68
- package/lib/src/metadata-builder/builders/section-builders/images-section-builder.js +58 -93
- package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.js +66 -99
- package/lib/src/metadata-builder/builders/section-builders/social-links-builder.js +57 -17
- package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.js +51 -85
- package/lib/src/metadata-builder/builders/section-builders/text-section-builder.js +49 -74
- package/lib/src/metadata-builder/builders/shape-color-utils.js +1 -1
- package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +13 -4
- package/lib/src/metadata-builder/parsers/section-tool-arguments.d.ts +66 -48
- package/lib/src/plugins/google-maps-plugin/google-maps-plugin.d.ts +1 -1
- package/lib/src/plugins/google-maps-plugin/google-maps-plugin.js +8 -8
- package/lib/src/shared/background-settings/components/background-shapes/BackgroundShapeSettings.mixin.d.ts +13 -13
- package/lib/src/shared/background-settings/store/background-settings-store.d.ts +3 -3
- package/lib/src/shared/color-picker/components/ColorPicker.mixin.d.ts +2 -4
- package/lib/src/shared/color-picker/components/ColorPicker.mixin.js +2 -2
- package/lib/src/shared/color-picker/components/ColorPickerSwatch.mixin.d.ts +2 -4
- package/lib/src/shared/color-picker/components/ColorPickerSwatch.mixin.js +0 -1
- package/lib/src/shared/confirm-modal/ConfirmModal.mixin.d.ts +2 -5
- package/lib/src/shared/confirm-modal/ConfirmModal.mixin.js +0 -1
- package/lib/src/shared/content-settings/components/GenericTextInput.mixin.d.ts +1 -0
- package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +129 -131
- package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.js +1 -2
- package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +110 -111
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +81 -84
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.js +0 -5
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +109 -117
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.js +14 -1
- package/lib/src/shared/content-settings/components/email-field/EmailField.mixin.d.ts +1 -0
- package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.d.ts +70 -72
- package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.js +3 -4
- package/lib/src/shared/content-settings/components/form-fields-field/FormFieldsField.mixin.d.ts +4 -4
- package/lib/src/shared/content-settings/components/icon-library/IconLibrary.mixin.d.ts +1 -3
- package/lib/src/shared/content-settings/components/icon-library/IconLibrary.mixin.js +0 -1
- package/lib/src/shared/content-settings/components/images-field/ImagesField.mixin.d.ts +2 -2
- package/lib/src/shared/content-settings/components/items-field/ItemsField.mixin.d.ts +3 -4
- package/lib/src/shared/content-settings/components/items-field/ItemsField.mixin.js +1 -1
- package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +40 -40
- package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigOptionField.mixin.d.ts +6 -5
- package/lib/src/shared/content-settings/components/shape-field/ShapeField.mixin.d.ts +1 -0
- package/lib/src/shared/content-settings/components/slider-field/SliderField.mixin.d.ts +2 -2
- package/lib/src/shared/content-settings/components/tel-field/TelField.mixin.d.ts +1 -0
- package/lib/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.mixin.d.ts +2 -1
- package/lib/src/shared/content-settings/components/text-field/TextField.mixin.d.ts +1 -0
- package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.d.ts +2 -1
- package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.js +1 -1
- package/lib/src/shared/content-settings/components/text-style-field/TextStyleField.mixin.d.ts +28 -28
- package/lib/src/shared/content-settings/components/textarea-field/TextareaField.mixin.d.ts +1 -0
- package/lib/src/shared/content-settings/components/toggle-field/ToggleField.mixin.d.ts +2 -2
- package/lib/src/shared/content-settings/components/url-field/UrlField.mixin.d.ts +1 -0
- package/lib/src/shared/content-settings/components/youtube-video-field/YoutubeVideoField.mixin.d.ts +1 -0
- package/lib/src/shared/content-settings/store/content-settings-store.d.ts +39 -39
- package/lib/src/shared/content-settings/utils.js +1 -0
- package/lib/src/shared/font-family-selector/FontFamilySelector.mixin.d.ts +4 -6
- package/lib/src/shared/font-family-selector/FontFamilySelector.mixin.js +0 -1
- package/lib/src/shared/image-gallery-style-settings/ImageGalleryStyleSettings.mixin.d.ts +2 -4
- package/lib/src/shared/image-gallery-style-settings/ImageGalleryStyleSettings.mixin.js +0 -1
- package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +21 -29
- package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.js +1 -1
- package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +51 -50
- package/lib/src/shared/logo-settings/components/LogoSettingsHeader.mixin.d.ts +4 -6
- package/lib/src/shared/logo-settings/components/LogoSettingsHeader.mixin.js +0 -1
- package/lib/src/shared/logo-settings/store/editable-logo-store.js +1 -1
- package/lib/src/shared/logo-settings/store/logo-settings-store.d.ts +1 -1
- package/lib/src/shared/logo-versions/LogoVersions.mixin.d.ts +5 -13
- package/lib/src/shared/logo-versions/LogoVersions.mixin.js +0 -1
- package/lib/src/shared/models.d.ts +0 -2
- package/lib/src/shared/my-designs/MyDesigns.mixin.d.ts +6 -14
- package/lib/src/shared/my-designs/MyDesigns.mixin.js +0 -1
- package/lib/src/shared/my-uploads/MyMedia.mixin.d.ts +5 -14
- package/lib/src/shared/my-uploads/MyMedia.mixin.js +0 -1
- package/lib/src/shared/my-uploads/MyUploads.mixin.d.ts +5 -14
- package/lib/src/shared/my-uploads/MyUploads.mixin.js +0 -1
- package/lib/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.mixin.d.ts +3 -5
- package/lib/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.mixin.js +0 -1
- package/lib/src/shared/navigation-style-settings/store/index.d.ts +2 -2
- package/lib/src/shared/page-navigation/store/page-navigation-store.d.ts +2 -2
- package/lib/src/shared/page-settings/components/new-page-modal/NewPageModal.mixin.d.ts +28 -27
- package/lib/src/shared/page-settings/components/new-page-modal/NewPageModal.mixin.js +2 -0
- package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +179 -188
- package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +177 -181
- package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.js +1 -1
- package/lib/src/shared/page-settings/store/page-settings-store.d.ts +9 -9
- package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +39 -39
- package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.js +1 -0
- package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +18 -18
- package/lib/src/shared/side-bar/components/SideBarTabButton.mixin.d.ts +6 -6
- package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +60 -66
- package/lib/src/shared/style-settings/store/style-settings-store.d.ts +1 -1
- package/lib/src/shared/style-settings/store/style-settings-store.js +1 -1
- package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.d.ts +450 -20
- package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.js +2 -2
- package/lib/src/shared/template-settings/models.d.ts +0 -1
- package/lib/src/shared/template-settings/store/template-settings-store.d.ts +0 -4
- package/lib/src/shared/template-settings/store/template-settings-store.js +11 -79
- package/lib/src/shared/unsplash-library/UnsplashLibrary.mixin.d.ts +4 -9
- package/package.json +57 -61
- package/src/brand-page/components/about-section/AboutSection.vue.test.ts +5 -7
- package/src/brand-page/components/brand-page-footer/BrandPageFooter.vue +1 -1
- package/src/brand-page/components/image/Image.mixin.ts +1 -1
- package/src/brand-page/components/image/Image.test.ts +1 -1
- package/src/brand-page/components/image-gallery/masonry/MasonryGallery.mixin.ts +2 -1
- package/src/brand-page/components/images-section/ImagesSection.vue +1 -0
- package/src/brand-page/components/logo/LogoRender.vue +188 -188
- package/src/brand-page/components/navigation/hamburger/HamburgerNavigation.mixin.ts +0 -1
- package/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.ts +6 -15
- package/src/brand-page/components/page-footer/PageFooter.vue +0 -1
- package/src/brand-page/components/page-header/HeaderLayout.vue +6 -12
- package/src/brand-page/components/page-header/PageHeader.vue +0 -1
- package/src/brand-page/components/shapes-section/ShapesSection.vue +1 -1
- package/src/brand-page/components/shop/CartModal.vue +3 -1
- package/src/brand-page/components/shop/FeaturedDisplay.vue +2 -2
- package/src/brand-page/components/shop/PaymentModal.vue +5 -1
- package/src/brand-page/components/shop/ProductDetailModal.vue +1 -1
- package/src/brand-page/components/shop/Shop.vue +1 -1
- package/src/brand-page/components/shop/TextDisplay.vue +1 -1
- package/src/brand-page/components/shop/ThumbnailDisplay.vue +2 -2
- package/src/brand-page/components/testimonial-section/TestimonialSection.vue +3 -3
- package/src/brand-page/components/text-wrapper/TextWrapper.vue +1 -3
- package/src/brand-page/constants/sections/footer-display.constants.ts +1 -1
- package/src/brand-page/models/index.ts +12 -4
- package/src/brand-page/models/payment.model.ts +1 -2
- package/src/brand-page/models/shop.model.ts +2 -0
- package/src/brand-page/models/user-personalisation.model.ts +2 -1
- package/src/brand-page/utils/__snapshots__/migration.util.test.ts.snap +0 -3
- package/src/brand-page/utils/__snapshots__/migration2.util.test.ts.snap +0 -1
- package/src/brand-page/utils/__snapshots__/model.util.test.ts.snap +0 -2
- package/src/brand-page/utils/migration/migration-01_1.ts +1 -1
- package/src/brand-page/utils/migration/migration-02.ts +1 -0
- package/src/brand-page/utils/migration/migration-03.ts +1 -0
- package/src/brand-page/utils/migration/migration-04.ts +1 -0
- package/src/brand-page/utils/migration/migration-05.ts +5 -1
- package/src/brand-page/utils/migration/migration-05_2.ts +1 -1
- package/src/brand-page/utils/migration/migration-08.test.ts +1 -1
- package/src/brand-page/utils/personalisation.util.test.ts +0 -35
- package/src/brand-page/utils/personalisation.util.ts +23 -119
- package/src/brand-page/view-models.ts +56 -38
- package/src/brand-page-maker/assessors/banner-section-description-visibility.assessor.ts +6 -6
- package/src/brand-page-maker/assessors/color-replacement-icon-visibility.assessor.ts +2 -2
- package/src/brand-page-maker/assessors/color-replacement-profile-visibility.assessor.ts +2 -2
- package/src/brand-page-maker/assessors/color-replacement-visibility.assessor.ts +2 -2
- package/src/brand-page-maker/assessors/contact-form-visibility.assessor.ts +14 -14
- package/src/brand-page-maker/components/action-bar/ActionBar.mixin.ts +0 -1
- package/src/brand-page-maker/components/ai-text-edit/TextBubble.vue +0 -1
- package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +1 -5
- package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.stories.ts +0 -1
- package/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.stories.ts +5 -2
- package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.ts +5 -0
- package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-payment.ts +8 -0
- package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-site-template.examples.ts +2 -0
- package/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.vue +0 -1
- package/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.ts +1 -1
- package/src/brand-page-maker/components/color-palette/BpColorPalette.vue +2 -1
- package/src/brand-page-maker/components/color-picker/components/ColorModeSelect.mixin.ts +0 -1
- package/src/brand-page-maker/components/color-picker/components/GradientColorSlider.mixin.ts +0 -1
- package/src/brand-page-maker/components/color-picker/components/GradientColorSliderHandler.mixin.ts +0 -1
- package/src/brand-page-maker/components/color-picker/components/GradientTypeSelector.mixin.ts +0 -1
- package/src/brand-page-maker/components/device/Device.mixin.ts +0 -1
- package/src/brand-page-maker/components/navigation/Navigation.mixin.ts +0 -1
- package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.vue +1 -3
- package/src/brand-page-maker/components/sensitive-content/SensitiveContent.vue +4 -1
- package/src/brand-page-maker/components/seo-settings/DeleteDomainModal.vue +1 -1
- package/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.ts +0 -1
- package/src/brand-page-maker/components/seo-settings/SeoPageSettings.vue +1 -1
- package/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.ts +1 -0
- package/src/brand-page-maker/components/seo-settings/UrlSettings.vue +1 -0
- package/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.vue +5 -1
- package/src/brand-page-maker/components/shop/AddOrEditProductContainer.vue +1 -1
- package/src/brand-page-maker/components/shop/ReplaceImageSettingsForShop.vue +1 -1
- package/src/brand-page-maker/components/social-share/SocialShare.vue +1 -1
- package/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.ts +8 -22
- package/src/brand-page-maker/components/template-preview/TemplatePreview.vue +10 -5
- package/src/brand-page-maker/components/video-play/VideoPlayButton.vue +1 -1
- package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +1 -1
- package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +6 -6
- package/src/brand-page-maker/constants/config-settings-constant.ts +3 -3
- package/src/brand-page-maker/convertors/text-image-display-style.convertor.ts +1 -1
- package/src/brand-page-maker/models/button-styles-config.ts +2 -4
- package/src/brand-page-maker/models/content-settings-configs.ts +2 -4
- package/src/brand-page-maker/models/navigation-style-configs.ts +6 -5
- package/src/brand-page-maker/stores/admin-logo-settings/admin-logo-settings-store.ts +1 -0
- package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.ts +5 -8
- package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.test.ts +3 -1
- package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +4 -12
- package/src/brand-page-maker/stores/ui/ui-store.ts +0 -16
- package/src/brand-page-maker/utils/content-settings.util.ts +1 -1
- package/src/brand-page-maker/utils/rich-text-editor.util.ts +4 -4
- package/src/clients/design-template-client.ts +0 -3
- package/src/clients/models.ts +0 -2
- package/src/composables/useSnapshot.ts +22 -19
- package/src/lib.ts +0 -1
- package/src/metadata-builder/builders/footer-builder.test.ts +245 -84
- package/src/metadata-builder/builders/footer-builder.ts +81 -130
- package/src/metadata-builder/builders/item-id-utils.test.ts +118 -0
- package/src/metadata-builder/builders/item-id-utils.ts +85 -0
- package/src/metadata-builder/builders/section-builders/image-gallery-builder.ts +62 -88
- package/src/metadata-builder/builders/section-builders/images-section-builder.ts +66 -129
- package/src/metadata-builder/builders/section-builders/shapes-section-builder.ts +105 -160
- package/src/metadata-builder/builders/section-builders/social-links-builder.ts +65 -20
- package/src/metadata-builder/builders/section-builders/testimonial-section-builder.ts +83 -146
- package/src/metadata-builder/builders/section-builders/text-section-builder.ts +70 -122
- package/src/metadata-builder/builders/shape-color-utils.ts +2 -2
- package/src/metadata-builder/parsers/ai-toolcall-parser.ts +13 -4
- package/src/metadata-builder/parsers/section-tool-arguments.ts +66 -48
- package/src/plugins/google-maps-plugin/google-maps-plugin.ts +8 -8
- package/src/shared/background-settings/components/BackgroundSettings.vue +1 -1
- package/src/shared/background-settings/components/background-color/BackgroundColorSettings.vue +1 -1
- package/src/shared/color-picker/components/ColorPicker.mixin.ts +7 -2
- package/src/shared/color-picker/components/ColorPickerSwatch.mixin.ts +0 -1
- package/src/shared/common/NumberInput.vue +0 -1
- package/src/shared/common/SideBarSettingsHeader.vue +2 -2
- package/src/shared/confirm-modal/ConfirmModal.mixin.ts +0 -1
- package/src/shared/content-settings/components/booking-url-field/BookingUrlField.vue +0 -1
- package/src/shared/content-settings/components/button-configuration-field/ButtonConfigurationField.vue +0 -1
- package/src/shared/content-settings/components/color-field/ColorField.vue +10 -3
- package/src/shared/content-settings/components/content-settings/ContentSettings.mixin.ts +1 -1
- package/src/shared/content-settings/components/content-settings/ContentSettingsLockedButton.vue +0 -1
- package/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.ts +0 -5
- package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.ts +14 -1
- package/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.ts +6 -4
- package/src/shared/content-settings/components/icon-library/IconLibrary.mixin.ts +0 -1
- package/src/shared/content-settings/components/items-field/ItemsField.mixin.ts +1 -1
- package/src/shared/content-settings/components/logo-selection-field/LogoSelectionField.vue +1 -1
- package/src/shared/content-settings/components/logo-size-field/LogoSizeSliderField.vue +1 -1
- package/src/shared/content-settings/components/page-dropdown-field/PageDropdownField.vue +1 -1
- package/src/shared/content-settings/components/personalisation-role-field/PersonalisationRoleField.vue +4 -4
- package/src/shared/content-settings/components/text-image-field/TextImageField.vue +8 -2
- package/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.ts +1 -1
- package/src/shared/content-settings/models.ts +2 -3
- package/src/shared/content-settings/utils.ts +1 -0
- package/src/shared/dropzone-image-uploader/components/DropzoneImageUploader.vue +0 -1
- package/src/shared/ecommerce-settings/store/cart-store.test.ts +1 -1
- package/src/shared/font-family-selector/FontFamilySelector.mixin.ts +0 -1
- package/src/shared/image-gallery-style-settings/ImageGalleryStyleSettings.mixin.ts +0 -1
- package/src/shared/logo-settings/components/EditLogoSettings.mixin.ts +1 -1
- package/src/shared/logo-settings/components/LogoSettings.mixin.ts +1 -0
- package/src/shared/logo-settings/components/LogoSettingsHeader.mixin.ts +0 -1
- package/src/shared/logo-settings/components/LogoStyleSettingsWithState.vue +2 -2
- package/src/shared/logo-settings/components/LogoTemplateSearch.vue +1 -1
- package/src/shared/logo-settings/store/editable-logo-store.ts +1 -1
- package/src/shared/logo-settings/store/logo-settings-store.test.ts +4 -4
- package/src/shared/logo-versions/LogoVersions.mixin.ts +0 -1
- package/src/shared/models.ts +0 -6
- package/src/shared/my-designs/MyDesigns.mixin.ts +0 -1
- package/src/shared/my-uploads/MyMedia.mixin.ts +0 -1
- package/src/shared/my-uploads/MyMediaSelectionItem.vue +1 -2
- package/src/shared/my-uploads/MyUploads.mixin.ts +0 -1
- package/src/shared/my-uploads/models.ts +2 -1
- package/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.mixin.ts +0 -1
- package/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.vue +1 -1
- package/src/shared/page-settings/components/new-page-modal/NewPageModal.mixin.ts +3 -0
- package/src/shared/page-settings/components/page-settings/NestedDraggable.vue +1 -1
- package/src/shared/page-settings/components/page-settings/PageSettings.vue +2 -1
- package/src/shared/page-settings/components/page-settings-section-styles/HeaderDisplayStyle.vue +1 -1
- package/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.ts +1 -1
- package/src/shared/page-settings/store/page-settings-store.test.ts +8 -4
- package/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.ts +1 -0
- package/src/shared/shape-library/ShapeLibrary.vue +2 -2
- package/src/shared/style-settings/store/style-settings-store.ts +1 -1
- package/src/shared/template-settings/components/TemplatesSettings.mixin.ts +2 -2
- package/src/shared/template-settings/models.ts +0 -1
- package/src/shared/template-settings/store/template-settings-store.ts +18 -105
- package/src/shared/unsplash-library/UnsplashLibrary.vue +6 -2
- package/src/shared/video-library/VideoLibrary.vue +1 -1
- package/lib/src/brand-page/components/banner-section/BannerSection.mixin.d.ts +0 -103
- package/lib/src/brand-page/components/banner-section/BannerSection.mixin.js +0 -178
- package/src/brand-page/components/banner-section/BannerSection.mixin.ts +0 -210
- package/src/brand-page-maker/components/template-preview/TemplatePreviewAiBadge.vue +0 -12
package/lib/src/lib.js
CHANGED
|
@@ -32,7 +32,7 @@ export { getOptimalLogoSize, calculateOptimizedLogoDimensions, applyLogoImageBas
|
|
|
32
32
|
export { sanitizeRTEHtml } from './brand-page-maker/utils';
|
|
33
33
|
export { getPageSlugFromPageTitle } from './brand-page-maker/utils/slug.util';
|
|
34
34
|
// stores
|
|
35
|
-
export { useBrandPageMakerStore, useBrandPageMakerUserStore, useUiStore, useBrandPageContainerStore, useEventManagerStore, useLocalisedRouteStore, useVideoStore,
|
|
35
|
+
export { useBrandPageMakerStore, useBrandPageMakerUserStore, useUiStore, useBrandPageContainerStore, useEventManagerStore, useLocalisedRouteStore, useVideoStore, } from './brand-page-maker/stores';
|
|
36
36
|
export { useShopConfigStore } from './shared/ecommerce-settings/store/shop-settings-store';
|
|
37
37
|
// for jest, need to set active pinia in library.brand-page as well
|
|
38
38
|
import { createPinia, setActivePinia } from 'pinia';
|
|
@@ -2,6 +2,7 @@ import {} from '../../brand-page/models';
|
|
|
2
2
|
import { BaseMetadataBuilder, } from '../models';
|
|
3
3
|
import { FOOTER_CHECKS } from './section-rules/footer.rules';
|
|
4
4
|
import { applyDetachedStyleOverride } from './section-field-utils';
|
|
5
|
+
import { ensureItemIds, generateItemId, removeItemsByIds, repositionItemByAnchor, } from './item-id-utils';
|
|
5
6
|
const normaliseSocialUrl = (url) => {
|
|
6
7
|
for (const prefix of ['mailto:', 'tel:']) {
|
|
7
8
|
if (url.startsWith(prefix))
|
|
@@ -9,88 +10,65 @@ const normaliseSocialUrl = (url) => {
|
|
|
9
10
|
}
|
|
10
11
|
return url;
|
|
11
12
|
};
|
|
12
|
-
const makeSocialLink = (icon, url) => ({
|
|
13
|
-
imageUrl: icon || '',
|
|
14
|
-
url: normaliseSocialUrl(url || ''),
|
|
15
|
-
imageTitle: '',
|
|
16
|
-
width: 0,
|
|
17
|
-
height: 0,
|
|
18
|
-
imageLink: '',
|
|
19
|
-
});
|
|
20
|
-
const hasSocialLinkMutation = (args) => args._replace_social_links === true ||
|
|
21
|
-
(args._remove_social_link_indices?.length ?? 0) > 0 ||
|
|
22
|
-
(args._reorder_social_links?.length ?? 0) > 0 ||
|
|
23
|
-
(args.social_links?.length ?? 0) > 0;
|
|
24
|
-
/**
|
|
25
|
-
* Social links are a GLOBAL footer concern — one logical list that both
|
|
26
|
-
* viewports render identically. Derive the new list ONCE from the current one
|
|
27
|
-
* WITHOUT mutating the input, so the caller can assign an independent copy to
|
|
28
|
-
* each viewport.
|
|
29
|
-
*
|
|
30
|
-
* Why this can't mutate per-viewport in place: footers migrated from the legacy
|
|
31
|
-
* single `footerStyles` model (migration-01) share ONE `socialLinks` array
|
|
32
|
-
* reference across pageFooterDesktop and pageFooterMobile, and `cloneDeep`
|
|
33
|
-
* preserves that shared reference. Running an in-place `splice` once per
|
|
34
|
-
* viewport therefore applies it TWICE to the same array — e.g. one requested
|
|
35
|
-
* removal index drops two links. Compute-once + assign-fresh is correct for
|
|
36
|
-
* both shared (legacy) and independent (new-model) footers.
|
|
37
|
-
*/
|
|
38
|
-
const computeSocialLinks = (current, args) => {
|
|
39
|
-
// _replace_social_links: replace entire list (empty/absent social_links = clear all).
|
|
40
|
-
// A replacement supersedes every other social link mutation.
|
|
41
|
-
if (args._replace_social_links) {
|
|
42
|
-
return (args.social_links ?? []).map((l) => makeSocialLink(l.social_link_icon, l.url));
|
|
43
|
-
}
|
|
44
|
-
const links = [...(current ?? [])];
|
|
45
|
-
// item_index-based updates for existing links — replace the item reference
|
|
46
|
-
// (never mutate the original object, which may be shared across viewports).
|
|
47
|
-
for (const link of args.social_links ?? []) {
|
|
48
|
-
if (link.item_index === undefined)
|
|
49
|
-
continue;
|
|
50
|
-
const existing = links[link.item_index];
|
|
51
|
-
if (!existing)
|
|
52
|
-
continue;
|
|
53
|
-
links[link.item_index] = {
|
|
54
|
-
...existing,
|
|
55
|
-
...(link.social_link_icon !== undefined
|
|
56
|
-
? { imageUrl: link.social_link_icon }
|
|
57
|
-
: {}),
|
|
58
|
-
...(link.url !== undefined ? { url: normaliseSocialUrl(link.url) } : {}),
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
// Remove by index (descending order to preserve indices during splice).
|
|
62
|
-
if (args._remove_social_link_indices?.length) {
|
|
63
|
-
const sorted = [...args._remove_social_link_indices].sort((a, b) => b - a);
|
|
64
|
-
for (const idx of sorted) {
|
|
65
|
-
if (idx >= 0 && idx < links.length)
|
|
66
|
-
links.splice(idx, 1);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
// Insert new links (descending insert_at order to preserve positions).
|
|
70
|
-
const insertLinks = (args.social_links ?? []).filter((l) => l.insert_at !== undefined && l.item_index === undefined);
|
|
71
|
-
const sortedInserts = [...insertLinks].sort((a, b) => b.insert_at - a.insert_at);
|
|
72
|
-
for (const link of sortedInserts) {
|
|
73
|
-
const pos = Math.max(0, Math.min(link.insert_at, links.length));
|
|
74
|
-
links.splice(pos, 0, makeSocialLink(link.social_link_icon, link.url));
|
|
75
|
-
}
|
|
76
|
-
// Reorder (requires ALL indices — partial reorder is not supported).
|
|
77
|
-
if (args._reorder_social_links?.length) {
|
|
78
|
-
const newOrder = args._reorder_social_links;
|
|
79
|
-
const unique = new Set(newOrder);
|
|
80
|
-
if (unique.size === newOrder.length &&
|
|
81
|
-
newOrder.every((idx) => idx >= 0 && idx < links.length)) {
|
|
82
|
-
const reordered = newOrder.map((idx) => links[idx]);
|
|
83
|
-
if (reordered.length === links.length)
|
|
84
|
-
return reordered;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return links;
|
|
88
|
-
};
|
|
89
13
|
const applyGlobalFooterChanges = (footer, args, textStyleOptions) => {
|
|
90
14
|
if (args.copyright_text !== undefined)
|
|
91
15
|
footer.copyrightText = args.copyright_text;
|
|
92
16
|
if (args.copyright_text_font_family !== undefined)
|
|
93
17
|
footer.copyrightStyle = applyDetachedStyleOverride(footer.copyrightStyle, { fontFamily: args.copyright_text_font_family }, textStyleOptions);
|
|
18
|
+
const links = args.social_links;
|
|
19
|
+
// _replace_social_links: replace entire list (empty/absent social_links = clear all).
|
|
20
|
+
// When replacing, all other social link mutations (remove, insert, reorder) are skipped —
|
|
21
|
+
// they are superseded by the replacement and running them would cause duplicates.
|
|
22
|
+
if (args._replace_social_links) {
|
|
23
|
+
footer.socialLinks = (links ?? []).map((l) => ({
|
|
24
|
+
id: generateItemId(),
|
|
25
|
+
imageUrl: l.social_link_icon || '',
|
|
26
|
+
url: normaliseSocialUrl(l.url || ''),
|
|
27
|
+
imageTitle: '',
|
|
28
|
+
width: 0,
|
|
29
|
+
height: 0,
|
|
30
|
+
imageLink: '',
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
// Targeted mutations — only run when NOT replacing the entire list.
|
|
35
|
+
// BP-5603: id-based contract (item_id / move_before_item_id / _remove_social_link_ids).
|
|
36
|
+
// Backfill ids on legacy links so they become referenceable after this call.
|
|
37
|
+
ensureItemIds(footer.socialLinks);
|
|
38
|
+
// Remove by id (order-independent — no index shifting needed).
|
|
39
|
+
footer.socialLinks = removeItemsByIds(footer.socialLinks, args._remove_social_link_ids);
|
|
40
|
+
// Update existing links (item_id present) or insert new links (no item_id).
|
|
41
|
+
if (links?.length) {
|
|
42
|
+
footer.socialLinks = footer.socialLinks ?? [];
|
|
43
|
+
for (const link of links) {
|
|
44
|
+
if (link.item_id) {
|
|
45
|
+
// Update existing link in place; reposition if move_before_item_id set.
|
|
46
|
+
const existing = footer.socialLinks.find((l) => l.id === link.item_id);
|
|
47
|
+
// Unknown id — skip rather than guess at a position.
|
|
48
|
+
if (!existing)
|
|
49
|
+
continue;
|
|
50
|
+
if (link.social_link_icon !== undefined)
|
|
51
|
+
existing.imageUrl = link.social_link_icon;
|
|
52
|
+
if (link.url !== undefined)
|
|
53
|
+
existing.url = normaliseSocialUrl(link.url);
|
|
54
|
+
repositionItemByAnchor(footer.socialLinks, existing, link.move_before_item_id);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
// New link — assign a stable id and position via move_before_item_id.
|
|
58
|
+
const newLink = {
|
|
59
|
+
id: generateItemId(),
|
|
60
|
+
imageUrl: link.social_link_icon || '',
|
|
61
|
+
url: normaliseSocialUrl(link.url || ''),
|
|
62
|
+
imageTitle: '',
|
|
63
|
+
width: 0,
|
|
64
|
+
height: 0,
|
|
65
|
+
imageLink: '',
|
|
66
|
+
};
|
|
67
|
+
repositionItemByAnchor(footer.socialLinks, newLink, link.move_before_item_id);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
94
72
|
};
|
|
95
73
|
const applyViewportFooterChanges = (footer, overrides) => {
|
|
96
74
|
if (overrides.display_style !== undefined)
|
|
@@ -148,24 +126,11 @@ export class FooterBuilder extends BaseMetadataBuilder {
|
|
|
148
126
|
}
|
|
149
127
|
const args = this.request.payload ?? {};
|
|
150
128
|
const textStyleOptions = model.styles?.textStyles?.textStyleOptions;
|
|
151
|
-
// Global
|
|
152
|
-
// viewports. These are idempotent assignments, safe to run per-viewport.
|
|
129
|
+
// Global fields (copyright_text, social links) always apply to both viewports.
|
|
153
130
|
if (model.pageFooterDesktop)
|
|
154
131
|
applyGlobalFooterChanges(model.pageFooterDesktop, args, textStyleOptions);
|
|
155
132
|
if (model.pageFooterMobile)
|
|
156
133
|
applyGlobalFooterChanges(model.pageFooterMobile, args, textStyleOptions);
|
|
157
|
-
// Social links are a single global list. Derive the new list ONCE, then
|
|
158
|
-
// assign an INDEPENDENT copy to each viewport — never mutate a (possibly
|
|
159
|
-
// shared) viewport array in place. See computeSocialLinks.
|
|
160
|
-
if (hasSocialLinkMutation(args)) {
|
|
161
|
-
const current = model.pageFooterDesktop?.socialLinks ??
|
|
162
|
-
model.pageFooterMobile?.socialLinks;
|
|
163
|
-
const updated = computeSocialLinks(current, args);
|
|
164
|
-
if (model.pageFooterDesktop)
|
|
165
|
-
model.pageFooterDesktop.socialLinks = updated.map((l) => ({ ...l }));
|
|
166
|
-
if (model.pageFooterMobile)
|
|
167
|
-
model.pageFooterMobile.socialLinks = updated.map((l) => ({ ...l }));
|
|
168
|
-
}
|
|
169
134
|
// Viewport-specific styling via explicit sub-objects.
|
|
170
135
|
if (args.desktop && model.pageFooterDesktop)
|
|
171
136
|
applyViewportFooterChanges(model.pageFooterDesktop, args.desktop);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sentinel anchor meaning "the end of the list", mirroring the section-level
|
|
3
|
+
* `move_before_content_id: "__end__"` convention used in base-section-builder.
|
|
4
|
+
*/
|
|
5
|
+
export declare const END_ITEM_ANCHOR = "__end__";
|
|
6
|
+
/** Generate a stable item id. Mirrors section-level `uuid.v4()` id generation. */
|
|
7
|
+
export declare const generateItemId: () => string;
|
|
8
|
+
/**
|
|
9
|
+
* Backfill ids onto any items missing one. Per BP-5603 this runs in the
|
|
10
|
+
* metadata builder when a section is processed, so the persisted metadata
|
|
11
|
+
* returned to the client gains stable ids that subsequent AI tool calls can
|
|
12
|
+
* reference. Mutates in place.
|
|
13
|
+
*/
|
|
14
|
+
export declare const ensureItemIds: <T extends {
|
|
15
|
+
id?: string | undefined;
|
|
16
|
+
}>(items: T[] | undefined) => void;
|
|
17
|
+
/**
|
|
18
|
+
* Remove items whose id appears in `ids`. Order-independent (no descending
|
|
19
|
+
* index sort needed) — the whole point of the id-based migration. Items
|
|
20
|
+
* without an id are never removed by id.
|
|
21
|
+
*/
|
|
22
|
+
export declare const removeItemsByIds: <T extends {
|
|
23
|
+
id?: string | undefined;
|
|
24
|
+
}>(items: T[] | undefined, ids: string[] | undefined) => T[];
|
|
25
|
+
/**
|
|
26
|
+
* Position `item` within `items` relative to an anchor id — the item-level
|
|
27
|
+
* mirror of base-section-builder's `moveContent`:
|
|
28
|
+
*
|
|
29
|
+
* - `moveBeforeItemId === undefined` → leave an existing item where it is;
|
|
30
|
+
* append a new (not-yet-present) item to the end.
|
|
31
|
+
* - `moveBeforeItemId === "__end__"` → move/insert at the very end.
|
|
32
|
+
* - anchor id found → insert immediately before it.
|
|
33
|
+
* - anchor id not found → fall through to the end (same
|
|
34
|
+
* forgiving behaviour as `moveContent`).
|
|
35
|
+
*
|
|
36
|
+
* Mutates `items` in place. `item` may be an existing element of `items`
|
|
37
|
+
* (a move) or a brand-new object (an insert).
|
|
38
|
+
*/
|
|
39
|
+
export declare const repositionItemByAnchor: <T extends {
|
|
40
|
+
id?: string | undefined;
|
|
41
|
+
}>(items: T[], item: T, moveBeforeItemId: string | undefined) => void;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
2
|
+
/**
|
|
3
|
+
* Sentinel anchor meaning "the end of the list", mirroring the section-level
|
|
4
|
+
* `move_before_content_id: "__end__"` convention used in base-section-builder.
|
|
5
|
+
*/
|
|
6
|
+
export const END_ITEM_ANCHOR = '__end__';
|
|
7
|
+
/** Generate a stable item id. Mirrors section-level `uuid.v4()` id generation. */
|
|
8
|
+
export const generateItemId = () => uuidv4();
|
|
9
|
+
/**
|
|
10
|
+
* Backfill ids onto any items missing one. Per BP-5603 this runs in the
|
|
11
|
+
* metadata builder when a section is processed, so the persisted metadata
|
|
12
|
+
* returned to the client gains stable ids that subsequent AI tool calls can
|
|
13
|
+
* reference. Mutates in place.
|
|
14
|
+
*/
|
|
15
|
+
export const ensureItemIds = (items) => {
|
|
16
|
+
if (!items)
|
|
17
|
+
return;
|
|
18
|
+
for (const item of items) {
|
|
19
|
+
if (!item.id)
|
|
20
|
+
item.id = generateItemId();
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Remove items whose id appears in `ids`. Order-independent (no descending
|
|
25
|
+
* index sort needed) — the whole point of the id-based migration. Items
|
|
26
|
+
* without an id are never removed by id.
|
|
27
|
+
*/
|
|
28
|
+
export const removeItemsByIds = (items, ids) => {
|
|
29
|
+
if (!items?.length)
|
|
30
|
+
return items ?? [];
|
|
31
|
+
if (!ids?.length)
|
|
32
|
+
return items;
|
|
33
|
+
const toRemove = new Set(ids);
|
|
34
|
+
return items.filter((item) => !item.id || !toRemove.has(item.id));
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Position `item` within `items` relative to an anchor id — the item-level
|
|
38
|
+
* mirror of base-section-builder's `moveContent`:
|
|
39
|
+
*
|
|
40
|
+
* - `moveBeforeItemId === undefined` → leave an existing item where it is;
|
|
41
|
+
* append a new (not-yet-present) item to the end.
|
|
42
|
+
* - `moveBeforeItemId === "__end__"` → move/insert at the very end.
|
|
43
|
+
* - anchor id found → insert immediately before it.
|
|
44
|
+
* - anchor id not found → fall through to the end (same
|
|
45
|
+
* forgiving behaviour as `moveContent`).
|
|
46
|
+
*
|
|
47
|
+
* Mutates `items` in place. `item` may be an existing element of `items`
|
|
48
|
+
* (a move) or a brand-new object (an insert).
|
|
49
|
+
*/
|
|
50
|
+
export const repositionItemByAnchor = (items, item, moveBeforeItemId) => {
|
|
51
|
+
const currentIndex = items.indexOf(item);
|
|
52
|
+
if (moveBeforeItemId === undefined) {
|
|
53
|
+
if (currentIndex === -1)
|
|
54
|
+
items.push(item);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (currentIndex !== -1)
|
|
58
|
+
items.splice(currentIndex, 1);
|
|
59
|
+
const anchorIndex = moveBeforeItemId === END_ITEM_ANCHOR
|
|
60
|
+
? -1
|
|
61
|
+
: items.findIndex((i) => i.id === moveBeforeItemId);
|
|
62
|
+
if (anchorIndex !== -1) {
|
|
63
|
+
items.splice(anchorIndex, 0, item);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
items.push(item);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import { applyScalarFields, isValidUrl } from '../section-field-utils';
|
|
2
2
|
import { BaseSectionBuilder } from './base-section-builder';
|
|
3
3
|
import { validateImageGallery } from '../section-rules/image-gallery.rules';
|
|
4
|
+
import { ensureItemIds, generateItemId, removeItemsByIds, repositionItemByAnchor, } from '../item-id-utils';
|
|
4
5
|
const applyGalleryType = (content, galleryType) => {
|
|
5
6
|
content.galleryStyles = {
|
|
6
7
|
...(content.galleryStyles || {}),
|
|
7
8
|
galleryType: galleryType,
|
|
8
9
|
};
|
|
9
10
|
};
|
|
11
|
+
/**
|
|
12
|
+
* Full rebuild: discard existing images and map the payload directly.
|
|
13
|
+
* Used on create and when `_replace_items` is set. Each item gets a fresh id
|
|
14
|
+
* (or keeps the caller-supplied `item_id` when provided).
|
|
15
|
+
*/
|
|
10
16
|
const applyGalleryImages = (content, images) => {
|
|
11
17
|
content.images = images.map((img) => ({
|
|
18
|
+
id: img.item_id || generateItemId(),
|
|
12
19
|
imageUrl: isValidUrl(img.image_url) ? img.image_url : '',
|
|
13
20
|
imageTitle: img.caption || '',
|
|
14
21
|
width: 0,
|
|
@@ -17,59 +24,46 @@ const applyGalleryImages = (content, images) => {
|
|
|
17
24
|
imageLink: '',
|
|
18
25
|
}));
|
|
19
26
|
};
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (content.images?.some((existing) => existing.imageUrl === img.image_url))
|
|
61
|
-
continue;
|
|
62
|
-
content.images = content.images ?? [];
|
|
63
|
-
const pos = Math.max(0, Math.min(img.insert_at ?? 0, content.images.length));
|
|
64
|
-
content.images.splice(pos, 0, {
|
|
65
|
-
imageUrl: img.image_url,
|
|
66
|
-
imageTitle: img.caption ?? '',
|
|
67
|
-
width: 0,
|
|
68
|
-
height: 0,
|
|
69
|
-
mediaType: 'image',
|
|
70
|
-
imageLink: '',
|
|
71
|
-
colorReplacements: [],
|
|
72
|
-
});
|
|
27
|
+
/**
|
|
28
|
+
* Id-based merge (BP-5603), mirroring testimonial-section-builder one level
|
|
29
|
+
* deeper into `content.images`:
|
|
30
|
+
* - `item_id` matches existing item → update in place; reposition if
|
|
31
|
+
* `move_before_item_id` is set.
|
|
32
|
+
* - no `item_id` → add new item, positioned by
|
|
33
|
+
* `move_before_item_id`.
|
|
34
|
+
* - `removeIds` → delete by id (order-independent).
|
|
35
|
+
*
|
|
36
|
+
* Existing items are id-backfilled first so legacy galleries become
|
|
37
|
+
* referenceable as soon as the metadata builder touches them.
|
|
38
|
+
*/
|
|
39
|
+
const mergeGalleryImages = (content, images, removeIds) => {
|
|
40
|
+
ensureItemIds(content.images);
|
|
41
|
+
content.images = removeItemsByIds(content.images, removeIds);
|
|
42
|
+
for (const img of images) {
|
|
43
|
+
if (img.item_id) {
|
|
44
|
+
const existing = content.images.find((i) => i.id === img.item_id);
|
|
45
|
+
// Unknown id — skip rather than guess at a position.
|
|
46
|
+
if (!existing)
|
|
47
|
+
continue;
|
|
48
|
+
if (img.image_url !== undefined) {
|
|
49
|
+
existing.imageUrl = isValidUrl(img.image_url) ? img.image_url : '';
|
|
50
|
+
}
|
|
51
|
+
if (img.caption !== undefined)
|
|
52
|
+
existing.imageTitle = img.caption;
|
|
53
|
+
repositionItemByAnchor(content.images, existing, img.move_before_item_id);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
const newItem = {
|
|
57
|
+
id: generateItemId(),
|
|
58
|
+
imageUrl: isValidUrl(img.image_url) ? img.image_url : '',
|
|
59
|
+
imageTitle: img.caption ?? '',
|
|
60
|
+
width: 0,
|
|
61
|
+
height: 0,
|
|
62
|
+
mediaType: 'image',
|
|
63
|
+
imageLink: '',
|
|
64
|
+
};
|
|
65
|
+
repositionItemByAnchor(content.images, newItem, img.move_before_item_id);
|
|
66
|
+
}
|
|
73
67
|
}
|
|
74
68
|
};
|
|
75
69
|
export class ImageGalleryBuilder extends BaseSectionBuilder {
|
|
@@ -91,24 +85,19 @@ export class ImageGalleryBuilder extends BaseSectionBuilder {
|
|
|
91
85
|
if (args.gallery_type) {
|
|
92
86
|
applyGalleryType(content, args.gallery_type);
|
|
93
87
|
}
|
|
94
|
-
if (args.images && Array.isArray(args.images)) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
mergeGalleryImages(content, args.images, !!args._replace_items);
|
|
100
|
-
}
|
|
88
|
+
if (args._replace_items && args.images && Array.isArray(args.images)) {
|
|
89
|
+
// Full replacement: discard existing images and rebuild from the payload.
|
|
90
|
+
applyGalleryImages(content, args.images);
|
|
101
91
|
}
|
|
102
|
-
if (
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (idx >= 0 && idx < content.images.length) {
|
|
106
|
-
content.images.splice(idx, 1);
|
|
107
|
-
}
|
|
92
|
+
else if (this.mode === 'create') {
|
|
93
|
+
if (args.images && Array.isArray(args.images)) {
|
|
94
|
+
applyGalleryImages(content, args.images);
|
|
108
95
|
}
|
|
109
96
|
}
|
|
110
|
-
if (args.images && Array.isArray(args.images)
|
|
111
|
-
|
|
97
|
+
else if ((args.images && Array.isArray(args.images)) ||
|
|
98
|
+
args._remove_item_ids?.length) {
|
|
99
|
+
// Update: id-based add / edit / move / remove in a single pass.
|
|
100
|
+
mergeGalleryImages(content, args.images ?? [], args._remove_item_ids);
|
|
112
101
|
}
|
|
113
102
|
return { request: this.request, model };
|
|
114
103
|
}
|
|
@@ -3,8 +3,15 @@ import { isTiptapDocument, } from '../../parsers/section-tool-arguments';
|
|
|
3
3
|
import { applyScalarFields, applyStyleFields, isValidUrl, resolveGlobalPresetIntoStyle, } from '../section-field-utils';
|
|
4
4
|
import { BaseSectionBuilder } from './base-section-builder';
|
|
5
5
|
import { validateImagesSection } from '../section-rules/images-section.rules';
|
|
6
|
+
import { ensureItemIds, generateItemId, removeItemsByIds, repositionItemByAnchor, } from '../item-id-utils';
|
|
7
|
+
/**
|
|
8
|
+
* Full replacement: discard existing items and rebuild from the payload.
|
|
9
|
+
* Assigns a stable `id` to each item; `itemsId` is set positionally here
|
|
10
|
+
* but will be re-indexed at the end of buildAsync.
|
|
11
|
+
*/
|
|
6
12
|
const applyImageItems = (content, items) => {
|
|
7
13
|
content.items = items.map((item, index) => ({
|
|
14
|
+
id: item.item_id || generateItemId(),
|
|
8
15
|
imageUrl: isValidUrl(item.image_url) ? item.image_url : '',
|
|
9
16
|
imageTitle: '',
|
|
10
17
|
width: 0,
|
|
@@ -18,16 +25,28 @@ const applyImageItems = (content, items) => {
|
|
|
18
25
|
colorReplacements: [],
|
|
19
26
|
}));
|
|
20
27
|
};
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Apply a batch of item operations by id (BP-5603), mirroring the
|
|
30
|
+
* section-level id-based contract one level deeper:
|
|
31
|
+
* - item with `item_id` matching an existing item → update in place (and
|
|
32
|
+
* reposition if `move_before_item_id` is set);
|
|
33
|
+
* - item without `item_id` → add a new item,
|
|
34
|
+
* positioned by `move_before_item_id`;
|
|
35
|
+
* - `_remove_item_ids` → delete by id.
|
|
36
|
+
*
|
|
37
|
+
* Existing items are id-backfilled first so legacy sections become
|
|
38
|
+
* referenceable the moment the metadata builder touches them.
|
|
39
|
+
* Order-independent: there are no positional indices to shift between ops.
|
|
40
|
+
*/
|
|
41
|
+
const mergeImageItems = (content, items, removeIds) => {
|
|
42
|
+
ensureItemIds(content.items);
|
|
43
|
+
content.items = removeItemsByIds(content.items, removeIds);
|
|
44
|
+
for (const item of items) {
|
|
45
|
+
if (item.item_id) {
|
|
46
|
+
const existing = content.items.find((i) => i.id === item.item_id);
|
|
47
|
+
// Unknown id — skip rather than guess at a position.
|
|
48
|
+
if (!existing)
|
|
29
49
|
continue;
|
|
30
|
-
const existing = content.items[targetIndex];
|
|
31
50
|
if (isValidUrl(item.image_url))
|
|
32
51
|
existing.imageUrl = item.image_url;
|
|
33
52
|
if (item.heading !== undefined)
|
|
@@ -36,36 +55,26 @@ const mergeImageItems = (content, items, replaceAll) => {
|
|
|
36
55
|
existing.paragraph = item.text;
|
|
37
56
|
if (item.button_text !== undefined)
|
|
38
57
|
existing.buttonText = item.button_text || false;
|
|
58
|
+
repositionItemByAnchor(content.items, existing, item.move_before_item_id);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
const newItem = {
|
|
62
|
+
id: generateItemId(),
|
|
63
|
+
imageUrl: isValidUrl(item.image_url) ? item.image_url : '',
|
|
64
|
+
imageTitle: '',
|
|
65
|
+
width: 0,
|
|
66
|
+
height: 0,
|
|
67
|
+
mediaType: 'image',
|
|
68
|
+
imageLink: '',
|
|
69
|
+
title: item.heading ?? '',
|
|
70
|
+
paragraph: item.text ?? '',
|
|
71
|
+
buttonText: item.button_text || false,
|
|
72
|
+
itemsId: 0, // re-indexed at the end of buildAsync
|
|
73
|
+
colorReplacements: [],
|
|
74
|
+
};
|
|
75
|
+
repositionItemByAnchor(content.items, newItem, item.move_before_item_id);
|
|
39
76
|
}
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
const itemsToMerge = items.filter((item) => item.insert_at === undefined);
|
|
43
|
-
const updatedItems = itemsToMerge.map((item, index) => {
|
|
44
|
-
const existing = content.items?.[index];
|
|
45
|
-
return {
|
|
46
|
-
...(existing || {}),
|
|
47
|
-
imageUrl: isValidUrl(item.image_url)
|
|
48
|
-
? item.image_url
|
|
49
|
-
: (existing?.imageUrl ?? ''),
|
|
50
|
-
imageTitle: existing?.imageTitle ?? '',
|
|
51
|
-
width: existing?.width ?? 0,
|
|
52
|
-
height: existing?.height ?? 0,
|
|
53
|
-
mediaType: existing?.mediaType ?? 'image',
|
|
54
|
-
imageLink: existing?.imageLink ?? '',
|
|
55
|
-
title: item.heading ?? existing?.title ?? '',
|
|
56
|
-
paragraph: item.text ?? existing?.paragraph ?? '',
|
|
57
|
-
buttonText: item.button_text ?? existing?.buttonText ?? '',
|
|
58
|
-
itemsId: existing?.itemsId ?? index,
|
|
59
|
-
colorReplacements: existing?.colorReplacements ?? [],
|
|
60
|
-
};
|
|
61
|
-
});
|
|
62
|
-
if (!replaceAll &&
|
|
63
|
-
content.items &&
|
|
64
|
-
content.items.length > itemsToMerge.length) {
|
|
65
|
-
const remaining = content.items.slice(itemsToMerge.length);
|
|
66
|
-
updatedItems.push(...remaining);
|
|
67
77
|
}
|
|
68
|
-
content.items = updatedItems;
|
|
69
78
|
};
|
|
70
79
|
export class ImagesSectionBuilder extends BaseSectionBuilder {
|
|
71
80
|
get sectionValidate() {
|
|
@@ -123,66 +132,22 @@ export class ImagesSectionBuilder extends BaseSectionBuilder {
|
|
|
123
132
|
])),
|
|
124
133
|
};
|
|
125
134
|
}
|
|
126
|
-
if (args.items && Array.isArray(args.items)) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
else {
|
|
131
|
-
mergeImageItems(content, args.items, !!args._replace_items);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
// Phase 2: Item operations (remove, insert, reorder)
|
|
135
|
-
if (args._remove_item_indices?.length && content.items) {
|
|
136
|
-
const sorted = [...args._remove_item_indices].sort((a, b) => b - a);
|
|
137
|
-
for (const idx of sorted) {
|
|
138
|
-
if (idx >= 0 && idx < content.items.length) {
|
|
139
|
-
content.items.splice(idx, 1);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
135
|
+
if (args._replace_items && args.items && Array.isArray(args.items)) {
|
|
136
|
+
// Full replacement: discard existing items and rebuild from the payload.
|
|
137
|
+
applyImageItems(content, args.items);
|
|
142
138
|
}
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const sortedInserts = [...insertItems].sort((a, b) => (b.insert_at ?? 0) - (a.insert_at ?? 0));
|
|
147
|
-
for (const item of sortedInserts) {
|
|
148
|
-
if (!isValidUrl(item.image_url))
|
|
149
|
-
continue;
|
|
150
|
-
// Skip if this image_url already exists — defensive against duplicate
|
|
151
|
-
// tool call application
|
|
152
|
-
if (content.items?.some((existing) => existing.imageUrl === item.image_url)) {
|
|
153
|
-
continue;
|
|
154
|
-
}
|
|
155
|
-
const pos = Math.max(0, Math.min(item.insert_at ?? 0, content.items?.length ?? 0));
|
|
156
|
-
const newItem = {
|
|
157
|
-
imageUrl: item.image_url,
|
|
158
|
-
imageTitle: '',
|
|
159
|
-
width: 0,
|
|
160
|
-
height: 0,
|
|
161
|
-
mediaType: 'image',
|
|
162
|
-
imageLink: '',
|
|
163
|
-
title: item.heading ?? '',
|
|
164
|
-
paragraph: item.text ?? '',
|
|
165
|
-
buttonText: item.button_text || '',
|
|
166
|
-
itemsId: pos,
|
|
167
|
-
colorReplacements: [],
|
|
168
|
-
};
|
|
169
|
-
content.items = content.items ?? [];
|
|
170
|
-
content.items.splice(pos, 0, newItem);
|
|
139
|
+
else if (this.mode === 'create') {
|
|
140
|
+
if (args.items && Array.isArray(args.items)) {
|
|
141
|
+
applyImageItems(content, args.items);
|
|
171
142
|
}
|
|
172
143
|
}
|
|
173
|
-
if (args.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const reordered = newOrder
|
|
178
|
-
.filter((idx) => idx >= 0 && idx < content.items.length)
|
|
179
|
-
.map((idx) => content.items[idx]);
|
|
180
|
-
if (reordered.length === content.items.length) {
|
|
181
|
-
content.items = reordered;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
144
|
+
else if ((args.items && Array.isArray(args.items)) ||
|
|
145
|
+
args._remove_item_ids?.length) {
|
|
146
|
+
// Update: id-based add / edit / move / remove in a single pass.
|
|
147
|
+
mergeImageItems(content, args.items ?? [], args._remove_item_ids);
|
|
184
148
|
}
|
|
185
|
-
// Re-index itemsId after
|
|
149
|
+
// Re-index itemsId after all id-based item operations (render concern —
|
|
150
|
+
// separate from the stable `id` used for targeting).
|
|
186
151
|
if (content.items) {
|
|
187
152
|
content.items.forEach((item, i) => {
|
|
188
153
|
item.itemsId = i;
|