@designcrowd/library.brand-page 6.1.3 → 6.1.4-ast-prepurchase

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 (149) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-Lk8J1vHg.js → CreatedOnBrandCrowd-de-de-BFDE6VfS.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-BbXj5fb1.js → CreatedOnBrandCrowd-en-us-CRhl6-Cd.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-CjnqvYCi.js → CreatedOnBrandCrowd-es-es-VaP_-7dv.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-Dbjv4qpN.js → CreatedOnBrandCrowd-fr-ca-BySGqvWO.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-Dbjv4qpN.js → CreatedOnBrandCrowd-fr-fr-BySGqvWO.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-BZIOPEvL.js → CreatedOnBrandCrowd-pt-br-BHjXVcSk.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-BZIOPEvL.js → CreatedOnBrandCrowd-pt-pt-BHjXVcSk.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-aN4JMRDI.js → CreatedOnDcom-de-de-DIFO5IZY.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-f3VD6Pz4.js → CreatedOnDcom-en-us-CcpDa04T.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-CQhNdtRP.js → CreatedOnDcom-es-es-DHwY0lWp.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-CFsC_XoO.js → CreatedOnDcom-fr-ca-BP3P0hJL.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-J4ZtCBO9.js → CreatedOnDcom-fr-fr-Bai1giy3.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-C1yFugh_.js → CreatedOnDcom-pt-br-GgKiDrbK.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-ycOo5lDn.js → CreatedOnDcom-pt-pt-uuuxCYR3.js} +1 -1
  15. package/lib/src/PreviewModal-DY2aAN0a.js +19931 -0
  16. package/lib/src/brand-page/components/page-footer/PageFooter.mixin.d.ts +0 -1
  17. package/lib/src/brand-page/components/page-footer/PageFooter.mixin.js +1 -4
  18. package/lib/src/brand-page/models/brand-page-context.model.d.ts +2 -0
  19. package/lib/src/brand-page/models/brand-page-context.model.js +12 -0
  20. package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.d.ts +2 -0
  21. package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.js +14 -1
  22. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +134 -0
  23. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +50 -0
  24. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +130 -0
  25. package/lib/src/brand-page-maker/components/navigation/Navigation.mixin.d.ts +1 -0
  26. package/lib/src/brand-page-maker/components/navigation/Navigation.mixin.js +3 -0
  27. package/lib/src/brand-page-maker/components/preview/Preview.mixin.d.ts +14 -0
  28. package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +130 -0
  29. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +130 -0
  30. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +130 -0
  31. package/lib/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.mixin.d.ts +130 -0
  32. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +130 -0
  33. package/lib/src/brand-page-maker/components/upgrade-to-premium-button/UpgradeToPremiumButton.mixin.d.ts +130 -0
  34. package/lib/src/brand-page-maker/composables/useEventTracker.d.ts +1 -0
  35. package/lib/src/brand-page-maker/composables/useEventTracker.js +1 -0
  36. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.d.ts +132 -0
  37. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.js +22 -6
  38. package/lib/src/bundled-translations-D42tE0D2.js +179 -0
  39. package/lib/src/bundled-translations.de-DE-D9aWGgFt.js +179 -0
  40. package/lib/src/bundled-translations.es-ES-lk4B0xQ7.js +179 -0
  41. package/lib/src/bundled-translations.fr-CA-DhOBNt6q.js +179 -0
  42. package/lib/src/bundled-translations.fr-FR-CnpafQeG.js +179 -0
  43. package/lib/src/bundled-translations.pt-BR-C4PnKrd9.js +179 -0
  44. package/lib/src/bundled-translations.pt-PT-CfKDVQC-.js +179 -0
  45. package/lib/src/bundles/bundled-translations.de-DE.json +5 -0
  46. package/lib/src/bundles/bundled-translations.es-ES.json +5 -0
  47. package/lib/src/bundles/bundled-translations.fr-CA.json +5 -0
  48. package/lib/src/bundles/bundled-translations.fr-FR.json +5 -0
  49. package/lib/src/bundles/bundled-translations.json +5 -0
  50. package/lib/src/bundles/bundled-translations.pt-BR.json +5 -0
  51. package/lib/src/bundles/bundled-translations.pt-PT.json +5 -0
  52. package/lib/src/clients/brand-page-client.d.ts +1 -0
  53. package/lib/src/composables/useTranslate.d.ts +2 -1
  54. package/lib/src/composables/useTranslate.js +2 -1
  55. package/lib/src/constants/brand-page-maker.d.ts +2 -0
  56. package/lib/src/constants/brand-page-maker.js +5 -0
  57. package/lib/src/constants/live-preview.constants.d.ts +15 -0
  58. package/lib/src/constants/live-preview.constants.js +15 -0
  59. package/lib/src/css/library.brand-page-brandCrowd.min.css +264 -121
  60. package/lib/src/css/library.brand-page-brandPage.min.css +268 -121
  61. package/lib/src/css/library.brand-page-designCom.min.css +264 -121
  62. package/lib/src/css/library.brand-page-preview.min.css +264 -121
  63. package/lib/src/index.d.ts +2 -1
  64. package/lib/src/index.mjs +102150 -225
  65. package/lib/src/lib.js +2 -1
  66. package/lib/src/preview-modal.d.ts +5 -0
  67. package/lib/src/preview-modal.js +12 -0
  68. package/lib/src/preview-modal.mjs +6 -0
  69. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +130 -0
  70. package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +130 -0
  71. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +130 -0
  72. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +130 -0
  73. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +144 -0
  74. package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +130 -0
  75. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +130 -0
  76. package/lib/src/tracker.mjs +1 -1
  77. package/lib/src/{useEventTracker-DmQ6AkNn.js → useEventTracker-Dmc2jFdN.js} +5 -4
  78. package/package.json +5 -1
  79. package/src/brand-page/components/button/Button.vue +11 -0
  80. package/src/brand-page/components/button/Button.vue.test.ts +90 -0
  81. package/src/brand-page/components/image-gallery/masonry/MasonryGallery.vue +1 -0
  82. package/src/brand-page/components/images-section/ImagesSection.vue +10 -0
  83. package/src/brand-page/components/media/Video.vue +60 -1
  84. package/src/brand-page/components/page-footer/PageFooter.mixin.ts +1 -4
  85. package/src/brand-page/components/page-footer/PageFooter.vue +0 -1
  86. package/src/brand-page/components/payment/Payment.vue +3 -0
  87. package/src/brand-page/components/payment/request-payment/RequestPayment.vue +1 -0
  88. package/src/brand-page/components/payment/support-me/SupportMe.vue +3 -0
  89. package/src/brand-page/components/shop/CartModal.vue +9 -0
  90. package/src/brand-page/components/shop/Shop.vue +19 -0
  91. package/src/brand-page/components/shop/Shop.vue.test.ts +182 -2
  92. package/src/brand-page/components/social-links/SocialLinks.vue +1 -9
  93. package/src/brand-page/components/social-links/SocialLinks.vue.test.ts +28 -8
  94. package/src/brand-page/components/social-links/SocialLinksItems.vue +6 -2
  95. package/src/brand-page/components/testimonial-section/TestimonialSection.vue +2 -2
  96. package/src/brand-page/components/video/Video.vue +3 -0
  97. package/src/brand-page/models/brand-page-context.model.ts +23 -0
  98. package/src/brand-page-maker/components/action-bar/ActionBar.mixin.ts +15 -0
  99. package/src/brand-page-maker/components/action-bar/ActionBarNavigation.test.ts +95 -0
  100. package/src/brand-page-maker/components/action-bar/ActionBarNavigation.vue +19 -4
  101. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +57 -0
  102. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.preview-gate.test.ts +113 -0
  103. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.vue +26 -1
  104. package/src/brand-page-maker/components/navigation/Navigation.mixin.ts +3 -0
  105. package/src/brand-page-maker/components/navigation/Navigation.vue +1 -0
  106. package/src/brand-page-maker/components/preview-modal/PreviewModal.test.ts +162 -0
  107. package/src/brand-page-maker/components/preview-modal/PreviewModal.vue +347 -0
  108. package/src/brand-page-maker/components/preview-modal/PreviewModalWithState.test.ts +226 -0
  109. package/src/brand-page-maker/components/preview-modal/PreviewModalWithState.vue +149 -0
  110. package/src/brand-page-maker/components/preview-modal/i18n/preview-modal.de-DE.json +6 -0
  111. package/src/brand-page-maker/components/preview-modal/i18n/preview-modal.es-ES.json +6 -0
  112. package/src/brand-page-maker/components/preview-modal/i18n/preview-modal.fr-CA.json +6 -0
  113. package/src/brand-page-maker/components/preview-modal/i18n/preview-modal.fr-FR.json +6 -0
  114. package/src/brand-page-maker/components/preview-modal/i18n/preview-modal.json +6 -0
  115. package/src/brand-page-maker/components/preview-modal/i18n/preview-modal.pt-BR.json +6 -0
  116. package/src/brand-page-maker/components/preview-modal/i18n/preview-modal.pt-PT.json +6 -0
  117. package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.vue +29 -17
  118. package/src/brand-page-maker/composables/useEventTracker.ts +1 -0
  119. package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.save.test.ts +106 -0
  120. package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.ts +40 -8
  121. package/src/bundles/bundled-translations.de-DE.json +5 -0
  122. package/src/bundles/bundled-translations.es-ES.json +5 -0
  123. package/src/bundles/bundled-translations.fr-CA.json +5 -0
  124. package/src/bundles/bundled-translations.fr-FR.json +5 -0
  125. package/src/bundles/bundled-translations.json +5 -0
  126. package/src/bundles/bundled-translations.pt-BR.json +5 -0
  127. package/src/bundles/bundled-translations.pt-PT.json +5 -0
  128. package/src/clients/brand-page-client.ts +2 -0
  129. package/src/composables/useTranslate.ts +2 -0
  130. package/src/constants/brand-page-maker.ts +5 -0
  131. package/src/constants/live-preview.constants.ts +15 -0
  132. package/src/lib.ts +5 -1
  133. package/src/preview-modal.ts +14 -0
  134. package/src/shared/common/i18n/common.de-DE.json +1 -0
  135. package/src/shared/common/i18n/common.es-ES.json +1 -0
  136. package/src/shared/common/i18n/common.fr-CA.json +1 -0
  137. package/src/shared/common/i18n/common.fr-FR.json +1 -0
  138. package/src/shared/common/i18n/common.json +1 -0
  139. package/src/shared/common/i18n/common.pt-BR.json +1 -0
  140. package/src/shared/common/i18n/common.pt-PT.json +1 -0
  141. package/src/shared/ecommerce-settings/store/cart-store.test.ts +38 -0
  142. package/lib/src/bundled-translations-2HkRBbBD.js +0 -177
  143. package/lib/src/bundled-translations.de-DE-CL9ZEhU2.js +0 -177
  144. package/lib/src/bundled-translations.es-ES-uj7Sliu0.js +0 -177
  145. package/lib/src/bundled-translations.fr-CA-BMnBtr_w.js +0 -177
  146. package/lib/src/bundled-translations.fr-FR-9PEZedzq.js +0 -177
  147. package/lib/src/bundled-translations.pt-BR-B3oNDkoe.js +0 -177
  148. package/lib/src/bundled-translations.pt-PT-DM7Vsf-h.js +0 -177
  149. package/lib/src/lib-CVwyHyBz.js +0 -121538
