@designcrowd/library.brand-page 5.18.6 → 5.18.7-ast-padding-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-DlYq1LAT.js → CreatedOnBrandCrowd-de-de-Cn8zNuGM.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-BssRIQqn.js → CreatedOnBrandCrowd-en-us-CP8xAFc-.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-BGF9pptH.js → CreatedOnBrandCrowd-es-es-Ds8NijwP.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-Caupqu2Z.js → CreatedOnBrandCrowd-fr-ca-BiVV_7lj.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-Caupqu2Z.js → CreatedOnBrandCrowd-fr-fr-BiVV_7lj.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-s9q4uJ4u.js → CreatedOnBrandCrowd-pt-br-CjjrYojo.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-s9q4uJ4u.js → CreatedOnBrandCrowd-pt-pt-CjjrYojo.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-UnYnZbA7.js → CreatedOnDcom-de-de-ChR5jvlP.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-rDv6H12L.js → CreatedOnDcom-en-us-C4rO1BMA.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-DKPLaT6o.js → CreatedOnDcom-es-es-DxGMS6JK.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-DAv34bG7.js → CreatedOnDcom-fr-ca-n31u4t7u.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-DsOHnS8q.js → CreatedOnDcom-fr-fr-gwdsX7YV.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-DpjDBCLj.js → CreatedOnDcom-pt-br-iZjFp--s.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-rFG0unf1.js → CreatedOnDcom-pt-pt-B3Z3-RLC.js} +1 -1
  15. package/lib/src/brand-page/components/contact-form/ContactForm.mixin.d.ts +4 -0
  16. package/lib/src/brand-page/components/contact-form/ContactForm.mixin.js +8 -4
  17. package/lib/src/brand-page/components/image-gallery/ImageGallery.mixin.d.ts +4 -0
  18. package/lib/src/brand-page/components/image-gallery/ImageGallery.mixin.js +4 -0
  19. package/lib/src/brand-page/components/mailing-list/MailingList.mixin.d.ts +4 -0
  20. package/lib/src/brand-page/components/mailing-list/MailingList.mixin.js +4 -1
  21. package/lib/src/brand-page/components/payment/request-payment/RequestPayment.mixin.d.ts +4 -0
  22. package/lib/src/brand-page/components/payment/request-payment/RequestPayment.mixin.js +4 -0
  23. package/lib/src/brand-page/components/payment/support-me/SupportMe.mixin.d.ts +4 -0
  24. package/lib/src/brand-page/components/payment/support-me/SupportMe.mixin.js +4 -1
  25. package/lib/src/brand-page/components/video/Video.mixin.d.ts +4 -0
  26. package/lib/src/brand-page/components/video/Video.mixin.js +4 -0
  27. package/lib/src/brand-page/constants/misc.constants.d.ts +26 -0
  28. package/lib/src/brand-page/constants/misc.constants.js +42 -0
  29. package/lib/src/brand-page/models/content.model.d.ts +2 -0
  30. package/lib/src/brand-page/utils/content-padding.util.d.ts +13 -0
  31. package/lib/src/brand-page/utils/content-padding.util.js +10 -0
  32. package/lib/src/brand-page/utils/index.d.ts +1 -0
  33. package/lib/src/brand-page/utils/index.js +1 -0
  34. package/lib/src/brand-page/utils/migration/migration-17.d.ts +2 -0
  35. package/lib/src/brand-page/utils/migration/migration-17.js +48 -0
  36. package/lib/src/brand-page/utils/migration.util.js +10 -0
  37. package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.d.ts +7 -2
  38. package/lib/src/brand-page-maker/components/admin-logo-settings/AdminLogoSettings.mixin.d.ts +2 -0
  39. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +19 -2
  40. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +8 -0
  41. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.mixin.d.ts +7 -2
  42. package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.js +1 -0
  43. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +104 -2
  44. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.js +5 -0
  45. package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.d.ts +7 -2
  46. package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +3 -0
  47. package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.js +11 -0
  48. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +7 -2
  49. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +7 -2
  50. package/lib/src/brand-page-maker/components/social-share/SocialShare.mixin.d.ts +7 -2
  51. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +7 -2
  52. package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +9 -0
  53. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +21 -1
  54. package/lib/src/brand-page-maker/composables/useEventTracker.d.ts +20 -0
  55. package/lib/src/brand-page-maker/composables/useEventTracker.js +17 -0
  56. package/lib/src/brand-page-maker/composables/useUndoRedoFlag.d.ts +17 -0
  57. package/lib/src/brand-page-maker/composables/useUndoRedoFlag.js +25 -0
  58. package/lib/src/brand-page-maker/constants/config-settings-constant.js +38 -0
  59. package/lib/src/brand-page-maker/convertors/about-display-style.convertor.js +9 -1
  60. package/lib/src/brand-page-maker/convertors/banner-align-display-style.convertor.js +7 -1
  61. package/lib/src/brand-page-maker/convertors/contact-layout-style.convertor.js +6 -1
  62. package/lib/src/brand-page-maker/models/content-settings.js +36 -2
  63. package/lib/src/brand-page-maker/stores/ai-checkpoint/ai-checkpoint-store.d.ts +12 -0
  64. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.d.ts +41 -2
  65. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +307 -5
  66. package/lib/src/brand-page-maker/stores/history/history-store.d.ts +86 -0
  67. package/lib/src/brand-page-maker/stores/history/history-store.js +501 -0
  68. package/lib/src/brand-page-maker/stores/logo-store/logo-store.d.ts +1 -0
  69. package/lib/src/brand-page-maker/stores/user/user-store.js +1 -0
  70. package/lib/src/bundled-translations-BUyt4scr.js +175 -0
  71. package/lib/src/bundled-translations.de-DE-DEw_OVai.js +175 -0
  72. package/lib/src/bundled-translations.es-ES-CFKWmkgY.js +175 -0
  73. package/lib/src/bundled-translations.fr-CA-DCl5LJS4.js +175 -0
  74. package/lib/src/bundled-translations.fr-FR-B5BjgllA.js +175 -0
  75. package/lib/src/bundled-translations.pt-BR-5PWpMPuM.js +175 -0
  76. package/lib/src/bundled-translations.pt-PT-B9_wN0HR.js +175 -0
  77. package/lib/src/bundles/bundled-translations.de-DE.json +5 -1
  78. package/lib/src/bundles/bundled-translations.es-ES.json +5 -1
  79. package/lib/src/bundles/bundled-translations.fr-CA.json +5 -1
  80. package/lib/src/bundles/bundled-translations.fr-FR.json +5 -1
  81. package/lib/src/bundles/bundled-translations.json +5 -1
  82. package/lib/src/bundles/bundled-translations.pt-BR.json +5 -1
  83. package/lib/src/bundles/bundled-translations.pt-PT.json +5 -1
  84. package/lib/src/constants/ui.d.ts +1 -0
  85. package/lib/src/css/library.brand-page-brandCrowd.min.css +128 -131
  86. package/lib/src/css/library.brand-page-brandPage.min.css +128 -132
  87. package/lib/src/css/library.brand-page-designCom.min.css +128 -131
  88. package/lib/src/css/library.brand-page-preview.min.css +128 -131
  89. package/lib/src/index.mjs +1 -1
  90. package/lib/src/{lib-ngdDRkSL.js → lib-CIj_C38s.js} +36378 -35591
  91. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +104 -2
  92. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.js +5 -0
  93. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.stories.js +1 -0
  94. package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +37 -2
  95. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +28 -0
  96. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +19 -2
  97. package/lib/src/shared/content-settings/components/draggable-item-list/DraggableItemList.mixin.d.ts +3 -0
  98. package/lib/src/shared/content-settings/components/draggable-item-list/DraggableItemList.mixin.js +19 -2
  99. package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.d.ts +12 -0
  100. package/lib/src/shared/content-settings/components/form-fields-field/FormFieldsField.mixin.js +18 -8
  101. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +67 -0
  102. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.js +6 -0
  103. package/lib/src/shared/content-settings/components/slider-field/SliderField.mixin.js +9 -0
  104. package/lib/src/shared/content-settings/store/content-settings-store.d.ts +12 -0
  105. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +19 -0
  106. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.js +11 -0
  107. package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +10 -2
  108. package/lib/src/shared/logo-settings/store/editable-logo-store.d.ts +5 -1
  109. package/lib/src/shared/logo-settings/store/editable-logo-store.js +31 -0
  110. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +40 -2
  111. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +24 -2
  112. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +23 -2
  113. package/lib/src/shared/side-bar/components/SideBarTabButton.mixin.d.ts +16 -0
  114. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +23 -2
  115. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.d.ts +16 -0
  116. package/lib/src/utils/minify-brand-page-metadata.js +11 -1
  117. package/package.json +1 -1
  118. package/src/brand-page/components/about-section/AboutSection.vue +10 -4
  119. package/src/brand-page/components/banner-section/BannerSection.vue +11 -4
  120. package/src/brand-page/components/booking-section/BookingSection.vue +11 -3
  121. package/src/brand-page/components/contact-form/ContactForm.mixin.ts +12 -6
  122. package/src/brand-page/components/contact-form/ContactForm.vue +105 -104
  123. package/src/brand-page/components/image-gallery/ImageGallery.mixin.ts +5 -0
  124. package/src/brand-page/components/image-gallery/ImageGallery.vue +1 -1
  125. package/src/brand-page/components/mailing-list/MailingList.mixin.ts +8 -1
  126. package/src/brand-page/components/mailing-list/MailingList.vue +1 -1
  127. package/src/brand-page/components/map/Map.vue +5 -1
  128. package/src/brand-page/components/payment/request-payment/RequestPayment.mixin.ts +5 -0
  129. package/src/brand-page/components/payment/request-payment/RequestPayment.vue +1 -0
  130. package/src/brand-page/components/payment/support-me/SupportMe.mixin.ts +8 -1
  131. package/src/brand-page/components/payment/support-me/SupportMe.vue +1 -0
  132. package/src/brand-page/components/shop/Shop.vue +7 -2
  133. package/src/brand-page/components/social-links/SocialLinks.vue +7 -3
  134. package/src/brand-page/components/text/Text.vue +12 -5
  135. package/src/brand-page/components/text-media-section/TextMediaSection.vue +11 -3
  136. package/src/brand-page/components/video/Video.mixin.ts +5 -0
  137. package/src/brand-page/components/video/Video.vue +1 -1
  138. package/src/brand-page/constants/misc.constants.ts +48 -0
  139. package/src/brand-page/models/content.model.ts +2 -0
  140. package/src/brand-page/utils/__snapshots__/migration.util.test.ts.snap +9 -3
  141. package/src/brand-page/utils/content-padding.util.test.ts +29 -0
  142. package/src/brand-page/utils/content-padding.util.ts +13 -0
  143. package/src/brand-page/utils/index.ts +1 -0
  144. package/src/brand-page/utils/migration/migration-17.ts +65 -0
  145. package/src/brand-page/utils/migration.util.test.ts +195 -0
  146. package/src/brand-page/utils/migration.util.ts +11 -0
  147. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +9 -0
  148. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.vue +2 -3
  149. package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.ts +1 -0
  150. package/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.ts +5 -0
  151. package/src/brand-page-maker/components/cookie-collection/CookieSettings.vue +18 -17
  152. package/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.ts +13 -0
  153. package/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.vue +26 -3
  154. package/src/brand-page-maker/components/quick-link-bar/RedoButton.vue +66 -0
  155. package/src/brand-page-maker/components/quick-link-bar/UndoButton.vue +66 -0
  156. package/src/brand-page-maker/components/quick-link-bar/i18n/quick-link-bar.de-DE.json +6 -4
  157. package/src/brand-page-maker/components/quick-link-bar/i18n/quick-link-bar.es-ES.json +6 -4
  158. package/src/brand-page-maker/components/quick-link-bar/i18n/quick-link-bar.fr-CA.json +6 -4
  159. package/src/brand-page-maker/components/quick-link-bar/i18n/quick-link-bar.fr-FR.json +6 -4
  160. package/src/brand-page-maker/components/quick-link-bar/i18n/quick-link-bar.json +3 -1
  161. package/src/brand-page-maker/components/quick-link-bar/i18n/quick-link-bar.pt-BR.json +6 -4
  162. package/src/brand-page-maker/components/quick-link-bar/i18n/quick-link-bar.pt-PT.json +6 -4
  163. package/src/brand-page-maker/components/quick-link-bar/undo-redo-buttons.test.ts +116 -0
  164. package/src/brand-page-maker/components/save-contact/SaveContact.vue +12 -19
  165. package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +10 -0
  166. package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +28 -1
  167. package/src/brand-page-maker/composables/useEventTracker.ts +29 -0
  168. package/src/brand-page-maker/composables/useUndoRedoFlag.ts +30 -0
  169. package/src/brand-page-maker/constants/config-settings-constant.ts +44 -0
  170. package/src/brand-page-maker/convertors/about-display-style.convertor.ts +10 -0
  171. package/src/brand-page-maker/convertors/banner-align-display-style.convertor.ts +8 -0
  172. package/src/brand-page-maker/convertors/contact-layout-style.convertor.test.ts +50 -0
  173. package/src/brand-page-maker/convertors/contact-layout-style.convertor.ts +8 -0
  174. package/src/brand-page-maker/models/content-settings.ts +38 -2
  175. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.test.ts +334 -0
  176. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +371 -4
  177. package/src/brand-page-maker/stores/history/history-store.test.ts +1120 -0
  178. package/src/brand-page-maker/stores/history/history-store.ts +666 -0
  179. package/src/brand-page-maker/stores/logo-store/logo-store.ts +5 -0
  180. package/src/brand-page-maker/stores/user/user-store.ts +1 -0
  181. package/src/bundles/bundled-translations.de-DE.json +5 -1
  182. package/src/bundles/bundled-translations.es-ES.json +5 -1
  183. package/src/bundles/bundled-translations.fr-CA.json +5 -1
  184. package/src/bundles/bundled-translations.fr-FR.json +5 -1
  185. package/src/bundles/bundled-translations.json +5 -1
  186. package/src/bundles/bundled-translations.pt-BR.json +5 -1
  187. package/src/bundles/bundled-translations.pt-PT.json +5 -1
  188. package/src/constants/ui.ts +1 -0
  189. package/src/shared/content-settings/components/content-settings/ContentSettings.mixin.ts +5 -0
  190. package/src/shared/content-settings/components/content-settings/ContentSettings.stories.ts +1 -0
  191. package/src/shared/content-settings/components/content-settings/i18n/content-settings.de-DE.json +2 -0
  192. package/src/shared/content-settings/components/content-settings/i18n/content-settings.es-ES.json +2 -0
  193. package/src/shared/content-settings/components/content-settings/i18n/content-settings.fr-CA.json +2 -0
  194. package/src/shared/content-settings/components/content-settings/i18n/content-settings.fr-FR.json +2 -0
  195. package/src/shared/content-settings/components/content-settings/i18n/content-settings.json +2 -0
  196. package/src/shared/content-settings/components/content-settings/i18n/content-settings.pt-BR.json +2 -0
  197. package/src/shared/content-settings/components/content-settings/i18n/content-settings.pt-PT.json +2 -0
  198. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.vue +1 -1
  199. package/src/shared/content-settings/components/draggable-item-list/DraggableItemList.mixin.ts +19 -2
  200. package/src/shared/content-settings/components/draggable-item-list/DraggableItemList.vue +1 -1
  201. package/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.vue +2 -2
  202. package/src/shared/content-settings/components/form-fields-field/FormFieldsField.mixin.ts +26 -10
  203. package/src/shared/content-settings/components/logo-selection-field/LogoSelection.vue +63 -48
  204. package/src/shared/content-settings/components/page-dropdown-field/PageDropdownField.vue +4 -0
  205. package/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.ts +7 -0
  206. package/src/shared/content-settings/components/slider-field/SliderField.mixin.ts +9 -0
  207. package/src/shared/content-settings/components/text-field/TextField.vue +1 -0
  208. package/src/shared/content-settings/components/text-image-field/TextImageField.vue +33 -4
  209. package/src/shared/logo-settings/components/EditLogoSettings.mixin.ts +11 -0
  210. package/src/shared/logo-settings/store/editable-logo-store.ts +42 -1
  211. package/src/utils/minify-brand-page-metadata.ts +11 -1
  212. package/lib/src/bundled-translations-B5Fkt3qd.js +0 -175
  213. package/lib/src/bundled-translations.de-DE-DpdVePM9.js +0 -175
  214. package/lib/src/bundled-translations.es-ES-BsIcrzZF.js +0 -175
  215. package/lib/src/bundled-translations.fr-CA-G1XCp2Qh.js +0 -175
  216. package/lib/src/bundled-translations.fr-FR-BdwLXOnB.js +0 -175
  217. package/lib/src/bundled-translations.pt-BR-Bvn5ePe7.js +0 -175
  218. package/lib/src/bundled-translations.pt-PT-CDtkb2k1.js +0 -175
