@designcrowd/library.brand-page 5.18.7 → 5.18.8-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 (144) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-CZmqvsOT.js → CreatedOnBrandCrowd-de-de-4K_VkRLQ.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-5nTR1eLT.js → CreatedOnBrandCrowd-en-us-n6Fd47e_.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-xLvoayrw.js → CreatedOnBrandCrowd-es-es-BcCANYX_.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-CN5n8X8v.js → CreatedOnBrandCrowd-fr-ca-qusGdhEQ.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-CN5n8X8v.js → CreatedOnBrandCrowd-fr-fr-qusGdhEQ.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-CdkYC12E.js → CreatedOnBrandCrowd-pt-br-C9IBrRc_.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-CdkYC12E.js → CreatedOnBrandCrowd-pt-pt-C9IBrRc_.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-B8rV2rD7.js → CreatedOnDcom-de-de-BY13DaXj.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-C4WaRIpF.js → CreatedOnDcom-en-us-BPc5Nacx.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-BPHPey0b.js → CreatedOnDcom-es-es-KrsweAGY.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-xrMr4xlv.js → CreatedOnDcom-fr-ca-NaPJNFZH.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-BEozL-o2.js → CreatedOnDcom-fr-fr-DjZKRox_.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-CoN-ZhjG.js → CreatedOnDcom-pt-br-xGSMGQZa.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-9vfUJ3ks.js → CreatedOnDcom-pt-pt-B7CcpJ4c.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/image-gallery/masonry/MasonryGallery.mixin.d.ts +1 -1
  20. package/lib/src/brand-page/components/mailing-list/MailingList.mixin.d.ts +4 -0
  21. package/lib/src/brand-page/components/mailing-list/MailingList.mixin.js +4 -1
  22. package/lib/src/brand-page/components/media/Media.mixin.d.ts +2 -2
  23. package/lib/src/brand-page/components/payment/request-payment/RequestPayment.mixin.d.ts +4 -0
  24. package/lib/src/brand-page/components/payment/request-payment/RequestPayment.mixin.js +4 -0
  25. package/lib/src/brand-page/components/payment/support-me/SupportMe.mixin.d.ts +4 -0
  26. package/lib/src/brand-page/components/payment/support-me/SupportMe.mixin.js +4 -1
  27. package/lib/src/brand-page/components/testimonial-section/TestimonialSection.mixin.d.ts +4 -0
  28. package/lib/src/brand-page/components/testimonial-section/TestimonialSection.mixin.js +4 -1
  29. package/lib/src/brand-page/components/video/Video.mixin.d.ts +4 -0
  30. package/lib/src/brand-page/components/video/Video.mixin.js +4 -0
  31. package/lib/src/brand-page/constants/misc.constants.d.ts +35 -0
  32. package/lib/src/brand-page/constants/misc.constants.js +51 -0
  33. package/lib/src/brand-page/models/content.model.d.ts +2 -0
  34. package/lib/src/brand-page/utils/content-padding.util.d.ts +13 -0
  35. package/lib/src/brand-page/utils/content-padding.util.js +10 -0
  36. package/lib/src/brand-page/utils/index.d.ts +1 -0
  37. package/lib/src/brand-page/utils/index.js +1 -0
  38. package/lib/src/brand-page/utils/migration/migration-17.d.ts +2 -0
  39. package/lib/src/brand-page/utils/migration/migration-17.js +54 -0
  40. package/lib/src/brand-page/utils/migration.util.js +10 -0
  41. package/lib/src/brand-page-maker/components/admin-logo-settings/AdminLogoSettings.mixin.d.ts +2 -0
  42. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +12 -0
  43. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +14 -0
  44. package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +16 -3
  45. package/lib/src/brand-page-maker/constants/config-settings-constant.js +39 -0
  46. package/lib/src/brand-page-maker/convertors/about-display-style.convertor.js +9 -1
  47. package/lib/src/brand-page-maker/convertors/banner-align-display-style.convertor.js +7 -1
  48. package/lib/src/brand-page-maker/convertors/contact-layout-style.convertor.js +6 -1
  49. package/lib/src/brand-page-maker/models/content-settings.js +38 -2
  50. package/lib/src/brand-page-maker/stores/ai-checkpoint/ai-checkpoint-store.d.ts +12 -0
  51. package/lib/src/{bundled-translations-D1q3rSEz.js → bundled-translations-BUyt4scr.js} +9 -9
  52. package/lib/src/{bundled-translations.de-DE-BxqLLwbh.js → bundled-translations.de-DE-DEw_OVai.js} +1 -1
  53. package/lib/src/{bundled-translations.es-ES-uh249NlJ.js → bundled-translations.es-ES-CFKWmkgY.js} +17 -17
  54. package/lib/src/{bundled-translations.fr-CA-BEQmv2fX.js → bundled-translations.fr-CA-DCl5LJS4.js} +1 -1
  55. package/lib/src/{bundled-translations.fr-FR-BnNuCojH.js → bundled-translations.fr-FR-B5BjgllA.js} +1 -1
  56. package/lib/src/{bundled-translations.pt-BR-CJUOxVlq.js → bundled-translations.pt-BR-5PWpMPuM.js} +1 -1
  57. package/lib/src/{bundled-translations.pt-PT-Ds9cMEqK.js → bundled-translations.pt-PT-B9_wN0HR.js} +9 -9
  58. package/lib/src/bundles/bundled-translations.de-DE.json +2 -0
  59. package/lib/src/bundles/bundled-translations.es-ES.json +2 -0
  60. package/lib/src/bundles/bundled-translations.fr-CA.json +2 -0
  61. package/lib/src/bundles/bundled-translations.fr-FR.json +2 -0
  62. package/lib/src/bundles/bundled-translations.json +2 -0
  63. package/lib/src/bundles/bundled-translations.pt-BR.json +2 -0
  64. package/lib/src/bundles/bundled-translations.pt-PT.json +2 -0
  65. package/lib/src/composables/useSnapshot.js +233 -21
  66. package/lib/src/css/library.brand-page-brandCrowd.min.css +147 -161
  67. package/lib/src/css/library.brand-page-brandPage.min.css +147 -161
  68. package/lib/src/css/library.brand-page-designCom.min.css +147 -161
  69. package/lib/src/css/library.brand-page-preview.min.css +147 -161
  70. package/lib/src/index.mjs +1 -1
  71. package/lib/src/{lib-xHNclG2R.js → lib-ClPLZIYL.js} +21178 -20848
  72. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +14 -0
  73. package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +14 -0
  74. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +12 -0
  75. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +12 -0
  76. package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.d.ts +12 -0
  77. package/lib/src/shared/content-settings/components/slider-field/SliderField.mixin.js +9 -0
  78. package/lib/src/shared/content-settings/store/content-settings-store.d.ts +12 -0
  79. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +16 -0
  80. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +14 -0
  81. package/lib/src/utils/minify-brand-page-metadata.js +11 -1
  82. package/package.json +1 -1
  83. package/src/brand-page/components/about-section/AboutSection.vue +10 -4
  84. package/src/brand-page/components/banner-section/BannerSection.vue +11 -4
  85. package/src/brand-page/components/booking-section/BookingSection.vue +11 -3
  86. package/src/brand-page/components/contact-form/ContactForm.mixin.ts +12 -6
  87. package/src/brand-page/components/contact-form/ContactForm.vue +105 -104
  88. package/src/brand-page/components/image-gallery/ImageGallery.mixin.ts +5 -0
  89. package/src/brand-page/components/image-gallery/ImageGallery.vue +1 -1
  90. package/src/brand-page/components/mailing-list/MailingList.mixin.ts +8 -1
  91. package/src/brand-page/components/mailing-list/MailingList.vue +1 -1
  92. package/src/brand-page/components/map/Map.vue +5 -1
  93. package/src/brand-page/components/payment/request-payment/RequestPayment.mixin.ts +5 -0
  94. package/src/brand-page/components/payment/request-payment/RequestPayment.vue +1 -0
  95. package/src/brand-page/components/payment/support-me/SupportMe.mixin.ts +8 -1
  96. package/src/brand-page/components/payment/support-me/SupportMe.vue +1 -0
  97. package/src/brand-page/components/shop/Shop.vue +7 -2
  98. package/src/brand-page/components/social-links/SocialLinks.vue +7 -3
  99. package/src/brand-page/components/testimonial-section/TestimonialSection.mixin.ts +7 -1
  100. package/src/brand-page/components/testimonial-section/TestimonialSection.vue +4 -6
  101. package/src/brand-page/components/text/Text.vue +12 -5
  102. package/src/brand-page/components/text-media-section/TextMediaSection.vue +11 -3
  103. package/src/brand-page/components/video/Video.mixin.ts +5 -0
  104. package/src/brand-page/components/video/Video.vue +1 -1
  105. package/src/brand-page/constants/misc.constants.ts +58 -0
  106. package/src/brand-page/models/content.model.ts +2 -0
  107. package/src/brand-page/utils/__snapshots__/migration.util.test.ts.snap +9 -3
  108. package/src/brand-page/utils/content-padding.util.test.ts +29 -0
  109. package/src/brand-page/utils/content-padding.util.ts +13 -0
  110. package/src/brand-page/utils/index.ts +1 -0
  111. package/src/brand-page/utils/migration/migration-17.ts +72 -0
  112. package/src/brand-page/utils/migration.util.test.ts +252 -0
  113. package/src/brand-page/utils/migration.util.ts +11 -0
  114. package/src/brand-page-maker/components/ai-website-builder/AiWebsiteBuilder.vue +3 -4
  115. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.vue +8 -1
  116. package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +19 -4
  117. package/src/brand-page-maker/constants/config-settings-constant.ts +45 -0
  118. package/src/brand-page-maker/convertors/about-display-style.convertor.ts +10 -0
  119. package/src/brand-page-maker/convertors/banner-align-display-style.convertor.ts +8 -0
  120. package/src/brand-page-maker/convertors/contact-layout-style.convertor.test.ts +50 -0
  121. package/src/brand-page-maker/convertors/contact-layout-style.convertor.ts +8 -0
  122. package/src/brand-page-maker/models/content-settings.ts +41 -2
  123. package/src/bundles/bundled-translations.de-DE.json +2 -0
  124. package/src/bundles/bundled-translations.es-ES.json +2 -0
  125. package/src/bundles/bundled-translations.fr-CA.json +2 -0
  126. package/src/bundles/bundled-translations.fr-FR.json +2 -0
  127. package/src/bundles/bundled-translations.json +2 -0
  128. package/src/bundles/bundled-translations.pt-BR.json +2 -0
  129. package/src/bundles/bundled-translations.pt-PT.json +2 -0
  130. package/src/composables/useSnapshot.ts +316 -31
  131. package/src/shared/content-settings/components/content-settings/i18n/content-settings.de-DE.json +2 -0
  132. package/src/shared/content-settings/components/content-settings/i18n/content-settings.es-ES.json +2 -0
  133. package/src/shared/content-settings/components/content-settings/i18n/content-settings.fr-CA.json +2 -0
  134. package/src/shared/content-settings/components/content-settings/i18n/content-settings.fr-FR.json +2 -0
  135. package/src/shared/content-settings/components/content-settings/i18n/content-settings.json +2 -0
  136. package/src/shared/content-settings/components/content-settings/i18n/content-settings.pt-BR.json +2 -0
  137. package/src/shared/content-settings/components/content-settings/i18n/content-settings.pt-PT.json +2 -0
  138. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.vue +1 -1
  139. package/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.vue +2 -2
  140. package/src/shared/content-settings/components/slider-field/SliderField.mixin.ts +9 -0
  141. package/src/utils/minify-brand-page-metadata.ts +11 -1
  142. package/lib/src/metadata-builder/builders/reorder-pages-builder.d.ts +0 -13
  143. package/lib/src/metadata-builder/builders/reorder-pages-builder.js +0 -49
  144. package/src/metadata-builder/builders/reorder-pages-builder.ts +0 -80