@@ -96,6 +96,11 @@ export interface BrandPageContainerState {
96
96
  isContextualUpgradeModalVisible: boolean;
97
97
  contextualUpgradeType: WebsiteContextUpgradeType | undefined;
98
98
  requestVerificationToken?: string;
99
+ // Set by the host whenever one of ITS OWN modals is open. The library can't see
100
+ // host-local visibility flags, so the preview has no other way to know to step back.
101
+ isHostModalVisible?: boolean;
102
+ // Signed live-preview URL returned by the most recent `saveOnly` save.
103
+ livePreviewUrl?: string;
99
104
  }
100
105
 
101
106
  export type GettyVideoEditorViewModelResponse = {
@@ -180,7 +185,9 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
180
185
  isSubsequentPublish: false,
181
186
  isContextualUpgradeModalVisible: false,
182
187
  contextualUpgradeType: undefined,
188
+ isHostModalVisible: false,
183
189
  requestVerificationToken: undefined,
190
+ livePreviewUrl: undefined,
184
191
  };
185
192
  },
186
193
  actions: {
@@ -338,6 +345,11 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
338
345
  this.isUpgradeModalVisible = payload.isVisible;
339
346
  },
340
347
 
348
+ // Hosts call this from their own modals so the live preview steps back for them.
349
+ setIsHostModalVisible(payload: { isVisible: boolean }) {
350
+ this.isHostModalVisible = payload.isVisible;
351
+ },
352
+
341
353
  setPublishErrorMessage(payload) {
342
354
  this.publishErrorMessage = payload.errorMessage;
343
355
  },
