@designcrowd/library.brand-page 6.0.3 → 6.0.4
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-BctSP4tp.js → CreatedOnBrandCrowd-de-de-Ruu5Az32.js} +3 -3
- package/lib/src/{CreatedOnBrandCrowd-en-us-BeNytcxt.js → CreatedOnBrandCrowd-en-us-DGUJtvld.js} +3 -3
- package/lib/src/{CreatedOnBrandCrowd-es-es-hY12f5TN.js → CreatedOnBrandCrowd-es-es-Dg-1uOfV.js} +3 -3
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-C4SCU39P.js → CreatedOnBrandCrowd-fr-ca-CRKraZl8.js} +3 -3
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-C4SCU39P.js → CreatedOnBrandCrowd-fr-fr-CRKraZl8.js} +3 -3
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-C5J5kWiD.js → CreatedOnBrandCrowd-pt-br-bZ9VlEAu.js} +3 -3
- package/lib/src/{CreatedOnBrandCrowd-pt-br-C5J5kWiD.js → CreatedOnBrandCrowd-pt-pt-bZ9VlEAu.js} +3 -3
- package/lib/src/{CreatedOnDcom-de-de-DXCeZZLg.js → CreatedOnDcom-de-de-CJYfwZx8.js} +3 -3
- package/lib/src/{CreatedOnDcom-en-us-GeBTaofv.js → CreatedOnDcom-en-us-rzA1lVxH.js} +3 -3
- package/lib/src/{CreatedOnDcom-es-es-BiPmv1q-.js → CreatedOnDcom-es-es-CNwGPjik.js} +3 -3
- package/lib/src/{CreatedOnDcom-fr-ca-Cns_iX4-.js → CreatedOnDcom-fr-ca-DKw7OGIz.js} +3 -3
- package/lib/src/{CreatedOnDcom-fr-fr-CC-f_hUR.js → CreatedOnDcom-fr-fr-WzOEaAZG.js} +3 -3
- package/lib/src/{CreatedOnDcom-pt-br-DnhSuPKo.js → CreatedOnDcom-pt-br-DkualVhm.js} +3 -3
- package/lib/src/{CreatedOnDcom-pt-pt-BCgbUsqY.js → CreatedOnDcom-pt-pt-w4Nnsdzq.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-background-settings/ShapePositionSlider.mixin.d.ts +1 -1
- 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 +6 -3
- 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 +3 -3
- 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/ai-assistant-client.d.ts +0 -7
- 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 -5
- package/lib/src/index.mjs +106 -110
- package/lib/src/{lib-Cw6L6CfQ.js → lib-Dy7MYyqz.js} +33240 -36457
- package/lib/src/lib.js +1 -11
- package/lib/src/metadata-builder/builders/footer-builder.js +62 -105
- package/lib/src/metadata-builder/builders/item-id-utils.d.ts +54 -0
- package/lib/src/metadata-builder/builders/item-id-utils.js +96 -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/section-field-utils.d.ts +0 -7
- package/lib/src/metadata-builder/builders/section-field-utils.js +1 -1
- package/lib/src/metadata-builder/builders/shape-color-utils.js +1 -1
- package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +16 -7
- 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/lib/src/utils/build-asset-manifest.d.ts +0 -4
- package/lib/src/utils/build-asset-manifest.js +0 -8
- package/lib/src/utils/minify-brand-page-metadata.d.ts +2 -0
- package/lib/src/utils/minify-brand-page-metadata.js +17 -2
- package/package.json +56 -60
- 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 +7 -3
- package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +6 -6
- package/src/brand-page-maker/constants/config-settings-constant.ts +5 -5
- 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/ai-assistant-client.ts +0 -7
- 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 -13
- package/src/metadata-builder/builders/footer-builder.test.ts +229 -130
- package/src/metadata-builder/builders/footer-builder.ts +90 -155
- package/src/metadata-builder/builders/item-id-utils.test.ts +184 -0
- package/src/metadata-builder/builders/item-id-utils.ts +117 -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/section-field-utils.ts +1 -1
- package/src/metadata-builder/builders/shape-color-utils.ts +2 -2
- package/src/metadata-builder/parsers/ai-toolcall-parser.ts +16 -7
- 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/src/utils/build-asset-manifest.ts +0 -12
- package/src/utils/minify-brand-page-metadata.ts +27 -7
- 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
|
@@ -10,22 +10,17 @@ import {
|
|
|
10
10
|
import type {
|
|
11
11
|
UpdateFooterArguments,
|
|
12
12
|
ViewportFooterOverrides,
|
|
13
|
-
FooterSocialLinkItem,
|
|
14
13
|
} from '../parsers/ai-toolcall-parser';
|
|
15
14
|
import type { Logger } from '../logger';
|
|
16
|
-
import type {
|
|
17
|
-
TextStyleDeclaration,
|
|
18
|
-
TextStyleOptions,
|
|
19
|
-
} from '../../brand-page/models/styles.model';
|
|
15
|
+
import type { TextStyleOptions } from '../../brand-page/models/styles.model';
|
|
20
16
|
import { FOOTER_CHECKS } from './section-rules/footer.rules';
|
|
17
|
+
import { applyDetachedStyleOverride } from './section-field-utils';
|
|
21
18
|
import {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
AbstractPageFooterStyles['socialLinks']
|
|
28
|
-
>[number];
|
|
19
|
+
ensureItemIds,
|
|
20
|
+
generateItemId,
|
|
21
|
+
removeItemsByIds,
|
|
22
|
+
repositionItemByAnchor,
|
|
23
|
+
} from './item-id-utils';
|
|
29
24
|
|
|
30
25
|
const normaliseSocialUrl = (url: string): string => {
|
|
31
26
|
for (const prefix of ['mailto:', 'tel:']) {
|
|
@@ -35,113 +30,6 @@ const normaliseSocialUrl = (url: string): string => {
|
|
|
35
30
|
return url;
|
|
36
31
|
};
|
|
37
32
|
|
|
38
|
-
const makeSocialLink = (
|
|
39
|
-
icon: string | undefined,
|
|
40
|
-
url: string | undefined,
|
|
41
|
-
): FooterSocialLink =>
|
|
42
|
-
({
|
|
43
|
-
imageUrl: icon || '',
|
|
44
|
-
url: normaliseSocialUrl(url || ''),
|
|
45
|
-
imageTitle: '',
|
|
46
|
-
width: 0,
|
|
47
|
-
height: 0,
|
|
48
|
-
imageLink: '',
|
|
49
|
-
}) as FooterSocialLink;
|
|
50
|
-
|
|
51
|
-
const hasSocialLinkMutation = (args: UpdateFooterArguments): boolean =>
|
|
52
|
-
args._replace_social_links === true ||
|
|
53
|
-
(args._remove_social_link_indices?.length ?? 0) > 0 ||
|
|
54
|
-
(args._reorder_social_links?.length ?? 0) > 0 ||
|
|
55
|
-
(args.social_links?.length ?? 0) > 0;
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Social links are a GLOBAL footer concern — one logical list that both
|
|
59
|
-
* viewports render identically. Derive the new list ONCE from the current one
|
|
60
|
-
* WITHOUT mutating the input, so the caller can assign an independent copy to
|
|
61
|
-
* each viewport.
|
|
62
|
-
*
|
|
63
|
-
* Why this can't mutate per-viewport in place: footers migrated from the legacy
|
|
64
|
-
* single `footerStyles` model (migration-01) share ONE `socialLinks` array
|
|
65
|
-
* reference across pageFooterDesktop and pageFooterMobile, and `cloneDeep`
|
|
66
|
-
* preserves that shared reference. Running an in-place `splice` once per
|
|
67
|
-
* viewport therefore applies it TWICE to the same array — e.g. one requested
|
|
68
|
-
* removal index drops two links. Compute-once + assign-fresh is correct for
|
|
69
|
-
* both shared (legacy) and independent (new-model) footers.
|
|
70
|
-
*/
|
|
71
|
-
const computeSocialLinks = (
|
|
72
|
-
current: FooterSocialLink[] | undefined,
|
|
73
|
-
args: UpdateFooterArguments,
|
|
74
|
-
): FooterSocialLink[] => {
|
|
75
|
-
// _replace_social_links: replace entire list (empty/absent social_links = clear all).
|
|
76
|
-
// A replacement supersedes every other social link mutation.
|
|
77
|
-
if (args._replace_social_links) {
|
|
78
|
-
return (args.social_links ?? []).map((l) =>
|
|
79
|
-
makeSocialLink(l.social_link_icon, l.url),
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const links: FooterSocialLink[] = [...(current ?? [])];
|
|
84
|
-
|
|
85
|
-
// item_index-based updates for existing links — replace the item reference
|
|
86
|
-
// (never mutate the original object, which may be shared across viewports).
|
|
87
|
-
for (const link of args.social_links ?? []) {
|
|
88
|
-
if (link.item_index === undefined) continue;
|
|
89
|
-
|
|
90
|
-
const existing = links[link.item_index];
|
|
91
|
-
|
|
92
|
-
if (!existing) continue;
|
|
93
|
-
|
|
94
|
-
links[link.item_index] = {
|
|
95
|
-
...existing,
|
|
96
|
-
...(link.social_link_icon !== undefined
|
|
97
|
-
? { imageUrl: link.social_link_icon }
|
|
98
|
-
: {}),
|
|
99
|
-
...(link.url !== undefined ? { url: normaliseSocialUrl(link.url) } : {}),
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Remove by index (descending order to preserve indices during splice).
|
|
104
|
-
if (args._remove_social_link_indices?.length) {
|
|
105
|
-
const sorted = [...args._remove_social_link_indices].sort((a, b) => b - a);
|
|
106
|
-
|
|
107
|
-
for (const idx of sorted) {
|
|
108
|
-
if (idx >= 0 && idx < links.length) links.splice(idx, 1);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Insert new links (descending insert_at order to preserve positions).
|
|
113
|
-
const insertLinks = (args.social_links ?? []).filter(
|
|
114
|
-
(l): l is FooterSocialLinkItem & { insert_at: number } =>
|
|
115
|
-
l.insert_at !== undefined && l.item_index === undefined,
|
|
116
|
-
);
|
|
117
|
-
const sortedInserts = [...insertLinks].sort(
|
|
118
|
-
(a, b) => b.insert_at - a.insert_at,
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
for (const link of sortedInserts) {
|
|
122
|
-
const pos = Math.max(0, Math.min(link.insert_at, links.length));
|
|
123
|
-
|
|
124
|
-
links.splice(pos, 0, makeSocialLink(link.social_link_icon, link.url));
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Reorder (requires ALL indices — partial reorder is not supported).
|
|
128
|
-
if (args._reorder_social_links?.length) {
|
|
129
|
-
const newOrder = args._reorder_social_links;
|
|
130
|
-
const unique = new Set(newOrder);
|
|
131
|
-
|
|
132
|
-
if (
|
|
133
|
-
unique.size === newOrder.length &&
|
|
134
|
-
newOrder.every((idx) => idx >= 0 && idx < links.length)
|
|
135
|
-
) {
|
|
136
|
-
const reordered = newOrder.map((idx) => links[idx]);
|
|
137
|
-
|
|
138
|
-
if (reordered.length === links.length) return reordered;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return links;
|
|
143
|
-
};
|
|
144
|
-
|
|
145
33
|
const applyGlobalFooterChanges = (
|
|
146
34
|
footer: AbstractPageFooterStyles,
|
|
147
35
|
args: UpdateFooterArguments,
|
|
@@ -150,27 +38,85 @@ const applyGlobalFooterChanges = (
|
|
|
150
38
|
if (args.copyright_text !== undefined)
|
|
151
39
|
footer.copyrightText = args.copyright_text;
|
|
152
40
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const updates: Partial<TextStyleDeclaration> = {};
|
|
41
|
+
if (args.copyright_text_font_family !== undefined)
|
|
42
|
+
footer.copyrightStyle = applyDetachedStyleOverride(
|
|
43
|
+
footer.copyrightStyle,
|
|
44
|
+
{ fontFamily: args.copyright_text_font_family },
|
|
45
|
+
textStyleOptions,
|
|
46
|
+
);
|
|
160
47
|
|
|
161
|
-
|
|
162
|
-
const normalized = normalizeStyleValue(key, value);
|
|
48
|
+
const links = args.social_links;
|
|
163
49
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
50
|
+
// _replace_social_links: replace entire list (empty/absent social_links = clear all).
|
|
51
|
+
// When replacing, all other social link mutations (remove, insert, reorder) are skipped —
|
|
52
|
+
// they are superseded by the replacement and running them would cause duplicates.
|
|
53
|
+
if (args._replace_social_links) {
|
|
54
|
+
footer.socialLinks = (links ?? []).map((l) => ({
|
|
55
|
+
id: generateItemId(),
|
|
56
|
+
imageUrl: l.social_link_icon || '',
|
|
57
|
+
url: normaliseSocialUrl(l.url || ''),
|
|
58
|
+
imageTitle: '',
|
|
59
|
+
width: 0,
|
|
60
|
+
height: 0,
|
|
61
|
+
imageLink: '',
|
|
62
|
+
}));
|
|
63
|
+
} else {
|
|
64
|
+
// Targeted mutations — only run when NOT replacing the entire list.
|
|
65
|
+
// BP-5603: id-based contract (item_id / move_before_item_id / _remove_social_link_ids).
|
|
66
|
+
// Backfill ids on legacy links so they become referenceable after this call.
|
|
67
|
+
ensureItemIds(footer.socialLinks);
|
|
68
|
+
|
|
69
|
+
// Remove by id (order-independent — no index shifting needed).
|
|
70
|
+
footer.socialLinks = removeItemsByIds(
|
|
71
|
+
footer.socialLinks,
|
|
72
|
+
args._remove_social_link_ids,
|
|
73
|
+
);
|
|
167
74
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
75
|
+
// Update existing links (item_id present) or insert new links (no item_id).
|
|
76
|
+
if (links?.length) {
|
|
77
|
+
footer.socialLinks = footer.socialLinks ?? [];
|
|
78
|
+
|
|
79
|
+
for (const link of links) {
|
|
80
|
+
if (link.item_id) {
|
|
81
|
+
// Update existing link in place; reposition if move_before_item_id set.
|
|
82
|
+
const existing = footer.socialLinks.find(
|
|
83
|
+
(l) => l.id === link.item_id,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
// Unknown id — skip rather than guess at a position.
|
|
87
|
+
if (!existing) continue;
|
|
88
|
+
|
|
89
|
+
if (link.social_link_icon !== undefined)
|
|
90
|
+
existing.imageUrl = link.social_link_icon;
|
|
91
|
+
|
|
92
|
+
if (link.url !== undefined)
|
|
93
|
+
existing.url = normaliseSocialUrl(link.url);
|
|
94
|
+
|
|
95
|
+
repositionItemByAnchor(
|
|
96
|
+
footer.socialLinks,
|
|
97
|
+
existing,
|
|
98
|
+
link.move_before_item_id,
|
|
99
|
+
);
|
|
100
|
+
} else {
|
|
101
|
+
// New link — assign a stable id and position via move_before_item_id.
|
|
102
|
+
const newLink = {
|
|
103
|
+
id: generateItemId(),
|
|
104
|
+
imageUrl: link.social_link_icon || '',
|
|
105
|
+
url: normaliseSocialUrl(link.url || ''),
|
|
106
|
+
imageTitle: '',
|
|
107
|
+
width: 0,
|
|
108
|
+
height: 0,
|
|
109
|
+
imageLink: '' as string | false,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
repositionItemByAnchor(
|
|
113
|
+
footer.socialLinks,
|
|
114
|
+
newLink,
|
|
115
|
+
link.move_before_item_id,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
174
120
|
}
|
|
175
121
|
};
|
|
176
122
|
|
|
@@ -195,6 +141,12 @@ const applyViewportFooterChanges = (
|
|
|
195
141
|
fill: overrides.icon_color,
|
|
196
142
|
};
|
|
197
143
|
|
|
144
|
+
if (overrides.copyright_text_color !== undefined)
|
|
145
|
+
footer.copyrightStyle = {
|
|
146
|
+
...footer.copyrightStyle,
|
|
147
|
+
color: overrides.copyright_text_color,
|
|
148
|
+
};
|
|
149
|
+
|
|
198
150
|
if (overrides.is_logo_visible !== undefined)
|
|
199
151
|
footer.isLogoVisible = overrides.is_logo_visible;
|
|
200
152
|
|
|
@@ -246,30 +198,13 @@ export class FooterBuilder extends BaseMetadataBuilder<UpdateFooterArguments> {
|
|
|
246
198
|
const args = this.request.payload ?? {};
|
|
247
199
|
const textStyleOptions = model.styles?.textStyles?.textStyleOptions;
|
|
248
200
|
|
|
249
|
-
// Global
|
|
250
|
-
// viewports. These are idempotent assignments, safe to run per-viewport.
|
|
201
|
+
// Global fields (copyright_text, social links) always apply to both viewports.
|
|
251
202
|
if (model.pageFooterDesktop)
|
|
252
203
|
applyGlobalFooterChanges(model.pageFooterDesktop, args, textStyleOptions);
|
|
253
204
|
|
|
254
205
|
if (model.pageFooterMobile)
|
|
255
206
|
applyGlobalFooterChanges(model.pageFooterMobile, args, textStyleOptions);
|
|
256
207
|
|
|
257
|
-
// Social links are a single global list. Derive the new list ONCE, then
|
|
258
|
-
// assign an INDEPENDENT copy to each viewport — never mutate a (possibly
|
|
259
|
-
// shared) viewport array in place. See computeSocialLinks.
|
|
260
|
-
if (hasSocialLinkMutation(args)) {
|
|
261
|
-
const current =
|
|
262
|
-
model.pageFooterDesktop?.socialLinks ??
|
|
263
|
-
model.pageFooterMobile?.socialLinks;
|
|
264
|
-
const updated = computeSocialLinks(current, args);
|
|
265
|
-
|
|
266
|
-
if (model.pageFooterDesktop)
|
|
267
|
-
model.pageFooterDesktop.socialLinks = updated.map((l) => ({ ...l }));
|
|
268
|
-
|
|
269
|
-
if (model.pageFooterMobile)
|
|
270
|
-
model.pageFooterMobile.socialLinks = updated.map((l) => ({ ...l }));
|
|
271
|
-
}
|
|
272
|
-
|
|
273
208
|
// Viewport-specific styling via explicit sub-objects.
|
|
274
209
|
if (args.desktop && model.pageFooterDesktop)
|
|
275
210
|
applyViewportFooterChanges(model.pageFooterDesktop, args.desktop);
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
END_ITEM_ANCHOR,
|
|
4
|
+
ensureBrandPageItemIds,
|
|
5
|
+
ensureItemIds,
|
|
6
|
+
generateItemId,
|
|
7
|
+
removeItemsByIds,
|
|
8
|
+
repositionItemByAnchor,
|
|
9
|
+
} from './item-id-utils';
|
|
10
|
+
import type { BrandPageModel } from '../../brand-page/models';
|
|
11
|
+
|
|
12
|
+
type Item = { id?: string; label: string };
|
|
13
|
+
|
|
14
|
+
const UUID_RE =
|
|
15
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
16
|
+
|
|
17
|
+
const items = (...labels: string[]): Item[] =>
|
|
18
|
+
labels.map((label) => ({ id: label, label }));
|
|
19
|
+
|
|
20
|
+
const labels = (list: Item[]): string[] => list.map((i) => i.label);
|
|
21
|
+
|
|
22
|
+
describe('generateItemId', () => {
|
|
23
|
+
it('returns unique uuid-shaped ids', () => {
|
|
24
|
+
const a = generateItemId();
|
|
25
|
+
const b = generateItemId();
|
|
26
|
+
|
|
27
|
+
expect(a).not.toBe(b);
|
|
28
|
+
expect(a).toMatch(
|
|
29
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('ensureItemIds', () => {
|
|
35
|
+
it('backfills only the items missing an id, preserving existing ones', () => {
|
|
36
|
+
const list: Item[] = [
|
|
37
|
+
{ id: 'keep', label: 'a' },
|
|
38
|
+
{ label: 'b' },
|
|
39
|
+
{ id: '', label: 'c' },
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
ensureItemIds(list);
|
|
43
|
+
|
|
44
|
+
expect(list[0].id).toBe('keep');
|
|
45
|
+
expect(list[1].id).toBeTruthy();
|
|
46
|
+
expect(list[2].id).toBeTruthy();
|
|
47
|
+
expect(new Set(list.map((i) => i.id)).size).toBe(3);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('is a no-op for undefined', () => {
|
|
51
|
+
expect(() => ensureItemIds(undefined)).not.toThrow();
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('removeItemsByIds', () => {
|
|
56
|
+
it('removes by id regardless of order (no index shifting)', () => {
|
|
57
|
+
const result = removeItemsByIds(items('a', 'b', 'c', 'd'), ['c', 'a']);
|
|
58
|
+
|
|
59
|
+
expect(labels(result)).toEqual(['b', 'd']);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('returns the list unchanged when no ids given', () => {
|
|
63
|
+
const list = items('a', 'b');
|
|
64
|
+
|
|
65
|
+
expect(removeItemsByIds(list, undefined)).toBe(list);
|
|
66
|
+
expect(removeItemsByIds(list, [])).toBe(list);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('returns [] for undefined items', () => {
|
|
70
|
+
expect(removeItemsByIds(undefined, ['x'])).toEqual([]);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('repositionItemByAnchor', () => {
|
|
75
|
+
it('appends a new item when no anchor is given', () => {
|
|
76
|
+
const list = items('a', 'b');
|
|
77
|
+
|
|
78
|
+
repositionItemByAnchor(list, { id: 'new', label: 'new' }, undefined);
|
|
79
|
+
|
|
80
|
+
expect(labels(list)).toEqual(['a', 'b', 'new']);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('leaves an existing item in place when no anchor is given', () => {
|
|
84
|
+
const list = items('a', 'b', 'c');
|
|
85
|
+
|
|
86
|
+
repositionItemByAnchor(list, list[1], undefined);
|
|
87
|
+
|
|
88
|
+
expect(labels(list)).toEqual(['a', 'b', 'c']);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('inserts a new item before the anchor id', () => {
|
|
92
|
+
const list = items('a', 'b', 'c');
|
|
93
|
+
|
|
94
|
+
repositionItemByAnchor(list, { id: 'new', label: 'new' }, 'b');
|
|
95
|
+
|
|
96
|
+
expect(labels(list)).toEqual(['a', 'new', 'b', 'c']);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('moves an existing item before the anchor id', () => {
|
|
100
|
+
const list = items('a', 'b', 'c', 'd');
|
|
101
|
+
|
|
102
|
+
// move 'd' before 'b'
|
|
103
|
+
repositionItemByAnchor(list, list[3], 'b');
|
|
104
|
+
|
|
105
|
+
expect(labels(list)).toEqual(['a', 'd', 'b', 'c']);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('moves an existing item to the end with the __end__ sentinel', () => {
|
|
109
|
+
const list = items('a', 'b', 'c');
|
|
110
|
+
|
|
111
|
+
repositionItemByAnchor(list, list[0], END_ITEM_ANCHOR);
|
|
112
|
+
|
|
113
|
+
expect(labels(list)).toEqual(['b', 'c', 'a']);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('falls through to the end when the anchor id is not found', () => {
|
|
117
|
+
const list = items('a', 'b');
|
|
118
|
+
|
|
119
|
+
repositionItemByAnchor(list, { id: 'new', label: 'new' }, 'missing');
|
|
120
|
+
|
|
121
|
+
expect(labels(list)).toEqual(['a', 'b', 'new']);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
describe('ensureBrandPageItemIds', () => {
|
|
126
|
+
const makeModel = (): BrandPageModel =>
|
|
127
|
+
({
|
|
128
|
+
pages: [
|
|
129
|
+
{
|
|
130
|
+
contents: [
|
|
131
|
+
{
|
|
132
|
+
type: 'image-gallery',
|
|
133
|
+
images: [{ imageUrl: 'a' }, { imageUrl: 'b' }],
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
type: 'testimonial-section',
|
|
137
|
+
items: [{ id: 'keep-me', name: 'X' }, { name: 'Y' }],
|
|
138
|
+
},
|
|
139
|
+
{ type: 'text', textItems: [{ text: 'hi' }] },
|
|
140
|
+
{ type: 'social-links', links: [{ url: 'u' }] },
|
|
141
|
+
{ type: 'divider-section' }, // no item arrays — must not throw
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
pageFooterDesktop: { socialLinks: [{ url: 'f' }] },
|
|
146
|
+
pageFooterMobile: { socialLinks: [{ url: 'm' }] },
|
|
147
|
+
}) as unknown as BrandPageModel;
|
|
148
|
+
|
|
149
|
+
it('stamps a uuid id onto every id-less nested item across sections + footer', () => {
|
|
150
|
+
const model = makeModel();
|
|
151
|
+
|
|
152
|
+
ensureBrandPageItemIds(model);
|
|
153
|
+
|
|
154
|
+
const c = model.pages[0].contents as any[];
|
|
155
|
+
|
|
156
|
+
expect(c[0].images[0].id).toMatch(UUID_RE);
|
|
157
|
+
expect(c[0].images[1].id).toMatch(UUID_RE);
|
|
158
|
+
expect(c[1].items[1].id).toMatch(UUID_RE);
|
|
159
|
+
expect(c[2].textItems[0].id).toMatch(UUID_RE);
|
|
160
|
+
expect(c[3].links[0].id).toMatch(UUID_RE);
|
|
161
|
+
expect((model.pageFooterDesktop as any).socialLinks[0].id).toMatch(UUID_RE);
|
|
162
|
+
expect((model.pageFooterMobile as any).socialLinks[0].id).toMatch(UUID_RE);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('preserves existing ids (idempotent)', () => {
|
|
166
|
+
const model = makeModel();
|
|
167
|
+
|
|
168
|
+
ensureBrandPageItemIds(model);
|
|
169
|
+
const first = (model.pages[0].contents as any[])[1].items[0].id;
|
|
170
|
+
|
|
171
|
+
ensureBrandPageItemIds(model);
|
|
172
|
+
const second = (model.pages[0].contents as any[])[1].items[0].id;
|
|
173
|
+
|
|
174
|
+
expect(first).toBe('keep-me');
|
|
175
|
+
expect(second).toBe('keep-me');
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('does not throw on an empty / partial model', () => {
|
|
179
|
+
expect(() => ensureBrandPageItemIds({} as BrandPageModel)).not.toThrow();
|
|
180
|
+
expect(() =>
|
|
181
|
+
ensureBrandPageItemIds({ pages: [] } as unknown as BrandPageModel),
|
|
182
|
+
).not.toThrow();
|
|
183
|
+
});
|
|
184
|
+
});
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
2
|
+
import type { BrandPageModel } from '../../brand-page/models';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Sentinel anchor meaning "the end of the list", mirroring the section-level
|
|
6
|
+
* `move_before_content_id: "__end__"` convention used in base-section-builder.
|
|
7
|
+
*/
|
|
8
|
+
export const END_ITEM_ANCHOR = '__end__';
|
|
9
|
+
|
|
10
|
+
/** Generate a stable item id. Mirrors section-level `uuid.v4()` id generation. */
|
|
11
|
+
export const generateItemId = (): string => uuidv4();
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Walk an entire BrandPageModel and backfill a stable uuid `id` onto every
|
|
15
|
+
* nested array item that lacks one (gallery images, images/shapes/testimonial
|
|
16
|
+
* items, text items, social links, and footer social links).
|
|
17
|
+
*
|
|
18
|
+
* BP-5603: this must run BEFORE the model is minified for the AI, so the same
|
|
19
|
+
* id the AI is shown (and copies into `item_id`) is the one the executor later
|
|
20
|
+
* matches. The maker holds a single live model instance for both the minify
|
|
21
|
+
* and the apply step, so mutating it here makes the ids round-trip; they then
|
|
22
|
+
* persist on the next save. Idempotent — existing ids are preserved.
|
|
23
|
+
*/
|
|
24
|
+
export const ensureBrandPageItemIds = (model: BrandPageModel): void => {
|
|
25
|
+
const ensureContentItemIds = (content: Record<string, unknown>): void => {
|
|
26
|
+
// Every array field that the minifier surfaces as a list of items.
|
|
27
|
+
for (const field of ['images', 'items', 'textItems', 'links'] as const) {
|
|
28
|
+
const arr = content[field];
|
|
29
|
+
|
|
30
|
+
if (Array.isArray(arr)) ensureItemIds(arr as { id?: string }[]);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
for (const page of model.pages ?? []) {
|
|
35
|
+
for (const content of page.contents ?? []) {
|
|
36
|
+
ensureContentItemIds(content as unknown as Record<string, unknown>);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
ensureItemIds(model.pageFooterDesktop?.socialLinks);
|
|
41
|
+
ensureItemIds(model.pageFooterMobile?.socialLinks);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Backfill ids onto any items missing one. Per BP-5603 this runs in the
|
|
46
|
+
* metadata builder when a section is processed, so the persisted metadata
|
|
47
|
+
* returned to the client gains stable ids that subsequent AI tool calls can
|
|
48
|
+
* reference. Mutates in place.
|
|
49
|
+
*/
|
|
50
|
+
export const ensureItemIds = <T extends { id?: string }>(
|
|
51
|
+
items: T[] | undefined,
|
|
52
|
+
): void => {
|
|
53
|
+
if (!items) return;
|
|
54
|
+
|
|
55
|
+
for (const item of items) {
|
|
56
|
+
if (!item.id) item.id = generateItemId();
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Remove items whose id appears in `ids`. Order-independent (no descending
|
|
62
|
+
* index sort needed) — the whole point of the id-based migration. Items
|
|
63
|
+
* without an id are never removed by id.
|
|
64
|
+
*/
|
|
65
|
+
export const removeItemsByIds = <T extends { id?: string }>(
|
|
66
|
+
items: T[] | undefined,
|
|
67
|
+
ids: string[] | undefined,
|
|
68
|
+
): T[] => {
|
|
69
|
+
if (!items?.length) return items ?? [];
|
|
70
|
+
|
|
71
|
+
if (!ids?.length) return items;
|
|
72
|
+
|
|
73
|
+
const toRemove = new Set(ids);
|
|
74
|
+
|
|
75
|
+
return items.filter((item) => !item.id || !toRemove.has(item.id));
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Position `item` within `items` relative to an anchor id — the item-level
|
|
80
|
+
* mirror of base-section-builder's `moveContent`:
|
|
81
|
+
*
|
|
82
|
+
* - `moveBeforeItemId === undefined` → leave an existing item where it is;
|
|
83
|
+
* append a new (not-yet-present) item to the end.
|
|
84
|
+
* - `moveBeforeItemId === "__end__"` → move/insert at the very end.
|
|
85
|
+
* - anchor id found → insert immediately before it.
|
|
86
|
+
* - anchor id not found → fall through to the end (same
|
|
87
|
+
* forgiving behaviour as `moveContent`).
|
|
88
|
+
*
|
|
89
|
+
* Mutates `items` in place. `item` may be an existing element of `items`
|
|
90
|
+
* (a move) or a brand-new object (an insert).
|
|
91
|
+
*/
|
|
92
|
+
export const repositionItemByAnchor = <T extends { id?: string }>(
|
|
93
|
+
items: T[],
|
|
94
|
+
item: T,
|
|
95
|
+
moveBeforeItemId: string | undefined,
|
|
96
|
+
): void => {
|
|
97
|
+
const currentIndex = items.indexOf(item);
|
|
98
|
+
|
|
99
|
+
if (moveBeforeItemId === undefined) {
|
|
100
|
+
if (currentIndex === -1) items.push(item);
|
|
101
|
+
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (currentIndex !== -1) items.splice(currentIndex, 1);
|
|
106
|
+
|
|
107
|
+
const anchorIndex =
|
|
108
|
+
moveBeforeItemId === END_ITEM_ANCHOR
|
|
109
|
+
? -1
|
|
110
|
+
: items.findIndex((i) => i.id === moveBeforeItemId);
|
|
111
|
+
|
|
112
|
+
if (anchorIndex !== -1) {
|
|
113
|
+
items.splice(anchorIndex, 0, item);
|
|
114
|
+
} else {
|
|
115
|
+
items.push(item);
|
|
116
|
+
}
|
|
117
|
+
};
|