@@ -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,7 +35,6 @@ const { promptText } = storeToRefs(aiWebsiteBuilderThreadStore);
35
35
 
36
36
  const emit = defineEmits<{
37
37
  back: [];
38
- 'capture-preview-snapshot': [];
39
38
  }>();
40
39
 
41
40
  const {
@@ -65,10 +64,10 @@ defineExpose({
65
64
  });
66
65
 
67
66
  onMounted(() => {
67
+ // Reset any stale snapshot from a previous session. The snapshot itself is
68
+ // captured on send (see useAiWebsiteBuilderChat.sendMessageAsync), so there's
69
+ // no need for a mount-time capture here.
68
70
  snapshotStore.clearSnapshot();
69
- setTimeout(() => {
70
- emit('capture-preview-snapshot');
71
- }, 50);
72
71
  });
73
72
  </script>
74
73
  <style>
@@ -78,7 +78,10 @@
78
78
  {{ commonTr('loadingText') }}
79
79
  </p>
80
80
  </div>
81
- <AiActionButtons :is-typing="true" />
81
+ <AiActionButtons
82
+ :is-typing="true"
83
+ @stop-generation="onStopAiGeneration"
84
+ />
82
85
  </div>
83
86
  </div>
84
87
 
@@ -225,6 +228,10 @@ export default {
225
228
  brandCrowdUrl: computed(() => localisedRouteStore.localisedBaseUrl),
226
229
  isAiProcessing: computed(() => aiWebsiteBuilderThreadStore.isProcessing),
227
230
  isBrandPageLoaded: computed(() => brandPageMakerStore.isBrandPageLoaded),
231
+ // The processing overlay's STOP button lives outside the AI builder tab,
232
+ // so it stops the build via the handle the chat composable registers on
233
+ // the thread store.
234
+ onStopAiGeneration: () => aiWebsiteBuilderThreadStore.stopGeneration?.(),
228
235
  eventTracker,
229
236
  };
230
237
  },