@@ -292,6 +292,7 @@ exports[`migration.util > Banner Contents - text Align and Font Family should no
292
292
  "contents": [
293
293
  {
294
294
  "backgroundStyle": {},
295
+ "bottomPadding": 32,
295
296
  "buttonLinkType": "url",
296
297
  "buttonPageId": "",
297
298
  "buttonText": "Get Started",
@@ -330,6 +331,7 @@ exports[`migration.util > Banner Contents - text Align and Font Family should no
330
331
  "textAlign": "center",
331
332
  "wordBreak": "normal",
332
333
  },
334
+ "topPadding": 32,
333
335
  "type": "banner-section",
334
336
  "url": "",
335
337
  },
@@ -454,7 +456,7 @@ exports[`migration.util > Banner Contents - text Align and Font Family should no
454
456
  },
455
457
  },
456
458
  },
457
- "v": 16,
459
+ "v": 17,
458
460
  },
459
461
  "useOldLogoRenderSize": true,
460
462
  }
@@ -751,6 +753,7 @@ exports[`migration.util > migrateBrandPageModel should return brand page model w
751
753
  {
752
754
  "contents": [
753
755
  {
756
+ "bottomPadding": 12,
754
757
  "id": "bec5aca6-e3c5-4d4c-93fa-2894816a8040",
755
758
  "text": "",
756
759
  "textColor": {},
@@ -774,6 +777,7 @@ exports[`migration.util > migrateBrandPageModel should return brand page model w
774
777
  "textAlign": "center",
775
778
  "textStyleType": "paragraphs",
776
779
  },
780
+ "topPadding": 12,
777
781
  "type": "text",
778
782
  },
779
783
  ],
@@ -897,7 +901,7 @@ exports[`migration.util > migrateBrandPageModel should return brand page model w
897
901
  },
898
902
  },
899
903
  },
900
- "v": 16,
904
+ "v": 17,
901
905
  },
902
906
  "useOldLogoRenderSize": true,
903
907
  }
