@designcrowd/library.brand-page 5.16.2 → 5.16.3-background-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 (87) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-Oj_ab97C.js → CreatedOnBrandCrowd-de-de-CKV5OfpA.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-GsCBx_Vo.js → CreatedOnBrandCrowd-en-us-CVeOIfuY.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-CWp_kHxD.js → CreatedOnBrandCrowd-es-es-Bky5jrsA.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-DrPrFgKC.js → CreatedOnBrandCrowd-fr-ca-vf78sk3H.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-DrPrFgKC.js → CreatedOnBrandCrowd-fr-fr-vf78sk3H.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-BgvbBOFa.js → CreatedOnBrandCrowd-pt-br-DhowdxCT.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-BgvbBOFa.js → CreatedOnBrandCrowd-pt-pt-DhowdxCT.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-BZRXmSAH.js → CreatedOnDcom-de-de-VM5ItYJf.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-D_xjisVj.js → CreatedOnDcom-en-us-josxNhmK.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-CJzkN8Oq.js → CreatedOnDcom-es-es-DiKAwjGC.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-C5ilNf57.js → CreatedOnDcom-fr-ca-BGELaNHY.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-CZypZWWq.js → CreatedOnDcom-fr-fr-3ReXfgyD.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-JZXunSWT.js → CreatedOnDcom-pt-br-QziCI0TB.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-CjL1qKnl.js → CreatedOnDcom-pt-pt-BJwKSkn3.js} +1 -1
  15. package/lib/src/brand-page/components/page/Page.mixin.js +20 -15
  16. package/lib/src/brand-page/components/page/Page.stories.js +2 -2
  17. package/lib/src/brand-page/models/index.d.ts +1 -0
  18. package/lib/src/brand-page/models/index.js +2 -0
  19. package/lib/src/brand-page/utils/migration/migration-07.js +1 -1
  20. package/lib/src/brand-page/utils/view-model.util.d.ts +2 -1
  21. package/lib/src/brand-page/utils/view-model.util.js +27 -2
  22. package/lib/src/brand-page/view-models.d.ts +17 -2
  23. package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.d.ts +3 -0
  24. package/lib/src/brand-page-maker/components/admin-background-settings/AdminBackgroundSettings.mixin.d.ts +7 -2
  25. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +4 -0
  26. package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.d.ts +3 -0
  27. package/lib/src/brand-page-maker/components/preview/Preview.stories.js +2 -2
  28. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +244 -1
  29. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.js +68 -4
  30. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +9 -1
  31. package/lib/src/brand-page-maker/stores/user/user-store.d.ts +4 -0
  32. package/lib/src/brand-page-maker/stores/user/user-store.js +4 -0
  33. package/lib/src/bundled-translations-DEk3SiLd.js +161 -0
  34. package/lib/src/bundles/bundled-translations.json +3 -1
  35. package/lib/src/clients/design-template-client.d.ts +1 -0
  36. package/lib/src/clients/models.d.ts +1 -0
  37. package/lib/src/css/library.brand-page-brandCrowd.min.css +48 -20
  38. package/lib/src/css/library.brand-page-brandPage.min.css +48 -20
  39. package/lib/src/css/library.brand-page-designCom.min.css +48 -20
  40. package/lib/src/css/library.brand-page-preview.min.css +48 -20
  41. package/lib/src/index.mjs +1 -1
  42. package/lib/src/{lib-BCV7U_Bf.js → lib-DMBCLH_G.js} +13306 -13120
  43. package/lib/src/shared/background-settings/components/background-shapes/BackgroundShapeSettings.mixin.d.ts +10 -2
  44. package/lib/src/shared/background-settings/store/background-settings-store.d.ts +3 -0
  45. package/lib/src/shared/background-settings/store/background-settings-store.js +40 -2
  46. package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +3 -0
  47. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +26 -0
  48. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.js +6 -1
  49. package/lib/src/shared/content-settings/components/image-field/ImageField.mixin.js +3 -1
  50. package/lib/src/shared/content-settings/components/page-dropdown-field/PageDropdownField.mixin.d.ts +3 -0
  51. package/lib/src/shared/page-settings/components/delete-page-modal/DeletePageModal.mixin.d.ts +1 -1
  52. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +3 -0
  53. package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +3 -0
  54. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +5 -0
  55. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.d.ts +1 -0
  56. package/lib/src/shared/template-settings/models.d.ts +2 -0
  57. package/lib/src/shared/template-settings/store/template-settings-store.d.ts +6 -0
  58. package/lib/src/shared/template-settings/store/template-settings-store.js +109 -35
  59. package/package.json +1 -1
  60. package/src/brand-page/components/page/Page.mixin.ts +24 -15
  61. package/src/brand-page/components/page/Page.stories.ts +2 -1
  62. package/src/brand-page/components/page/Page.vue +18 -3
  63. package/src/brand-page/models/index.ts +3 -0
  64. package/src/brand-page/utils/__snapshots__/migration.util.test.ts.snap +3 -0
  65. package/src/brand-page/utils/__snapshots__/migration2.util.test.ts.snap +1 -0
  66. package/src/brand-page/utils/__snapshots__/model.util.test.ts.snap +2 -0
  67. package/src/brand-page/utils/migration/migration-07.ts +6 -4
  68. package/src/brand-page/utils/view-model.util.ts +42 -2
  69. package/src/brand-page/view-models.ts +23 -1
  70. package/src/brand-page-maker/components/preview/Preview.stories.ts +2 -1
  71. package/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.ts +90 -5
  72. package/src/brand-page-maker/components/template-preview/TemplatePreview.vue +41 -4
  73. package/src/brand-page-maker/components/template-preview-with-state/TemplatePreviewWithState.vue +4 -6
  74. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +14 -1
  75. package/src/brand-page-maker/stores/user/user-store.ts +5 -0
  76. package/src/bundles/bundled-translations.json +3 -1
  77. package/src/clients/design-template-client.ts +1 -0
  78. package/src/clients/models.ts +1 -0
  79. package/src/shared/background-settings/components/BackgroundSettings.vue +28 -8
  80. package/src/shared/background-settings/components/ReplaceImageSettingsForBackgroundSettings.vue +9 -0
  81. package/src/shared/background-settings/components/i18n/background-settings.json +3 -1
  82. package/src/shared/background-settings/store/background-settings-store.ts +57 -2
  83. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.ts +9 -3
  84. package/src/shared/content-settings/components/image-field/ImageField.mixin.ts +4 -1
  85. package/src/shared/template-settings/models.ts +2 -0
  86. package/src/shared/template-settings/store/template-settings-store.ts +141 -41
  87. package/lib/src/bundled-translations-D9iHE5G9.js +0 -161