@@ -451,9 +451,6 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
451
451
  historyStore.captureAiChangeset();
452
452
  }
453
453
 
454
- // Re-capture snapshot so subsequent messages reflect the updated page
455
- await snapshotStore.refreshSnapshotAsync();
456
-
457
454
  return {
458
455
  shouldContinue: toolResults.length > 0 && aiThreadStore.runId !== null,
459
456
  toolResults,
@@ -666,7 +663,6 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
666
663
  settled = true;
667
664
  clearTimeout(timeout);
668
665
  finishBuild();
669
- await snapshotStore.refreshSnapshotAsync();
670
666
  resolve({
671
667
  text: aiResponse.message || lastAiMessage || '',
672
668
  });
@@ -887,6 +883,25 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
887
883
  aiLogger.startGroup();
888
884
  aiLogger.log('sendMessageAsync', { messageOptions });
889
885
 
886
+ // Capture a fresh, full-page snapshot before building the request payload,
887
+ // so every turn — including the first message and any manual edits between
888
+ // turns — carries an up-to-date snapshot. Done here (after the user/typing
889
+ // bubbles are already on screen) so a slow or failed capture never delays
890
+ // or blocks the message from appearing in the thread.
891
+ //
892
+ // Best-effort: the snapshot is optional context, so a capture failure must
893
+ // never fail the AI request. Swallow any error and proceed — the pipeline
894
+ // handles a missing websiteSnapshot, and `callApiBuildAsync` already falls
895
+ // back to `undefined` when the store has no snapshot.
896
+ try {
897
+ await snapshotStore.refreshSnapshotAsync();
898
+ } catch (snapshotError) {
899
+ console.error(
900
+ 'Snapshot capture failed; sending message without it:',
901
+ snapshotError,
902
+ );
903
+ }
904
+
890
905
  const result = await callApiBuildAsync(text || '', userMessage.id);
891
906
 
892
907
  if (isStopped.value) return;
@@ -201,6 +201,34 @@ const SETTINGS_STYLE_FIElD_GROUPS = (): ContentSettingsFieldGroup[] => {
201
201
  ];
202
202
  };
203
203
 
204
+ /**
205
+ * Shared Top/Bottom padding sliders (BP-5687). Reuses the same `slider` control
206
+ * as the Divider block (track + editable number box), range 0–100, continuous.
207
+ * Spread into a block's `fields` to expose the Padding Control on that block.
208
+ * Pass the Style field-group id for blocks that use grouped panels.
209
+ */
210
+ const PADDING_CONTROL_FIELDS = (
211
+ groupId?: string,
212
+ ): {
213
+ topPadding: ContentSettingsField<Content>;
214
+ bottomPadding: ContentSettingsField<Content>;
215
+ } => ({
216
+ topPadding: {
217
+ type: 'slider',
218
+ title: contentSettingsTr(`topPaddingTitle`),
219
+ minLength: 0,
220
+ maxLength: 100,
221
+ groupId,
222
+ },
223
+ bottomPadding: {
224
+ type: 'slider',
225
+ title: contentSettingsTr(`bottomPaddingTitle`),
226
+ minLength: 0,
227
+ maxLength: 100,
228
+ groupId,
229
+ },
230
+ });
231
+
204
232
  const DEFAULT_TITLE_STYLE_SETTINGS_FILED =
