@designcrowd/library.brand-page 5.19.1-error-html2canvas-1 → 5.19.1-error-html2canvas-2

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.
Files changed (356) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-CxCJU9cc.js → CreatedOnBrandCrowd-de-de-DmKe7W8L.js} +3 -3
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-zDJCWP5n.js → CreatedOnBrandCrowd-en-us-D2EeiNep.js} +3 -3
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-DNna1Sh9.js → CreatedOnBrandCrowd-es-es-BqVwNY1D.js} +3 -3
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-C5XVf_hD.js → CreatedOnBrandCrowd-fr-ca-C756a27-.js} +3 -3
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-C5XVf_hD.js → CreatedOnBrandCrowd-fr-fr-C756a27-.js} +3 -3
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-9eUHV_M3.js → CreatedOnBrandCrowd-pt-br-FNHAnZUw.js} +3 -3
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-9eUHV_M3.js → CreatedOnBrandCrowd-pt-pt-FNHAnZUw.js} +3 -3
  8. package/lib/src/{CreatedOnDcom-de-de-D9HMpK8Q.js → CreatedOnDcom-de-de-8AZZFmDt.js} +3 -3
  9. package/lib/src/{CreatedOnDcom-en-us-BCTkchV5.js → CreatedOnDcom-en-us-DizTP32i.js} +3 -3
  10. package/lib/src/{CreatedOnDcom-es-es-B0N7VoTp.js → CreatedOnDcom-es-es-qnp9_n_A.js} +3 -3
  11. package/lib/src/{CreatedOnDcom-fr-ca-Gi4oz_Mm.js → CreatedOnDcom-fr-ca-jUs352uK.js} +3 -3
  12. package/lib/src/{CreatedOnDcom-fr-fr-DJI8eJo1.js → CreatedOnDcom-fr-fr-CTxXtHyk.js} +3 -3
  13. package/lib/src/{CreatedOnDcom-pt-br-YNWMAuQf.js → CreatedOnDcom-pt-br-nQHj8P7d.js} +3 -3
  14. package/lib/src/{CreatedOnDcom-pt-pt-DCIIK3sy.js → CreatedOnDcom-pt-pt-DJmVYQuL.js} +3 -3
  15. package/lib/src/brand-page/clients/brand-page.client.d.ts +9 -9
  16. package/lib/src/brand-page/components/banner-section/BannerSection.mixin.d.ts +103 -0
  17. package/lib/src/brand-page/components/banner-section/BannerSection.mixin.js +178 -0
  18. package/lib/src/brand-page/components/image-gallery/masonry/MasonryGallery.mixin.d.ts +0 -1
  19. package/lib/src/brand-page/components/navigation/hamburger/HamburgerNavigation.mixin.d.ts +4 -2
  20. package/lib/src/brand-page/components/navigation/hamburger/HamburgerNavigation.mixin.js +1 -0
  21. package/lib/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.d.ts +4 -2
  22. package/lib/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.js +5 -4
  23. package/lib/src/brand-page/components/page/Page.mixin.d.ts +1 -1
  24. package/lib/src/brand-page/components/page/PageComponent.mixin.d.ts +1 -1
  25. package/lib/src/brand-page/components/payment/Payment.mixin.d.ts +3 -3
  26. package/lib/src/brand-page/components/payment/__fixtures__/request-payment.d.ts +13 -13
  27. package/lib/src/brand-page/components/payment/__fixtures__/support-me.d.ts +13 -13
  28. package/lib/src/brand-page/constants/sections/footer-display.constants.js +1 -1
  29. package/lib/src/brand-page/models/index.d.ts +2 -1
  30. package/lib/src/brand-page/models/index.js +3 -0
  31. package/lib/src/brand-page/models/payment.model.d.ts +1 -1
  32. package/lib/src/brand-page/utils/personalisation.util.js +72 -14
  33. package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.d.ts +21 -19
  34. package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.js +1 -0
  35. package/lib/src/brand-page-maker/components/admin-background-settings/AdminBackgroundSettings.mixin.d.ts +16 -10
  36. package/lib/src/brand-page-maker/components/admin-logo-settings/AdminLogoSettings.mixin.d.ts +3 -3
  37. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +181 -170
  38. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +3 -0
  39. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.stories.js +1 -0
  40. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.mixin.d.ts +12 -12
  41. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.stories.js +2 -2
  42. package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-payment.js +0 -7
  43. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +148 -149
  44. package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.d.ts +21 -21
  45. package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.js +1 -1
  46. package/lib/src/brand-page-maker/components/color-picker/components/ColorModeSelect.mixin.d.ts +4 -2
  47. package/lib/src/brand-page-maker/components/color-picker/components/ColorModeSelect.mixin.js +1 -0
  48. package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSlider.mixin.d.ts +4 -2
  49. package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSlider.mixin.js +1 -0
  50. package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSliderHandler.mixin.d.ts +5 -2
  51. package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSliderHandler.mixin.js +1 -0
  52. package/lib/src/brand-page-maker/components/color-picker/components/GradientTypeSelector.mixin.d.ts +4 -2
  53. package/lib/src/brand-page-maker/components/color-picker/components/GradientTypeSelector.mixin.js +1 -0
  54. package/lib/src/brand-page-maker/components/device/Device.mixin.d.ts +4 -2
  55. package/lib/src/brand-page-maker/components/device/Device.mixin.js +1 -0
  56. package/lib/src/brand-page-maker/components/navigation/Navigation.mixin.d.ts +4 -2
  57. package/lib/src/brand-page-maker/components/navigation/Navigation.mixin.js +1 -0
  58. package/lib/src/brand-page-maker/components/preview/Preview.mixin.d.ts +3 -3
  59. package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +11 -11
  60. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +27 -25
  61. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.js +1 -0
  62. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +27 -27
  63. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.js +1 -1
  64. package/lib/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.mixin.d.ts +17 -12
  65. package/lib/src/brand-page-maker/components/social-share/SocialShare.mixin.d.ts +12 -12
  66. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +30 -32
  67. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.js +16 -5
  68. package/lib/src/brand-page-maker/components/upgrade-to-premium-button/UpgradeToPremiumButton.mixin.d.ts +11 -11
  69. package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +1 -1
  70. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.d.ts +1 -1
  71. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +6 -6
  72. package/lib/src/brand-page-maker/composables/useEventTracker.d.ts +2 -2
  73. package/lib/src/brand-page-maker/constants/config-settings-constant.d.ts +6 -6
  74. package/lib/src/brand-page-maker/constants/config-settings-constant.js +1 -1
  75. package/lib/src/brand-page-maker/convertors/text-image-display-style.convertor.d.ts +1 -1
  76. package/lib/src/brand-page-maker/convertors/text-image-display-style.convertor.js +1 -1
  77. package/lib/src/brand-page-maker/models/content-settings.d.ts +1 -1
  78. package/lib/src/brand-page-maker/models/navigation-style-configs.js +1 -1
  79. package/lib/src/brand-page-maker/routing/brand-page-maker-router.d.ts +1 -2
  80. package/lib/src/brand-page-maker/stores/ai-checkpoint/ai-checkpoint-store.d.ts +366 -360
  81. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.d.ts +5 -4
  82. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.js +8 -5
  83. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.d.ts +3 -1
  84. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +7 -3
  85. package/lib/src/brand-page-maker/stores/history/history-store.d.ts +15 -15
  86. package/lib/src/brand-page-maker/stores/ui/ui-store.d.ts +6 -0
  87. package/lib/src/brand-page-maker/stores/ui/ui-store.js +8 -0
  88. package/lib/src/brand-page-maker/utils/content-settings.util.js +1 -1
  89. package/lib/src/brand-page-maker/utils/rich-text-editor.util.d.ts +1 -1
  90. package/lib/src/brand-page-maker/utils/rich-text-editor.util.js +4 -4
  91. package/lib/src/clients/brand-page-client.d.ts +16 -15
  92. package/lib/src/clients/design-template-client.d.ts +3 -0
  93. package/lib/src/clients/media-client.d.ts +2 -2
  94. package/lib/src/clients/models.d.ts +2 -0
  95. package/lib/src/css/library.brand-page-brandCrowd.min.css +342 -324
  96. package/lib/src/css/library.brand-page-brandPage.min.css +620 -324
  97. package/lib/src/css/library.brand-page-designCom.min.css +342 -324
  98. package/lib/src/css/library.brand-page-preview.min.css +598 -324
  99. package/lib/src/index.d.ts +1 -1
  100. package/lib/src/index.mjs +16 -15
  101. package/lib/src/{lib-CaY174HB.js → lib-DityivZa.js} +35668 -32633
  102. package/lib/src/lib.js +1 -1
  103. package/lib/src/metadata-builder/builders/footer-builder.js +90 -65
  104. package/lib/src/metadata-builder/builders/section-builders/image-gallery-builder.js +1 -1
  105. package/lib/src/metadata-builder/builders/section-builders/images-section-builder.js +1 -1
  106. package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.js +1 -1
  107. package/lib/src/metadata-builder/builders/section-builders/text-section-builder.js +1 -1
  108. package/lib/src/metadata-builder/builders/shape-color-utils.js +1 -1
  109. package/lib/src/plugins/google-maps-plugin/google-maps-plugin.d.ts +1 -1
  110. package/lib/src/plugins/google-maps-plugin/google-maps-plugin.js +8 -8
  111. package/lib/src/shared/background-settings/components/background-shapes/BackgroundShapeSettings.mixin.d.ts +13 -13
  112. package/lib/src/shared/background-settings/store/background-settings-store.d.ts +3 -3
  113. package/lib/src/shared/color-picker/components/ColorPicker.mixin.d.ts +4 -2
  114. package/lib/src/shared/color-picker/components/ColorPicker.mixin.js +2 -2
  115. package/lib/src/shared/color-picker/components/ColorPickerSwatch.mixin.d.ts +4 -2
  116. package/lib/src/shared/color-picker/components/ColorPickerSwatch.mixin.js +1 -0
  117. package/lib/src/shared/confirm-modal/ConfirmModal.mixin.d.ts +5 -2
  118. package/lib/src/shared/confirm-modal/ConfirmModal.mixin.js +1 -0
  119. package/lib/src/shared/content-settings/components/GenericTextInput.mixin.d.ts +0 -1
  120. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +131 -129
  121. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.js +2 -1
  122. package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +111 -110
  123. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +84 -81
  124. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.js +5 -0
  125. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +117 -109
  126. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.js +1 -14
  127. package/lib/src/shared/content-settings/components/email-field/EmailField.mixin.d.ts +0 -1
  128. package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.d.ts +72 -70
  129. package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.js +4 -3
  130. package/lib/src/shared/content-settings/components/form-fields-field/FormFieldsField.mixin.d.ts +4 -4
  131. package/lib/src/shared/content-settings/components/icon-library/IconLibrary.mixin.d.ts +3 -1
  132. package/lib/src/shared/content-settings/components/icon-library/IconLibrary.mixin.js +1 -0
  133. package/lib/src/shared/content-settings/components/images-field/ImagesField.mixin.d.ts +2 -2
  134. package/lib/src/shared/content-settings/components/items-field/ItemsField.mixin.d.ts +4 -3
  135. package/lib/src/shared/content-settings/components/items-field/ItemsField.mixin.js +1 -1
  136. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +40 -40
  137. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigOptionField.mixin.d.ts +5 -6
  138. package/lib/src/shared/content-settings/components/shape-field/ShapeField.mixin.d.ts +0 -1
  139. package/lib/src/shared/content-settings/components/slider-field/SliderField.mixin.d.ts +2 -2
  140. package/lib/src/shared/content-settings/components/tel-field/TelField.mixin.d.ts +0 -1
  141. package/lib/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.mixin.d.ts +1 -2
  142. package/lib/src/shared/content-settings/components/text-field/TextField.mixin.d.ts +0 -1
  143. package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.d.ts +1 -2
  144. package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.js +1 -1
  145. package/lib/src/shared/content-settings/components/text-style-field/TextStyleField.mixin.d.ts +28 -28
  146. package/lib/src/shared/content-settings/components/textarea-field/TextareaField.mixin.d.ts +0 -1
  147. package/lib/src/shared/content-settings/components/toggle-field/ToggleField.mixin.d.ts +2 -2
  148. package/lib/src/shared/content-settings/components/url-field/UrlField.mixin.d.ts +0 -1
  149. package/lib/src/shared/content-settings/components/youtube-video-field/YoutubeVideoField.mixin.d.ts +0 -1
  150. package/lib/src/shared/content-settings/store/content-settings-store.d.ts +39 -39
  151. package/lib/src/shared/content-settings/utils.js +0 -1
  152. package/lib/src/shared/font-family-selector/FontFamilySelector.mixin.d.ts +6 -4
  153. package/lib/src/shared/font-family-selector/FontFamilySelector.mixin.js +1 -0
  154. package/lib/src/shared/image-gallery-style-settings/ImageGalleryStyleSettings.mixin.d.ts +4 -2
  155. package/lib/src/shared/image-gallery-style-settings/ImageGalleryStyleSettings.mixin.js +1 -0
  156. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +29 -21
  157. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.js +1 -1
  158. package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +50 -51
  159. package/lib/src/shared/logo-settings/components/LogoSettingsHeader.mixin.d.ts +6 -4
  160. package/lib/src/shared/logo-settings/components/LogoSettingsHeader.mixin.js +1 -0
  161. package/lib/src/shared/logo-settings/store/editable-logo-store.js +1 -1
  162. package/lib/src/shared/logo-settings/store/logo-settings-store.d.ts +1 -1
  163. package/lib/src/shared/logo-versions/LogoVersions.mixin.d.ts +13 -5
  164. package/lib/src/shared/logo-versions/LogoVersions.mixin.js +1 -0
  165. package/lib/src/shared/models.d.ts +2 -0
  166. package/lib/src/shared/my-designs/MyDesigns.mixin.d.ts +14 -6
  167. package/lib/src/shared/my-designs/MyDesigns.mixin.js +1 -0
  168. package/lib/src/shared/my-uploads/MyMedia.mixin.d.ts +14 -5
  169. package/lib/src/shared/my-uploads/MyMedia.mixin.js +1 -0
  170. package/lib/src/shared/my-uploads/MyUploads.mixin.d.ts +14 -5
  171. package/lib/src/shared/my-uploads/MyUploads.mixin.js +1 -0
  172. package/lib/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.mixin.d.ts +5 -3
  173. package/lib/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.mixin.js +1 -0
  174. package/lib/src/shared/navigation-style-settings/store/index.d.ts +2 -2
  175. package/lib/src/shared/page-navigation/store/page-navigation-store.d.ts +2 -2
  176. package/lib/src/shared/page-settings/components/new-page-modal/NewPageModal.mixin.d.ts +27 -28
  177. package/lib/src/shared/page-settings/components/new-page-modal/NewPageModal.mixin.js +0 -2
  178. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +188 -177
  179. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +181 -175
  180. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.js +1 -1
  181. package/lib/src/shared/page-settings/store/page-settings-store.d.ts +9 -9
  182. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +39 -39
  183. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.js +0 -1
  184. package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +18 -18
  185. package/lib/src/shared/side-bar/components/SideBarTabButton.mixin.d.ts +6 -6
  186. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +66 -60
  187. package/lib/src/shared/style-settings/store/style-settings-store.d.ts +1 -1
  188. package/lib/src/shared/style-settings/store/style-settings-store.js +1 -1
  189. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.d.ts +20 -450
  190. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.js +2 -2
  191. package/lib/src/shared/template-settings/models.d.ts +1 -0
  192. package/lib/src/shared/template-settings/store/template-settings-store.d.ts +4 -0
  193. package/lib/src/shared/template-settings/store/template-settings-store.js +79 -11
  194. package/lib/src/shared/unsplash-library/UnsplashLibrary.mixin.d.ts +9 -4
  195. package/package.json +61 -57
  196. package/src/brand-page/components/about-section/AboutSection.vue.test.ts +7 -5
  197. package/src/brand-page/components/banner-section/BannerSection.mixin.ts +210 -0
  198. package/src/brand-page/components/brand-page-footer/BrandPageFooter.vue +1 -1
  199. package/src/brand-page/components/image/Image.mixin.ts +1 -1
  200. package/src/brand-page/components/image/Image.test.ts +1 -1
  201. package/src/brand-page/components/images-section/ImagesSection.vue +0 -1
  202. package/src/brand-page/components/logo/LogoRender.vue +188 -188
  203. package/src/brand-page/components/navigation/hamburger/HamburgerNavigation.mixin.ts +1 -0
  204. package/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.ts +15 -6
  205. package/src/brand-page/components/page-footer/PageFooter.vue +1 -0
  206. package/src/brand-page/components/page-header/HeaderLayout.vue +12 -6
  207. package/src/brand-page/components/page-header/PageHeader.vue +1 -0
  208. package/src/brand-page/components/shapes-section/ShapesSection.vue +1 -1
  209. package/src/brand-page/components/shop/CartModal.vue +1 -3
  210. package/src/brand-page/components/shop/FeaturedDisplay.vue +2 -2
  211. package/src/brand-page/components/shop/PaymentModal.vue +1 -5
  212. package/src/brand-page/components/shop/ProductDetailModal.vue +1 -1
  213. package/src/brand-page/components/shop/Shop.vue +1 -1
  214. package/src/brand-page/components/shop/TextDisplay.vue +1 -1
  215. package/src/brand-page/components/shop/ThumbnailDisplay.vue +2 -2
  216. package/src/brand-page/components/testimonial-section/TestimonialSection.vue +3 -3
  217. package/src/brand-page/components/text-wrapper/TextWrapper.vue +3 -1
  218. package/src/brand-page/constants/sections/footer-display.constants.ts +1 -1
  219. package/src/brand-page/models/index.ts +4 -0
  220. package/src/brand-page/models/payment.model.ts +2 -1
  221. package/src/brand-page/models/shop.model.ts +0 -2
  222. package/src/brand-page/models/user-personalisation.model.ts +1 -2
  223. package/src/brand-page/utils/__snapshots__/migration.util.test.ts.snap +3 -0
  224. package/src/brand-page/utils/__snapshots__/migration2.util.test.ts.snap +1 -0
  225. package/src/brand-page/utils/__snapshots__/model.util.test.ts.snap +2 -0
  226. package/src/brand-page/utils/migration/migration-01_1.ts +1 -1
  227. package/src/brand-page/utils/migration/migration-02.ts +0 -1
  228. package/src/brand-page/utils/migration/migration-03.ts +0 -1
  229. package/src/brand-page/utils/migration/migration-04.ts +0 -1
  230. package/src/brand-page/utils/migration/migration-05.ts +1 -5
  231. package/src/brand-page/utils/migration/migration-05_2.ts +1 -1
  232. package/src/brand-page/utils/migration/migration-08.test.ts +1 -1
  233. package/src/brand-page/utils/personalisation.util.test.ts +35 -0
  234. package/src/brand-page/utils/personalisation.util.ts +119 -23
  235. package/src/brand-page/view-models.ts +38 -56
  236. package/src/brand-page-maker/assessors/banner-section-description-visibility.assessor.ts +6 -6
  237. package/src/brand-page-maker/assessors/color-replacement-icon-visibility.assessor.ts +2 -2
  238. package/src/brand-page-maker/assessors/color-replacement-profile-visibility.assessor.ts +2 -2
  239. package/src/brand-page-maker/assessors/color-replacement-visibility.assessor.ts +2 -2
  240. package/src/brand-page-maker/assessors/contact-form-visibility.assessor.ts +14 -14
  241. package/src/brand-page-maker/components/action-bar/ActionBar.mixin.ts +1 -0
  242. package/src/brand-page-maker/components/ai-text-edit/TextBubble.vue +1 -0
  243. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +5 -1
  244. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.stories.ts +1 -0
  245. package/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.stories.ts +2 -5
  246. package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.ts +0 -5
  247. package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-payment.ts +0 -8
  248. package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-site-template.examples.ts +0 -2
  249. package/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.vue +1 -0
  250. package/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.ts +1 -1
  251. package/src/brand-page-maker/components/color-palette/BpColorPalette.vue +1 -2
  252. package/src/brand-page-maker/components/color-picker/components/ColorModeSelect.mixin.ts +1 -0
  253. package/src/brand-page-maker/components/color-picker/components/GradientColorSlider.mixin.ts +1 -0
  254. package/src/brand-page-maker/components/color-picker/components/GradientColorSliderHandler.mixin.ts +1 -0
  255. package/src/brand-page-maker/components/color-picker/components/GradientTypeSelector.mixin.ts +1 -0
  256. package/src/brand-page-maker/components/device/Device.mixin.ts +1 -0
  257. package/src/brand-page-maker/components/navigation/Navigation.mixin.ts +1 -0
  258. package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.vue +3 -1
  259. package/src/brand-page-maker/components/sensitive-content/SensitiveContent.vue +1 -4
  260. package/src/brand-page-maker/components/seo-settings/DeleteDomainModal.vue +1 -1
  261. package/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.ts +1 -0
  262. package/src/brand-page-maker/components/seo-settings/SeoPageSettings.vue +1 -1
  263. package/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.ts +0 -1
  264. package/src/brand-page-maker/components/seo-settings/UrlSettings.vue +0 -1
  265. package/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.vue +1 -5
  266. package/src/brand-page-maker/components/shop/AddOrEditProductContainer.vue +1 -1
  267. package/src/brand-page-maker/components/shop/ReplaceImageSettingsForShop.vue +1 -1
  268. package/src/brand-page-maker/components/social-share/SocialShare.vue +1 -1
  269. package/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.ts +22 -8
  270. package/src/brand-page-maker/components/template-preview/TemplatePreview.vue +5 -10
  271. package/src/brand-page-maker/components/template-preview/TemplatePreviewAiBadge.vue +12 -0
  272. package/src/brand-page-maker/components/video-play/VideoPlayButton.vue +1 -1
  273. package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +1 -1
  274. package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +6 -6
  275. package/src/brand-page-maker/constants/config-settings-constant.ts +3 -3
  276. package/src/brand-page-maker/convertors/text-image-display-style.convertor.ts +1 -1
  277. package/src/brand-page-maker/models/button-styles-config.ts +4 -2
  278. package/src/brand-page-maker/models/content-settings-configs.ts +4 -2
  279. package/src/brand-page-maker/models/navigation-style-configs.ts +5 -6
  280. package/src/brand-page-maker/stores/admin-logo-settings/admin-logo-settings-store.ts +0 -1
  281. package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.ts +8 -5
  282. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.test.ts +1 -3
  283. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +12 -4
  284. package/src/brand-page-maker/stores/ui/ui-store.ts +16 -0
  285. package/src/brand-page-maker/utils/content-settings.util.ts +1 -1
  286. package/src/brand-page-maker/utils/rich-text-editor.util.ts +4 -4
  287. package/src/clients/design-template-client.ts +3 -0
  288. package/src/clients/models.ts +2 -0
  289. package/src/lib.ts +1 -0
  290. package/src/metadata-builder/builders/footer-builder.test.ts +137 -0
  291. package/src/metadata-builder/builders/footer-builder.ts +129 -89
  292. package/src/metadata-builder/builders/section-builders/image-gallery-builder.ts +1 -1
  293. package/src/metadata-builder/builders/section-builders/images-section-builder.ts +1 -1
  294. package/src/metadata-builder/builders/section-builders/testimonial-section-builder.ts +1 -1
  295. package/src/metadata-builder/builders/section-builders/text-section-builder.ts +1 -1
  296. package/src/metadata-builder/builders/shape-color-utils.ts +2 -2
  297. package/src/plugins/google-maps-plugin/google-maps-plugin.ts +8 -8
  298. package/src/shared/background-settings/components/BackgroundSettings.vue +1 -1
  299. package/src/shared/background-settings/components/background-color/BackgroundColorSettings.vue +1 -1
  300. package/src/shared/color-picker/components/ColorPicker.mixin.ts +2 -7
  301. package/src/shared/color-picker/components/ColorPickerSwatch.mixin.ts +1 -0
  302. package/src/shared/common/NumberInput.vue +1 -0
  303. package/src/shared/common/SideBarSettingsHeader.vue +2 -2
  304. package/src/shared/confirm-modal/ConfirmModal.mixin.ts +1 -0
  305. package/src/shared/content-settings/components/booking-url-field/BookingUrlField.vue +1 -0
  306. package/src/shared/content-settings/components/button-configuration-field/ButtonConfigurationField.vue +1 -0
  307. package/src/shared/content-settings/components/color-field/ColorField.vue +3 -10
  308. package/src/shared/content-settings/components/content-settings/ContentSettings.mixin.ts +1 -1
  309. package/src/shared/content-settings/components/content-settings/ContentSettingsLockedButton.vue +1 -0
  310. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.ts +5 -0
  311. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.ts +1 -14
  312. package/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.ts +4 -6
  313. package/src/shared/content-settings/components/icon-library/IconLibrary.mixin.ts +1 -0
  314. package/src/shared/content-settings/components/items-field/ItemsField.mixin.ts +1 -1
  315. package/src/shared/content-settings/components/logo-selection-field/LogoSelectionField.vue +1 -1
  316. package/src/shared/content-settings/components/logo-size-field/LogoSizeSliderField.vue +1 -1
  317. package/src/shared/content-settings/components/page-dropdown-field/PageDropdownField.vue +1 -1
  318. package/src/shared/content-settings/components/personalisation-role-field/PersonalisationRoleField.vue +4 -4
  319. package/src/shared/content-settings/components/text-image-field/TextImageField.vue +2 -8
  320. package/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.ts +1 -1
  321. package/src/shared/content-settings/models.ts +3 -2
  322. package/src/shared/content-settings/utils.ts +0 -1
  323. package/src/shared/dropzone-image-uploader/components/DropzoneImageUploader.vue +1 -0
  324. package/src/shared/ecommerce-settings/store/cart-store.test.ts +1 -1
  325. package/src/shared/font-family-selector/FontFamilySelector.mixin.ts +1 -0
  326. package/src/shared/image-gallery-style-settings/ImageGalleryStyleSettings.mixin.ts +1 -0
  327. package/src/shared/logo-settings/components/EditLogoSettings.mixin.ts +1 -1
  328. package/src/shared/logo-settings/components/LogoSettings.mixin.ts +0 -1
  329. package/src/shared/logo-settings/components/LogoSettingsHeader.mixin.ts +1 -0
  330. package/src/shared/logo-settings/components/LogoStyleSettingsWithState.vue +2 -2
  331. package/src/shared/logo-settings/components/LogoTemplateSearch.vue +1 -1
  332. package/src/shared/logo-settings/store/editable-logo-store.ts +1 -1
  333. package/src/shared/logo-settings/store/logo-settings-store.test.ts +4 -4
  334. package/src/shared/logo-versions/LogoVersions.mixin.ts +1 -0
  335. package/src/shared/models.ts +6 -0
  336. package/src/shared/my-designs/MyDesigns.mixin.ts +1 -0
  337. package/src/shared/my-uploads/MyMedia.mixin.ts +1 -0
  338. package/src/shared/my-uploads/MyMediaSelectionItem.vue +2 -1
  339. package/src/shared/my-uploads/MyUploads.mixin.ts +1 -0
  340. package/src/shared/my-uploads/models.ts +1 -2
  341. package/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.mixin.ts +1 -0
  342. package/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.vue +1 -1
  343. package/src/shared/page-settings/components/new-page-modal/NewPageModal.mixin.ts +0 -3
  344. package/src/shared/page-settings/components/page-settings/NestedDraggable.vue +1 -1
  345. package/src/shared/page-settings/components/page-settings/PageSettings.vue +1 -2
  346. package/src/shared/page-settings/components/page-settings-section-styles/HeaderDisplayStyle.vue +1 -1
  347. package/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.ts +1 -1
  348. package/src/shared/page-settings/store/page-settings-store.test.ts +4 -8
  349. package/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.ts +0 -1
  350. package/src/shared/shape-library/ShapeLibrary.vue +2 -2
  351. package/src/shared/style-settings/store/style-settings-store.ts +1 -1
  352. package/src/shared/template-settings/components/TemplatesSettings.mixin.ts +2 -2
  353. package/src/shared/template-settings/models.ts +1 -0
  354. package/src/shared/template-settings/store/template-settings-store.ts +105 -18
  355. package/src/shared/unsplash-library/UnsplashLibrary.vue +2 -6
  356. package/src/shared/video-library/VideoLibrary.vue +1 -1
