@designcrowd/library.brand-page 5.19.1-id-based-items-2 → 5.19.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 (116) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-Ruu5Az32.js → CreatedOnBrandCrowd-de-de-Ekmn0O3s.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-DGUJtvld.js → CreatedOnBrandCrowd-en-us-BjeXlKTS.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-Dg-1uOfV.js → CreatedOnBrandCrowd-es-es-rpNINAMY.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-CRKraZl8.js → CreatedOnBrandCrowd-fr-ca-BL4nSaLj.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-CRKraZl8.js → CreatedOnBrandCrowd-fr-fr-BL4nSaLj.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-bZ9VlEAu.js → CreatedOnBrandCrowd-pt-br-K0r4FyYq.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-bZ9VlEAu.js → CreatedOnBrandCrowd-pt-pt-K0r4FyYq.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-CJYfwZx8.js → CreatedOnDcom-de-de-0XYyEKYc.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-rzA1lVxH.js → CreatedOnDcom-en-us-E8hvwiMd.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-CNwGPjik.js → CreatedOnDcom-es-es-pRuCd7xX.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-DKw7OGIz.js → CreatedOnDcom-fr-ca-Bu4V3jpn.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-WzOEaAZG.js → CreatedOnDcom-fr-fr-CCcrGNz2.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-DkualVhm.js → CreatedOnDcom-pt-br-1GTvaLKd.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-w4Nnsdzq.js → CreatedOnDcom-pt-pt-CTIYW10X.js} +1 -1
  15. package/lib/src/brand-page/components/image-gallery/masonry/MasonryGallery.mixin.d.ts +1 -1
  16. package/lib/src/brand-page/models/index.d.ts +1 -12
  17. package/lib/src/brand-page/models/index.js +3 -0
  18. package/lib/src/brand-page/utils/personalisation.util.js +72 -14
  19. package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.d.ts +1 -1
  20. package/lib/src/brand-page-maker/components/admin-background-settings/AdminBackgroundSettings.mixin.d.ts +6 -0
  21. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +12 -1
  22. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +2 -0
  23. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.stories.js +1 -0
  24. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.mixin.d.ts +1 -1
  25. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +1 -1
  26. package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.d.ts +1 -1
  27. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +1 -1
  28. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +1 -1
  29. package/lib/src/brand-page-maker/components/social-share/SocialShare.mixin.d.ts +1 -1
  30. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +2 -3
  31. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.js +16 -5
  32. package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +0 -5
  33. package/lib/src/brand-page-maker/stores/ai-checkpoint/ai-checkpoint-store.d.ts +6 -18
  34. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.d.ts +1 -0
  35. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.js +3 -0
  36. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.d.ts +3 -1
  37. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +5 -1
  38. package/lib/src/brand-page-maker/stores/ui/ui-store.d.ts +6 -0
  39. package/lib/src/brand-page-maker/stores/ui/ui-store.js +8 -0
  40. package/lib/src/clients/design-template-client.d.ts +3 -0
  41. package/lib/src/clients/models.d.ts +2 -0
  42. package/lib/src/css/library.brand-page-brandCrowd.min.css +19 -7
  43. package/lib/src/css/library.brand-page-brandPage.min.css +19 -7
  44. package/lib/src/css/library.brand-page-designCom.min.css +19 -7
  45. package/lib/src/css/library.brand-page-preview.min.css +19 -7
  46. package/lib/src/index.mjs +1 -1
  47. package/lib/src/{lib-Dy7MYyqz.js → lib-BfgUqu0B.js} +25060 -24791
  48. package/lib/src/metadata-builder/builders/footer-builder.js +44 -34
  49. package/lib/src/metadata-builder/builders/section-builders/image-gallery-builder.js +68 -57
  50. package/lib/src/metadata-builder/builders/section-builders/images-section-builder.js +93 -58
  51. package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.js +99 -66
  52. package/lib/src/metadata-builder/builders/section-builders/social-links-builder.js +17 -57
  53. package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.js +85 -51
  54. package/lib/src/metadata-builder/builders/section-builders/text-section-builder.js +74 -49
  55. package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +4 -13
  56. package/lib/src/metadata-builder/parsers/section-tool-arguments.d.ts +48 -66
  57. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +1 -1
  58. package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +1 -1
  59. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +7 -1
  60. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +9 -0
  61. package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +1 -1
  62. package/lib/src/shared/logo-versions/LogoVersions.mixin.d.ts +6 -0
  63. package/lib/src/shared/models.d.ts +2 -0
  64. package/lib/src/shared/my-designs/MyDesigns.mixin.d.ts +6 -0
  65. package/lib/src/shared/my-uploads/MyMedia.mixin.d.ts +6 -0
  66. package/lib/src/shared/my-uploads/MyUploads.mixin.d.ts +6 -0
  67. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +7 -3
  68. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +7 -3
  69. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +1 -1
  70. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +7 -1
  71. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.d.ts +10 -439
  72. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.js +2 -2
  73. package/lib/src/shared/template-settings/models.d.ts +1 -0
  74. package/lib/src/shared/template-settings/store/template-settings-store.d.ts +4 -0
  75. package/lib/src/shared/template-settings/store/template-settings-store.js +79 -11
  76. package/lib/src/shared/unsplash-library/UnsplashLibrary.mixin.d.ts +6 -0
  77. package/lib/src/utils/minify-brand-page-metadata.d.ts +0 -2
  78. package/lib/src/utils/minify-brand-page-metadata.js +1 -8
  79. package/package.json +1 -1
  80. package/src/brand-page/components/image-gallery/masonry/MasonryGallery.mixin.ts +1 -2
  81. package/src/brand-page/models/index.ts +4 -12
  82. package/src/brand-page/utils/__snapshots__/migration.util.test.ts.snap +3 -0
  83. package/src/brand-page/utils/__snapshots__/migration2.util.test.ts.snap +1 -0
  84. package/src/brand-page/utils/__snapshots__/model.util.test.ts.snap +2 -0
  85. package/src/brand-page/utils/personalisation.util.test.ts +35 -0
  86. package/src/brand-page/utils/personalisation.util.ts +119 -23
  87. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +4 -0
  88. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.stories.ts +1 -0
  89. package/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.ts +22 -8
  90. package/src/brand-page-maker/components/template-preview/TemplatePreview.vue +5 -10
  91. package/src/brand-page-maker/components/template-preview/TemplatePreviewAiBadge.vue +12 -0
  92. package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +0 -6
  93. package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.ts +5 -0
  94. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +10 -0
  95. package/src/brand-page-maker/stores/ui/ui-store.ts +16 -0
  96. package/src/clients/design-template-client.ts +3 -0
  97. package/src/clients/models.ts +2 -0
  98. package/src/metadata-builder/builders/footer-builder.test.ts +0 -298
  99. package/src/metadata-builder/builders/footer-builder.ts +65 -56
  100. package/src/metadata-builder/builders/section-builders/image-gallery-builder.ts +88 -62
  101. package/src/metadata-builder/builders/section-builders/images-section-builder.ts +129 -66
  102. package/src/metadata-builder/builders/section-builders/shapes-section-builder.ts +160 -105
  103. package/src/metadata-builder/builders/section-builders/social-links-builder.ts +20 -65
  104. package/src/metadata-builder/builders/section-builders/testimonial-section-builder.ts +146 -83
  105. package/src/metadata-builder/builders/section-builders/text-section-builder.ts +122 -70
  106. package/src/metadata-builder/parsers/ai-toolcall-parser.ts +4 -13
  107. package/src/metadata-builder/parsers/section-tool-arguments.ts +48 -66
  108. package/src/shared/models.ts +6 -0
  109. package/src/shared/template-settings/components/TemplatesSettings.mixin.ts +2 -2
  110. package/src/shared/template-settings/models.ts +1 -0
  111. package/src/shared/template-settings/store/template-settings-store.ts +105 -18
  112. package/src/utils/minify-brand-page-metadata.ts +2 -14
  113. package/lib/src/metadata-builder/builders/item-id-utils.d.ts +0 -54
  114. package/lib/src/metadata-builder/builders/item-id-utils.js +0 -96
  115. package/src/metadata-builder/builders/item-id-utils.test.ts +0 -184
  116. package/src/metadata-builder/builders/item-id-utils.ts +0 -117