@@ -895,7 +907,15 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
895
907
  },
896
908
 
897
909
  async saveBrandPage(
898
- payload: { isPublish?: boolean; eventButtonLocation?: string } = {},
910
+ payload: {
911
+ isPublish?: boolean;
912
+ eventButtonLocation?: string;
913
+ // Save the draft WITHOUT pushing it live, even when the site is already
914
+ // published. Used by the live preview: previewing unpublished changes must
915
+ // never republish the site out from under the user. Default (omitted) keeps
916
+ // the existing behaviour — a save on a live site republishes it.
917
+ saveOnly?: boolean;
918
+ } = {},
899
919
  ) {
900
920
  const userStore = useBrandPageMakerUserStore();
901
921
  const brandPageMakerStore = useBrandPageMakerStore();
@@ -920,7 +940,7 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
920
940
 
921
941
  const response = await brandPageClient.saveBrandPageAsync(
922
942
  brandPageMakerStore.brandPageType,
923
- saveRequest,
943
+ { ...saveRequest, saveOnly: !!payload.saveOnly },
924
944
  this.designDraftToken,
925
945
  );
926
946
 
@@ -928,6 +948,8 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
928
948
  return false;
929
949
  }
930
950
 
951
+ this.livePreviewUrl = response.livePreviewUrl;
952
+
931
953
  if (this.brandPageStatus !== response.status) {
932
954
  await this.setBrandPageStatus(response.status);
933
955
  }