@@ -4,6 +4,7 @@ import type { ContentViewModel, BrandPageViewModel } from '../../view-models';
4
4
  import {
5
5
  mapToPageFooterViewModel,
6
6
  mapToPageHeaderViewModel,
7
+ mapToPageStyleViewModel,
7
8
  mapToViewModel,
8
9
  } from '../../utils';
9
10
  import {
@@ -41,7 +42,7 @@ const pages = brandPageModel.pages.map((p) => ({
41
42
 
42
43
  const viewModel: BrandPageViewModel = {
43
44
  showBrandCrowdLogo: true,
44
- styles: brandPageModel.styles,
45
+ styles: mapToPageStyleViewModel(brandPageModel.styles, {}),
45
46
  headerViewModelDesktop: mapToPageHeaderViewModel(
46
47
  brandPageModel.pageHeaderDesktop,
47
48
  brandPageModel.styles,
@@ -1,5 +1,18 @@
1
1
  <template>
2
- <div class="brand-page-root-background" :style="rootBackgroundStyles" />
2
+ <div
3
+ class="brand-page-root-background"
4
+ :style="rootbackgroundStylesViewModel"
5
+ />
6
+ <Media
7
+ v-if="viewModel.styles?.backgroundStylesViewModel?.mediaViewModel"
8
+ :media="viewModel.styles.backgroundStylesViewModel.mediaViewModel"
9
+ :context="context"
10
+ :img-classes="{
11
+ 'tw-w-full tw-h-full tw-object-cover tw-absolute tw-left-0 tw-top-0 tw-z-0': true,
12
+ }"
13
+ :media-type="viewModel.styles.backgroundStylesViewModel.mediaViewModel.type"
14
+ content-index="0"
15
+ />
3
16
  <div
4
17
  class="brand-page-root"
5
18
  :style="rootElementStyles"
@@ -50,9 +63,9 @@
50
63
  'tw-cursor-pointer': context.isPreview,
51
64
  'brand-page__content--outline-selected': isHeaderSelected,
52
65
  }"
66
+ :is-mobile="true"
53
67
  @open-side-menu="openSideMenu"
54
68
  @header-container-click="onPageHeaderContainerClick"
55
- :is-mobile="true"
56
69
  />
57
70
  </template>
58
71
  </MediaQuery>
@@ -211,9 +224,9 @@
211
224
  isFooterSelected,
212
225
  }"
213
226
  :show-brand-crowd-logo="showBrandCrowdLogo"
227
+ :is-mobile="true"
214
228
  @footer-container-click="onPageFooterContainerClick"
215
229
  @on-logo-click="onLogoClick"
216
- :is-mobile="true"
217
230
  />
218
231
  </template>
219
232
  </MediaQuery>
@@ -266,6 +279,7 @@ import PageFooter from '../page-footer/PageFooter.vue';
266
279
  import NavigationSideMenu from '../navigation/navigation-side-menu/NavigationSideMenu.vue';
267
280
  import BrandSiteNavigationLayout from './BrandSiteNavigationLayout.vue';
268
281
  import MediaQuery from '../media-query';
282
+ import Media from '../media/Media.vue';
269
283
 
270
284
  export default {
271
285
  components: {
@@ -278,6 +292,7 @@ export default {
278
292
  PageHeader,
279
293
  PageFooter,
280
294
  BrandSiteNavigationLayout,
295
+ Media,
281
296
  },
282
297
  mixins: [PageMixin],
283
298
  setup(props) {
@@ -29,6 +29,7 @@ import { EMPTY_LOGO_IMAGE_MODEL, LogoStyles } from './logo.model';
29
29
  import type { LogoImageModel, LogoTemplateImageModel } from './logo.model';
30
30
  import cloneDeep from 'lodash.clonedeep';
31
31
  import type { BrandPagePaymentConfig } from './payment.model';
32
+ import type { MediaViewModel } from '../view-models';
32
33
 
33
34
  export * from './brand-page-context.model';
34
35
  export * from './payment.model';
@@ -83,6 +84,7 @@ export class BackgroundStyles {
83
84
  public backgroundImageUrl: string;
84
85
  public backgroundShapes: BackgroundShape[];
85
86
  public personalisationRole?: PersonalisationRole;
87
+ public media?: AbstractMedia;
86
88
 
87
89
  constructor(option: Partial<BackgroundStyles> = {}) {
88
90
  this.backgroundImageUrl = option.backgroundImageUrl || '';
@@ -96,6 +98,7 @@ export class BackgroundStyles {
96
98
  background: '',
97
99
  };
98
100
  this.personalisationRole = option.personalisationRole;
101
+ this.media = option.media || undefined;
99
102
  }
100
103
  }
101
104
 
@@ -327,6 +327,7 @@ exports[`migration.util > Banner Contents - text Align and Font Family should no
327
327
  "background": "",
328
328
  },
329
329
  "backgroundShapes": [],
330
+ "media": undefined,
330
331
  "personalisationRole": undefined,
331
332
  "style": {
332
333
  "background": "logo-background-color",
@@ -744,6 +745,7 @@ exports[`migration.util > migrateBrandPageModel should return brand page model w
744
745
  "background": "",
745
746
  },
746
747
  "backgroundShapes": [],
748
+ "media": undefined,
747
749
  "personalisationRole": undefined,
748
750
  "style": {
749
751
  "background": "logo-background-color",
@@ -1168,6 +1170,7 @@ exports[`migration.util > migrateBrandPageModel should return brand page model w
1168
1170
  "background": "",
1169
1171
  },
1170
1172
  "backgroundShapes": [],
1173
+ "media": undefined,
1171
1174
  "personalisationRole": undefined,
1172
1175
  "style": {
1173
1176
  "background": "logo-background-color",
@@ -365,6 +365,7 @@ exports[`migration02.ts > migration02 should return converted letterspacing 1`]
365
365
  "background": "",
366
366
  },
367
367
  "backgroundShapes": [],
368
+ "media": undefined,
368
369
  "personalisationRole": undefined,
369
370
  "style": {
370
371
  "background": "logo-background-color",
@@ -339,6 +339,7 @@ BrandPageModel {
339
339
  "background": "",
340
340
  },
341
341
  "backgroundShapes": [],
342
+ "media": undefined,
342
343
  "personalisationRole": undefined,
343
344
  "style": {
344
345
  "background": "#0000ff",
@@ -795,6 +796,7 @@ BrandPageModel {
795
796
  "background": "",
796
797
  },
797
798
  "backgroundShapes": [],
799
+ "media": undefined,
798
800
  "personalisationRole": undefined,
799
801
  "style": {
800
802
  "background": "#0000ff",
@@ -1,12 +1,14 @@
1
- import {
2
- BRAND_PAGE_TYPES,
3
- DEFAULT_LOGO_HEIGHT,
4
- DEFAULT_LOGO_WIDTH,
1
+ import type {
5
2
  PageFooterDesktop,
6
3
  PageFooterMobile,
7
4
  PageHeaderDesktop,
8
5
  PageHeaderMobile,
9
6
  } from '../..';
7
+ import {
8
+ BRAND_PAGE_TYPES,
9
+ DEFAULT_LOGO_HEIGHT,
10
+ DEFAULT_LOGO_WIDTH,
11
+ } from '../..';
10
12
  import { FabricRenderClient } from '../../../clients/fabric-render-client';
11
13
  import { calculateLogoDimensions } from '../logo.util';
12
14
  import type { MigrationData } from '../migration.util';
@@ -40,6 +40,7 @@ import type {
40
40
  TextShapeItem,
41
41
  GettyVideoMedia,
42
42
  AbstractMedia,
43
+ BackgroundStyles,
43
44
  } from '../models';
44
45
  import { ButtonStyles, SENSITIVE_CONTENT_TYPES, VIEWPORTS } from '../models';
45
46
  import {
@@ -78,6 +79,8 @@ import type {
78
79
  ShopViewModel,
79
80
  BookingSectionViewModel,
80
81
  GettyVideoViewModel,
82
+ PageStylesViewModel,
83
+ BackgroundStylesViewModel,
81
84
  } from '../view-models';
82
85
  import { isHexTransparent, setRgbAlpha } from './color.util';
83
86
  import type { ContentTextStylePropertyKey } from '../constants';
@@ -985,6 +988,22 @@ export const mapToBookingSectionViewModel = (
985
988
  );
986
989
  };
987
990
 
991
+ export const mapToPageStyleViewModel = (
992
+ pageStyles: PageStyles,
993
+ options: ViewModelMappingOptions,
994
+ ): PageStylesViewModel => {
995
+ return {
996
+ backgroundStylesViewModel: mapBackgroundStylesToViewModel(
997
+ pageStyles.backgroundStyles,
998
+ options,
999
+ ),
1000
+ buttonStyles: pageStyles.buttonStyles,
1001
+ logoStyles: pageStyles.logoStyles,
1002
+ textStyles: pageStyles.textStyles,
1003
+ galleryStyles: pageStyles.galleryStyles,
1004
+ };
1005
+ };
1006
+
988
1007
  export const mapToPageHeaderViewModel = (
989
1008
  pageHeader: PageHeaderDesktop | PageHeaderMobile,
990
1009
  pageStyles: PageStyles,
@@ -1284,6 +1303,26 @@ interface ViewModelMappingOptions {
1284
1303
  ) => void;
1285
1304
  }
1286
1305
 
1306
+ const mapBackgroundStylesToViewModel = (
1307
+ backgroundStyles: BackgroundStyles,
1308
+ options: ViewModelMappingOptions,
1309
+ ): BackgroundStylesViewModel => {
1310
+ // TODO(jyao): These need to be mapped to a view model eventually
1311
+ return {
1312
+ style: backgroundStyles.style,
1313
+ backgroundShapeStyle: backgroundStyles.backgroundShapeStyle,
1314
+ backgroundImageUrl: backgroundStyles.backgroundImageUrl,
1315
+ backgroundShapes: backgroundStyles.backgroundShapes,
1316
+ personalisationRole: backgroundStyles.personalisationRole,
1317
+ mediaViewModel: backgroundStyles.media
1318
+ ? mapMediaToContentViewModel({
1319
+ media: backgroundStyles.media,
1320
+ options,
1321
+ })
1322
+ : undefined,
1323
+ };
1324
+ };
1325
+
1287
1326
  export const getBrandPageViewModelFromBrandPageModel = (
1288
1327
  model: BrandPageModel,
1289
1328
  brandPageToken: string | undefined,
@@ -1313,7 +1352,7 @@ export const getBrandPageViewModelFromBrandPageModel = (
1313
1352
  brandPageToken,
1314
1353
  pages,
1315
1354
  showBrandCrowdLogo,
1316
- styles: model.styles,
1355
+ styles: mapToPageStyleViewModel(model.styles, options),
1317
1356
  headerViewModelDesktop: mapToPageHeaderViewModel(
1318
1357
  model.pageHeaderDesktop,
1319
1358
  model.styles,
@@ -1460,7 +1499,8 @@ export const getCriticalResourceURLs = (
1460
1499
  }
1461
1500
 
1462
1501
  // shapes
1463
- const bgShapeFullBg = viewModel.styles?.backgroundStyles.backgroundImageUrl;
1502
+ const bgShapeFullBg =
1503
+ viewModel.styles?.backgroundStylesViewModel.backgroundImageUrl;
1464
1504
 
1465
1505
  if (typeof bgShapeFullBg !== 'undefined' && isValidSvgUrl(bgShapeFullBg)) {
1466
1506
  shapes.push(String(bgShapeFullBg));
@@ -39,6 +39,10 @@ import type {
39
39
  SensitiveContent,
40
40
  BookingSectionContent,
41
41
  MediaTypes,
42
+ TextStyles,
43
+ BackgroundStyle,
44
+ BackgroundShape,
45
+ PersonalisationRole,
42
46
  } from './models';
43
47
  import type { ImagesSectionContentDisplayStyle } from './constants';
44
48
 
@@ -280,10 +284,28 @@ export interface PageFooterViewModel
280
284
  logo: LogoViewModel;
281
285
  }
282
286
 
287
+ export interface BackgroundStylesViewModel {
288
+ style: BackgroundStyle;
289
+ backgroundShapeStyle: BackgroundStyle;
290
+ backgroundImageUrl: string;
291
+ backgroundShapes: BackgroundShape[];
292
+ personalisationRole?: PersonalisationRole;
293
+ mediaViewModel?: MediaViewModel;
294
+ }
295
+
296
+ // Note(jyao): View model for page styles, we will need to create new view model mapping for each style here in future
297
+ export interface PageStylesViewModel {
298
+ backgroundStylesViewModel: BackgroundStylesViewModel;
299
+ buttonStyles: ButtonStyles; // TODO(jyao): Convert to view model
300
+ logoStyles: LogoStyles; // TODO(jyao): Convert to view model
301
+ textStyles: TextStyles; // TODO(jyao): Convert to view model
302
+ galleryStyles: GalleryStyles; // TODO(jyao): Convert to view model
303
+ }
304
+
283
305
  export interface BrandPageViewModel {
284
306
  brandPageToken?: string;
285
307
  showBrandCrowdLogo: boolean;
286
- styles: PageStyles;
308
+ styles: PageStylesViewModel;
287
309
  pages: PageViewModel[];
288
310
  brandPageType: BrandPageType;
289
311
  headerViewModelDesktop: PageHeaderViewModel;
@@ -17,6 +17,7 @@ import { setupStoryPinia } from '../brand-page-maker/__fixtures__/store-fixture'
17
17
  import {
18
18
  mapToPageFooterViewModel,
19
19
  mapToPageHeaderViewModel,
20
+ mapToPageStyleViewModel,
20
21
  mapToViewModel,
21
22
  } from '../../../brand-page/utils';
22
23
 
@@ -46,7 +47,7 @@ const pages = [
46
47
 
47
48
  const viewModel: BrandPageViewModel = {
48
49
  showBrandCrowdLogo: true,
49
- styles: pageStyles,
50
+ styles: mapToPageStyleViewModel(pageStyles, {}),
50
51
  headerViewModelDesktop: mapToPageHeaderViewModel(
51
52
  new PageHeaderDesktop(),
52
53
  pageStyles,
@@ -15,11 +15,19 @@ import {
15
15
  getBrandPageViewModelFromBrandPageModel,
16
16
  } from '../../../brand-page/utils';
17
17
  import { STYLE_THEME_KEYS } from '../../../brand-page/constants';
18
- import type { TemplateSettingsTemplate } from '../../../shared/template-settings/models';
18
+ import {
19
+ TEMPLATE_TABS,
20
+ type TemplateSettingsTemplate,
21
+ } from '../../../shared/template-settings/models';
19
22
  import type { DebounceHandle } from 'lodash.debounce';
20
23
  import debounce from 'lodash.debounce';
21
24
  import { MOBILE_HEIGHT, MOBILE_WIDTH } from '../../constants';
22
- import { useBrandPageMakerStore } from '../../stores';
25
+ import {
26
+ useBrandPageContainerStore,
27
+ useBrandPageMakerStore,
28
+ useBrandPageMakerUserStore,
29
+ } from '../../stores';
30
+ import { useUiTemplateSettingsStore } from '../../../shared/template-settings/store';
23
31
  import {
24
32
  applyLogoImageBase64UrlToBrandPageTemplateModel,
25
33
  applyLogoImageToBrandPageTemplateModel,
@@ -41,17 +49,35 @@ interface TemplatePreviewData {
41
49
  renderHeight: number;
42
50
  renderWidth: number;
43
51
  rootStyles: BrandPageCssStyle;
52
+ imageLoadError: boolean;
53
+ imageLoading: boolean;
44
54
  }
45
55
 
46
56
  export default defineComponent({
47
57
  emits: ['template-selected'],
48
58
  setup() {
49
59
  const brandPageMakerStore = useBrandPageMakerStore();
60
+ const brandPageContainerStore = useBrandPageContainerStore();
61
+ const brandPageMakerUserStore = useBrandPageMakerUserStore();
62
+ const templateSettingsStore = useUiTemplateSettingsStore();
50
63
 
51
64
  return {
52
65
  selectedTemplateId: computed(
53
66
  () => brandPageMakerStore.selectedTemplateId,
54
67
  ),
68
+ isPrePurchase: computed(() => brandPageContainerStore.isPrePurchase),
69
+ runtimeEnvironment: computed(
70
+ () => brandPageContainerStore.runtimeEnvironment,
71
+ ),
72
+ isAdmin: computed(() => brandPageMakerUserStore.isAdmin),
73
+ userToken: computed(() => brandPageMakerUserStore.userToken),
74
+ isBrandSite: computed(
75
+ () => brandPageMakerStore.brandPageType === BRAND_PAGE_TYPES.brandSite,
76
+ ),
77
+ selectedTab: computed(() => templateSettingsStore.selectedTab.key),
78
+ renderAsImage: computed(() => templateSettingsStore.renderAsImage),
79
+ brandPageMakerUserStore,
80
+ brandPageContainerStore,
55
81
  brandPageMakerStore,
56
82
  };
57
83
  },
@@ -111,6 +137,8 @@ export default defineComponent({
111
137
  renderWidth: 400,
112
138
  rootStyles: {},
113
139
  viewModel: undefined,
140
+ imageLoadError: false,
141
+ imageLoading: true,
114
142
  };
115
143
 
116
144
  return data;
@@ -202,16 +230,52 @@ export default defineComponent({
202
230
 
203
231
  return cssVariables;
204
232
  },
233
+ previewImageUrl(): string {
234
+ let previewImageUrl = this.template.previewImageUrl;
235
+
236
+ if (!previewImageUrl) {
237
+ return '';
238
+ }
239
+
240
+ if (
241
+ this.selectedTab === TEMPLATE_TABS.AI &&
242
+ this.template.contentKey &&
243
+ this.userToken
244
+ ) {
245
+ previewImageUrl += `&contentKey=${this.template.contentKey}&userToken=${this.userToken}`;
246
+ }
247
+
248
+ if (this.logoImage?.logoVariation !== undefined) {
249
+ previewImageUrl += `&logoVariation=${this.logoImage.logoVariation}`;
250
+ }
251
+
252
+ return previewImageUrl;
253
+ },
205
254
  },
206
255
  watch: {
256
+ template() {
257
+ if (this.isAdmin || this.isPrePurchase) {
258
+ this.updateViewModel();
259
+ } else {
260
+ // Reset loading state when template changes for image-based previews
261
+ this.imageLoading = true;
262
+ this.imageLoadError = false;
263
+ }
264
+ },
207
265
  logoTheme: {
208
266
  handler() {
209
- this.updateViewModel();
267
+ if (this.isAdmin || this.isPrePurchase) {
268
+ this.updateViewModel();
269
+ }
210
270
  },
211
271
  deep: true,
212
272
  },
213
- template() {
214
- this.updateViewModel();
273
+ previewImageUrl() {
274
+ // Reset loading state whenever the preview URL changes
275
+ if (!this.isAdmin && !this.isPrePurchase) {
276
+ this.imageLoading = true;
277
+ this.imageLoadError = false;
278
+ }
215
279
  },
216
280
  },
217
281
  created() {
@@ -260,7 +324,28 @@ export default defineComponent({
260
324
  this.rootStyles = styles;
261
325
  },
262
326
 
327
+ onImageError() {
328
+ this.imageLoadError = true;
329
+ this.imageLoading = false;
330
+ },
331
+
332
+ onImageLoad() {
333
+ this.imageLoadError = false;
334
+ this.imageLoading = false;
335
+ },
336
+
337
+ regeneratePreview() {
338
+ this.imageLoadError = false;
339
+ this.imageLoading = true;
340
+ this.$forceUpdate();
341
+ },
342
+
263
343
  async updateViewModel(forceUpdate = true) {
344
+ // Only update view model for admin or pre-purchase mode
345
+ if (!this.isAdmin && !this.isPrePurchase) {
346
+ return;
347
+ }
348
+
264
349
  const videoStore = useVideoStore();
265
350
 
266
351
  let model = this.template.brandPageModel;
@@ -18,8 +18,11 @@
18
18
  <span class="tw-sr-only">Select Template</span>
19
19
  </button>
20
20
  <!-- End Overlay-->
21
- <!-- Start Page -->
22
- <div class="template-preview__page" :style="cssVariablesStyle">
21
+ <div
22
+ v-if="!renderAsImage"
23
+ class="template-preview__page"
24
+ :style="cssVariablesStyle"
25
+ >
23
26
  <Page
24
27
  v-if="viewModel"
25
28
  :context="context"
@@ -29,7 +32,28 @@
29
32
  @on-set-preview-styles="onSetPreviewStyles"
30
33
  />
31
34
  </div>
32
- <!-- End Page -->
35
+ <!-- Start Preview Image -->
36
+ <div v-else class="template-preview__image-container">
37
+ <!-- Loading spinner -->
38
+ <div
39
+ v-if="imageLoading"
40
+ class="tw-absolute tw-inset-0 tw-flex tw-items-center tw-justify-center tw-bg-gray-50 tw-z-10"
41
+ >
42
+ <div class="tw-scale-150">
43
+ <Loader />
44
+ </div>
45
+ </div>
46
+
47
+ <img
48
+ :src="previewImageUrl"
49
+ :alt="`Template ${template.id} preview`"
50
+ class="template-preview__image"
51
+ :class="{ 'tw-opacity-0': imageLoading }"
52
+ @error="onImageError"
53
+ @load="onImageLoad"
54
+ />
55
+ </div>
56
+ <!-- End Preview Image -->
33
57
  <!-- Start personalisation tag -->
34
58
  <div
35
59
  v-if="isPersonalisable"
@@ -47,10 +71,12 @@
47
71
  import { defineComponent } from 'vue';
48
72
  import TemplatePreviewMixin from './TemplatePreview.mixin.ts';
49
73
  import Page from '../../../brand-page/components/page/Page.vue';
74
+ import { Loader } from '@designcrowd/fe-shared-lib';
50
75
 
51
76
  export default defineComponent({
52
77
  components: {
53
78
  Page,
79
+ Loader,
54
80
  },
55
81
  mixins: [TemplatePreviewMixin],
56
82
  setup(props, context) {
@@ -66,13 +92,24 @@ export default defineComponent({
66
92
 
67
93
  .template-preview__overlay {
68
94
  @apply tw-absolute tw-top-0 tw-left-0 tw-right-0 tw-bottom-0 tw-opacity-0 tw-cursor-pointer tw-w-full tw-h-full;
95
+ z-index: 100;
69
96
  }
70
97
 
98
+ .template-preview__image-container {
99
+ @apply tw-pointer-events-none;
100
+ @apply tw-w-full tw-h-full;
101
+ }
102
+ .template-preview__image {
103
+ @apply tw-w-full tw-h-full tw-object-fill;
104
+ transition: filter 0.2s ease;
105
+ }
71
106
  .template-preview__page {
72
107
  @apply tw-pointer-events-none;
73
108
  }
74
-
75
109
  .template-preview :deep(.c-shape-background) {
76
110
  @apply tw-absolute;
77
111
  }
112
+ .template-preview__image :deep(.c-shape-background) {
113
+ @apply tw-absolute;
114
+ }
78
115
  </style>
@@ -41,12 +41,10 @@ const pageSettingsStore = useUiPageSettingsStore();
41
41
 
42
42
  const logoTheme = computed(() => uiStore.logoTheme);
43
43
 
44
- const personalisationData = computed(() =>
45
- uiStore.personalisationData?.length
46
- ? uiStore.personalisationData[props.template.personalisationContentIndex]
47
- .userPersonalisation
48
- : undefined,
49
- );
44
+ const personalisationData = computed(() => {
45
+ const index = props.template.personalisationContentIndex;
46
+ return uiStore.personalisationData?.[index]?.userPersonalisation;
47
+ });
50
48
 
51
49
  const templateLogoImage = computed(() => {
52
50
  const desktopPageHeader =
@@ -360,7 +360,7 @@ export const useBrandPageMakerStore = defineStore('brandPageMaker', {
360
360
  return;
361
361
  }
362
362
 
363
- const template = templateSettingsStore.getTemplateByTemplateId(
363
+ let template = templateSettingsStore.getTemplateByTemplateId(
364
364
  this.selectedTemplateId,
365
365
  );
366
366
 
@@ -372,6 +372,19 @@ export const useBrandPageMakerStore = defineStore('brandPageMaker', {
372
372
  return;
373
373
  }
374
374
 
375
+ // If template doesn't have brandPageModel (post-purchase mode), fetch it
376
+ if (!template.brandPageModel) {
377
+ template = await templateSettingsStore.getCachedTemplateByTokenAsync(
378
+ this.selectedTemplateId,
379
+ );
380
+ }
381
+
382
+ if (!template?.brandPageModel) {
383
+ console.error('Failed to fetch template brandPageModel');
384
+
385
+ return;
386
+ }
387
+
375
388
  this.isApplyingTemplate = true;
376
389
 
377
390
  let brandPageModel = cloneDeep(template.brandPageModel);
@@ -9,6 +9,7 @@ export interface UserState extends UIUserState {
9
9
  emailAddress: string;
10
10
  hasBrandPagePremiumSubscription: boolean;
11
11
  brandPageCommissionPercentage: number | undefined;
12
+ userToken?: string;
12
13
  }
13
14
 
14
15
  export const DEFAULT_MAX_NUM_OF_PAGES = 2;
@@ -37,6 +38,7 @@ export const useBrandPageMakerUserStore = defineStore('brandPageMakerUser', {
37
38
  hasBrandPagePremiumSubscription: false,
38
39
  brandPageCommissionPercentage: undefined,
39
40
  isAdmin: false, // this is currently used as way to identify admin maker mode
41
+ userToken: undefined,
40
42
  }),
41
43
  actions: {
42
44
  setEmailAddress(payload: string): void {
@@ -54,5 +56,8 @@ export const useBrandPageMakerUserStore = defineStore('brandPageMakerUser', {
54
56
  setBrandPageCommissionPercentage(payload: number): void {
55
57
  this.brandPageCommissionPercentage = payload;
56
58
  },
59
+ setUserToken(payload: { userToken: string }): void {
60
+ this.userToken = payload.userToken;
61
+ },
57
62
  },
58
63
  });
@@ -297,7 +297,9 @@
297
297
  "addMedia": "Add Media",
298
298
  "addImage": "Add Image",
299
299
  "replaceImage": "Replace Image",
300
- "image": "Image"
300
+ "image": "Image",
301
+ "media": "Media",
302
+ "replaceMedia": "Replace Media"
301
303
  },
302
304
  "colorPicker": {
303
305
  "newColor": "New Color",
@@ -19,6 +19,7 @@ interface GetTemplatesAsyncOptions {
19
19
  searchTerm?: string;
20
20
  side?: string;
21
21
  logoDraftToken?: string;
22
+ logoVariation?: number;
22
23
  useLogoForRecommendedTemplates?: boolean;
23
24
  page?: number;
24
25
  pageSize?: number;
@@ -14,6 +14,7 @@ export interface DesignTemplate {
14
14
 
15
15
  export interface PaginatedDesignTemplateItem {
16
16
  designTemplateToken: string;
17
+ previewImageUrl?: string;
17
18
  }
18
19
 
19
20
  export interface DisplayLogoDraftAsset {