@@ -1,5 +1,5 @@
1
1
  import { openBlock as e, createElementBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-Dy7MYyqz.js";
2
+ import { _ as t } from "./lib-BfgUqu0B.js";
3
3
  const i = {}, h = {
4
4
  width: "275",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as e, createElementBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-Dy7MYyqz.js";
2
+ import { _ as t } from "./lib-BfgUqu0B.js";
3
3
  const i = {}, h = {
4
4
  width: "251",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as e, createElementBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-Dy7MYyqz.js";
2
+ import { _ as t } from "./lib-BfgUqu0B.js";
3
3
  const i = {}, h = {
4
4
  width: "250",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as e, createElementBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-Dy7MYyqz.js";
2
+ import { _ as t } from "./lib-BfgUqu0B.js";
3
3
  const i = {}, h = {
4
4
  width: "237",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as e, createElementBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-Dy7MYyqz.js";
2
+ import { _ as t } from "./lib-BfgUqu0B.js";
3
3
  const i = {}, h = {
4
4
  width: "237",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as e, createElementBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-Dy7MYyqz.js";
2
+ import { _ as t } from "./lib-BfgUqu0B.js";
3
3
  const i = {}, h = {
4
4
  width: "263",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as e, createElementBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-Dy7MYyqz.js";
2
+ import { _ as t } from "./lib-BfgUqu0B.js";
3
3
  const i = {}, h = {
4
4
  width: "263",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as H, createElementBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as e } from "./lib-Dy7MYyqz.js";
2
+ import { _ as e } from "./lib-BfgUqu0B.js";
3
3
  const M = {}, Z = {
4
4
  width: "242",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as H, createElementBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as e } from "./lib-Dy7MYyqz.js";
2
+ import { _ as e } from "./lib-BfgUqu0B.js";
3
3
  const i = {}, M = {
4
4
  width: "231",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as H, createElementBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as e } from "./lib-Dy7MYyqz.js";
2
+ import { _ as e } from "./lib-BfgUqu0B.js";
3
3
  const M = {}, Z = {
4
4
  width: "230",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as H, createElementBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as e } from "./lib-Dy7MYyqz.js";
2
+ import { _ as e } from "./lib-BfgUqu0B.js";
3
3
  const i = {}, l = {
4
4
  width: "216",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as H, createElementBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as e } from "./lib-Dy7MYyqz.js";
2
+ import { _ as e } from "./lib-BfgUqu0B.js";
3
3
  const i = {}, l = {
4
4
  width: "216",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as H, createElementBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as M } from "./lib-Dy7MYyqz.js";
2
+ import { _ as M } from "./lib-BfgUqu0B.js";
3
3
  const Z = {}, e = {
4
4
  width: "232",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as H, createElementBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as M } from "./lib-Dy7MYyqz.js";
2
+ import { _ as M } from "./lib-BfgUqu0B.js";
3
3
  const Z = {}, e = {
4
4
  width: "232",
5
5
  height: "36",
@@ -3,7 +3,7 @@ import type { PropType } from 'vue';
3
3
  import type { ImageGalleryViewModel } from '../../../view-models';
4
4
  import type { DebounceHandle } from 'lodash.debounce';
5
5
  import type { BrandPageContext, ImageGalleryItem } from '../../../models';
6
- interface IndexedImageGalleryItem extends Omit<ImageGalleryItem, 'id'> {
6
+ interface IndexedImageGalleryItem extends ImageGalleryItem {
7
7
  id: number;
8
8
  }
9
9
  declare const _default: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
@@ -110,13 +110,6 @@ export interface ImageContent extends Content {
110
110
  height?: number;
111
111
  }
112
112
  export interface ImageItem {
113
- /**
114
- * Stable per-item identifier. Mirrors the section-level `Content.id` one
115
- * level deeper so AI tool calls can reference items by id rather than by
116
- * positional index. Optional for backward compatibility with persisted data
117
- * that predates item ids — backfilled on load (see ensureItemIds).
118
- */
119
- id?: string;
120
113
  imageUrl: string;
121
114
  imageTitle: string;
122
115
  width: number;
@@ -318,8 +311,6 @@ export interface ShapeItem extends ImageItem {
318
311
  paragraphOverride?: string;
319
312
  }
320
313
  export interface TestimonialItems {
321
- /** Stable per-item identifier. See ImageItem.id. */
322
- id?: string;
323
314
  imageUrl: string;
324
315
  name: string;
325
316
  position: string;
@@ -334,8 +325,6 @@ export interface TestimonialItems {
334
325
  positionOverride?: string;
335
326
  }
336
327
  export interface TextItem {
337
- /** Stable per-item identifier. See ImageItem.id. */
338
- id?: string;
339
328
  text: string;
340
329
  textStyle: TextStyleDeclaration;
341
330
  textOverride?: string;
@@ -396,7 +385,6 @@ export interface AboutSectionContent extends Content {
396
385
  size?: string;
397
386
  }
398
387
  export interface LinksItem {
399
- id?: string;
400
388
  imageUrl: string;
401
389
  url: string;
402
390
  size?: string;
@@ -559,6 +547,7 @@ export interface SaveContactOptions {
559
547
  }
560
548
  export declare class BrandPageModel {
561
549
  v: number;
550
+ userPromptContentKey?: string;
562
551
  styles: PageStyles;
563
552
  /** @deprecated */
564
553
  headerStyles?: AbstractPageHeaderStyles;
@@ -400,6 +400,9 @@ export class PageFooterMobile extends AbstractPageFooterStyles {
400
400
  export class BrandPageModel {
401
401
  // Model version
402
402
  v;
403
+ // AI personalisation key persisted with the draft so previews survive login/checkout-back/
404
+ // refresh - content is retrieved by this token (user-agnostic), not regenerated (bp-5742).
405
+ userPromptContentKey;
403
406
  styles;
404
407
  /** @deprecated */
405
408
  headerStyles;
@@ -206,15 +206,59 @@ const getPersonalisationValueAsync = async (section, property) => {
206
206
  }
207
207
  return { value: propertyValue, section };
208
208
  };
209
+ // The userPrompt AI content generation only populates these content-bearing sections
210
+ // (see GenerateAiDesignMakerContentService / GenerateWebsiteContentService - About,
211
+ // Information, Profile, Media). Sections like email/website/phone are never generated, so
212
+ // blocks whose role points at an ungenerated section fall back to this pool.
213
+ const PERSONALISATION_FALLBACK_ROLES = [
214
+ 'profile',
215
+ 'about',
216
+ 'information',
217
+ 'media',
218
+ ];
219
+ // "Effectively empty" = no renderable content (ungenerated userPrompt sections like
220
+ // email/website/phone). A section that has data but lacks one property is NOT empty - it
221
+ // intentionally keeps its original content.
222
+ const isSectionEffectivelyEmpty = (section) => {
223
+ if (!section) {
224
+ return true;
225
+ }
226
+ return (!section.title &&
227
+ !section.name &&
228
+ !section.url &&
229
+ !section.description &&
230
+ !section.descriptionShort &&
231
+ !section.ctaTitle &&
232
+ !section.imageUrls?.length &&
233
+ !section.shapes?.length &&
234
+ !section.items?.length &&
235
+ !section.mainShapesCollection?.tall?.length &&
236
+ !section.mainShapesCollection?.square?.length &&
237
+ !section.mainShapesCollection?.wide?.length);
238
+ };
239
+ // Resolve a property from a specific role's section. Returns null when that section is
240
+ // ungenerated (effectively empty) or cannot supply the property, so the caller can try the
241
+ // next role.
242
+ const resolvePersonalisationValueForRoleAsync = async (role, property, personalisation) => {
243
+ const key = `${role}Section`;
244
+ const section = personalisation[key];
245
+ if (isSectionEffectivelyEmpty(section)) {
246
+ return null;
247
+ }
248
+ const { value, section: updatedSection, valuesToUpdate, } = await getPersonalisationValueAsync(section, property);
249
+ if (value === undefined || value === null) {
250
+ return null;
251
+ }
252
+ return {
253
+ value,
254
+ personalisation: { ...personalisation, [key]: updatedSection },
255
+ valuesToUpdate,
256
+ };
257
+ };
209
258
  const getPersonalisationValueFromPropertyAsync = async (propertyKey, propertyValue, personalisationRole, personalisationOverride, personalisation, contentType) => {
210
259
  if (!personalisationRole || personalisationOverride === 'none') {
211
260
  return { value: undefined, personalisation };
212
261
  }
213
- const matchingValue = Object.entries(personalisation).find(([key]) => key === `${personalisationRole}Section`);
214
- if (!matchingValue) {
215
- return { value: undefined, personalisation };
216
- }
217
- const section = matchingValue[1];
218
262
  const mapping = getPersonalisationMappingForContentType(contentType);
219
263
  const matchingProperty = Object.entries(mapping).find(([, value]) => value.includes(propertyKey));
220
264
  if (!matchingProperty) {
@@ -225,15 +269,29 @@ const getPersonalisationValueFromPropertyAsync = async (propertyKey, propertyVal
225
269
  brandPageType: personalisation.type,
226
270
  isSvgShape: typeof propertyValue === 'string' && propertyValue.endsWith('.svg'),
227
271
  });
228
- const { value, section: updatedSection, valuesToUpdate, } = await getPersonalisationValueAsync(section, property);
229
- return {
230
- value,
231
- personalisation: {
232
- ...personalisation,
233
- [`${personalisationRole}Section`]: updatedSection,
234
- },
235
- valuesToUpdate,
236
- };
272
+ const primaryKey = `${personalisationRole}Section`;
273
+ const primarySection = personalisation[primaryKey];
274
+ // When the block's own section has content, use it as-is - this preserves existing
275
+ // behaviour, including legitimately keeping the original when that section lacks a
276
+ // specific property (e.g. no items, or an invalid shape).
277
+ if (!isSectionEffectivelyEmpty(primarySection)) {
278
+ const { value, section: updatedSection, valuesToUpdate, } = await getPersonalisationValueAsync(primarySection, property);
279
+ return {
280
+ value,
281
+ personalisation: { ...personalisation, [primaryKey]: updatedSection },
282
+ valuesToUpdate,
283
+ };
284
+ }
285
+ // The block's section was never generated - fall back to the first populated section that
286
+ // can supply this property, so it doesn't render the "should be AI generated" placeholder.
287
+ // Never reached when the section exists (above) or all are populated (AI Website Builder).
288
+ for (const role of PERSONALISATION_FALLBACK_ROLES) {
289
+ const resolved = await resolvePersonalisationValueForRoleAsync(role, property, personalisation);
290
+ if (resolved) {
291
+ return resolved;
292
+ }
293
+ }
294
+ return { value: undefined, personalisation };
237
295
  };
238
296
  const applyPersonalisationToBrandPageContentsRecursiveAsync = async (personalisation, mappingType, content, personalisationRole) => {
239
297
  let isApplied = false;
@@ -127,7 +127,7 @@ declare const _default: import("vue").DefineComponent<{}, {
127
127
  brandPageType: "default" | "brandSite" | "brandContact";
128
128
  }): void;
129
129
  initialiseStoresByBrandPageModelAsync(brandPageModel: import("@brand-page/models").BrandPageModel): Promise<void>;
130
- initialise({ brandPage, brandPageType, logoDraftDesignAttributes, unsplashApplicationName, templateCategories, personalisationData, isPersonalisationEnabled, businessName, industry, layout, logoVariationImageUrls, shopConfigData, isServerRenderOverride, }: import("@brand-page-maker/stores").InitialisePayload): Promise<void>;
130
+ initialise({ brandPage, brandPageType, logoDraftDesignAttributes, unsplashApplicationName, templateCategories, personalisationData, isPersonalisationEnabled, userPromptContentKey, showAiTemplatesTab, businessName, industry, layout, logoVariationImageUrls, shopConfigData, isServerRenderOverride, }: import("@brand-page-maker/stores").InitialisePayload): Promise<void>;
131
131
  initialisePages({ pages, sections, }: {
132
132
  pages: import("@brand-page/models").PageModel[];
133
133
  sections: import("../../../shared/page-settings/store").PageSettingsStateSections;
@@ -251,6 +251,12 @@ declare const _default: import("vue").DefineComponent<{}, {
251
251
  setUserPersonalisationData({ personalisationData, }: {
252
252
  personalisationData: import("../../../brand-page").UserPersonalisationContent[];
253
253
  }): void;
254
+ setUserPromptContentKey({ userPromptContentKey, }: {
255
+ userPromptContentKey: string | undefined;
256
+ }): void;
257
+ setShowAiTemplatesTab({ showAiTemplatesTab, }: {
258
+ showAiTemplatesTab: boolean;
259
+ }): void;
254
260
  onBackgroundChanged(): void;
255
261
  onContentChanged(): void;
256
262
  onStyleChanged(): void;
@@ -20,6 +20,8 @@ export interface BrandPageMakerViewModel {
20
20
  initialCategories: InitialCategories;
21
21
  personalisation?: UserPersonalisationContent[];
22
22
  isPersonalisationEnabled?: boolean;
23
+ userPromptContentKey?: string;
24
+ showAiTemplatesTab?: boolean;
23
25
  brandPageType?: BrandPageType;
24
26
  businessName?: string;
25
27
  industry?: string;
@@ -172,7 +174,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
172
174
  brandPageType: "default" | "brandSite" | "brandContact";
173
175
  }): void;
174
176
  initialiseStoresByBrandPageModelAsync(brandPageModel: import("@brand-page").BrandPageModel): Promise<void>;
175
- initialise({ brandPage, brandPageType, logoDraftDesignAttributes, unsplashApplicationName, templateCategories, personalisationData, isPersonalisationEnabled, businessName, industry, layout, logoVariationImageUrls, shopConfigData, isServerRenderOverride, }: import("@brand-page-maker/stores").InitialisePayload): Promise<void>;
177
+ initialise({ brandPage, brandPageType, logoDraftDesignAttributes, unsplashApplicationName, templateCategories, personalisationData, isPersonalisationEnabled, userPromptContentKey, showAiTemplatesTab, businessName, industry, layout, logoVariationImageUrls, shopConfigData, isServerRenderOverride, }: import("@brand-page-maker/stores").InitialisePayload): Promise<void>;
176
178
  initialisePages({ pages, sections, }: {
177
179
  pages: import("@brand-page").PageModel[];
178
180
  sections: import("@shared/page-settings/store").PageSettingsStateSections;
@@ -953,6 +955,12 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
953
955
  setUserPersonalisationData({ personalisationData, }: {
954
956
  personalisationData: UserPersonalisationContent[];
955
957
  }): void;
958
+ setUserPromptContentKey({ userPromptContentKey, }: {
959
+ userPromptContentKey: string | undefined;
960
+ }): void;
961
+ setShowAiTemplatesTab({ showAiTemplatesTab, }: {
962
+ showAiTemplatesTab: boolean;
963
+ }): void;
956
964
  onBackgroundChanged(): void;
957
965
  onContentChanged(): void;
958
966
  onStyleChanged(): void;
@@ -1099,6 +1107,9 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
1099
1107
  initialSearchTerm: string;
1100
1108
  onSearchTermChanged?: import("@shared/template-settings/store").OnSearchTermChangedCallback | undefined;
1101
1109
  }): void;
1110
+ setAiTemplateKeywords(payload: {
1111
+ aiTemplateKeywords: string;
1112
+ }): void;
1102
1113
  notifySearchTermChanged(searchTerm: string | undefined): void;
1103
1114
  clearTemplates(): void;
1104
1115
  getTemplateByTemplateId(id: string): import("@shared/template-settings/models").TemplateSettingsTemplate | undefined;
@@ -150,6 +150,8 @@ export default defineComponent({
150
150
  templateCategories: this.viewModel.templateCategories,
151
151
  personalisationData: this.viewModel.personalisation,
152
152
  isPersonalisationEnabled: this.viewModel.isPersonalisationEnabled || false,
153
+ userPromptContentKey: this.viewModel.userPromptContentKey,
154
+ showAiTemplatesTab: this.viewModel.showAiTemplatesTab || false,
153
155
  brandPageType: this.viewModel.brandPageType,
154
156
  businessName: this.viewModel.businessName,
155
157
  industry: this.viewModel.industry,
@@ -179,6 +179,7 @@ const InitialiseMakerStores = (options) => {
179
179
  isContextualUpgradeModalVisible: false,
180
180
  gettyVideos: [],
181
181
  templateSearchTerm: undefined,
182
+ aiTemplateKeywords: undefined,
182
183
  });
183
184
  userStore.setUserState({
184
185
  isAdmin: options.isAdmin,
@@ -116,7 +116,7 @@ declare const _default: import("vue").DefineComponent<{}, {
116
116
  brandPageType: "default" | "brandSite" | "brandContact";
117
117
  }): void;
118
118
  initialiseStoresByBrandPageModelAsync(brandPageModel: import("../../../lib").BrandPageModel): Promise<void>;
119
- initialise({ brandPage, brandPageType, logoDraftDesignAttributes, unsplashApplicationName, templateCategories, personalisationData, isPersonalisationEnabled, businessName, industry, layout, logoVariationImageUrls, shopConfigData, isServerRenderOverride, }: import("../../stores").InitialisePayload): Promise<void>;
119
+ initialise({ brandPage, brandPageType, logoDraftDesignAttributes, unsplashApplicationName, templateCategories, personalisationData, isPersonalisationEnabled, userPromptContentKey, showAiTemplatesTab, businessName, industry, layout, logoVariationImageUrls, shopConfigData, isServerRenderOverride, }: import("../../stores").InitialisePayload): Promise<void>;
120
120
  initialisePages({ pages, sections, }: {
121
121
  pages: import("../../../lib").PageModel[];
122
122
  sections: import("../../../shared/page-settings/store").PageSettingsStateSections;
@@ -636,7 +636,7 @@ declare const _default: import("vue").DefineComponent<{}, {
636
636
  brandPageType: "default" | "brandSite" | "brandContact";
637
637
  }): void;
638
638
  initialiseStoresByBrandPageModelAsync(brandPageModel: import("@brand-page").BrandPageModel): Promise<void>;
639
- initialise({ brandPage, brandPageType, logoDraftDesignAttributes, unsplashApplicationName, templateCategories, personalisationData, isPersonalisationEnabled, businessName, industry, layout, logoVariationImageUrls, shopConfigData, isServerRenderOverride, }: import("@brand-page-maker/stores").InitialisePayload): Promise<void>;
639
+ initialise({ brandPage, brandPageType, logoDraftDesignAttributes, unsplashApplicationName, templateCategories, personalisationData, isPersonalisationEnabled, userPromptContentKey, showAiTemplatesTab, businessName, industry, layout, logoVariationImageUrls, shopConfigData, isServerRenderOverride, }: import("@brand-page-maker/stores").InitialisePayload): Promise<void>;
640
640
  initialisePages({ pages, sections, }: {
641
641
  pages: import("@brand-page").PageModel[];
642
642
  sections: import("@shared/page-settings/store").PageSettingsStateSections;
@@ -122,7 +122,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
122
122
  brandPageType: "default" | "brandSite" | "brandContact";
123
123
  }): void;
124
124
  initialiseStoresByBrandPageModelAsync(brandPageModel: import("../../../brand-page").BrandPageModel): Promise<void>;
125
- initialise({ brandPage, brandPageType, logoDraftDesignAttributes, unsplashApplicationName, templateCategories, personalisationData, isPersonalisationEnabled, businessName, industry, layout, logoVariationImageUrls, shopConfigData, isServerRenderOverride, }: import("@brand-page-maker/stores").InitialisePayload): Promise<void>;
125
+ initialise({ brandPage, brandPageType, logoDraftDesignAttributes, unsplashApplicationName, templateCategories, personalisationData, isPersonalisationEnabled, userPromptContentKey, showAiTemplatesTab, businessName, industry, layout, logoVariationImageUrls, shopConfigData, isServerRenderOverride, }: import("@brand-page-maker/stores").InitialisePayload): Promise<void>;
126
126
  initialisePages({ pages, sections, }: {
127
127
  pages: import("../../../brand-page").PageModel[];
128
128
  sections: import("../../../shared/page-settings/store").PageSettingsStateSections;
@@ -400,7 +400,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
400
400
  brandPageType: "default" | "brandSite" | "brandContact";
401
401
  }): void;
402
402
  initialiseStoresByBrandPageModelAsync(brandPageModel: import("../../../brand-page").BrandPageModel): Promise<void>;
403
- initialise({ brandPage, brandPageType, logoDraftDesignAttributes, unsplashApplicationName, templateCategories, personalisationData, isPersonalisationEnabled, businessName, industry, layout, logoVariationImageUrls, shopConfigData, isServerRenderOverride, }: import("@brand-page-maker/stores").InitialisePayload): Promise<void>;
403
+ initialise({ brandPage, brandPageType, logoDraftDesignAttributes, unsplashApplicationName, templateCategories, personalisationData, isPersonalisationEnabled, userPromptContentKey, showAiTemplatesTab, businessName, industry, layout, logoVariationImageUrls, shopConfigData, isServerRenderOverride, }: import("@brand-page-maker/stores").InitialisePayload): Promise<void>;
404
404
  initialisePages({ pages, sections, }: {
405
405
  pages: import("../../../brand-page").PageModel[];
406
406
  sections: import("../../../shared/page-settings/store").PageSettingsStateSections;
@@ -401,7 +401,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
401
401
  brandPageType: "default" | "brandSite" | "brandContact";
402
402
  }): void;
403
403
  initialiseStoresByBrandPageModelAsync(brandPageModel: import("../../../brand-page").BrandPageModel): Promise<void>;
404
- initialise({ brandPage, brandPageType, logoDraftDesignAttributes, unsplashApplicationName, templateCategories, personalisationData, isPersonalisationEnabled, businessName, industry, layout, logoVariationImageUrls, shopConfigData, isServerRenderOverride, }: import("@brand-page-maker/stores").InitialisePayload): Promise<void>;
404
+ initialise({ brandPage, brandPageType, logoDraftDesignAttributes, unsplashApplicationName, templateCategories, personalisationData, isPersonalisationEnabled, userPromptContentKey, showAiTemplatesTab, businessName, industry, layout, logoVariationImageUrls, shopConfigData, isServerRenderOverride, }: import("@brand-page-maker/stores").InitialisePayload): Promise<void>;
405
405
  initialisePages({ pages, sections, }: {
406
406
  pages: import("../../../brand-page").PageModel[];
407
407
  sections: import("../../../shared/page-settings/store").PageSettingsStateSections;
@@ -132,7 +132,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
132
132
  brandPageType: "default" | "brandSite" | "brandContact";
133
133
  }): void;
134
134
  initialiseStoresByBrandPageModelAsync(brandPageModel: import("../../../brand-page").BrandPageModel): Promise<void>;
135
- initialise({ brandPage, brandPageType, logoDraftDesignAttributes, unsplashApplicationName, templateCategories, personalisationData, isPersonalisationEnabled, businessName, industry, layout, logoVariationImageUrls, shopConfigData, isServerRenderOverride, }: import("@brand-page-maker/stores").InitialisePayload): Promise<void>;
135
+ initialise({ brandPage, brandPageType, logoDraftDesignAttributes, unsplashApplicationName, templateCategories, personalisationData, isPersonalisationEnabled, userPromptContentKey, showAiTemplatesTab, businessName, industry, layout, logoVariationImageUrls, shopConfigData, isServerRenderOverride, }: import("@brand-page-maker/stores").InitialisePayload): Promise<void>;
136
136
  initialisePages({ pages, sections, }: {
137
137
  pages: import("../../../brand-page").PageModel[];
138
138
  sections: import("../../../shared/page-settings/store").PageSettingsStateSections;
@@ -1,7 +1,7 @@
1
1
  /// <reference types="types/lodash-shims" />
2
2
  import type { PropType } from 'vue';
3
3
  import type { BrandPageContext, BrandPageViewModel, LogoImageModel, LogoTemplateImageModel, LogoTheme, UserPersonalisation } from '@brand-page';
4
- import { type TemplateSettingsTemplate } from '@shared/template-settings/models';
4
+ import type { TemplateSettingsTemplate } from '@shared/template-settings/models';
5
5
  import type { DebounceHandle } from 'lodash.debounce';
6
6
  interface TemplatePreviewData {
7
7
  containerStyle: BrandPageCssStyle;
@@ -68,7 +68,6 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
68
68
  isAdmin: import("vue").ComputedRef<boolean>;
69
69
  userToken: import("vue").ComputedRef<string | undefined>;
70
70
  isBrandSite: import("vue").ComputedRef<boolean>;
71
- selectedTab: import("vue").ComputedRef<string>;
72
71
  renderAsImage: import("vue").ComputedRef<boolean>;
73
72
  brandPageMakerUserStore: import("pinia").Store<"brandPageMakerUser", import("@brand-page-maker/stores").UserState, {}, {
74
73
  setUserState(payload: {
@@ -452,7 +451,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
452
451
  brandPageType: "default" | "brandSite" | "brandContact";
453
452
  }): void;
454
453
  initialiseStoresByBrandPageModelAsync(brandPageModel: import("@brand-page").BrandPageModel): Promise<void>;
455
- initialise({ brandPage, brandPageType, logoDraftDesignAttributes, unsplashApplicationName, templateCategories, personalisationData, isPersonalisationEnabled, businessName, industry, layout, logoVariationImageUrls, shopConfigData, isServerRenderOverride, }: import("@brand-page-maker/stores").InitialisePayload): Promise<void>;
454
+ initialise({ brandPage, brandPageType, logoDraftDesignAttributes, unsplashApplicationName, templateCategories, personalisationData, isPersonalisationEnabled, userPromptContentKey, showAiTemplatesTab, businessName, industry, layout, logoVariationImageUrls, shopConfigData, isServerRenderOverride, }: import("@brand-page-maker/stores").InitialisePayload): Promise<void>;
456
455
  initialisePages({ pages, sections, }: {
457
456
  pages: import("@brand-page").PageModel[];
458
457
  sections: import("../../../shared/page-settings/store").PageSettingsStateSections;
@@ -2,7 +2,6 @@ import { computed, defineComponent } from 'vue';
2
2
  import { BRAND_PAGE_TYPES, MEDIA_SIZES, VIEWPORTS } from '@brand-page';
3
3
  import { applyLogoThemeToBrandPageModel, applyUserPersonalisationToBrandPageModelAsync, getBrandPageViewModelFromBrandPageModel, } from '@brand-page/utils';
4
4
  import { STYLE_THEME_KEYS } from '@brand-page/constants';
5
- import { TEMPLATE_TABS, } from '@shared/template-settings/models';
6
5
  import debounce from 'lodash.debounce';
7
6
  import { MOBILE_HEIGHT, MOBILE_WIDTH } from '@brand-page-maker/constants';
8
7
  import { useBrandPageContainerStore, useBrandPageMakerStore, useBrandPageMakerUserStore, } from '@brand-page-maker/stores';
@@ -24,7 +23,6 @@ export default defineComponent({
24
23
  isAdmin: computed(() => brandPageMakerUserStore.isAdmin),
25
24
  userToken: computed(() => brandPageMakerUserStore.userToken),
26
25
  isBrandSite: computed(() => brandPageMakerStore.brandPageType === BRAND_PAGE_TYPES.brandSite),
27
- selectedTab: computed(() => templateSettingsStore.selectedTab.key),
28
26
  renderAsImage: computed(() => templateSettingsStore.renderAsImage),
29
27
  brandPageMakerUserStore,
30
28
  brandPageContainerStore,
@@ -171,11 +169,24 @@ export default defineComponent({
171
169
  if (!previewImageUrl) {
172
170
  return '';
173
171
  }
174
- if (this.selectedTab === TEMPLATE_TABS.AI && this.template.contentKey) {
175
- if (this.userToken) {
176
- previewImageUrl += `&contentKey=${this.template.contentKey}&userToken=${this.userToken}`;
172
+ const isAlreadyPersonalised = previewImageUrl.includes('contentKey=') ||
173
+ previewImageUrl.includes('userPromptContentKey=');
174
+ if (this.isPersonalisable &&
175
+ this.template.contentKey &&
176
+ !isAlreadyPersonalised) {
177
+ if (this.userToken && !this.template.usesUserPromptContentKey) {
178
+ previewImageUrl += `&contentKey=${this.template.contentKey}`;
179
+ // The backend already bakes userToken into brand-site preview URLs. Only add
180
+ // it when missing - two userToken params parse as an array and the preview
181
+ // renderer rejects it ("userToken must be a string type") (bp-5765).
182
+ if (!previewImageUrl.includes('userToken=')) {
183
+ previewImageUrl += `&userToken=${this.userToken}`;
184
+ }
177
185
  }
178
186
  else {
187
+ // userPromptContentKey resolves from the userPrompt S3 bucket (real AI images).
188
+ // Post-purchase designs with a userPrompt key route here too, NOT through the
189
+ // userToken/regular-bucket branch above which holds placeholders (bp-5454).
179
190
  previewImageUrl += `&userPromptContentKey=${this.template.contentKey}`;
180
191
  }
181
192
  }
@@ -5,7 +5,6 @@ import { parseLogoThemeToCssStyles } from '../../../brand-page/utils/style.util'
5
5
  import { AI_ASSISTANT_TOOL_NAMES } from '../../../metadata-builder/parsers/ai-toolcall-parser';
6
6
  import { WebSocketGatewayClient, } from '../../../clients/websocket-gateway-client';
7
7
  import { minifyBrandPageMetadata } from '../../../utils/minify-brand-page-metadata';
8
- import { ensureBrandPageItemIds } from '../../../metadata-builder/builders/item-id-utils';
9
8
  import { buildAssetManifest } from '../../../utils/build-asset-manifest';
10
9
  import { usePageNavigationStore } from '../../../shared/page-navigation/store/page-navigation-store';
11
10
  import { navigateToPageByPageId } from '../../routing';
@@ -178,10 +177,6 @@ export function useAiWebsiteBuilderChat() {
178
177
  };
179
178
  const buildMessagePayload = async (userPrompt) => {
180
179
  const brandPageData = brandPageMakerStore.brandPageData;
181
- // BP-5603: stamp stable uuid ids onto every nested item BEFORE minifying,
182
- // so the id the AI is shown (and returns as `item_id`) is the exact id the
183
- // executor matches when applying tool calls to this same live model.
184
- ensureBrandPageItemIds(brandPageData);
185
180
  const headerLogoDraftToken = brandPageData.pageHeaderDesktop?.logoImage?.logoDraftToken ??
186
181
  uiStore.logoDraftToken;
187
182
  const [assets, logoContext] = await Promise.all([