@@ -985,10 +1007,6 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
985
1007
  this.setSlug({ slug: response.slug });
986
1008
  }
987
1009
 
988
- this.setTriggerSaveSuccessMessage({
989
- triggerSaveSuccessMessage: true,
990
- });
991
-
992
1010
  if (brandPageMakerStore.contentErrorCount > 0) {
993
1011
  await brandPageMakerStore.setSelectedTabName({
994
1012
  tabName: SIDE_BAR_TAB_NAMES.CONTENT_SETTINGS,
@@ -999,7 +1017,9 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
999
1017
  triggerSaveSuccessMessage: true,
1000
1018
  });
1001
1019
 
1002
- if (!payload.isPublish) {
1020
+ // Deferred, not skipped, when something covers the editor: the publish modal
1021
+ // and the preview each raise it on close.
1022
+ if (!payload.isPublish && !payload.saveOnly) {
1003
1023
  await this.showSaveSuccessMessage();
1004
1024
 
1005
1025
  await brandPageMakerStore.showNextNotificationMessage();
@@ -1204,7 +1224,9 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
1204
1224
  }
1205
1225
 
1206
1226
  this.setIsUpgradeModalVisible({ isVisible: true });
1207
- await this.saveBrandPage();
1227
+ // The upgrade modal is already open over the editor, so don't fire the
1228
+ // save banner underneath it — `closeUpgradeModal` replays it on dismiss.
1229
+ await this.saveBrandPage({ isPublish: true });
1208
1230
  },
1209
1231
 
1210
1232
  async getContextualUpgradeResponseAsync(): Promise<
@@ -1513,5 +1535,15 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
1513
1535
  },
1514
1536
 
1515
1537
  isUserDraft: (state): boolean => !!state.designDraftToken,
1538
+
1539
+ // Every modal that can open OVER the editor. The live preview is a full-viewport
1540
+ // takeover, so it has to step back for all of them or they open behind it —
1541
+ // add new modals here (or via isHostModalVisible) rather than to the caller.
1542
+ isAnyModalVisible: (state): boolean =>
1543
+ state.isPublishModalVisible ||
1544
+ state.isUpgradeModalVisible ||
1545
+ state.isContextualUpgradeModalVisible ||
1546
+ state.isStripeOnboardingModalVisible ||
1547
+ !!state.isHostModalVisible,
1516
1548
  },