205
233
  (): ContentSettingsField<Content> => ({
206
234
  type: 'text-style',
@@ -1097,6 +1125,7 @@ export const IMAGE_GALLERY_CONTENT_SETTINGS_CONFIG = (): ContentSettingsConfig<
1097
1125
  defaultValue: false,
1098
1126
  visibilityAssessor: imageGalleryFieldVisibilityAssessor,
1099
1127
  },
1128
+ ...PADDING_CONTROL_FIELDS(),
1100
1129
  },
1101
1130
  isEnabled: true,
1102
1131
  isLocked: (features) => !features.canAddImageContents,
@@ -1136,6 +1165,7 @@ export const VIDEO_CONTENT_SETTINGS_CONFIG = (): ContentSettingsConfig<
1136
1165
  label: contentSettingsTr(`muteLabel`),
1137
1166
  valueConvertor: videoContentStateConvertor,
1138
1167
  },
1168
+ ...PADDING_CONTROL_FIELDS(),
1139
1169
  },
1140
1170
  isEnabled: true,
1141
1171
  isLocked: (features) => !features.canAddVideoContents,
@@ -1278,6 +1308,7 @@ export const TEXT_CONTENT_SETTINGS_CONFIG = (): ContentSettingsConfig<
1278
1308
  variant: 'icon',
1279
1309
  visibilityAssessor: brandSiteTypeVisibilityAssessor,
1280
1310
  },
1311
+ ...PADDING_CONTROL_FIELDS(SETTINGS_STYLE_FIELD_GROUP_IDS.style),
1281
1312
  backgroundColor: {
1282
1313
  type: 'color',
1283
1314
  defaultValue: {},
@@ -1736,6 +1767,7 @@ export const MAP_CONTENT_SETTINGS_CONFIG =
1736
1767
  type: 'address',
1737
1768
  title: contentSettingsTr(`addressTitle`),
1738
1769
  },
1770
+ ...PADDING_CONTROL_FIELDS(),
1739
1771
  },
1740
1772
  isEnabled: true,
1741
1773
  isLocked: (features) => !features.canAddMapContents,
@@ -1787,6 +1819,7 @@ export const MAILING_LIST_CONTENT_SETTINGS_CONFIG =
1787
1819
  },
1788
1820
  titleStyle: DEFAULT_TITLE_STYLE_SETTINGS_FILED_WITH_TITLE(),
1789
1821
  buttonTextStyle: DEFAULT_BUTTON_TEXT_STYLE_FIELD(),
1822
+ ...PADDING_CONTROL_FIELDS(SETTINGS_STYLE_FIELD_GROUP_IDS.style),
1790
1823
  },
1791
1824
  isEnabled: true,
1792
1825
  isLocked: false,
@@ -1971,6 +2004,7 @@ export const REQUEST_PAYMENT_CONTENT_SETTINGS_CONFIG =
1971
2004
  defaultValue: {},
1972
2005
  label: contentSettingsTr(`buttonTextStyleLabel`),
1973
2006
  },
2007
+ ...PADDING_CONTROL_FIELDS(REQUEST_PAYMENT_GROUPS.style),
1974
2008
  },
1975
2009
  isEnabled: (features) => features.canAddRequestPaymentContents,
1976
2010
  isLocked: false,
@@ -2038,6 +2072,7 @@ export const SUPPORT_ME_CONTENT_SETTINGS_CONFIG =
2038
2072
  label: contentSettingsTr(`itemStyleLabel`),
2039
2073
  },
2040
2074
  buttonTextStyle: DEFAULT_BUTTON_TEXT_STYLE_FIELD(),
2075
+ ...PADDING_CONTROL_FIELDS(SETTINGS_STYLE_FIELD_GROUP_IDS.style),
2041
2076
  },
2042
2077
  isEnabled: (features) => features.canAddRequestPaymentContents,
2043
2078
  isLocked: false,
@@ -2170,6 +2205,7 @@ export const CONTACT_FORM_SETTINGS_CONFIG =
2170
2205
  variant: 'icon',
2171
2206
  visibilityAssessor: brandSiteTypeVisibilityAssessor,
2172
2207
  },
2208
+ ...PADDING_CONTROL_FIELDS(CONTACT_FORM_GROUPS.style),
2173
2209
  titleStyle: DEFAULT_TITLE_STYLE_SETTINGS_FILED_WITH_TITLE(),
2174
2210
  descriptionStyle: DEFAULT_DESCRIPTION_STYLE_FILED(),
2175
2211
  buttonTextStyle: DEFAULT_BUTTON_TEXT_STYLE_FIELD(),
@@ -2229,6 +2265,7 @@ export const BANNER_SECTION_SETTINGS_CONFIG =
2229
2265
  groupId: SETTINGS_STYLE_FIELD_GROUP_IDS.style,
2230
2266
  variant: 'icon',
2231
2267
  },
2268
+ ...PADDING_CONTROL_FIELDS(SETTINGS_STYLE_FIELD_GROUP_IDS.style),
2232
2269
  overlayColor: {
2233
2270
  type: 'color',
2234
2271
  title: contentSettingsTr(`overlayColorTitle`),
@@ -2507,6 +2544,7 @@ export const ABOUT_SECTION_SETTINGS_CONFIG =
2507
2544
  groupId: SETTINGS_STYLE_FIELD_GROUP_IDS.style,
2508
2545
  variant: 'icon',
2509
2546
  },