@@ -21,7 +21,6 @@ import {
21
21
  BRAND_PAGE_TYPES,
22
22
  SENSITIVE_CONTENT_TYPES,
23
23
  getAbTestResults,
24
- getValueType,
25
24
  type AbTest,
26
25
  type LogoContent,
27
26
  } from '@brand-page';
@@ -34,7 +33,6 @@ import {
34
33
  TRIGGER_TYPE,
35
34
  UPGRADE_CTA_LOCATIONS,
36
35
  useEventTracker,
37
- EVENTS,
38
36
  } from '@brand-page-maker/composables/useEventTracker';
39
37
  import { navigationTr } from '@src/composables/useTranslate';
40
38
  import type { WebsiteSlugCheckResponse } from '@brand-page-maker/models/api.model';
@@ -123,6 +121,7 @@ export type InitialisePayload = Omit<
123
121
  logoDraftAssets: LogoDraftAsset[];
124
122
  gettyVideos: GettyVideoEditorViewModelResponse[];
125
123
  templateSearchTerm: string | undefined;
124
+ aiTemplateKeywords: string | undefined;
126
125
  onSearchTermChanged?: OnSearchTermChangedCallback;
127
126
  };
128
127
 
@@ -266,6 +265,10 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
266
265
  onSearchTermChanged: payload.onSearchTermChanged,