1517
1549
  });
@@ -1126,6 +1126,10 @@
1126
1126
  "linkInBioFriendlyName": "Link in der Biografie",
1127
1127
  "digitalBusinessCardFriendlyName": "Digitale Visitenkarte"
1128
1128
  },
1129
+ "previewModal": {
1130
+ "edit": "Bearbeiten",
1131
+ "retry": "Erneut versuchen"
1132
+ },
1129
1133
  "quickLinkBar": {
1130
1134
  "myWebPageLabel": "Meine Webseite:",
1131
1135
  "copyButton": "Kopieren",
@@ -1347,6 +1351,7 @@
1347
1351
  "settings": "Konfig.",
1348
1352
  "domains": "Domains",
1349
1353
  "sensitiveContent": "Sensible Inhalte",
1354
+ "close": "schließen",
1350
1355
  "displayStyle": "Anzeigestil",
1351
1356
  "colorMatched": "Farblich abgestimmt",
1352
1357
  "iconColor": "Symbolfarbe",
@@ -1126,6 +1126,10 @@
1126
1126
  "linkInBioFriendlyName": "Enlace en la bio",
1127
1127
  "digitalBusinessCardFriendlyName": "Tarjeta de visita digital"
1128
1128
  },
1129
+ "previewModal": {
1130
+ "edit": "Editar",
1131
+ "retry": "Vuelve a intentarlo"
1132
+ },
1129
1133
  "quickLinkBar": {
1130
1134
  "myWebPageLabel": "Mi página web:",
1131
1135
  "copyButton": "Copiar",
@@ -1347,6 +1351,7 @@
1347
1351
  "settings": "Ajustes",
1348
1352
  "domains": "Dominios",
1349
1353
  "sensitiveContent": "Contenido sensible",
1354
+ "close": "cierra",
1350
1355
  "displayStyle": "Estilo de visualización",
1351
1356
  "colorMatched": "Color combinado",
1352
1357
  "iconColor": "Color del icono",
@@ -1126,6 +1126,10 @@
1126
1126
  "linkInBioFriendlyName": "Lien dans la bio",
1127
1127
  "digitalBusinessCardFriendlyName": "Carte de visite numérique"
1128
1128
  },
1129
+ "previewModal": {
1130
+ "edit": "Éditer",
1131
+ "retry": "Réessayez"
1132
+ },
1129
1133
  "quickLinkBar": {
1130
1134
  "myWebPageLabel": "Ma page Web :",
1131
1135
  "copyButton": "Copier",
@@ -1347,6 +1351,7 @@
1347
1351
  "settings": "Paramètres",
1348
1352
  "domains": "Domaines",
1349
1353
  "sensitiveContent": "Contenu sensible",
1354
+ "close": "fermer",
1350
1355
  "displayStyle": "Style d'affichage",
1351
1356
  "colorMatched": "Couleur assortie",
1352
1357
  "iconColor": "Couleur de l'icône",
@@ -1126,6 +1126,10 @@
1126
1126
  "linkInBioFriendlyName": "Lien dans la bio",
1127
1127
  "digitalBusinessCardFriendlyName": "Carte de visite numérique"
1128
1128
  },
1129
+ "previewModal": {
1130
+ "edit": "Éditer",
1131
+ "retry": "Réessayez"
1132
+ },
1129
1133
  "quickLinkBar": {
1130
1134
  "myWebPageLabel": "Ma page Web :",
1131
1135
  "copyButton": "Copier",
@@ -1347,6 +1351,7 @@
1347
1351
  "settings": "Paramètres",
1348
1352
  "domains": "Domaines",
1349
1353
  "sensitiveContent": "Contenu sensible",
1354
+ "close": "fermer",
1350
1355
  "displayStyle": "Style d'affichage",
1351
1356
  "colorMatched": "Couleur assortie",
1352
1357
  "iconColor": "Couleur de l'icône",
@@ -1126,6 +1126,10 @@
1126
1126
  "linkInBioFriendlyName": "Link in Bio",
1127
1127
  "digitalBusinessCardFriendlyName": "Digital Business Card"
1128
1128
  },
