@designcrowd/library.brand-page 5.16.17-pre-temp-2 → 5.16.18-ast-save-bc

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 (120) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-CFZJ9B0_.js → CreatedOnBrandCrowd-de-de-DyUz0u__.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-Co2tanrg.js → CreatedOnBrandCrowd-en-us-CjKMC3AM.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-DWcr6V-z.js → CreatedOnBrandCrowd-es-es-BVDz6Ixy.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-De72i4oQ.js → CreatedOnBrandCrowd-fr-ca-BcxKWT6E.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-De72i4oQ.js → CreatedOnBrandCrowd-fr-fr-BcxKWT6E.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-CcznKAcC.js → CreatedOnBrandCrowd-pt-br-Co7QQ80l.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-CcznKAcC.js → CreatedOnBrandCrowd-pt-pt-Co7QQ80l.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-xh1FG9UT.js → CreatedOnDcom-de-de-CEDmsGBR.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-DwRJ-NGl.js → CreatedOnDcom-en-us-BoGpFhlg.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-qa4GXYmC.js → CreatedOnDcom-es-es-HABf8vVH.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-Ck443ItA.js → CreatedOnDcom-fr-ca-BHsSmAb4.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-DysZVU4Z.js → CreatedOnDcom-fr-fr-DwQ4Flp7.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-6zBZ72NO.js → CreatedOnDcom-pt-br-1SnSRC6J.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-Dtvbafy6.js → CreatedOnDcom-pt-pt-D91oqYtM.js} +1 -1
  15. package/lib/src/brand-page/components/page/Page.mixin.d.ts +1 -0
  16. package/lib/src/brand-page/components/page/Page.mixin.js +16 -0
  17. package/lib/src/brand-page/components/page-footer/PageFooter.mixin.d.ts +12 -1
  18. package/lib/src/brand-page/components/page-footer/PageFooter.mixin.js +5 -0
  19. package/lib/src/brand-page/components/payment/__fixtures__/request-payment.d.ts +2 -0
  20. package/lib/src/brand-page/components/payment/__fixtures__/support-me.d.ts +2 -0
  21. package/lib/src/brand-page/models/brand-page-context.model.d.ts +3 -0
  22. package/lib/src/brand-page/utils/vcard.util.d.ts +13 -0
  23. package/lib/src/brand-page/utils/vcard.util.js +176 -0
  24. package/lib/src/brand-page-maker/assessors/banner-section-description-visibility.assessor.js +1 -1
  25. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +1 -0
  26. package/lib/src/brand-page-maker/components/preview/Preview.mixin.js +1 -0
  27. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +2 -0
  28. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.js +9 -0
  29. package/lib/src/brand-page-maker/composables/useEventTracker.d.ts +2 -0
  30. package/lib/src/brand-page-maker/composables/useEventTracker.js +2 -0
  31. package/lib/src/bundled-translations-Dp4KzW9M.js +165 -0
  32. package/lib/src/bundled-translations.de-DE-CMNy5LEQ.js +165 -0
  33. package/lib/src/bundled-translations.es-ES-B20ONBTs.js +165 -0
  34. package/lib/src/bundled-translations.fr-CA-DwBf1MZ8.js +165 -0
  35. package/lib/src/bundled-translations.fr-FR-3GhDgrC4.js +165 -0
  36. package/lib/src/bundled-translations.pt-BR-DuzEDMF5.js +165 -0
  37. package/lib/src/bundled-translations.pt-PT-CtT4FOlX.js +165 -0
  38. package/lib/src/bundles/bundled-translations.de-DE.json +7 -1
  39. package/lib/src/bundles/bundled-translations.es-ES.json +7 -1
  40. package/lib/src/bundles/bundled-translations.fr-CA.json +7 -1
  41. package/lib/src/bundles/bundled-translations.fr-FR.json +7 -1
  42. package/lib/src/bundles/bundled-translations.json +7 -1
  43. package/lib/src/bundles/bundled-translations.pt-BR.json +7 -1
  44. package/lib/src/bundles/bundled-translations.pt-PT.json +7 -1
  45. package/lib/src/clients/fabric-render-client.d.ts +0 -1
  46. package/lib/src/composables/useTranslate.d.ts +2 -1
  47. package/lib/src/composables/useTranslate.js +2 -1
  48. package/lib/src/css/library.brand-page-brandCrowd.min.css +185 -64
  49. package/lib/src/css/library.brand-page-brandPage.min.css +187 -64
  50. package/lib/src/css/library.brand-page-designCom.min.css +185 -64
  51. package/lib/src/css/library.brand-page-preview.min.css +185 -64
  52. package/lib/src/index.d.ts +1 -1
  53. package/lib/src/index.mjs +65 -66
  54. package/lib/src/{lib-DTMYf8OY.js → lib-CqQoDVDz.js} +21912 -21591
  55. package/lib/src/lib.js +1 -1
  56. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.js +2 -0
  57. package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.js +2 -0
  58. package/lib/src/shared/logo-settings/store/editable-logo-store.js +0 -1
  59. package/package.json +1 -1
  60. package/src/brand-page/components/banner-section/BannerSection.vue +5 -1
  61. package/src/brand-page/components/brand-page-footer/i18n/brand-page-footer.de-DE.json +5 -5
  62. package/src/brand-page/components/brand-page-footer/i18n/brand-page-footer.es-ES.json +5 -5
  63. package/src/brand-page/components/brand-page-footer/i18n/brand-page-footer.fr-CA.json +5 -5
  64. package/src/brand-page/components/brand-page-footer/i18n/brand-page-footer.fr-FR.json +5 -5
  65. package/src/brand-page/components/brand-page-footer/i18n/brand-page-footer.pt-BR.json +5 -5
  66. package/src/brand-page/components/brand-page-footer/i18n/brand-page-footer.pt-PT.json +5 -5
  67. package/src/brand-page/components/button/Button.vue +64 -54
  68. package/src/brand-page/components/page/Page.mixin.ts +20 -0
  69. package/src/brand-page/components/page/Page.vue +10 -1
  70. package/src/brand-page/components/page-footer/PageFooter.mixin.ts +9 -1
  71. package/src/brand-page/components/save-contact/SaveContactWidget.vue +212 -0
  72. package/src/brand-page/components/save-contact/i18n/save-contact.de-DE.json +8 -0
  73. package/src/brand-page/components/save-contact/i18n/save-contact.es-ES.json +8 -0
  74. package/src/brand-page/components/save-contact/i18n/save-contact.fr-CA.json +8 -0
  75. package/src/brand-page/components/save-contact/i18n/save-contact.fr-FR.json +8 -0
  76. package/src/brand-page/components/save-contact/i18n/save-contact.json +8 -0
  77. package/src/brand-page/components/save-contact/i18n/save-contact.pt-BR.json +8 -0
  78. package/src/brand-page/components/save-contact/i18n/save-contact.pt-PT.json +8 -0
  79. package/src/brand-page/components/save-contact/popup-card/PopupCard.vue +156 -0
  80. package/src/brand-page/components/shop/ProductDetailModal.vue +1 -1
  81. package/src/brand-page/models/brand-page-context.model.ts +3 -0
  82. package/src/brand-page/utils/vcard.util.ts +252 -0
  83. package/src/brand-page-maker/assessors/banner-section-description-visibility.assessor.ts +1 -1
  84. package/src/brand-page-maker/components/color-palette/BpColorPalette.vue +3 -1
  85. package/src/brand-page-maker/components/preview/Preview.mixin.ts +1 -0
  86. package/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.ts +12 -0
  87. package/src/brand-page-maker/composables/useEventTracker.ts +2 -0
  88. package/src/bundles/bundled-translations.de-DE.json +7 -1
  89. package/src/bundles/bundled-translations.es-ES.json +7 -1
  90. package/src/bundles/bundled-translations.fr-CA.json +7 -1
  91. package/src/bundles/bundled-translations.fr-FR.json +7 -1
  92. package/src/bundles/bundled-translations.json +7 -1
  93. package/src/bundles/bundled-translations.pt-BR.json +7 -1
  94. package/src/bundles/bundled-translations.pt-PT.json +7 -1
  95. package/src/clients/fabric-render-client.ts +0 -1
  96. package/src/composables/useTranslate.ts +3 -0
  97. package/src/lib.ts +0 -1
  98. package/src/shared/content-settings/components/content-settings/i18n/content-settings.de-DE.json +1 -1
  99. package/src/shared/content-settings/components/content-settings/i18n/content-settings.es-ES.json +1 -1
  100. package/src/shared/content-settings/components/content-settings/i18n/content-settings.fr-CA.json +1 -1
  101. package/src/shared/content-settings/components/content-settings/i18n/content-settings.fr-FR.json +1 -1
  102. package/src/shared/content-settings/components/content-settings/i18n/content-settings.json +1 -1
  103. package/src/shared/content-settings/components/content-settings/i18n/content-settings.pt-BR.json +1 -1
  104. package/src/shared/content-settings/components/content-settings/i18n/content-settings.pt-PT.json +1 -1
  105. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.ts +2 -0
  106. package/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.ts +2 -0
  107. package/src/shared/logo-settings/store/editable-logo-store.ts +0 -1
  108. package/src/shared/shape-library/i18n/shape-library.de-DE.json +3 -3
  109. package/src/shared/shape-library/i18n/shape-library.es-ES.json +3 -3
  110. package/src/shared/shape-library/i18n/shape-library.fr-CA.json +3 -3
  111. package/src/shared/shape-library/i18n/shape-library.fr-FR.json +3 -3
  112. package/src/shared/shape-library/i18n/shape-library.pt-BR.json +3 -3
  113. package/src/shared/shape-library/i18n/shape-library.pt-PT.json +3 -3
  114. package/lib/src/bundled-translations-BYa_U-US.js +0 -163
  115. package/lib/src/bundled-translations.de-DE-DypSwCKV.js +0 -163
  116. package/lib/src/bundled-translations.es-ES-IiXZIQwt.js +0 -163
  117. package/lib/src/bundled-translations.fr-CA-B4yILHO8.js +0 -163
  118. package/lib/src/bundled-translations.fr-FR-C6C6FR8Q.js +0 -163
  119. package/lib/src/bundled-translations.pt-BR-C6Ym9BZY.js +0 -163
  120. package/lib/src/bundled-translations.pt-PT-CYohhAyJ.js +0 -163