2547
+ ...PADDING_CONTROL_FIELDS(SETTINGS_STYLE_FIELD_GROUP_IDS.style),
2510
2548
  titleStyle: DEFAULT_TITLE_STYLE_SETTINGS_FILED_WITH_TITLE(),
2511
2549
  paragraphStyle: {
2512
2550
  type: 'text-style',
@@ -2594,6 +2632,7 @@ export const IMAGES_SECTION_SETTINGS_CONFIG =
2594
2632
  ],
2595
2633
  fields: {
2596
2634
  displayStyle: TEXT_MEDIA_DISPLAY_STYLE_FIELD(MEDIA_TYPES.image),
2635
+ ...PADDING_CONTROL_FIELDS(SETTINGS_STYLE_FIELD_GROUP_IDS.style),
2597
2636
  aspectRatio: {
2598
2637
  type: 'radio',
2599
2638
  role: 'multi',
@@ -2681,6 +2720,7 @@ export const TESTIMONIALS_SECTION_SETTINGS_CONFIG =
2681
2720
  groupId: SETTINGS_STYLE_FIELD_GROUP_IDS.style,
2682
2721
  variant: 'icon',
2683
2722
  },
2723
+ ...PADDING_CONTROL_FIELDS(SETTINGS_STYLE_FIELD_GROUP_IDS.style),
2684
2724
  title: {
2685
2725
  type: 'text',
2686
2726
  placeholder: contentSettingsTr(`titlePlaceholder`),
@@ -2793,6 +2833,7 @@ export const SOCIAL_LINKS_SETTINGS_CONFIG =
2793
2833
  optionsConvertor: socialLinksIconDisplayStyleConvertor,
2794
2834
  variant: 'icon',
2795
2835
  },
2836
+ ...PADDING_CONTROL_FIELDS(SOCIAL_LINKS_GROUPS.style),
2796
2837
  titleStyle: {
2797
2838
  type: 'text-style',
2798
2839
  groupId: SOCIAL_LINKS_GROUPS.style,
@@ -2905,6 +2946,7 @@ export const SHAPES_SECTION_SETTINGS_CONFIG =
2905
2946
  ],
2906
2947
  fields: {
2907
2948
  displayStyle: TEXT_MEDIA_DISPLAY_STYLE_FIELD(MEDIA_TYPES.shape),
2949
+ ...PADDING_CONTROL_FIELDS(SETTINGS_STYLE_FIELD_GROUP_IDS.style),
2908
2950
  size: IMAGE_SIZE_FIELD(),
2909
2951
  title: TEXT_MEDIA_TITLE_FIELD(),
2910
2952
  description: TEXT_MEDIA_DESCRIPTION_FIELD(),
@@ -2942,6 +2984,7 @@ export const SHAPES_SECTION_SETTINGS_CONFIG =
2942
2984
  ? MAX_BS_MEDIA_AND_IMAGE_ITEMS
2943
2985
  : MAX_BP_MEDIA_AND_IMAGE_ITEMS,
2944
2986
  },
2987
+ ...PADDING_CONTROL_FIELDS(SETTINGS_STYLE_FIELD_GROUP_IDS.style),
2945
2988
  },
2946
2989
  isEnabled: true,
2947
2990
  isLocked: false,
@@ -3003,6 +3046,7 @@ export const SHOP_SECTION_SETTINGS_CONFIG = (): ContentSettingsConfig<
3003
3046
  optionsConvertor: shopAspectRatioConvertor,
3004
3047
  visibilityAssessor: shopImageOptionVisibilityAssessor,
3005
3048
  },
3049
+ ...PADDING_CONTROL_FIELDS(REQUEST_PAYMENT_GROUPS.style),
3006
3050
  title: {
3007
3051
  type: 'title',
3008
3052
  groupId: REQUEST_PAYMENT_GROUPS.settings,
@@ -3166,6 +3210,7 @@ export const BOOKING_SECTION_SETTINGS_CONFIG =
3166
3210
  visibilityAssessor: (c, b) =>
3167
3211
  personalisationOverrideVisibility(c, b, 'buttonText'),
3168
3212
  },