267
266
  });
268
267
 
268
+ templateSettingsStore.setAiTemplateKeywords({
269
+ aiTemplateKeywords: payload.aiTemplateKeywords ?? '',
270
+ });
271
+
269
272
  brandPageMakerStore.setSelectedTemplateId({
270
273
  templateId: this.designTemplateToken,
271
274
  });
@@ -446,7 +449,7 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
446
449
 
447
450
  async publishBrandPage({ shouldPublish, slug }) {
448
451
  const brandPageMakerStore = useBrandPageMakerStore();
449
- const eventTracker = useEventTracker();
452
+ const _eventTracker = useEventTracker();
450
453
 
451
454
  if (!this.designDraftToken) {
452
455
  throw new Error(
@@ -553,7 +556,7 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
553
556
  isPurchasedDomain,
554
557
  }) {
555
558
  const brandPageMakerStore = useBrandPageMakerStore();
556
- const eventTracker = useEventTracker();
559
+ const _eventTracker = useEventTracker();
557
560
 
558
561
  if (!this.designDraftToken) {
559
562
  throw new Error(
@@ -887,7 +890,7 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
887
890
  ) {
888
891
  const userStore = useBrandPageMakerUserStore();
889
892
  const brandPageMakerStore = useBrandPageMakerStore();
890
- const eventTracker = useEventTracker();
893
+ const _eventTracker = useEventTracker();
891
894
 
892
895
  if (userStore.isAdmin) {
893
896
  throw new Error('save brand page is not allowed in admin mode');
@@ -2,7 +2,6 @@ import { vi } from 'vitest';
2
2
  import {
3
3
  BRAND_PAGE,
4
4
  INITIALISE_PAYLOAD,
5
- USER_FEATURES,
6
5
  userFeatures,
7
6
  } from '../../components/brand-page-maker/__fixtures__';
8
7
  import {
@@ -44,6 +43,7 @@ import { useUiBackgroundSettingsStore } from '@shared/background-settings/store'
44
43
  import { useBrandPageMakerUserStore } from '../user';
45
44
  import { useBrandPageContainerStore } from '../brandpage-container';
46
45
  import { useUiTemplateSettingsStore } from '@shared/template-settings/store';
46
+ import { usePageNavigationStore } from '@shared/page-navigation/store/page-navigation-store';
47
47
  import {
48
48
  CONTENT_SETTINGS_MODES,
49
49
  useUiContentSettingsStore,
@@ -54,8 +54,6 @@ import { SIDE_BAR_TAB_NAMES } from '@brand-page-maker/constants';
54
54
  import { PAGE_SECTIONS } from '@shared/page-settings/models';
55
55
  import { FabricRenderClient } from '../../../clients/fabric-render-client';
56
56
  import { setLocaleAsync } from '@src/composables/useTranslate';
57
- import { usePageNavigationStore } from '@shared/page-navigation/store/page-navigation-store';
58
- import type { NavModel } from '@brand-page/models';
59
57
 
60
58
  const createInitialisePayload = () => {
61
59
  const initialisePayload = {
@@ -23,14 +23,12 @@ import {
23
23
  CONTENT_TYPES,
24
24
  NavigationDesktop,
25
25
  NavigationMobile,
26
- NavModel,
27
26
  } from '@brand-page';
28
27
  import type {
29
28
  DesignTemplateType,
30
29
  InitialCategories,
31
30
  TemplateCategory,
32
31
  } from '@shared/template-settings/models';
33
- import type { UserFeatures } from '../user';
34
32
  import { useBrandPageMakerUserStore } from '../user';
35
33
  import { defineStore } from 'pinia';
36
34
  import { toRaw } from 'vue';
@@ -125,6 +123,8 @@ export interface InitialisePayload {
125
123
  templateCategories: TemplateCategory[];
126
124
  personalisationData?: UserPersonalisationContent[];
127
125
  isPersonalisationEnabled: boolean;
126
+ userPromptContentKey?: string;
127
+ showAiTemplatesTab?: boolean;
128
128
  businessName: string | undefined;
129
129
  industry: string | undefined;
130
130
  layout?: string;
@@ -1230,11 +1230,13 @@ export const useBrandPageMakerStore = defineStore('brandPageMaker', {
1230
1230
  templateCategories,
1231
1231
  personalisationData,
1232
1232
  isPersonalisationEnabled,
1233
+ userPromptContentKey,
1234
+ showAiTemplatesTab = false,
1233
1235
  businessName,
1234
1236
  industry,
1235
1237
  layout,
1236
1238
  logoVariationImageUrls,
1237
- shopConfigData,
1239
+ shopConfigData: _shopConfigData,
1238
1240
  isServerRenderOverride = false,
1239
1241
  }: InitialisePayload) {
1240
1242
  const brandPageContainerStore = useBrandPageContainerStore();
@@ -1246,7 +1248,7 @@ export const useBrandPageMakerStore = defineStore('brandPageMaker', {
1246
1248
  const backgroundSettingsStore = useUiBackgroundSettingsStore();
1247
1249
  const styleSettingsStore = useUiStyleSettingsStore();
1248
1250
  const navigationStyleSettingsStore = useUiNavigationStyleSettingsStore();
1249
- const sideBarStore = useUiSideBarStore();
1251
+ const _sideBarStore = useUiSideBarStore();
1250
1252
 
1251
1253
  navigationStyleSettingsStore.initialise({ reset: false });
1252
1254
 
@@ -1353,6 +1355,10 @@ export const useBrandPageMakerStore = defineStore('brandPageMaker', {
1353
1355
  });
1354
1356
  }
1355
1357
 
1358
+ uiStore.setUserPromptContentKey({ userPromptContentKey });
1359
+
1360
+ uiStore.setShowAiTemplatesTab({ showAiTemplatesTab });
1361
+
1356
1362
  templateSettingsStore.setTemplateCategories({
1357
1363
  categories: templateCategories,
1358
1364
  });
@@ -1800,6 +1806,7 @@ export const useBrandPageMakerStore = defineStore('brandPageMaker', {
1800
1806
  const navigationStyleSettingsStore = useUiNavigationStyleSettingsStore();
1801
1807
  const shopStore = useShopConfigStore();
1802
1808
  const pageNavigationStore = usePageNavigationStore();
1809
+ const uiStore = useUiStore();
1803
1810
 
1804
1811
  const pages = pageSettingsStore.pages.map((p) => ({
1805
1812
  ...p,
@@ -1817,6 +1824,7 @@ export const useBrandPageMakerStore = defineStore('brandPageMaker', {
1817
1824
 
1818
1825
  return {
1819
1826
  v: GetLatestModelVersion(),
1827
+ userPromptContentKey: uiStore.userPromptContentKey,
1820
1828
  pages,
1821
1829
  styles: {
1822
1830
  logoStyles,
@@ -48,6 +48,8 @@ export const useUiStore = defineStore('ui', {
48
48
  },
49
49
  personalisationData: undefined,
50
50
  isPersonalisationEnabled: false,
51
+ userPromptContentKey: undefined,
52
+ showAiTemplatesTab: false,
51
53
  }),
52
54
  actions: {
53
55
  setLogoTheme(payload: { logoTheme: LogoTheme }) {
@@ -78,6 +80,20 @@ export const useUiStore = defineStore('ui', {
78
80
  }) {
79
81
  this.personalisationData = personalisationData;
80
82
  },
83
+ setUserPromptContentKey({
84
+ userPromptContentKey,
85
+ }: {
86
+ userPromptContentKey: string | undefined;
87
+ }) {
88
+ this.userPromptContentKey = userPromptContentKey;
89
+ },
90
+ setShowAiTemplatesTab({
91
+ showAiTemplatesTab,
92
+ }: {
93
+ showAiTemplatesTab: boolean;
94
+ }) {
95
+ this.showAiTemplatesTab = showAiTemplatesTab;
96
+ },
81
97
  onBackgroundChanged() {
82
98
  const brandPageMakerStore = useBrandPageMakerStore();
83
99
 
@@ -7,7 +7,7 @@ import type {
7
7
  ContentSettingsConfig,
8
8
  CreateInitialContentOptions,
9
9
  } from '../models';
10
- import { SENSITIVE_CONTENT_TYPES, type Content } from '@brand-page';
10
+ import { type Content } from '@brand-page';
11
11
  import { RESERVED_FIELD_NAMES } from '@shared/content-settings/constants';
12
12
  import { CONTENT_SETTINGS_CONFIGS } from '../constants';
13
13
  import type { UIUserFeatures } from '@src/constants/ui';
@@ -431,7 +431,7 @@ const transformRTEField = (
431
431
  if (textStyleType && (textStyleType === type || uiStyleSettingsStore)) {
432
432
  let globalContentStyle = uiStyleSettingsStore
433
433
  ? uiStyleSettingsStore.textStyles.textStyleOptions[textStyleType].style
434
- : newStyle ?? ({} as TextStyleDeclaration);
434
+ : (newStyle ?? ({} as TextStyleDeclaration));
435
435
 
436
436
  globalContentStyle = {
437
437
  ...globalContentStyle,
@@ -549,7 +549,7 @@ export const transformToRTE = (
549
549
  ? uiStyleSettingsStore.textStyles.textStyleOptions[
550
550
  textItemStyleType
551
551
  ].style
552
- : newStyle ?? ({} as TextStyleDeclaration);
552
+ : (newStyle ?? ({} as TextStyleDeclaration));
553
553
 
554
554
  globalContentStyle = {
555
555
  ...globalContentStyle,
@@ -593,7 +593,7 @@ export const transformToRTE = (
593
593
  let globalContentStyle = uiStyleSettingsStore
594
594
  ? uiStyleSettingsStore.textStyles.textStyleOptions[textStyleType]
595
595
  .style
596
- : newStyle ?? ({} as TextStyleDeclaration);
596
+ : (newStyle ?? ({} as TextStyleDeclaration));
597
597
 
598
598
  globalContentStyle = {
599
599
  ...globalContentStyle,
@@ -647,7 +647,7 @@ export const switchAllContentToRTE = (
647
647
 
648
648
  if (textContent.textItems && textContent.textItems.length > 0) {
649
649
  for (const [
650
- itemIndex,
650
+ _itemIndex,
651
651
  textItemContent,
652
652
  ] of textContent.textItems.entries()) {
653
653
  const textItemStyleType = textItemContent.textStyle.textStyleType;
@@ -11,6 +11,7 @@ interface DesignTemplateClientOptions {}
11
11
  interface GetTemplatesAsyncOptions {
12
12
  categoryName?: string;
13
13
  searchTerm?: string;
14
+ keywords?: string;
14
15
  side?: string;
15
16
  logoDraftToken?: string;
16
17
  logoVariation?: number;
@@ -22,6 +23,8 @@ interface GetTemplatesAsyncOptions {
22
23
  locale?: string;
23
24
  logoS3Token?: string;
24
25
  logoTemplateToken?: string;
26
+ pageSection?: string;
27
+ pageName?: string;
25
28
  }
26
29
 
27
30
  export const getTemplatesEndpoint = (templateTypeName: string) =>
@@ -4,6 +4,7 @@ export interface Paginated<T> {
4
4
  pageSize: number;
5
5
  pageCount: number;
6
6
  totalResultCount: number;
7
+ abTestValuesToBePushed?: Record<string, string>;
7
8
  }
8
9
 
9
10
  export interface DesignTemplate {
@@ -14,6 +15,7 @@ export interface DesignTemplate {
14
15
 
15
16
  export interface PaginatedDesignTemplateItem {
16
17
  designTemplateToken: string;
18
+ isPersonalisable?: boolean;
17
19
  previewImageUrl?: string;
18
20
  }
19
21
 
package/src/lib.ts CHANGED
@@ -96,6 +96,7 @@ export {
96
96
  useEventManagerStore,
97
97
  useLocalisedRouteStore,
98
98
  useVideoStore,
99
+ useRouteStore,
99
100
  } from './brand-page-maker/stores';
100
101
  export { useShopConfigStore } from './shared/ecommerce-settings/store/shop-settings-store';
101
102
 
@@ -74,3 +74,140 @@ describe('FooterBuilder — copyright font vs global style', () => {
74
74
  expect(style.textAlign).toBe('center');
75
75
  });
76
76
  });
77
+
78
+ type Link = { imageUrl: string; url: string };
79
+
80
+ const link = (imageUrl: string): Link => ({
81
+ imageUrl,
82
+ url: `https://${imageUrl}.com`,
83
+ });
84
+
85
+ /**
86
+ * Footers migrated from the legacy single `footerStyles` model
87
+ * (migration-01) split into desktop + mobile via a shallow spread, leaving
88
+ * both viewports' `socialLinks` pointing at ONE shared array. `cloneDeep`
89
+ * preserves that shared reference. This factory reproduces that shape.
90
+ */
91
+ const makeSharedSocialModel = (links: Link[]): BrandPageModel => {
92
+ const shared = links.map((l) => ({ ...l }));
93
+
94
+ return {
95
+ styles: { textStyles: { textStyleOptions } },
96
+ pageFooterDesktop: { socialLinks: shared },
97
+ pageFooterMobile: { socialLinks: shared },
98
+ } as unknown as BrandPageModel;
99
+ };
100
+
101
+ const makeIndependentSocialModel = (links: Link[]): BrandPageModel =>
102
+ ({
103
+ styles: { textStyles: { textStyleOptions } },
104
+ pageFooterDesktop: { socialLinks: links.map((l) => ({ ...l })) },
105
+ pageFooterMobile: { socialLinks: links.map((l) => ({ ...l })) },
106
+ }) as unknown as BrandPageModel;
107
+
108
+ const socialIcons = (footer: { socialLinks?: Link[] } | undefined) =>
109
+ (footer?.socialLinks ?? []).map((l) => l.imageUrl);
110
+
111
+ describe('FooterBuilder — social link removal (shared-array regression)', () => {
112
+ // Reproduces the bug: a single requested removal index dropped TWO links
113
+ // because both viewports shared one array and the builder spliced it twice.
114
+ it('removes exactly one link per requested index even when viewports share the array', async () => {
115
+ const model = makeSharedSocialModel([
116
+ link('facebook'),
117
+ link('instagram'),
118
+ link('x'),
119
+ link('youtube'),
120
+ ]);
121
+
122
+ const { model: out } = await run(
123
+ { _remove_social_link_indices: [2] },
124
+ model,
125
+ );
126
+
127
+ expect(socialIcons(out.pageFooterDesktop)).toEqual([
128
+ 'facebook',
129
+ 'instagram',
130
+ 'youtube',
131
+ ]);
132
+ expect(socialIcons(out.pageFooterMobile)).toEqual([
133
+ 'facebook',
134
+ 'instagram',
135
+ 'youtube',
136
+ ]);
137
+ });
138
+
139
+ it('un-shares the viewport arrays so later in-place edits cannot cross-corrupt', async () => {
140
+ const model = makeSharedSocialModel([
141
+ link('facebook'),
142
+ link('instagram'),
143
+ link('x'),
144
+ ]);
145
+
146
+ const { model: out } = await run(
147
+ { _remove_social_link_indices: [0] },
148
+ model,
149
+ );
150
+
151
+ expect(out.pageFooterDesktop!.socialLinks).not.toBe(
152
+ out.pageFooterMobile!.socialLinks,
153
+ );
154
+ });
155
+
156
+ it('handles multiple removal indices on a shared array (descending splice)', async () => {
157
+ const model = makeSharedSocialModel([
158
+ link('facebook'),
159
+ link('instagram'),
160
+ link('x'),
161
+ link('youtube'),
162
+ ]);
163
+
164
+ const { model: out } = await run(
165
+ { _remove_social_link_indices: [0, 2] },
166
+ model,
167
+ );
168
+
169
+ expect(socialIcons(out.pageFooterDesktop)).toEqual([
170
+ 'instagram',
171
+ 'youtube',
172
+ ]);
173
+ expect(socialIcons(out.pageFooterMobile)).toEqual(['instagram', 'youtube']);
174
+ });
175
+
176
+ it('removes one link per index for independent viewport arrays (no regression)', async () => {
177
+ const model = makeIndependentSocialModel([
178
+ link('facebook'),
179
+ link('instagram'),
180
+ link('x'),
181
+ ]);
182
+
183
+ const { model: out } = await run(
184
+ { _remove_social_link_indices: [1] },
185
+ model,
186
+ );
187
+
188
+ expect(socialIcons(out.pageFooterDesktop)).toEqual(['facebook', 'x']);
189
+ expect(socialIcons(out.pageFooterMobile)).toEqual(['facebook', 'x']);
190
+ });
191
+
192
+ it('inserts exactly one link on a shared array (symmetric add guard)', async () => {
193
+ const model = makeSharedSocialModel([link('facebook'), link('instagram')]);
194
+
195
+ const { model: out } = await run(
196
+ {
197
+ social_links: [{ insert_at: 1, social_link_icon: 'x', url: 'x.com' }],
198
+ },
199
+ model,
200
+ );
201
+
202
+ expect(socialIcons(out.pageFooterDesktop)).toEqual([
203
+ 'facebook',
204
+ 'x',
205
+ 'instagram',
206
+ ]);
207
+ expect(socialIcons(out.pageFooterMobile)).toEqual([
208
+ 'facebook',
209
+ 'x',
210
+ 'instagram',
211
+ ]);
212
+ });
213
+ });
@@ -17,6 +17,10 @@ import type { TextStyleOptions } from '../../brand-page/models/styles.model';
17
17
  import { FOOTER_CHECKS } from './section-rules/footer.rules';
18
18
  import { applyDetachedStyleOverride } from './section-field-utils';
19
19
 
20
+ type FooterSocialLink = NonNullable<
21
+ AbstractPageFooterStyles['socialLinks']
22
+ >[number];
23
+
20
24
  const normaliseSocialUrl = (url: string): string => {
21
25
  for (const prefix of ['mailto:', 'tel:']) {
22
26
  if (url.startsWith(prefix)) return url.slice(prefix.length);
@@ -25,108 +29,127 @@ const normaliseSocialUrl = (url: string): string => {
25
29
  return url;
26
30
  };
27
31
 
28
- const applyGlobalFooterChanges = (
29
- footer: AbstractPageFooterStyles,
32
+ const makeSocialLink = (
33
+ icon: string | undefined,
34
+ url: string | undefined,
35
+ ): FooterSocialLink =>
36
+ ({
37
+ imageUrl: icon || '',
38
+ url: normaliseSocialUrl(url || ''),
39
+ imageTitle: '',
40
+ width: 0,
41
+ height: 0,
42
+ imageLink: '',
43
+ }) as FooterSocialLink;
44
+
45
+ const hasSocialLinkMutation = (args: UpdateFooterArguments): boolean =>
46
+ args._replace_social_links === true ||
47
+ (args._remove_social_link_indices?.length ?? 0) > 0 ||
48
+ (args._reorder_social_links?.length ?? 0) > 0 ||
49
+ (args.social_links?.length ?? 0) > 0;
50
+
51
+ /**
52
+ * Social links are a GLOBAL footer concern — one logical list that both
53
+ * viewports render identically. Derive the new list ONCE from the current one
54
+ * WITHOUT mutating the input, so the caller can assign an independent copy to
55
+ * each viewport.
56
+ *
57
+ * Why this can't mutate per-viewport in place: footers migrated from the legacy
58
+ * single `footerStyles` model (migration-01) share ONE `socialLinks` array
59
+ * reference across pageFooterDesktop and pageFooterMobile, and `cloneDeep`
60
+ * preserves that shared reference. Running an in-place `splice` once per
61
+ * viewport therefore applies it TWICE to the same array — e.g. one requested
62
+ * removal index drops two links. Compute-once + assign-fresh is correct for
63
+ * both shared (legacy) and independent (new-model) footers.
64
+ */
65
+ const computeSocialLinks = (
66
+ current: FooterSocialLink[] | undefined,
30
67
  args: UpdateFooterArguments,
31
- textStyleOptions: TextStyleOptions | undefined,
32
- ): void => {
33
- if (args.copyright_text !== undefined)
34
- footer.copyrightText = args.copyright_text;
35
-
36
- if (args.copyright_text_font_family !== undefined)
37
- footer.copyrightStyle = applyDetachedStyleOverride(
38
- footer.copyrightStyle,
39
- { fontFamily: args.copyright_text_font_family },
40
- textStyleOptions,
68
+ ): FooterSocialLink[] => {
69
+ // _replace_social_links: replace entire list (empty/absent social_links = clear all).
70
+ // A replacement supersedes every other social link mutation.
71
+ if (args._replace_social_links) {
72
+ return (args.social_links ?? []).map((l) =>
73
+ makeSocialLink(l.social_link_icon, l.url),
41
74
  );
75
+ }
42
76
 
43
- const links = args.social_links;
77
+ const links: FooterSocialLink[] = [...(current ?? [])];
44
78
 
45
- // _replace_social_links: replace entire list (empty/absent social_links = clear all).
46
- // When replacing, all other social link mutations (remove, insert, reorder) are skipped —
47
- // they are superseded by the replacement and running them would cause duplicates.
48
- if (args._replace_social_links) {
49
- footer.socialLinks = (links ?? []).map((l) => ({
50
- imageUrl: l.social_link_icon || '',
51
- url: normaliseSocialUrl(l.url || ''),
52
- imageTitle: '',
53
- width: 0,
54
- height: 0,
55
- imageLink: '',
56
- }));
57
- } else {
58
- // Targeted mutations — only run when NOT replacing the entire list.
59
-
60
- // item_index-based updates for existing links
61
- if (links?.length) {
62
- for (const link of links) {
63
- if (link.item_index === undefined) continue;
64
-
65
- const existing = footer.socialLinks?.[link.item_index];
66
-
67
- if (!existing) continue;
68
-
69
- if (link.social_link_icon !== undefined)
70
- existing.imageUrl = link.social_link_icon;
71
-
72
- if (link.url !== undefined) existing.url = normaliseSocialUrl(link.url);
73
- }
74
- }
79
+ // item_index-based updates for existing links — replace the item reference
80
+ // (never mutate the original object, which may be shared across viewports).
81
+ for (const link of args.social_links ?? []) {
82
+ if (link.item_index === undefined) continue;
75
83
 
76
- // Remove by index (descending order to preserve indices during splice)
77
- if (args._remove_social_link_indices?.length && footer.socialLinks) {
78
- const sorted = [...args._remove_social_link_indices].sort(
79
- (a, b) => b - a,
80
- );
84
+ const existing = links[link.item_index];
81
85
 
82
- for (const idx of sorted) {
83
- if (idx >= 0 && idx < footer.socialLinks.length)
84
- footer.socialLinks.splice(idx, 1);
85
- }
86
- }
86
+ if (!existing) continue;
87
87
 
88
- // Insert new links (descending insert_at order to preserve positions during splice)
89
- const insertLinks = (links ?? []).filter(
90
- (l): l is FooterSocialLinkItem & { insert_at: number } =>
91
- l.insert_at !== undefined && l.item_index === undefined,
92
- );
93
- const sortedInserts = [...insertLinks].sort(
94
- (a, b) => b.insert_at - a.insert_at,
95
- );
88
+ links[link.item_index] = {
89
+ ...existing,
90
+ ...(link.social_link_icon !== undefined
91
+ ? { imageUrl: link.social_link_icon }
92
+ : {}),
93
+ ...(link.url !== undefined ? { url: normaliseSocialUrl(link.url) } : {}),
94
+ };
95
+ }
96
96
 
97
- for (const link of sortedInserts) {
98
- const pos = Math.max(
99
- 0,
100
- Math.min(link.insert_at, footer.socialLinks?.length ?? 0),
101
- );
102
-
103
- footer.socialLinks = footer.socialLinks ?? [];
104
- footer.socialLinks.splice(pos, 0, {
105
- imageUrl: link.social_link_icon || '',
106
- url: normaliseSocialUrl(link.url || ''),
107
- imageTitle: '',
108
- width: 0,
109
- height: 0,
110
- imageLink: '',
111
- });
97
+ // Remove by index (descending order to preserve indices during splice).
98
+ if (args._remove_social_link_indices?.length) {
99
+ const sorted = [...args._remove_social_link_indices].sort((a, b) => b - a);
100
+
101
+ for (const idx of sorted) {
102
+ if (idx >= 0 && idx < links.length) links.splice(idx, 1);
112
103
  }
104
+ }
105
+
106
+ // Insert new links (descending insert_at order to preserve positions).
107
+ const insertLinks = (args.social_links ?? []).filter(
108
+ (l): l is FooterSocialLinkItem & { insert_at: number } =>
109
+ l.insert_at !== undefined && l.item_index === undefined,
110
+ );
111
+ const sortedInserts = [...insertLinks].sort(
112
+ (a, b) => b.insert_at - a.insert_at,
113
+ );
113
114
 
114
- // Reorder (requires ALL indices — partial reorder is not supported)
115
- if (args._reorder_social_links?.length && footer.socialLinks) {
116
- const newOrder = args._reorder_social_links;
117
- const unique = new Set(newOrder);
115
+ for (const link of sortedInserts) {
116
+ const pos = Math.max(0, Math.min(link.insert_at, links.length));
117
+
118
+ links.splice(pos, 0, makeSocialLink(link.social_link_icon, link.url));
119
+ }
118
120
 
119
- if (
120
- unique.size === newOrder.length &&
121
- newOrder.every((idx) => idx >= 0 && idx < footer.socialLinks!.length)
122
- ) {
123
- const reordered = newOrder.map((idx) => footer.socialLinks![idx]);
121
+ // Reorder (requires ALL indices — partial reorder is not supported).
122
+ if (args._reorder_social_links?.length) {
123
+ const newOrder = args._reorder_social_links;
124
+ const unique = new Set(newOrder);
124
125
 
125
- if (reordered.length === footer.socialLinks.length)
126
- footer.socialLinks = reordered;
127
- }
126
+ if (
127
+ unique.size === newOrder.length &&
128
+ newOrder.every((idx) => idx >= 0 && idx < links.length)
129
+ ) {
130
+ const reordered = newOrder.map((idx) => links[idx]);
131
+
132
+ if (reordered.length === links.length) return reordered;
128
133
  }
129
134
  }
135
+
136
+ return links;
137
+ };
138
+
139
+ const applyGlobalFooterChanges = (
140
+ footer: AbstractPageFooterStyles,
141
+ args: UpdateFooterArguments,
142
+ textStyleOptions: TextStyleOptions | undefined,
143
+ ): void => {
144
+ if (args.copyright_text !== undefined)
145
+ footer.copyrightText = args.copyright_text;
146
+
147
+ if (args.copyright_text_font_family !== undefined)
148
+ footer.copyrightStyle = applyDetachedStyleOverride(
149
+ footer.copyrightStyle,
150
+ { fontFamily: args.copyright_text_font_family },
151
+ textStyleOptions,
152
+ );
130
153
  };
131
154
 
132
155
  const applyViewportFooterChanges = (
@@ -207,13 +230,30 @@ export class FooterBuilder extends BaseMetadataBuilder<UpdateFooterArguments> {
207
230
  const args = this.request.payload ?? {};
208
231
  const textStyleOptions = model.styles?.textStyles?.textStyleOptions;
209
232
 
210
- // Global fields (copyright_text, social links) always apply to both viewports.
233
+ // Global scalar/style fields (copyright text + font) apply to both
234
+ // viewports. These are idempotent assignments, safe to run per-viewport.
211
235
  if (model.pageFooterDesktop)
212
236
  applyGlobalFooterChanges(model.pageFooterDesktop, args, textStyleOptions);
213
237
 
214
238
  if (model.pageFooterMobile)
215
239
  applyGlobalFooterChanges(model.pageFooterMobile, args, textStyleOptions);
216
240
 
241
+ // Social links are a single global list. Derive the new list ONCE, then
242
+ // assign an INDEPENDENT copy to each viewport — never mutate a (possibly
243
+ // shared) viewport array in place. See computeSocialLinks.
244
+ if (hasSocialLinkMutation(args)) {
245
+ const current =
246
+ model.pageFooterDesktop?.socialLinks ??
247
+ model.pageFooterMobile?.socialLinks;
248
+ const updated = computeSocialLinks(current, args);
249
+
250
+ if (model.pageFooterDesktop)
251
+ model.pageFooterDesktop.socialLinks = updated.map((l) => ({ ...l }));
252
+
253
+ if (model.pageFooterMobile)
254
+ model.pageFooterMobile.socialLinks = updated.map((l) => ({ ...l }));
255
+ }
256
+
217
257
  // Viewport-specific styling via explicit sub-objects.
218
258
  if (args.desktop && model.pageFooterDesktop)
219
259
  applyViewportFooterChanges(model.pageFooterDesktop, args.desktop);