@@ -1194,6 +1198,7 @@ exports[`migration.util > migrateBrandPageModel should return brand page model w
1194
1198
  {
1195
1199
  "contents": [
1196
1200
  {
1201
+ "bottomPadding": 12,
1197
1202
  "id": "bec5aca6-e3c5-4d4c-93fa-2894816a8040",
1198
1203
  "text": "",
1199
1204
  "textColor": {},
@@ -1224,6 +1229,7 @@ exports[`migration.util > migrateBrandPageModel should return brand page model w
1224
1229
  "textAlign": "center",
1225
1230
  "textStyleType": "paragraphs",
1226
1231
  },
1232
+ "topPadding": 12,
1227
1233
  "type": "text",
1228
1234
  },
1229
1235
  ],
@@ -1347,7 +1353,7 @@ exports[`migration.util > migrateBrandPageModel should return brand page model w
1347
1353
  },
1348
1354
  },
1349
1355
  },
1350
- "v": 16,
1356
+ "v": 17,
1351
1357
  },
1352
1358
  "useOldLogoRenderSize": true,
1353
1359
  }
@@ -0,0 +1,29 @@
1
+ import { describe, test, expect } from 'vitest';
2
+ import { contentPaddingStyle } from './content-padding.util';
3
+
4
+ describe('content-padding.util', () => {
5
+ test('contentPaddingStyle should map stored padding to px values', () => {
6
+ expect(contentPaddingStyle({ topPadding: 53, bottomPadding: 24 })).toEqual({
7
+ paddingTop: '53px',
8
+ paddingBottom: '24px',
9
+ });
10
+ });
11
+
12
+ test('contentPaddingStyle should default missing values to 0 for content created before the field existed', () => {
13
+ expect(contentPaddingStyle({})).toEqual({
14
+ paddingTop: '0px',
15
+ paddingBottom: '0px',
16
+ });
17
+ expect(contentPaddingStyle({ topPadding: 16 })).toEqual({
18
+ paddingTop: '16px',
19
+ paddingBottom: '0px',
20
+ });
21
+ });
22
+
23
+ test('contentPaddingStyle should keep an explicit 0 rather than treating it as unset', () => {
24
+ expect(contentPaddingStyle({ topPadding: 0, bottomPadding: 0 })).toEqual({
25
+ paddingTop: '0px',
26
+ paddingBottom: '0px',
27
+ });
28
+ });
29
+ });
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Block top/bottom padding (BP-5687) as a bindable CSS style object. Defaults
3
+ * live in the data — `content-settings` for new content, a migration for
4
+ * existing — so this just reads the stored value (`?? 0` covers content from
5
+ * before the field existed).
6
+ */
7
+ export const contentPaddingStyle = (content: {
8
+ topPadding?: number;
9
+ bottomPadding?: number;
10
+ }): { paddingTop: string; paddingBottom: string } => ({
11
+ paddingTop: `${content.topPadding ?? 0}px`,
12
+ paddingBottom: `${content.bottomPadding ?? 0}px`,
13
+ });
@@ -1,4 +1,5 @@
1
1
  export * from './style.util';
2
+ export * from './content-padding.util';
2
3
  export * from './view-model.util';
3
4
  export * from './text.util';
4
5
  export * from './model.util';
@@ -0,0 +1,65 @@
1
+ import type { MigrationData } from '../migration.util';
2
+ import type { BannerSectionContent, ContactFormContent } from '../../models';
3
+ import {
4
+ CONTACT_FORM_LAYOUT_DEFAULT_PADDING,
5
+ bannerDisplayStyleDefaultPadding,
6
+ } from '../../constants';
7
+
8
+ /**
9
+ * Padding Control backfill (BP-5699 Tier 2, BP-5700 Store): blocks that already
10
+ * had hard-coded top/bottom spacing. Backfill that spacing as the block's explicit
11
+ * topPadding/bottomPadding so existing pages render unchanged once the spacing
12
+ * moves to the Padding Control sliders. Type-scoped and idempotent — only the
13
+ * listed types, and only when the value isn't already set.
14
+ */
15
+ const BLOCK_DEFAULT_PADDING: Partial<Record<string, number>> = {
16
+ text: 12,
17
+ 'images-section': 32,
18
+ 'social-links': 32,
19
+ 'shapes-section': 32,
20
+ 'booking-section': 32,
21
+ 'shop-section': 16,
22
+ 'about-section': 32,
23
+ };
24
+
25
+ export const migration17 = async (
26
+ migrationResult: MigrationData,
27
+ ): Promise<MigrationData> => {
28
+ const { brandPageModel } = migrationResult;
29
+
30
+ brandPageModel.pages.forEach((page) => {
31
+ page.contents.forEach((content) => {
32
+ // Contact Form and Banner previously varied their hard-coded spacing by
33
+ // layout/display style (full-bleed image layouts had no outer padding), so they're
34
+ // keyed by that rather than a single per-type value.
35
+ let value: number | undefined;
36
+
37
+ if (content.type === 'contact-form') {
38
+ value =
39
+ CONTACT_FORM_LAYOUT_DEFAULT_PADDING[
40
+ (content as ContactFormContent).layoutStyle ?? ''
41
+ ];
42
+ } else if (content.type === 'banner-section') {
43
+ value = bannerDisplayStyleDefaultPadding(
44
+ (content as BannerSectionContent).displayStyle,
45
+ );
46
+ } else {
47
+ value = BLOCK_DEFAULT_PADDING[content.type];
48
+ }
49
+
50
+ if (value === undefined) {
51
+ return;
52
+ }
53
+
54
+ if (content.topPadding === undefined) {
55
+ content.topPadding = value;
56
+ }
57
+
58
+ if (content.bottomPadding === undefined) {
59
+ content.bottomPadding = value;
60
+ }
61
+ });
62
+ });
63
+
64
+ return migrationResult;
65
+ };
@@ -24,6 +24,12 @@ import {
24
24
  createInitialTestimonialSectionContent,
25
25
  } from '@brand-page-maker/models';
26
26
  import {
27
+ ALIGN_CARD_CENTER_IMAGE,
28
+ ALIGN_LEFT_FULL_IMAGE,
29
+ ALIGN_RIGHT_FULL_IMAGE,
30
+ ALIGN_TOP_FULL_IMAGE,
31
+ ALIGN_BOTTOM_FULL_IMAGE,
32
+ ALIGN_MIDDLE_FULL_IMAGE,
27
33
  DEFAULT_LETTER_SPACING,
28
34
  LINE_HEIGHT_BODY,
29
35
  LINE_HEIGHT_HEADINGS,
@@ -1464,6 +1470,195 @@ describe('migration.util', () => {
1464
1470
  expect(content.layoutStyle).toBe(TEXT_ONLY);
1465
1471
  });
1466
1472
 
1473
+ test('migration17 should backfill contact form padding from its layout style', async () => {
1474
+ const model = await migrateBrandPageModel(getBsModel(), {
1475
+ isUserDraft: false,
1476
+ isServerRender: false,
1477
+ });
1478
+
1479
+ const collapsible = model.brandPageModel.pages[3]
1480
+ .contents[0] as ContactFormContent;
1481
+ const textOnly = model.brandPageModel.pages[3]
1482
+ .contents[1] as ContactFormContent;
1483
+
1484
+ expect(collapsible.topPadding).toBe(0);
1485
+ expect(collapsible.bottomPadding).toBe(0);
1486
+ expect(textOnly.topPadding).toBe(32);
1487
+ expect(textOnly.bottomPadding).toBe(32);
1488
+ });
1489
+
1490
+ test.each([
1491
+ [ALIGN_LEFT_FULL_IMAGE],
1492
+ [ALIGN_RIGHT_FULL_IMAGE],
1493
+ [ALIGN_CARD_CENTER_IMAGE],
1494
+ ])(
1495
+ 'migration17 should backfill zero padding for the %s contact form layout',
1496
+ async (layoutStyle) => {
1497
+ const brandPageModel = getBsModel();
1498
+
1499
+ (
1500
+ brandPageModel.pages[3].contents[1] as ContactFormContent
1501
+ ).layoutStyle = layoutStyle;
1502
+
1503
+ const model = await migrateBrandPageModel(brandPageModel, {
1504
+ isUserDraft: false,
1505
+ isServerRender: false,
1506
+ });
1507
+
1508
+ const content = model.brandPageModel.pages[3]
1509
+ .contents[1] as ContactFormContent;
1510
+
1511
+ expect(content.topPadding).toBe(0);
1512
+ expect(content.bottomPadding).toBe(0);
1513
+ },
1514
+ );
1515
+
1516
+ test('migration17 should not overwrite contact form padding that is already set', async () => {
1517
+ const brandPageModel = getBsModel();
1518
+
1519
+ (brandPageModel.pages[3].contents[1] as ContactFormContent).topPadding =
1520
+ 10;
1521
+
1522
+ const model = await migrateBrandPageModel(brandPageModel, {
1523
+ isUserDraft: false,
1524
+ isServerRender: false,
1525
+ });
1526
+
1527
+ const content = model.brandPageModel.pages[3]
1528
+ .contents[1] as ContactFormContent;
1529
+
1530
+ expect(content.topPadding).toBe(10);
1531
+ expect(content.bottomPadding).toBe(32);
1532
+ });
1533
+
1534
+ test('migration17 should backfill 32 padding for standard banner display styles', async () => {
1535
+ const model = await migrateBrandPageModel(getBsModel(), {
1536
+ isUserDraft: false,
1537
+ isServerRender: false,
1538
+ });
1539
+
1540
+ // pages[0].contents[0] is a 'centered' banner (standard, not full-bleed).
1541
+ const banner = model.brandPageModel.pages[0]
1542
+ .contents[0] as BannerSectionContent;
1543
+
1544
+ expect(banner.topPadding).toBe(32);
1545
+ expect(banner.bottomPadding).toBe(32);
1546
+ });
1547
+
1548
+ test.each([
1549
+ [ALIGN_LEFT_FULL_IMAGE],
1550
+ [ALIGN_RIGHT_FULL_IMAGE],
1551
+ [ALIGN_TOP_FULL_IMAGE],
1552
+ [ALIGN_BOTTOM_FULL_IMAGE],
1553
+ [ALIGN_MIDDLE_FULL_IMAGE],
1554
+ ])(
1555
+ 'migration17 should backfill zero padding for the %s full-bleed banner style',
1556
+ async (displayStyle) => {
1557
+ const brandPageModel = getBsModel();
1558
+
1559
+ (
1560
+ brandPageModel.pages[0].contents[0] as BannerSectionContent
1561
+ ).displayStyle = displayStyle;
1562
+
1563
+ const model = await migrateBrandPageModel(brandPageModel, {
1564
+ isUserDraft: false,
1565
+ isServerRender: false,
1566
+ });
1567
+
1568
+ const banner = model.brandPageModel.pages[0]
1569
+ .contents[0] as BannerSectionContent;
1570
+
1571
+ expect(banner.topPadding).toBe(0);
1572
+ expect(banner.bottomPadding).toBe(0);
1573
+ },
1574
+ );
1575
+
1576
+ test('migration17 should backfill 32 padding for standard about display styles', async () => {
1577
+ const model = await migrateBrandPageModel(getBsModel(), {
1578
+ isUserDraft: false,
1579
+ isServerRender: false,
1580
+ });
1581
+
1582
+ // pages[0].contents[2] is a 'centered' about section (standard, not full-image).
1583
+ const about = model.brandPageModel.pages[0]
1584
+ .contents[2] as AboutSectionContent;
1585
+
1586
+ expect(about.topPadding).toBe(32);
1587
+ expect(about.bottomPadding).toBe(32);
1588
+ });
1589
+
1590
+ test.each([[ALIGN_LEFT_FULL_IMAGE], [ALIGN_RIGHT_FULL_IMAGE]])(
1591
+ 'migration17 should backfill 32 padding for the %s full-image about style',
1592
+ async (displayStyle) => {
1593
+ const brandPageModel = getBsModel();
1594
+
1595
+ (
1596
+ brandPageModel.pages[0].contents[2] as AboutSectionContent
1597
+ ).displayStyle = displayStyle;
1598
+
1599
+ const model = await migrateBrandPageModel(brandPageModel, {
1600
+ isUserDraft: false,
1601
+ isServerRender: false,
1602
+ });
1603
+
1604
+ const about = model.brandPageModel.pages[0]
1605
+ .contents[2] as AboutSectionContent;
1606
+
1607
+ expect(about.topPadding).toBe(32);
1608
+ expect(about.bottomPadding).toBe(32);
1609
+ },
1610
+ );
1611
+
1612
+ test('migration17 should backfill 16 padding for the shop section', async () => {
1613
+ const oldTemplate: BrandPageModel = {
1614
+ pages: [
1615
+ {
1616
+ slug: 'shop',
1617
+ title: 'Shop',
1618
+ contents: [{ type: 'shop-section', id: 'shop-1' }],
1619
+ },
1620
+ ],
1621
+ brandPageType: 'brandSite',
1622
+ } as any;
1623
+
1624
+ const model = await migrateBrandPageModel(
1625
+ new BrandPageModel(oldTemplate),
1626
+ {
1627
+ isUserDraft: false,
1628
+ isServerRender: false,
1629
+ },
1630
+ );
1631
+ const shop = model.brandPageModel.pages[0].contents[0] as any;
1632
+
1633
+ expect(shop.topPadding).toBe(16);
1634
+ expect(shop.bottomPadding).toBe(16);
1635
+ });
1636
+
1637
+ test('migration17 should not overwrite shop padding that is already set', async () => {
1638
+ const oldTemplate: BrandPageModel = {
1639
+ pages: [
1640
+ {
1641
+ slug: 'shop',
1642
+ title: 'Shop',
1643
+ contents: [{ type: 'shop-section', id: 'shop-1', topPadding: 40 }],
1644
+ },
1645
+ ],
1646
+ brandPageType: 'brandSite',
1647
+ } as any;
1648
+
1649
+ const model = await migrateBrandPageModel(
1650
+ new BrandPageModel(oldTemplate),
1651
+ {
1652
+ isUserDraft: false,
1653
+ isServerRender: false,
1654
+ },
1655
+ );
1656
+ const shop = model.brandPageModel.pages[0].contents[0] as any;
1657
+
1658
+ expect(shop.topPadding).toBe(40);
1659
+ expect(shop.bottomPadding).toBe(16);
1660
+ });
1661
+
1467
1662
  test('migrateNewLogoLogic should migrate logoDraftToken and logoVariation', () => {
1468
1663
  const oldTemplate: BrandPageData = {
1469
1664
  pages: [
@@ -19,6 +19,7 @@ import { migration13 } from './migration/migration-13';
19
19
  import { migration14 } from './migration/migration-14';
20
20
  import { migration15 } from './migration/migration-15';
21
21
  import { migration16 } from './migration/migration-16';
22
+ import { migration17 } from './migration/migration-17';
22
23
 
23
24
  export interface MigrationData {
24
25
  brandPageModel: BrandPageModel;
@@ -149,6 +150,16 @@ const MIGRATION_TABLE = [
149
150
  description:
150
151
  'Default sub nav background color to color match on for TAB_2 and hamburger navs depending on font color only on first load flow',
151
152
  },
153
+ {
154
+ version: 17,
155
+ migrateFn: migration17,
156
+ // runAlways: re-apply on every load (ticket stack) so already-migrated pages
157
+ // pick up newly-added block defaults (e.g. Store) without a new migration.
158
+ // Idempotent — only backfills when topPadding/bottomPadding aren't already set.
159
+ runAlways: true,
160
+ description:
161
+ 'Padding Control backfill (BP-5699 Tier 2 + BP-5700 Store): backfill existing top/bottom spacing as explicit padding for text (12px), images/social links/shapes/booking (32px), store (16px), contact form (per layout), banner and about (per display style)',
162
+ },
152
163
  ] as MigrationTableItem[];
153
164
 
154
165
  export const GetLatestModelVersion = () =>
@@ -35,6 +35,8 @@ import {
35
35
  useSnapshotStore,
36
36
  useVideoStore,
37
37
  } from '@brand-page-maker/stores';
38
+ import { useHistoryStore } from '@brand-page-maker/stores/history/history-store';
39
+ import { useUndoRedoFlag } from '@brand-page-maker/composables/useUndoRedoFlag';
38
40
  import type { AdminPreviewLogoTemplateModel } from '@brand-page-maker/stores/admin-logo-settings';
39
41
  import { useUiContentSettingsStore } from '@shared/content-settings/store';
40
42
  import { useUiTemplateSettingsStore } from '@shared/template-settings/store';
@@ -283,6 +285,13 @@ export default defineComponent({
283
285
  // Mark brand page as fully loaded
284
286
  this.brandPageMakerStore.setIsBrandPageLoaded(true);
285
287
 
288
+ // Capture baseline for undo/redo when the feature is active for this
289
+ // session — see useUndoRedoFlag.ts for the gate (LaunchDarkly flag +
290
+ // brand-site + non-admin maker).
291
+ if (useUndoRedoFlag().value) {
292
+ useHistoryStore().captureBaseline();
293
+ }
294
+
286
295
  this.$emit(EVENTS.Initialised);
287
296
  },
288
297
  mounted() {
@@ -23,7 +23,6 @@
23
23
  >
24
24
  <div class="tw-flex tw-flex-col tw-w-full tw-h-full">
25
25
  <QuickLinkBar
26
- v-if="isPublished && !isAdmin"
27
26
  class="c-quick-link-bar"
28
27
  :brand-page-base-url="brandPageBaseUrl"
29
28
  :slug="brandPageSlug"
@@ -87,8 +86,8 @@
87
86
  v-if="isBrandPageLoaded"
88
87
  :is-mobile-device="isMobileDevice"
89
88
  :is-design-com="isDesignCom"
90
- :has-quick-links="isPublished"
91
89
  :container="previewContainer"
90
+ :has-quick-links="isPublished"
92
91
  >
93
92
  <div ref="previewContent" class="tw-h-full">
94
93
  <PreviewWithState :device-mode="deviceMode" />
@@ -123,9 +122,9 @@
123
122
  </div>
124
123
 
125
124
  <SideBar
126
- :has-quick-links="isPublished"
127
125
  :mobile-tab-name="SideBarTabNames.PREVIEW"
128
126
  :is-mobile-screen-size="isMobileScreenSize"
127
+ :has-quick-links="isPublished"
129
128
  >
130
129
  <template #tab>
131
130
  <component
@@ -90,6 +90,7 @@ export const userFeatures: UserFeatures = {
90
90
  canUseGettyVideos: false,
91
91
  canUseGoogleAdsense: false,
92
92
  googleAdsenseEnabled: false,
93
+ canUseUndoRedo: false,
93
94
  };
94
95
 
95
96
  export const BRAND_PAGE: BrandPageData = {
@@ -36,6 +36,7 @@ import {
36
36
  import { useExternalRichTextEditor } from '@brand-page-maker/composables/rich-text-editor/useRichTextEditor';
37
37
  import { useUiStyleSettingsStore } from '@shared/style-settings/store';
38
38
  import { STYLE_THEME_KEYS } from '@brand-page/constants';
39
+ import { useHistoryStore } from '@brand-page-maker/stores/history/history-store';
39
40
 
40
41
  export default defineComponent({
41
42
  mixins: [PageMixin],
@@ -51,6 +52,7 @@ export default defineComponent({
51
52
  const eventTracker = useEventTracker();
52
53
  const { externalEditor } = useExternalRichTextEditor();
53
54
  const styleSettingsStore = useUiStyleSettingsStore();
55
+ const historyStore = useHistoryStore();
54
56
 
55
57
  return {
56
58
  items: computed(() => contentSettingsStore.items),
@@ -84,6 +86,7 @@ export default defineComponent({
84
86
  eventTracker,
85
87
  externalEditor,
86
88
  styleSettingsStore,
89
+ historyStore,
87
90
  };
88
91
  },
89
92
  data() {
@@ -301,6 +304,8 @@ export default defineComponent({
301
304
  }
302
305
  }
303
306
 
307
+ // RTE rewrap on section selection — fold into current head.
308
+ this.historyStore.mergeNextMutation();
304
309
  transformToRTE(
305
310
  this.pageSettingsStore,
306
311
  this.externalEditor,
@@ -20,14 +20,14 @@
20
20
  </div>
21
21
  <Toggle
22
22
  id="show-cookie-banner"
23
- :model-value="data.isToggled"
23
+ :model-value="isToggled"
24
24
  class="tw-pointer-events-none tw-touch-none"
25
25
  color="primary"
26
26
  @update:model-value="onShowCookieBanner()"
27
27
  />
28
28
  </div>
29
29
  </div>
30
- <div v-if="data.isToggled" class="tw-flex-none tw-mt-4">
30
+ <div v-if="isToggled" class="tw-flex-none tw-mt-4">
31
31
  <div
32
32
  class="tw-flex tw-items-center tw-justify-between tw-cursor-pointer"
33
33
  @click="onShowPreviewCookieBanner"
@@ -41,7 +41,7 @@
41
41
  </div>
42
42
  <Toggle
43
43
  id="show-preview-cookie-banner"
44
- :model-value="data.isPreviewToggled"
44
+ :model-value="isPreviewToggled"
45
45
  class="tw-pointer-events-none tw-touch-none"
46
46
  color="primary"
47
47
  @update:model-value="onShowPreviewCookieBanner()"
@@ -55,10 +55,10 @@
55
55
  import { Toggle } from '@designcrowd/fe-shared-lib';
56
56
  import { cookieSettingTr } from '@src/composables/useTranslate';
57
57
  import type { CookieOptions } from '@brand-page/models';
58
- import { reactive, type PropType } from 'vue';
58
+ import { computed, type PropType } from 'vue';
59
59
  import { useBrandPageMakerStore } from '@brand-page-maker/stores';
60
60
 
61
- const props = defineProps({
61
+ defineProps({
62
62
  viewModel: {
63
63
  type: Object as PropType<CookieOptions>,
64
64
  required: true,
@@ -67,25 +67,26 @@ const props = defineProps({
67
67
 
68
68
  const brandPageMakerStore = useBrandPageMakerStore();
69
69
 
70
- const data = reactive({
71
- isToggled: props.viewModel.isCookieEnabled,
72
- isPreviewToggled: props.viewModel.isCookiePreviewEnabled,
73
- });
70
+ // Read directly from the store so undo/redo (and any other external
71
+ // mutation of cookieOptions) is reflected in the toggles.
72
+ const isToggled = computed(
73
+ () => brandPageMakerStore.cookieOptions.isCookieEnabled,
74
+ );
75
+ const isPreviewToggled = computed(
76
+ () => brandPageMakerStore.cookieOptions.isCookiePreviewEnabled,
77
+ );
74
78
 
75
79
  const onShowCookieBanner = () => {
76
- data.isToggled = !data.isToggled;
77
- brandPageMakerStore.setCookieEnabled({
78
- isCookieEnabled: data.isToggled,
79
- });
80
- data.isPreviewToggled = data.isToggled;
80
+ const next = !isToggled.value;
81
+
82
+ brandPageMakerStore.setCookieEnabled({ isCookieEnabled: next });
81
83
  brandPageMakerStore.setCookiePreviewEnabled({
82
- isCookiePreviewEnabled: data.isPreviewToggled,
84
+ isCookiePreviewEnabled: next,
83
85
  });
84
86
  };
85
87
  const onShowPreviewCookieBanner = () => {
86
- data.isPreviewToggled = !data.isPreviewToggled;
87
88
  brandPageMakerStore.setCookiePreviewEnabled({
88
- isCookiePreviewEnabled: data.isPreviewToggled,
89
+ isCookiePreviewEnabled: !isPreviewToggled.value,
89
90
  });
90
91
  };
91
92
  </script>
@@ -4,6 +4,7 @@ import {
4
4
  useBrandPageContainerStore,
5
5
  useEventManagerStore,
6
6
  } from '@brand-page-maker/stores';
7
+ import { useUndoRedoFlag } from '@brand-page-maker/composables/useUndoRedoFlag';
7
8
  import { quickLinkBarTr } from '@src/composables/useTranslate';
8
9
 
9
10
  export default defineComponent({
@@ -21,6 +22,7 @@ export default defineComponent({
21
22
  return {
22
23
  brandPageContainerStore: useBrandPageContainerStore(),
23
24
  eventManagerStore: useEventManagerStore(),
25
+ undoRedoEnabled: useUndoRedoFlag(),
24
26
  };
25
27
  },
26
28
  data() {
@@ -29,6 +31,17 @@ export default defineComponent({
29
31
  };
30
32
  },
31
33
  computed: {
34
+ isPublished(): boolean {
35
+ return this.brandPageContainerStore.isPublished;
36
+ },
37
+
38
+ // Only render the bar when at least one inner cluster has something to
39
+ // show. Otherwise we'd render an empty white strip — e.g. on an
40
+ // unpublished page with the undo flag off.
41
+ shouldShowBar(): boolean {
42
+ return Boolean(this.undoRedoEnabled) || this.isPublished;
43
+ },
44
+
32
45
  brandPageUrl(): string {
33
46
  if (
34
47
  this.brandPageContainerStore.isCustomDomainEnabled &&
@@ -1,10 +1,24 @@
1
1
  <template>
2
2
  <div
3
+ v-if="shouldShowBar"
3
4
  data-component="quick-link-bar"
4
5
  class="c-quick-links tw-w-full tw-flex-none tw-bg-white md:tw-h-12 tw-border-b tw-border-grayscale-500 tw-px-2 lg:tw-px-4 tw-box-border tw-flex tw-items-center tw-text-grayscale-800 tw-fixed lg:tw-static"
5
6
  >
6
- <p
7
- class="tw-flex tw-items-center tw-justify-between lg:tw-justify-center tw-w-full"
7
+ <!-- Left slot: Undo/Redo buttons. Always rendered for layout balance
8
+ (flex-1 reserves equal space on left and right) so the center
9
+ cluster stays geometrically centered in the bar regardless of
10
+ whether the buttons are visible. -->
11
+ <div class="tw-flex tw-flex-1 tw-justify-start tw-gap-1">
12
+ <template v-if="undoRedoEnabled">
13
+ <UndoButton />
14
+ <RedoButton />
15
+ </template>
16
+ </div>
17
+
18
+ <!-- Center cluster: URL label, link, copy button -->
19
+ <div
20
+ v-if="isPublished"
21
+ class="tw-flex tw-items-center tw-gap-2 tw-justify-center"
8
22
  >
9
23
  <strong class="tw-font-semibold tw-hidden xl:tw-inline-block">
10
24
  {{ quickLinkBarTr('myWebPageLabel') }}
@@ -27,7 +41,12 @@
27
41
  }"
28
42
  @on-click.stop="onCopyClick"
29
43
  />
30
- </p>
44
+ </div>
45
+
46
+ <!-- Right spacer: balances the left slot so the center cluster is
47
+ geometrically centered. -->
48
+ <div class="tw-flex-1" />
49
+
31
50
  <textarea ref="textarea" :value="brandPageUrl" class="tw-sr-only" />
32
51
  </div>
33
52
  </template>
@@ -35,10 +54,14 @@
35
54
  import QuickLinkBarMixin from './QuickLinkBar.mixin.ts';
36
55
  import { Button } from '@designcrowd/fe-shared-lib';
37
56
  import { quickLinkBarTr } from '@src/composables/useTranslate';
57
+ import UndoButton from './UndoButton.vue';
58
+ import RedoButton from './RedoButton.vue';
38
59
 
39
60
  export default {
40
61
  components: {
41
62
  Button,
63
+ UndoButton,
64
+ RedoButton,
42
65
  },
43
66
  mixins: [QuickLinkBarMixin],
44
67
  setup(props, context) {