@designcrowd/library.brand-page 5.16.18-pre-temp-5 → 5.16.18-save-7

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 (113) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-CdAKMu3Z.js → CreatedOnBrandCrowd-de-de-DRDyO3Nx.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-BBMDDAa_.js → CreatedOnBrandCrowd-en-us-B4n8hMbK.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-DTwS7YK8.js → CreatedOnBrandCrowd-es-es-DtqF14OB.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-5VHOtmPC.js → CreatedOnBrandCrowd-fr-ca-22zD1vMd.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-5VHOtmPC.js → CreatedOnBrandCrowd-fr-fr-22zD1vMd.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-B7GPKvjK.js → CreatedOnBrandCrowd-pt-br-ZFYnp1CJ.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-B7GPKvjK.js → CreatedOnBrandCrowd-pt-pt-ZFYnp1CJ.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-KIlwGfjA.js → CreatedOnDcom-de-de-BIYI--dR.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-CSdRVDnn.js → CreatedOnDcom-en-us-D3MjlZKo.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-CPFtzvn4.js → CreatedOnDcom-es-es-BHyAebHO.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-CJqQeuni.js → CreatedOnDcom-fr-ca-BN3nlrRA.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-bYbEQhxp.js → CreatedOnDcom-fr-fr-DvGvHuuL.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-Cwe4yt9x.js → CreatedOnDcom-pt-br-BUrqir03.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-CgV-hgaC.js → CreatedOnDcom-pt-pt-Cm65TWeg.js} +1 -1
  15. package/lib/src/brand-page/components/button/Button.mixin.d.ts +1 -0
  16. package/lib/src/brand-page/components/button/Button.mixin.js +3 -0
  17. package/lib/src/brand-page/components/page/Page.mixin.d.ts +1 -0
  18. package/lib/src/brand-page/components/page/Page.mixin.js +16 -0
  19. package/lib/src/brand-page/components/page-footer/PageFooter.mixin.d.ts +12 -1
  20. package/lib/src/brand-page/components/page-footer/PageFooter.mixin.js +5 -0
  21. package/lib/src/brand-page/components/payment/__fixtures__/request-payment.d.ts +1 -0
  22. package/lib/src/brand-page/components/payment/__fixtures__/support-me.d.ts +1 -0
  23. package/lib/src/brand-page/models/brand-page-context.model.d.ts +1 -0
  24. package/lib/src/brand-page/utils/vcard.util.d.ts +13 -0
  25. package/lib/src/brand-page/utils/vcard.util.js +176 -0
  26. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +1 -0
  27. package/lib/src/brand-page-maker/components/preview/Preview.mixin.js +1 -0
  28. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.js +5 -4
  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 +6 -0
  39. package/lib/src/bundles/bundled-translations.es-ES.json +6 -0
  40. package/lib/src/bundles/bundled-translations.fr-CA.json +6 -0
  41. package/lib/src/bundles/bundled-translations.fr-FR.json +6 -0
  42. package/lib/src/bundles/bundled-translations.json +6 -0
  43. package/lib/src/bundles/bundled-translations.pt-BR.json +6 -0
  44. package/lib/src/bundles/bundled-translations.pt-PT.json +6 -0
  45. package/lib/src/clients/design-template-client.d.ts +0 -2
  46. package/lib/src/clients/fabric-render-client.d.ts +0 -3
  47. package/lib/src/composables/useTranslate.d.ts +2 -1
  48. package/lib/src/composables/useTranslate.js +2 -1
  49. package/lib/src/css/library.brand-page-brandCrowd.min.css +161 -40
  50. package/lib/src/css/library.brand-page-brandPage.min.css +163 -40
  51. package/lib/src/css/library.brand-page-designCom.min.css +161 -40
  52. package/lib/src/css/library.brand-page-preview.min.css +161 -40
  53. package/lib/src/index.d.ts +1 -1
  54. package/lib/src/index.mjs +65 -66
  55. package/lib/src/{lib-DDTH2L4M.js → lib-CqYQxuXU.js} +17036 -16749
  56. package/lib/src/lib.js +1 -1
  57. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.js +1 -0
  58. package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.js +1 -0
  59. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +0 -2
  60. package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +0 -2
  61. package/lib/src/shared/logo-settings/store/editable-logo-store.d.ts +0 -4
  62. package/lib/src/shared/logo-settings/store/editable-logo-store.js +0 -11
  63. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +0 -2
  64. package/lib/src/shared/template-settings/store/template-settings-store.js +8 -31
  65. package/package.json +1 -1
  66. package/src/brand-page/components/brand-page-footer/i18n/brand-page-footer.de-DE.json +5 -5
  67. package/src/brand-page/components/brand-page-footer/i18n/brand-page-footer.es-ES.json +5 -5
  68. package/src/brand-page/components/brand-page-footer/i18n/brand-page-footer.fr-CA.json +5 -5
  69. package/src/brand-page/components/brand-page-footer/i18n/brand-page-footer.fr-FR.json +5 -5
  70. package/src/brand-page/components/brand-page-footer/i18n/brand-page-footer.pt-BR.json +5 -5
  71. package/src/brand-page/components/brand-page-footer/i18n/brand-page-footer.pt-PT.json +5 -5
  72. package/src/brand-page/components/button/Button.mixin.ts +3 -0
  73. package/src/brand-page/components/button/Button.vue +68 -58
  74. package/src/brand-page/components/page/Page.mixin.ts +20 -0
  75. package/src/brand-page/components/page/Page.vue +10 -1
  76. package/src/brand-page/components/page-footer/PageFooter.mixin.ts +9 -1
  77. package/src/brand-page/components/save-contact/SaveContactWidget.vue +213 -0
  78. package/src/brand-page/components/save-contact/i18n/save-contact.de-DE.json +8 -0
  79. package/src/brand-page/components/save-contact/i18n/save-contact.es-ES.json +8 -0
  80. package/src/brand-page/components/save-contact/i18n/save-contact.fr-CA.json +8 -0
  81. package/src/brand-page/components/save-contact/i18n/save-contact.fr-FR.json +8 -0
  82. package/src/brand-page/components/save-contact/i18n/save-contact.json +8 -0
  83. package/src/brand-page/components/save-contact/i18n/save-contact.pt-BR.json +8 -0
  84. package/src/brand-page/components/save-contact/i18n/save-contact.pt-PT.json +8 -0
  85. package/src/brand-page/components/save-contact/popup-card/PopupCard.vue +156 -0
  86. package/src/brand-page/components/shop/ProductDetailModal.vue +1 -1
  87. package/src/brand-page/models/brand-page-context.model.ts +1 -0
  88. package/src/brand-page/utils/vcard.util.ts +252 -0
  89. package/src/brand-page-maker/components/preview/Preview.mixin.ts +1 -0
  90. package/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.ts +5 -4
  91. package/src/brand-page-maker/composables/useEventTracker.ts +2 -0
  92. package/src/bundles/bundled-translations.de-DE.json +6 -0
  93. package/src/bundles/bundled-translations.es-ES.json +6 -0
  94. package/src/bundles/bundled-translations.fr-CA.json +6 -0
  95. package/src/bundles/bundled-translations.fr-FR.json +6 -0
  96. package/src/bundles/bundled-translations.json +6 -0
  97. package/src/bundles/bundled-translations.pt-BR.json +6 -0
  98. package/src/bundles/bundled-translations.pt-PT.json +6 -0
  99. package/src/clients/design-template-client.ts +0 -2
  100. package/src/clients/fabric-render-client.ts +0 -3
  101. package/src/composables/useTranslate.ts +3 -0
  102. package/src/lib.ts +0 -1
  103. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.ts +1 -0
  104. package/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.ts +1 -0
  105. package/src/shared/logo-settings/store/editable-logo-store.ts +0 -13
  106. package/src/shared/template-settings/store/template-settings-store.ts +9 -44
  107. package/lib/src/bundled-translations-_qB5IIQe.js +0 -163
  108. package/lib/src/bundled-translations.de-DE-BO_hJ5Bu.js +0 -163
  109. package/lib/src/bundled-translations.es-ES-B5U67zCi.js +0 -163
  110. package/lib/src/bundled-translations.fr-CA-C5ZFrUtX.js +0 -163
  111. package/lib/src/bundled-translations.fr-FR-hG15gX3m.js +0 -163
  112. package/lib/src/bundled-translations.pt-BR-DlCmapd7.js +0 -163
  113. package/lib/src/bundled-translations.pt-PT-lUdbHOo4.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-DDTH2L4M.js";