1129
+ "previewModal": {
1130
+ "edit": "Edit",
1131
+ "retry": "Retry"
1132
+ },
1129
1133
  "quickLinkBar": {
1130
1134
  "myWebPageLabel": "My web page:",
1131
1135
  "copyButton": "Copy",
@@ -1347,6 +1351,7 @@
1347
1351
  "settings": "Settings",
1348
1352
  "domains": "Domains",
1349
1353
  "sensitiveContent": "Sensitive Content",
1354
+ "close": "Close",
1350
1355
  "displayStyle": "Display style",
1351
1356
  "colorMatched": "Color Matched",
1352
1357
  "iconColor": "Icon color",
@@ -1126,6 +1126,10 @@
1126
1126
  "linkInBioFriendlyName": "Link na Bio",
1127
1127
  "digitalBusinessCardFriendlyName": "Cartão de visita digital"
1128
1128
  },
1129
+ "previewModal": {
1130
+ "edit": "Editar",
1131
+ "retry": "Tente novamente"
1132
+ },
1129
1133
  "quickLinkBar": {
1130
1134
  "myWebPageLabel": "Minha página web:",
1131
1135
  "copyButton": "Copiar",
@@ -1347,6 +1351,7 @@
1347
1351
  "settings": "Ajustes",
1348
1352
  "domains": "Domínios",
1349
1353
  "sensitiveContent": "Conteúdo sensível",
1354
+ "close": "fechar",
1350
1355
  "displayStyle": "Estilo de exibição",
1351
1356
  "colorMatched": "Cor combinada",
1352
1357
  "iconColor": "Cor do ícone",
@@ -1126,6 +1126,10 @@
1126
1126
  "linkInBioFriendlyName": "Link na biografia",
1127
1127
  "digitalBusinessCardFriendlyName": "Cartão de visita digital"
1128
1128
  },