@@ -1,5 +1,5 @@
1
1
  import { createElementBlock as e, openBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-DTMYf8OY.js";
2
+ import { _ as t } from "./lib-CqQoDVDz.js";
3
3
  const i = {}, h = {
4
4
  width: "275",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { createElementBlock as e, openBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-DTMYf8OY.js";
2
+ import { _ as t } from "./lib-CqQoDVDz.js";
3
3
  const i = {}, h = {
4
4
  width: "251",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { createElementBlock as e, openBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-DTMYf8OY.js";
2
+ import { _ as t } from "./lib-CqQoDVDz.js";
3
3
  const i = {}, h = {
4
4
  width: "250",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { createElementBlock as e, openBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-DTMYf8OY.js";
2
+ import { _ as t } from "./lib-CqQoDVDz.js";
3
3
  const i = {}, h = {
4
4
  width: "237",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { createElementBlock as e, openBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-DTMYf8OY.js";
2
+ import { _ as t } from "./lib-CqQoDVDz.js";
3
3
  const i = {}, h = {
4
4
  width: "237",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { createElementBlock as e, openBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-DTMYf8OY.js";
2
+ import { _ as t } from "./lib-CqQoDVDz.js";
3
3
  const i = {}, h = {
4
4
  width: "263",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { createElementBlock as e, openBlock as l, createStaticVNode as a } from "vue";
2
- import { _ as t } from "./lib-DTMYf8OY.js";
2
+ import { _ as t } from "./lib-CqQoDVDz.js";
3
3
  const i = {}, h = {
4
4
  width: "263",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { createElementBlock as H, openBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as e } from "./lib-DTMYf8OY.js";
2
+ import { _ as e } from "./lib-CqQoDVDz.js";
3
3
  const M = {}, Z = {
4
4
  width: "242",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { createElementBlock as H, openBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as e } from "./lib-DTMYf8OY.js";
2
+ import { _ as e } from "./lib-CqQoDVDz.js";
3
3
  const i = {}, M = {
4
4
  width: "231",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { createElementBlock as H, openBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as e } from "./lib-DTMYf8OY.js";
2
+ import { _ as e } from "./lib-CqQoDVDz.js";
3
3
  const M = {}, Z = {
4
4
  width: "230",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { createElementBlock as H, openBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as e } from "./lib-DTMYf8OY.js";
2
+ import { _ as e } from "./lib-CqQoDVDz.js";
3
3
  const i = {}, l = {
4
4
  width: "216",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { createElementBlock as H, openBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as e } from "./lib-DTMYf8OY.js";
2
+ import { _ as e } from "./lib-CqQoDVDz.js";
3
3
  const i = {}, l = {
4
4
  width: "216",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { createElementBlock as H, openBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as M } from "./lib-DTMYf8OY.js";
2
+ import { _ as M } from "./lib-CqQoDVDz.js";
3
3
  const Z = {}, e = {
4
4
  width: "232",
5
5
  height: "36",
@@ -1,5 +1,5 @@
1
1
  import { createElementBlock as H, openBlock as V, createStaticVNode as t } from "vue";
2
- import { _ as M } from "./lib-DTMYf8OY.js";
2
+ import { _ as M } from "./lib-CqQoDVDz.js";
3
3
  const Z = {}, e = {
4
4
  width: "232",
5
5
  height: "36",
@@ -73,6 +73,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
73
73
  bpShowTopNavigationMobile(): boolean;
74
74
  bpShowTopNavigationDesktop(): boolean;
75
75
  slug(): string;
76
+ shouldShowSaveContactWidget(): boolean;
76
77
  }, {
77
78
  openSideMenu(): void;
78
79
  onLogoClick(tabName: string): void;
@@ -2,6 +2,7 @@ import { defineComponent } from 'vue';
2
2
  import { DEFAULT_FONT_FAMILY_KEY, FALLBACK_FONT_FAMILIES, FONT_FAMILY_CONFIGS, } from '../../constants';
3
3
  import { getSlugFromContext } from '../../utils';
4
4
  import { BRAND_PAGE_TYPES } from '../../models';
5
+ import { hasProfileContent as checkHasProfileContent } from '../../utils/vcard.util';
5
6
  export default defineComponent({
6
7
  props: {
7
8
  context: {
@@ -263,6 +264,21 @@ export default defineComponent({
263
264
  slug() {
264
265
  return getSlugFromContext(this.context);
265
266
  },
267
+ shouldShowSaveContactWidget() {
268
+ try {
269
+ if (this.context.isPreview ||
270
+ this.context.options?.showOnGeneratedPreviews === false ||
271
+ !this.context.isBrandContact) {
272
+ return false;
273
+ }
274
+ const brandPageData = { pages: this.context?.pages || [] };
275
+ return checkHasProfileContent(brandPageData);
276
+ }
277
+ catch (error) {
278
+ console.error('Error checking profile content:', error);
279
+ return false;
280
+ }
281
+ },
266
282
  },
267
283
  watch: {
268
284
  rootElementStyles() {
@@ -1,4 +1,4 @@
1
- import type { PageFooterViewModel } from '../../view-models';
1
+ import type { PageFooterViewModel, BrandPageViewModel } from '../../view-models';
2
2
  import type { PropType } from 'vue';
3
3
  import type { BrandPageContext } from '../../models';
4
4
  declare const _default: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
@@ -19,6 +19,11 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
19
19
  required: false;
20
20
  default: boolean;
21
21
  };
22
+ brandPageViewModel: {
23
+ type: PropType<BrandPageViewModel>;
24
+ required: false;
25
+ default: undefined;
26
+ };
22
27
  }>, {}, {}, {
23
28
  containerStyle(): BrandPageCssStyle;
24
29
  socialLinksIconStyle(): BrandPageCssStyle;
@@ -46,10 +51,16 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
46
51
  required: false;
47
52
  default: boolean;
48
53
  };
54
+ brandPageViewModel: {
55
+ type: PropType<BrandPageViewModel>;
56
+ required: false;
57
+ default: undefined;
58
+ };
49
59
  }>> & Readonly<{
50
60
  "onOn-logo-click"?: ((...args: any[]) => any) | undefined;
51
61
  "onFooter-container-click"?: ((...args: any[]) => any) | undefined;
52
62
  }>, {
63
+ brandPageViewModel: BrandPageViewModel;
53
64
  isMobile: boolean;
54
65
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
55
66
  export default _default;
@@ -20,6 +20,11 @@ export default defineComponent({
20
20
  required: false,
21
21
  default: false,
22
22
  },
23
+ brandPageViewModel: {
24
+ type: Object,
25
+ required: false,
26
+ default: undefined,
27
+ },
23
28
  },
24
29
  emits: ['on-logo-click', 'footer-container-click'],
25
30
  computed: {
@@ -24,9 +24,11 @@ export declare const context: {
24
24
  mediaSizes?: "size1x" | "size2x" | "sizeThumb" | undefined;
25
25
  renderVideoAsImage?: boolean | undefined;
26
26
  shouldPlayVideos?: boolean | undefined;
27
+ showOnGeneratedPreviews?: boolean | undefined;
27
28
  } | undefined;
28
29
  abTests?: import("../../../models").AbTest | undefined;
29
30
  isCapturingPreview: boolean;
31
+ showOnGeneratedPreviews?: boolean | undefined;
30
32
  disableLogoRenderOnServerside?: boolean | undefined;
31
33
  };
32
34
  export declare const viewModel: RequestPaymentViewModel;
@@ -24,9 +24,11 @@ export declare const context: {
24
24
  mediaSizes?: "size1x" | "size2x" | "sizeThumb" | undefined;
25
25
  renderVideoAsImage?: boolean | undefined;
26
26
  shouldPlayVideos?: boolean | undefined;
27
+ showOnGeneratedPreviews?: boolean | undefined;
27
28
  } | undefined;
28
29
  abTests?: import("../../../models").AbTest | undefined;
29
30
  isCapturingPreview: boolean;
31
+ showOnGeneratedPreviews?: boolean | undefined;
30
32
  disableLogoRenderOnServerside?: boolean | undefined;
31
33
  };
32
34
  export declare const viewModel: SupportMeViewModel;
@@ -71,10 +71,13 @@ export interface BrandPageContext {
71
71
  mediaSizes?: MediaSizes;
72
72
  renderVideoAsImage?: boolean;
73
73
  shouldPlayVideos?: boolean;
74
+ showOnGeneratedPreviews?: boolean;
74
75
  };
75
76
  abTests?: AbTest;
76
77
  /** Is brand page rendered for preview */
77
78
  isCapturingPreview: boolean;
79
+ /** Show on generated previews (template gallery, content settings) */
80
+ showOnGeneratedPreviews?: boolean;
78
81
  disableLogoRenderOnServerside?: boolean;
79
82
  }
80
83
  export declare const getValueType: (key: string, abtestValue?: string) => AbTestResult;
@@ -0,0 +1,13 @@
1
+ import type { ProfileContent, BrandPageModel } from '../models';
2
+ export declare const findProfileContent: (brandPageData?: BrandPageModel | {
3
+ pages?: any[];
4
+ }) => ProfileContent | undefined;
5
+ export declare const hasProfileContent: (brandPageData?: BrandPageModel | {
6
+ pages?: any[];
7
+ }) => boolean;
8
+ export declare const generateVCard: (brandPageData: BrandPageModel | {
9
+ pages?: any[];
10
+ }) => string;
11
+ export declare const saveContact: (brandPageData: BrandPageModel | {
12
+ pages?: any[];
13
+ }) => void;
@@ -0,0 +1,176 @@
1
+ import { isValidUrl } from '../../helpers/url.helper';
2
+ // Constants
3
+ const HTML_ENTITIES = {
4
+ '&nbsp;': ' ',
5
+ '&amp;': '&',
6
+ '&lt;': '<',
7
+ '&gt;': '>',
8
+ '&quot;': '"',
9
+ };
10
+ const SOCIAL_TYPE_MAP = {
11
+ facebook: 'FACEBOOK',
12
+ instagram: 'INSTAGRAM',
13
+ x: 'TWITTER',
14
+ linkedin: 'LINKEDIN',
15
+ youtube: 'YOUTUBE',
16
+ pinterest: 'PINTEREST',
17
+ tiktok: 'TIKTOK',
18
+ twitch: 'TWITCH',
19
+ website: 'WEBSITE',
20
+ };
21
+ // Utility Functions
22
+ const sanitizeForVCard = (value) => {
23
+ if (!value || typeof value !== 'string')
24
+ return '';
25
+ let text = value.replace(/<[^>]*>/g, ''); // Strip HTML tags
26
+ // Decode HTML entities
27
+ Object.entries(HTML_ENTITIES).forEach(([entity, char]) => {
28
+ text = text.replace(new RegExp(entity, 'g'), char);
29
+ });
30
+ // Escape backslash FIRST, then other vCard special characters
31
+ text = text.replace(/\\/g, '\\\\');
32
+ text = text.replace(/\n/g, '\\n');
33
+ text = text.replace(/,/g, '\\,');
34
+ text = text.replace(/;/g, '\\;');
35
+ return text.trim();
36
+ };
37
+ const normalizeUrl = (url) => {
38
+ const trimmed = url.trim();
39
+ if (!trimmed)
40
+ return '';
41
+ // Add protocol if missing
42
+ if (trimmed.startsWith('//')) {
43
+ return isValidUrl(`https:${trimmed}`) ? `https:${trimmed}` : '';
44
+ }
45
+ if (!trimmed.startsWith('http://') && !trimmed.startsWith('https://')) {
46
+ return isValidUrl(`https://${trimmed}`) ? `https://${trimmed}` : '';
47
+ }
48
+ return isValidUrl(trimmed) ? trimmed : '';
49
+ };
50
+ const findContentsByType = (brandPageData, type) => {
51
+ if (!brandPageData?.pages)
52
+ return [];
53
+ return brandPageData.pages.flatMap((page) => page.contents?.filter((content) => content.type === type) || []);
54
+ };
55
+ export const findProfileContent = (brandPageData) => {
56
+ if (!brandPageData?.pages)
57
+ return undefined;
58
+ for (const page of brandPageData.pages) {
59
+ const profile = page.contents?.find((content) => content.type === 'profile');
60
+ if (profile)
61
+ return profile;
62
+ }
63
+ return undefined;
64
+ };
65
+ export const hasProfileContent = (brandPageData) => findProfileContent(brandPageData) !== undefined;
66
+ // vCard Entry Handlers
67
+ const addPhoneEntry = (phoneNumber, vcardLines) => {
68
+ const cleaned = phoneNumber.replace(/[^\d+]/g, '');
69
+ vcardLines.push(`TEL;TYPE=CELL:${cleaned}`);
70
+ };
71
+ const addEmailEntry = (email, vcardLines) => {
72
+ vcardLines.push(`EMAIL:${email}`, `EMAIL;TYPE=WORK:${email}`);
73
+ };
74
+ const addUrlEntry = (url, type, vcardLines) => {
75
+ const formatted = normalizeUrl(url);
76
+ // Skip invalid URLs
77
+ if (!formatted)
78
+ return;
79
+ if (type) {
80
+ vcardLines.push(`URL;TYPE=${type}:${formatted}`);
81
+ }
82
+ else {
83
+ vcardLines.push(`URL:${formatted}`);
84
+ }
85
+ };
86
+ const processContactUrl = (url, iconType, vcardLines) => {
87
+ if (url.startsWith('tel:')) {
88
+ addPhoneEntry(url.replace('tel:', ''), vcardLines);
89
+ }
90
+ else if (url.startsWith('mailto:')) {
91
+ addEmailEntry(url.replace('mailto:', ''), vcardLines);
92
+ }
93
+ else if (iconType === 'email') {
94
+ addEmailEntry(url, vcardLines);
95
+ }
96
+ else if (iconType === 'phone') {
97
+ addPhoneEntry(url, vcardLines);
98
+ }
99
+ else {
100
+ addUrlEntry(url, SOCIAL_TYPE_MAP[iconType], vcardLines);
101
+ }
102
+ };
103
+ const processButton = (button, vcardLines) => {
104
+ if (!button.url)
105
+ return;
106
+ const url = button.url.trim();
107
+ const iconType = button.iconUrl?.toLowerCase() || '';
108
+ processContactUrl(url, iconType, vcardLines);
109
+ };
110
+ const processSocialLinks = (socialLinksContent, vcardLines) => {
111
+ if (!socialLinksContent.links?.length)
112
+ return;
113
+ socialLinksContent.links.forEach((link) => {
114
+ if (!link.url)
115
+ return;
116
+ const url = link.url.trim();
117
+ const platform = link.imageUrl?.toLowerCase() || '';
118
+ processContactUrl(url, platform, vcardLines);
119
+ });
120
+ };
121
+ const addProfileInfo = (profile, vcardLines) => {
122
+ const name = sanitizeForVCard(profile.name || '');
123
+ const title = sanitizeForVCard(profile.title || '');
124
+ const description = sanitizeForVCard(profile.description || '');
125
+ if (name) {
126
+ const nameParts = name.trim().split(/\s+/);
127
+ const lastName = nameParts.length > 1 ? nameParts.pop() || '' : '';
128
+ const middleName = nameParts.length > 1 ? nameParts.pop() || '' : '';
129
+ const firstName = nameParts.join(' ');
130
+ vcardLines.push(`FN:${name}`, `N:${lastName};${firstName};${middleName};;`);
131
+ }
132
+ if (title)
133
+ vcardLines.push(`TITLE:${title}`);
134
+ if (description)
135
+ vcardLines.push(`NOTE:${description}`);
136
+ };
137
+ // Main Functions
138
+ export const generateVCard = (brandPageData) => {
139
+ const vcardLines = ['BEGIN:VCARD', 'VERSION:3.0'];
140
+ const profile = findProfileContent(brandPageData);
141
+ if (profile) {
142
+ addProfileInfo(profile, vcardLines);
143
+ }
144
+ const buttons = findContentsByType(brandPageData, 'button');
145
+ buttons.forEach((button) => processButton(button, vcardLines));
146
+ const socialLinks = findContentsByType(brandPageData, 'social-links');
147
+ socialLinks.forEach((links) => processSocialLinks(links, vcardLines));
148
+ vcardLines.push('END:VCARD');
149
+ return vcardLines.join('\r\n');
150
+ };
151
+ const generateVCardFilename = (name) => {
152
+ if (!name)
153
+ return 'contact.vcf';
154
+ const safeName = name
155
+ .replace(/[^a-z0-9]/gi, '_')
156
+ .toLowerCase()
157
+ .slice(0, 50);
158
+ return `${safeName}.vcf`;
159
+ };
160
+ const downloadVCard = (vcard, filename) => {
161
+ const blob = new Blob([vcard], { type: 'text/vcard;charset=utf-8' });
162
+ const url = URL.createObjectURL(blob);
163
+ const link = document.createElement('a');
164
+ link.href = url;
165
+ link.download = filename;
166
+ document.body.appendChild(link);
167
+ link.click();
168
+ document.body.removeChild(link);
169
+ URL.revokeObjectURL(url);
170
+ };
171
+ export const saveContact = (brandPageData) => {
172
+ const vcard = generateVCard(brandPageData);
173
+ const profile = findProfileContent(brandPageData);
174
+ const filename = generateVCardFilename(profile?.name);
175
+ downloadVCard(vcard, filename);
176
+ };
@@ -18,7 +18,7 @@ export const bannerDisplayTypeVisibilityAssessor = (content) => {
18
18
  content?.displayStyle === ALIGN_CARD_LEFT_IMAGE);
19
19
  };
20
20
  export const bannerOverlayOptionsVisibilityAssessor = (content) => {
21
- return Boolean(content.imageUrl &&
21
+ return Boolean((content.media?.type === 'getty-video' || content.imageUrl) &&
22
22
  [
23
23
  ALIGN_CARD_CENTER_IMAGE,
24
24
  ALIGN_CARD_LEFT_IMAGE,
@@ -1169,6 +1169,7 @@ declare const _default: import("vue").DefineComponent<{}, {
1169
1169
  bpShowTopNavigationMobile(): boolean;
1170
1170
  bpShowTopNavigationDesktop(): boolean;
1171
1171
  slug(): string;
1172
+ shouldShowSaveContactWidget(): boolean;
1172
1173
  }, {
1173
1174
  openSideMenu(): void;
1174
1175
  onLogoClick(tabName: string): void;
@@ -81,6 +81,7 @@ export default defineComponent({
81
81
  mediaSizes: MEDIA_SIZES.size1x,
82
82
  renderVideoAsImage: false,
83
83
  shouldPlayVideos: this.shouldPlayVideos,
84
+ showOnGeneratedPreviews: false,
84
85
  },
85
86
  stripePublishableKey: undefined,
86
87
  runtimeEnvironment: this.runtimeEnvironment,
@@ -432,6 +432,8 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
432
432
  scaledContainerStyle(): BrandPageCssStyle;
433
433
  innerContainerStyle(): BrandPageCssStyle;
434
434
  isPersonalisable(): boolean;
435
+ isAiTemplate(): boolean;
436
+ shouldRenderAsPage(): boolean;
435
437
  cssVariablesStyle(): Record<string, string>;
436
438
  previewImageUrl(): string;
437
439
  }, {
@@ -118,8 +118,10 @@ export default defineComponent({
118
118
  disableNavigationSideMenu: true,
119
119
  mediaSizes: MEDIA_SIZES.sizeThumb,
120
120
  renderVideoAsImage: true,
121
+ showOnGeneratedPreviews: false,
121
122
  },
122
123
  isCapturingPreview: false,
124
+ showOnGeneratedPreviews: false,
123
125
  };
124
126
  },
125
127
  previewViewport() {
@@ -147,6 +149,13 @@ export default defineComponent({
147
149
  isPersonalisable() {
148
150
  return this.template.isPersonalisable || false;
149
151
  },
152
+ isAiTemplate() {
153
+ return this.selectedTab.key === TEMPLATE_TABS.AI;
154
+ },
155
+ shouldRenderAsPage() {
156
+ const result = this.isPrePurchase || this.isAiTemplate;
157
+ return result;
158
+ },
150
159
  cssVariablesStyle() {
151
160
  if (!this.logoTheme) {
152
161
  return {};
@@ -47,6 +47,8 @@ export declare const EVENTS: {
47
47
  WEBSITE_MAKER_AI_SEND_PROMPT: string;
48
48
  WEBSITE_MAKER_AI_COPY_RESPONSE: string;
49
49
  WEBSITE_MAKER_AI_STOP_GENERATION: string;
50
+ WEBSITE_SAVE_CONTACT: string;
51
+ WEBSITE_START_FOR_FREE: string;
50
52
  };
51
53
  export declare const SELECT_LOCATIONS: {
52
54
  MAKER_PREVIEW: string;
@@ -30,6 +30,8 @@ export const EVENTS = {
30
30
  WEBSITE_MAKER_AI_SEND_PROMPT: 'website_maker_ai_send_prompt',
31
31
  WEBSITE_MAKER_AI_COPY_RESPONSE: 'website_maker_ai_copy_response',
32
32
  WEBSITE_MAKER_AI_STOP_GENERATION: 'website_maker_ai_stop_generation',
33
+ WEBSITE_SAVE_CONTACT: 'website_save_contact',
34
+ WEBSITE_START_FOR_FREE: 'website_start_for_free',
33
35
  };
34
36
  export const SELECT_LOCATIONS = {
35
37
  MAKER_PREVIEW: 'maker_preview',