3213
+ ...PADDING_CONTROL_FIELDS(SETTINGS_STYLE_FIELD_GROUP_IDS.style),
3169
3214
  backgroundStyle: {
3170
3215
  type: 'color',
3171
3216
  groupId: SETTINGS_STYLE_FIELD_GROUP_IDS.style,
@@ -6,6 +6,7 @@ import {
6
6
  ALIGN_RIGHT_ALIGNED,
7
7
  ALIGN_RIGHT_FULL_IMAGE,
8
8
  TEXT_ONLY,
9
+ ABOUT_DEFAULT_PADDING,
9
10
  } from '@brand-page/constants';
10
11
 
11
12
  import type { AboutSectionContent } from '@brand-page';
@@ -76,11 +77,18 @@ export const aboutDisplayStyleConvertor: ValueConvertor<
76
77
  convertBack(config: ButtonGroupConfig): Partial<AboutSectionContent> {
77
78
  const selectedOption = config.options.find((v) => v.isSelected);
78
79
 
80
+ // Switching display style adopts that style's canonical look — like the
81
+ // textAlign reset below — including its default block padding (a flat 32
82
+ // for every About style).
83
+ const padding = ABOUT_DEFAULT_PADDING;
84
+
79
85
  if (!selectedOption || selectedOption.value === ALIGN_CENTERED) {
80
86
  const textAlign = 'center';
81
87
 
82
88
  return {
83
89
  displayStyle: selectedOption?.value,
90
+ topPadding: padding,
91
+ bottomPadding: padding,
84
92
  titleStyle: {
85
93
  textAlign,
86
94
  },
@@ -94,6 +102,8 @@ export const aboutDisplayStyleConvertor: ValueConvertor<
94
102
 
95
103
  return {
96
104
  displayStyle: selectedOption?.value,
105
+ topPadding: padding,
106
+ bottomPadding: padding,
97
107
  titleStyle: {
98
108
  textAlign,
99
109
  },
@@ -15,6 +15,7 @@ import {
15
15
  ALIGN_TOP_FULL_IMAGE,
16
16
  ALIGN_BOTTOM_FULL_IMAGE,
17
17
  ALIGN_MIDDLE_FULL_IMAGE,
18
+ bannerDisplayStyleDefaultPadding,
18
19
  } from '@brand-page/constants';
19
20
  import type { BannerSectionContent } from '@brand-page';
20
21
 
@@ -172,8 +173,15 @@ export const bannerAlignDisplayStyleConvertor: ValueConvertor<
172
173
  textAlign = 'center';
173
174
  }
174
175
 
176
+ // Switching display style adopts that style's canonical look — like the
177
+ // textAlign resets above — including its default block padding. Full-bleed
178
+ // image styles default to 0 (image flush to the edges); the rest to 32.
179
+ const padding = bannerDisplayStyleDefaultPadding(selectedOption?.value);
180
+
175
181
  return {
176
182
  displayStyle: selectedOption?.value,
183
+ topPadding: padding,
184
+ bottomPadding: padding,
177
185
  titleStyle: {
178
186
  textAlign,
179
187
  },
@@ -0,0 +1,50 @@
1
+ import { describe, test, expect } from 'vitest';
2
+ import { contactLayoutStyleConvertor } from './contact-layout-style.convertor';
3
+ import {
4
+ ALIGN_CENTERED,
5
+ ALIGN_CARD_CENTER,
6
+ ALIGN_CARD_CENTER_IMAGE,
7
+ ALIGN_LEFT_FULL_IMAGE,
8
+ TEXT_ONLY,
9
+ } from '@brand-page/constants';
10
+
11
+ const configWithSelected = (selected: string) => ({
12
+ options: contactLayoutStyleConvertor
13
+ .convert(selected)
14
+ .options.map((option) => ({
15
+ ...option,
16
+ isSelected: option.value === selected,
17
+ })),
18
+ });
19
+
20
+ describe('contact-layout-style.convertor', () => {
21
+ test.each([
22
+ [ALIGN_CARD_CENTER, 32, 'center'],
23
+ [ALIGN_CENTERED, 32, 'center'],
24
+ [ALIGN_CARD_CENTER_IMAGE, 0, 'center'],
25
+ [TEXT_ONLY, 32, 'left'],
26
+ [ALIGN_LEFT_FULL_IMAGE, 0, 'left'],
27
+ ])(
28
+ 'convertBack should apply the default padding and text alignment for %s',
29
+ (layoutStyle, padding, textAlign) => {
30
+ const result = contactLayoutStyleConvertor.convertBack(
31
+ configWithSelected(layoutStyle),
32
+ );
33
+
34
+ expect(result).toStrictEqual({
35
+ layoutStyle,
36
+ topPadding: padding,
37
+ bottomPadding: padding,
38
+ titleStyle: {
39
+ textAlign,
40
+ },
41
+ descriptionStyle: {
42
+ textAlign,
43
+ },
44
+ buttonTextStyle: {
45
+ textAlign: 'center',
46
+ },
47
+ });
48
+ },
49
+ );
50
+ });
@@ -6,6 +6,7 @@ import {
6
6
  ALIGN_CARD_CENTER_IMAGE,
7
7
  TEXT_ONLY,
8
8
  ALIGN_CARD_CENTER,
9
+ CONTACT_FORM_LAYOUT_DEFAULT_PADDING,
9
10
  } from '@brand-page/constants';
10
11
  import type { ContactFormContent } from '@brand-page';
11
12
 
@@ -84,8 +85,15 @@ export const contactLayoutStyleConvertor: ValueConvertor<
84
85
  textAlign = 'left';
85
86
  }
86
87
 
88
+ // Switching layout adopts that layout's canonical look — same as the
89
+ // textAlign resets below — including its default block padding.
90
+ const padding =
91
+ CONTACT_FORM_LAYOUT_DEFAULT_PADDING[selectedOption?.value ?? ''] ?? 0;
92
+
87
93
  return {
88
94
  layoutStyle: selectedOption?.value,
95
+ topPadding: padding,
96
+ bottomPadding: padding,
89
97
  titleStyle: {
90
98
  textAlign,
91
99
  },
@@ -24,6 +24,8 @@ import {
24
24
  EMPTY_LOGO_IMAGE_MODEL,
25
25
  BRAND_PAGE_TYPES,
26
26
  SENSITIVE_CONTENT_TYPES,
27
+ CONTACT_FORM_LAYOUT_DEFAULT_PADDING,
28
+ TESTIMONIAL_DEFAULT_PADDING,
27
29
  } from '@brand-page';
28
30
  import type {
29
31
  ButtonContent,
@@ -171,6 +173,8 @@ export const createInitialImageGalleryContent = (): ImageGalleryContent => {
171
173
  galleryStyles: {
172
174
  galleryType: 'grid',
173
175
  },
176
+ topPadding: 0,
177
+ bottomPadding: 0,
174
178
  };
175
179
  };
176
180
 
@@ -182,6 +186,8 @@ export const createInitialVideoContent = (): VideoContent => {
182
186
  displayStyle: DISPLAY_STYLE_PREVIEW,
183
187
  mute: false,
184
188
  videoUrl: '',
189
+ topPadding: 0,
190
+ bottomPadding: 0,
185
191
  };
186
192
  };
187
193
 
@@ -239,6 +245,8 @@ export const createInitialTextContent = (
239
245
  ]
240
246
  : undefined,
241
247
  type: 'text',
248
+ topPadding: 12,
249
+ bottomPadding: 12,
242
250
  textSize: {
243
251
  fontSize: FONT_SIZE_BODY,
244
252
  lineHeight: LINE_HEIGHT_BODY,
@@ -282,6 +290,8 @@ export const createInitialMapContent = (): MapContent => {
282
290
  formattedAddress: '',
283
291
  placeId: '',
284
292
  },
293
+ topPadding: 0,
294
+ bottomPadding: 0,
285
295
  };
286
296
  };
287
297
 
@@ -291,6 +301,8 @@ export const createInitialMailingListContent = (
291
301
  return {
292
302
  id: uuid.v4(),
293
303
  type: 'mailing-list',
304
+ topPadding: 0,
305
+ bottomPadding: 0,
294
306
  title: contentSettingsTr(`mailingListTitle`),
295
307
  buttonText: contentSettingsTr(`subscribePlaceholder`),
296
308
  acceptedFields: 'emailOnly',
@@ -324,6 +336,8 @@ export const createInitialRequestPaymentContent = (
324
336
  successMessage: '',
325
337
  title: contentSettingsTr(`buyNowTitle`),
326
338
  type: 'request-payment',
339
+ topPadding: 0,
340
+ bottomPadding: 0,
327
341
  fillColor: {},
328
342
  defaultBorderColor: {},
329
343
  selectedBorderColor: {},
@@ -356,6 +370,8 @@ export const createInitialShopContent = (
356
370
  return {
357
371
  id: uuid.v4(),
358
372
  description: '',
373
+ topPadding: 16,
374
+ bottomPadding: 16,
359
375
  products: [],
360
376
  displayStyle: PAYMENT_OPTION_DISPLAY_TYPES.thumbnail,
361
377
  aspectRatio: PAYMENT_OPTION_IMAGE_TYPES.auto,
@@ -415,6 +431,8 @@ export const createInitialSupportMeContent = (
415
431
  successMessage: contentSettingsTr(`successSupportPlaceholder`),
416
432
  description: contentSettingsTr(`makeADonationDescription`),
417
433
  type: 'support-me',
434
+ topPadding: 0,
435
+ bottomPadding: 0,
418
436
  titleStyle: {
419
437
  applyAutoScale: options?.brandPageType === BRAND_PAGE_TYPES.brandSite,
420
438
  textStyleType: TEXT_STYLE_TYPES.headings,
@@ -453,14 +471,21 @@ export const createInitialContactFormContent: CreateInitialContentFunction<
453
471
  console.error('userState.emailAddress should not be undefined');
454
472
  }
455
473
 
474
+ // New blocks inherit the padding their initial layout previously had
475
+ // hard-coded — same source as the migration backfill for existing pages.
476
+ const layoutStyle =
477
+ options?.brandPageType === 'brandSite' ? 'center-card-aligned' : '';
478
+ const padding = CONTACT_FORM_LAYOUT_DEFAULT_PADDING[layoutStyle] ?? 0;
479
+
456
480
  return {
457
481
  id: uuid.v4(),
458
482
  title: contentSettingsTr(`contactUsTitle`),
459
483
  description: '',
460
484
  buttonText: contentSettingsTr(`sendPlaceholder`),
461
485
  displayStyle: DISPLAY_STYLE_PREVIEW,
462
- layoutStyle:
463
- options?.brandPageType === 'brandSite' ? 'center-card-aligned' : '',
486
+ layoutStyle,
487
+ topPadding: padding,
488
+ bottomPadding: padding,
464
489
  imageUrl: '',
465
490
  fields: [
466
491
  {
@@ -553,6 +578,8 @@ export const createInitialBannerSectionContent: CreateInitialContentFunction<
553
578
  > = (options?: CreateInitialContentOptions) => {
554
579
  return {
555
580
  id: uuid.v4(),
581
+ topPadding: 32,
582
+ bottomPadding: 32,
556
583
  imageUrl: '',
557
584
  title: contentSettingsTr(`thisIsABannerTitle`),
558
585
  description: '',
@@ -599,6 +626,8 @@ export const createInitialBookingSectionContent: CreateInitialContentFunction<
599
626
  buttonText: contentSettingsTr(`bookNowLabel`),
600
627
  url: '',
601
628
  type: 'booking-section',
629
+ topPadding: 32,
630
+ bottomPadding: 32,
602
631
  descriptionStyle: {
603
632
  applyAutoScale: options?.brandPageType === BRAND_PAGE_TYPES.brandSite,
604
633
  textStyleType: TEXT_STYLE_TYPES.paragraphs,
@@ -628,6 +657,8 @@ export const createInitialImagesSectionContent: CreateInitialContentFunction<
628
657
  title: contentSettingsTr(`imagesTitle`),
629
658
  description: '',
630
659
  type: 'images-section',
660
+ topPadding: 32,
661
+ bottomPadding: 32,
631
662
  displayStyle: 'centered',
632
663
  aspectRatio: 'Default',
633
664
  areImagesFullWidth: false,
@@ -683,6 +714,8 @@ export const createInitialTestimonialSectionContent: CreateInitialContentFunctio
683
714
  title: contentSettingsTr(`testimonialsTitle`),
684
715
  type: 'testimonial-section',
685
716
  displayStyle: 'centered',
717
+ topPadding: TESTIMONIAL_DEFAULT_PADDING,
718
+ bottomPadding: TESTIMONIAL_DEFAULT_PADDING,
686
719
  items: [],
687
720
  titleStyle: {
688
721
  applyAutoScale: options?.brandPageType === BRAND_PAGE_TYPES.brandSite,
@@ -731,6 +764,8 @@ export const createInitialAboutSectionContent: CreateInitialContentFunction<
731
764
  textAlign: 'center',
732
765
  },
733
766
  backgroundStyle: {},
767
+ topPadding: 32,
768
+ bottomPadding: 32,
734
769
  };
735
770
  };
736
771
 
@@ -793,6 +828,8 @@ export const createInitialSocialLinksContent = (
793
828
  return {
794
829
  id: uuid.v4(),
795
830
  type: 'social-links',
831
+ topPadding: 32,
832
+ bottomPadding: 32,
796
833
  title: contentSettingsTr(`followUsOnTitle`),
797
834
  links: [
798
835
  {
@@ -846,6 +883,8 @@ export const createInitialShapesSectionContent: CreateInitialContentFunction<
846
883
  title: contentSettingsTr(`shapesTitle`),
847
884
  description: '',
848
885
  type: 'shapes-section',
886
+ topPadding: 32,
887
+ bottomPadding: 32,
849
888
  displayStyle: 'centered',
850
889
  items: [
851
890
  {
@@ -1529,6 +1529,8 @@
1529
1529
  "iconFillColorTitle": "Farbe der Symbolfüllung",
1530
1530
  "iconBackgroundColorTitle": "Symbolhintergrundfarbe",
1531
1531
  "paddingTitle": "Polsterung",
1532
+ "topPaddingTitle": "Polsterung oben",
1533
+ "bottomPaddingTitle": "Polsterung unten",
1532
1534
  "dividerStyleTitle": "Trennlinienstil",
1533
1535
  "dividerColorTitle": "Trennlinienfarbe",
1534
1536
  "addItemTitle": "Artikel hinzufügen",
@@ -1529,6 +1529,8 @@
1529
1529
  "iconFillColorTitle": "Color de relleno del icono",
1530
1530
  "iconBackgroundColorTitle": "Color de fondo del icono",
1531
1531
  "paddingTitle": "Relleno",
1532
+ "topPaddingTitle": "Relleno superior",
1533
+ "bottomPaddingTitle": "Relleno inferior",
1532
1534
  "dividerStyleTitle": "Estilo del divisor",
1533
1535
  "dividerColorTitle": "Color del separador",
1534
1536
  "addItemTitle": "Añadir artículo",
@@ -1529,6 +1529,8 @@
1529
1529
  "iconFillColorTitle": "Couleur de remplissage de l’icône",
1530
1530
  "iconBackgroundColorTitle": "Couleur d’arrière-plan de l’icône",
1531
1531
  "paddingTitle": "Marges intérieures",
1532
+ "topPaddingTitle": "Marge intérieure supérieure",
1533
+ "bottomPaddingTitle": "Marges intérieures inférieures",
1532
1534
  "dividerStyleTitle": "Style de séparateur",
1533
1535
  "dividerColorTitle": "Couleur du séparateur",
1534
1536
  "addItemTitle": "Ajouter un article",
@@ -1529,6 +1529,8 @@
1529
1529
  "iconFillColorTitle": "Couleur de remplissage de l’icône",
1530
1530
  "iconBackgroundColorTitle": "Couleur d’arrière-plan de l’icône",
1531
1531
  "paddingTitle": "Marges intérieures",
1532
+ "topPaddingTitle": "Marges intérieures supérieures",
1533
+ "bottomPaddingTitle": "Marges intérieures inférieures",
1532
1534
  "dividerStyleTitle": "Style de séparateur",
1533
1535
  "dividerColorTitle": "Couleur du séparateur",
1534
1536
  "addItemTitle": "Ajouter un article",
@@ -1529,6 +1529,8 @@
1529
1529
  "iconFillColorTitle": "Icon fill color",
1530
1530
  "iconBackgroundColorTitle": "Icon background color",
1531
1531
  "paddingTitle": "Padding",
1532
+ "topPaddingTitle": "Top padding",
1533
+ "bottomPaddingTitle": "Bottom padding",
1532
1534
  "dividerStyleTitle": "Divider Style",
1533
1535
  "dividerColorTitle": "Divider color",
1534
1536
  "addItemTitle": "Add Item",
@@ -1529,6 +1529,8 @@
1529
1529
  "iconFillColorTitle": "Cor de preenchimento do ícone",
1530
1530
  "iconBackgroundColorTitle": "Cor de fundo do ícone",
1531
1531
  "paddingTitle": "Preenchimento",
1532
+ "topPaddingTitle": "Preenchimento superior",
1533
+ "bottomPaddingTitle": "Preenchimento inferior",
1532
1534
  "dividerStyleTitle": "Estilo do separador",
1533
1535
  "dividerColorTitle": "Cor do separador",
1534
1536
  "addItemTitle": "Adicionar item",
@@ -1529,6 +1529,8 @@
1529
1529
  "iconFillColorTitle": "Cor de preenchimento do ícone",
1530
1530
  "iconBackgroundColorTitle": "Cor de fundo do ícone",
1531
1531
  "paddingTitle": "Preenchimento",
1532
+ "topPaddingTitle": "Preenchimento superior",
1533
+ "bottomPaddingTitle": "Preenchimento inferior",
1532
1534
  "dividerStyleTitle": "Estilo do separador",
1533
1535
  "dividerColorTitle": "Cor do separador",
1534
1536
  "addItemTitle": "Adicionar Item",