1129
+ "previewModal": {
1130
+ "edit": "Editar",
1131
+ "retry": "Repetir"
1132
+ },
1129
1133
  "quickLinkBar": {
1130
1134
  "myWebPageLabel": "A minha página Web:",
1131
1135
  "copyButton": "Copiar",
@@ -1347,6 +1351,7 @@
1347
1351
  "settings": "Definições",
1348
1352
  "domains": "Domínios",
1349
1353
  "sensitiveContent": "Conteúdo sensível",
1354
+ "close": "fechar",
1350
1355
  "displayStyle": "Estilo de exibição",
1351
1356
  "colorMatched": "Cor combinada",
1352
1357
  "iconColor": "Cor do ícone",
@@ -11,6 +11,8 @@ export interface SaveBrandPageResponse {
11
11
  slug: string;
12
12
  canPublish: boolean;
13
13
  renameUrl?: string;
14
+ // Only returned for a `saveOnly` save — the signed URL for the live-preview iframe.
15
+ livePreviewUrl?: string;
14
16
  websiteUpsellModalViewModel: any;
15
17
  }
16
18
 
@@ -189,6 +189,7 @@ const mapTr = (key) => tr(`map.${key}`);
189
189
  const imagesSectionTr = (key) => tr(`imagesSection.${key}`);
190
190
  const imageGalleryTr = (key) => tr(`imageGallery.${key}`);
191
191
  const newPageModalTr = (key) => tr(`newPageModal.${key}`);
192
+ const previewModalTr = (key) => tr(`previewModal.${key}`);
192
193
  const personalisationOverrideTr = (key, valuesToInterpolate = {}) =>
193
194
  tr(`personalisationOverride.${key}`, valuesToInterpolate);
194
195
  const paymentModalTr = (key, valuesToInterpolate = {}) =>
@@ -318,6 +319,7 @@ export {
318
319
  imagesSectionTr,
319
320
  imageGalleryTr,
320
321
  newPageModalTr,
322
+ previewModalTr,
321
323
  personalisationOverrideTr,
322
324
  paymentModalTr,
323
325
  mailingListTr,
@@ -6,6 +6,11 @@ export {
6
6
  export const EVENTS = {
7
7
  Save: 'save',
8
8
  Publish: 'publish',
9
+ Preview: 'preview',
10
+ // The Live Preview button needs the host's Save Progress flow to run first —
11
+ // sign-in for a signed-out customer, draft creation pre-purchase. Also emitted
12
+ // by the modal when it needs a pre-purchase save it can't perform itself.
13
+ LivePreviewClicked: 'livepreviewclicked',
9
14
  Initialised: 'initialised',
10
15
  Back: 'Back',
11
16
  } as const;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Messages the framed live preview (`/_p`, web-renderer) posts up to the editor.
3
+ * The frame is cross-origin, so a key pressed inside it never reaches the parent.
4
+ * Both repos import this — a drifting literal would fail silently.
5
+ */
6
+ export const LIVE_PREVIEW_MESSAGES = {
7
+ escape: 'bc-live-preview:escape',
8
+ /**
9
+ * Sent once the preview has actually painted — fonts settled and every image and
10
+ * video holding a frame. The iframe's own `load` event fires well before this
11
+ * (media elements release it around metadata, not buffered data), so revealing on
12
+ * `load` shows a half-drawn page. The editor waits for this instead.
13
+ */
14
+ ready: 'bc-live-preview:ready',
15
+ } as const;
package/src/lib.ts CHANGED
@@ -28,6 +28,7 @@ export {
28
28
  RECAPTCHA_MIN_SCORE,
29
29
  } from './brand-page/constants';
30
30
  export * from './brand-page-maker/constants';
31
+ export { LIVE_PREVIEW_MESSAGES } from './constants/live-preview.constants';
31
32
  export * as BackgroundShapeStarterKit from './brand-page-maker/components/brand-page-maker/starter-kits/background-shapes';
32
33
  export * as BackgroundColorsStarterKit from './brand-page-maker/components/brand-page-maker/starter-kits/background-colors';
33
34
  export * as BackgroundGradientStarterKit from './brand-page-maker/components/brand-page-maker/starter-kits/background-gradients';
@@ -104,7 +105,10 @@ export { getPageSlugFromPageTitle } from './brand-page-maker/utils/slug.util';
104
105
  // metadata-builder / route utils.
105
106
  export { executeToolCallsAsync } from './metadata-builder/ai-metadata-executor';
106
107
  export type { ParsedToolCall } from './metadata-builder/parsers/ai-toolcall-parser';
107
- export { findNavItemByPageSlug } from './brand-page/utils/route.util';
108
+ export {
109
+ findNavItemByPageSlug,
110
+ findNavItemByRelativePath,
111
+ } from './brand-page/utils/route.util';
108
112
  // Tiptap-JSON RTE -> HTML (same converter the metadata builders use). Lets the
109
113
  // preview render the agent's raw Tiptap fields, which the renderer expects as HTML.
110
114
  export { tiptapJsonToHtml } from './metadata-builder/helpers/rte.helpers';
@@ -0,0 +1,14 @@
1
+ // Lightweight subpath entry: `@designcrowd/library.brand-page/preview-modal`.
2
+ // Re-exports ONLY the stateless PreviewModal shell (previewUrl + cta, no maker
3
+ // store), so consumers (the BrandCrowd.Nuxt search page) can open the live-preview
4
+ // modal without pulling the full library graph (maker, TipTap, renderer). The
5
+ // multi-entry build hoists the shared deps into a chunk shared with `index` —
6
+ // verified maker/TipTap-free at build time.
7
+ //
8
+ // `setLocaleAsync` is exported alongside the component because the modal renders
9
+ // its labels via i18n; without initialising the locale first they show as raw keys.
10
+ export { default as PreviewModal } from './brand-page-maker/components/preview-modal/PreviewModal.vue';
11
+ export { LIVE_PREVIEW_MESSAGES } from './constants/live-preview.constants';
12
+ export { setLocaleAsync } from './composables/useTranslate';
13
+ export type { UiDeviceMode } from './shared/models';
14
+ export type { LocaleTypes } from './composables/useTranslate';
@@ -19,6 +19,7 @@
19
19
  "settings": "Konfig.",
20
20
  "domains": "Domains",
21
21
  "sensitiveContent": "Sensible Inhalte",
22
+ "close": "schließen",
22
23
 
23
24
  "displayStyle": "Anzeigestil",
24
25
  "colorMatched": "Farblich abgestimmt",
@@ -19,6 +19,7 @@
19
19
  "settings": "Ajustes",
20
20
  "domains": "Dominios",
21
21
  "sensitiveContent": "Contenido sensible",
22
+ "close": "cierra",
22
23
 
23
24
  "displayStyle": "Estilo de visualización",
24
25
  "colorMatched": "Color combinado",
@@ -19,6 +19,7 @@
19
19
  "settings": "Paramètres",
20
20
  "domains": "Domaines",
21
21
  "sensitiveContent": "Contenu sensible",
22
+ "close": "fermer",
22
23
 
23
24
  "displayStyle": "Style d'affichage",
24
25
  "colorMatched": "Couleur assortie",
@@ -19,6 +19,7 @@
19
19
  "settings": "Paramètres",
20
20
  "domains": "Domaines",
21
21
  "sensitiveContent": "Contenu sensible",
22
+ "close": "fermer",
22
23
 
23
24
  "displayStyle": "Style d'affichage",
24
25
  "colorMatched": "Couleur assortie",
@@ -19,6 +19,7 @@
19
19
  "settings": "Settings",
20
20
  "domains": "Domains",
21
21
  "sensitiveContent": "Sensitive Content",
22
+ "close": "Close",
22
23
 
23
24
  "displayStyle": "Display style",
24
25
  "colorMatched": "Color Matched",
@@ -19,6 +19,7 @@
19
19
  "settings": "Ajustes",
20
20
  "domains": "Domínios",
21
21
  "sensitiveContent": "Conteúdo sensível",
22
+ "close": "fechar",
22
23
 
23
24
  "displayStyle": "Estilo de exibição",
24
25
  "colorMatched": "Cor combinada",
@@ -19,6 +19,7 @@
19
19
  "settings": "Definições",
20
20
  "domains": "Domínios",
21
21
  "sensitiveContent": "Conteúdo sensível",
22
+ "close": "fechar",
22
23
 
23
24
  "displayStyle": "Estilo de exibição",
24
25
  "colorMatched": "Cor combinada",
@@ -166,6 +166,44 @@ describe('Cart Store', () => {
166
166
  expect(cartStore.cartItems[0].enableEdit).toBe(false);
167
167
  });
168
168
 
169
+ // Mirrors ProductDetailModal.onAdd: the product is registered in the shop store
170
+ // (as the preview now does), and Add to Cart resolves the SKU + price from it. This
171
+ // is the in-memory add-to-cart path that the live preview exercises — no network.
172
+ it('adds a product to the cart via the shop store (ProductDetailModal.onAdd path)', () => {
173
+ shopConfigStoreMock.addProduct({
174
+ id: 'product-1',
175
+ name: 'Test Product',
176
+ hasVariants: false,
177
+ skus: [{ skuKey: 'sku-123', id: 'sku-id-1', price: 100, variant: [] }],
178
+ });
179
+
180
+ cartStore.addOrUpdateSkuItemToCart({
181
+ skuKey: 'sku-123',
182
+ productId: 'product-1',
183
+ quantity: 2,
184
+ });
185
+
186
+ expect(cartStore.cartItems).toHaveLength(1);
187
+ expect(cartStore.cartItems[0]).toEqual({
188
+ productId: 'product-1',
189
+ productSkuId: 'sku-id-1',
190
+ skuKey: 'sku-123',
191
+ unitPrice: 100,
192
+ quantity: 2,
193
+ notes: undefined,
194
+ });
195
+ });
196
+
197
+ it('does not add to the cart when the product is not in the shop store', () => {
198
+ cartStore.addOrUpdateSkuItemToCart({
199
+ skuKey: 'sku-123',
200
+ productId: 'missing-product',
201
+ quantity: 1,
202
+ });
203
+
204
+ expect(cartStore.cartItems).toHaveLength(0);
205
+ });
206
+
169
207
  it('should handle decimal prices correctly', () => {
170
208
  cartStore.cartItems.push({
171
209
  skuKey: 'sku-789',