2
+ import { _ as t } from "./lib-CqYQxuXU.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-DDTH2L4M.js";
2
+ import { _ as t } from "./lib-CqYQxuXU.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-DDTH2L4M.js";
2
+ import { _ as t } from "./lib-CqYQxuXU.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-DDTH2L4M.js";
2
+ import { _ as t } from "./lib-CqYQxuXU.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-DDTH2L4M.js";
2
+ import { _ as t } from "./lib-CqYQxuXU.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-DDTH2L4M.js";
2
+ import { _ as t } from "./lib-CqYQxuXU.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-DDTH2L4M.js";
2
+ import { _ as t } from "./lib-CqYQxuXU.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-DDTH2L4M.js";
2
+ import { _ as e } from "./lib-CqYQxuXU.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-DDTH2L4M.js";
2
+ import { _ as e } from "./lib-CqYQxuXU.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-DDTH2L4M.js";
2
+ import { _ as e } from "./lib-CqYQxuXU.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-DDTH2L4M.js";
2
+ import { _ as e } from "./lib-CqYQxuXU.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-DDTH2L4M.js";
2
+ import { _ as e } from "./lib-CqYQxuXU.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-DDTH2L4M.js";
2
+ import { _ as M } from "./lib-CqYQxuXU.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-DDTH2L4M.js";
2
+ import { _ as M } from "./lib-CqYQxuXU.js";
3
3
  const Z = {}, e = {
4
4
  width: "232",
5
5
  height: "36",
@@ -19,6 +19,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
19
19
  isModalVisible: boolean;
20
20
  }, {
21
21
  buttonStyle(): BrandPageCssStyle;
22
+ buttonTitle(): string;
22
23
  iconImgStyle(): BrandPageCssStyle;
23
24
  isIconImage(): boolean;
24
25
  iconColor(): string | undefined;
@@ -29,6 +29,9 @@ export default defineComponent({
29
29
  buttonStyle() {
30
30
  return this.viewModel.styles?.style || {};
31
31
  },
32
+ buttonTitle() {
33
+ return this.viewModel.title || '';
34
+ },
32
35
  iconImgStyle() {
33
36
  if (!this.viewModel.styles?.style) {
34
37
  return {};
@@ -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,6 +24,7 @@ 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;
@@ -24,6 +24,7 @@ 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;
@@ -71,6 +71,7 @@ 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 */
@@ -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
+ };
@@ -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,
@@ -118,6 +118,7 @@ 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,
123
124
  };
@@ -188,7 +189,7 @@ export default defineComponent({
188
189
  },
189
190
  watch: {
190
191
  template() {
191
- if (this.isAdmin) {
192
+ if (this.isAdmin || this.isPrePurchase) {
192
193
  this.updateViewModel();
193
194
  }
194
195
  else {
@@ -199,7 +200,7 @@ export default defineComponent({
199
200
  },
200
201
  logoTheme: {
201
202
  handler() {
202
- if (this.isAdmin) {
203
+ if (this.isAdmin || this.isPrePurchase) {
203
204
  this.updateViewModel();
204
205
  }
205
206
  },
@@ -207,7 +208,7 @@ export default defineComponent({
207
208
  },
208
209
  previewImageUrl() {
209
210
  // Reset loading state whenever the preview URL changes
210
- if (!this.isAdmin) {
211
+ if (!this.isAdmin && !this.isPrePurchase) {
211
212
  this.imageLoading = true;
212
213
  this.imageLoadError = false;
213
214
  }
@@ -266,7 +267,7 @@ export default defineComponent({
266
267
  },
267
268
  async updateViewModel(forceUpdate = true) {
268
269
  // Only update view model for admin or pre-purchase mode
269
- if (!this.isAdmin) {
270
+ if (!this.isAdmin && !this.isPrePurchase) {
270
271
  return;
271
272
  }
272
273
  const videoStore = useVideoStore();
@@ -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',