@designcrowd/library.brand-page 6.2.9 → 6.2.10-ast-faq-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.
- package/lib/src/{CreatedOnBrandCrowd-de-de-9uC6t5HU.js → CreatedOnBrandCrowd-de-de-BZrMq1gI.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-P6TzcklZ.js → CreatedOnBrandCrowd-en-us-DPC8TAr4.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-DimkGb1_.js → CreatedOnBrandCrowd-es-es-B94gSf_i.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-CL_iFuJw.js → CreatedOnBrandCrowd-fr-ca-DziGGjA1.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-CL_iFuJw.js → CreatedOnBrandCrowd-fr-fr-DziGGjA1.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-DSIjEoMv.js → CreatedOnBrandCrowd-pt-br-CfTCQ9nC.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-DSIjEoMv.js → CreatedOnBrandCrowd-pt-pt-CfTCQ9nC.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-CKRvl9Ky.js → CreatedOnDcom-de-de-C22-PnKc.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-ChplPDfS.js → CreatedOnDcom-en-us-CZqr71VB.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-DCIXsW9X.js → CreatedOnDcom-es-es-BinRuIc_.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-lakt1nLU.js → CreatedOnDcom-fr-ca-DYYBqMhv.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-RsGK1y5g.js → CreatedOnDcom-fr-fr-3ytJgZBj.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-DyA4XodM.js → CreatedOnDcom-pt-br-D1UqN_eq.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-BK51dTyw.js → CreatedOnDcom-pt-pt-BnIpbt_8.js} +1 -1
- package/lib/src/brand-page/constants/misc.constants.d.ts +8 -0
- package/lib/src/brand-page/constants/misc.constants.js +7 -0
- package/lib/src/brand-page/constants/styles.constants.d.ts +2 -0
- package/lib/src/brand-page/constants/styles.constants.js +2 -0
- package/lib/src/brand-page/models/content.model.d.ts +1 -0
- package/lib/src/brand-page/models/content.model.js +1 -0
- package/lib/src/brand-page/models/index.d.ts +22 -0
- package/lib/src/brand-page/utils/content-callback-util.d.ts +2 -1
- package/lib/src/brand-page/utils/content-callback-util.js +3 -0
- package/lib/src/brand-page/utils/view-model.util.js +22 -0
- package/lib/src/brand-page/view-models.d.ts +7 -2
- package/lib/src/brand-page-maker/assessors/faq-accordion-color-field-visibility.assessor.d.ts +3 -0
- package/lib/src/brand-page-maker/assessors/faq-accordion-color-field-visibility.assessor.js +4 -0
- package/lib/src/brand-page-maker/assessors/index.d.ts +1 -0
- package/lib/src/brand-page-maker/assessors/index.js +1 -0
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +9 -5
- package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +9 -5
- package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +6 -5
- package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +7 -5
- package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.js +5 -0
- package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +6 -5
- package/lib/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.mixin.d.ts +6 -5
- package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +6 -5
- package/lib/src/brand-page-maker/components/upgrade-to-premium-button/UpgradeToPremiumButton.mixin.d.ts +6 -5
- package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.d.ts +13 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +33 -12
- package/lib/src/brand-page-maker/constants/config-settings-constant.d.ts +2 -1
- package/lib/src/brand-page-maker/constants/config-settings-constant.js +103 -4
- package/lib/src/brand-page-maker/convertors/faq-display-style.convertor.d.ts +3 -0
- package/lib/src/brand-page-maker/convertors/faq-display-style.convertor.js +49 -0
- package/lib/src/brand-page-maker/models/content-settings-configs.d.ts +1 -0
- package/lib/src/brand-page-maker/models/content-settings-configs.js +1 -0
- package/lib/src/brand-page-maker/models/content-settings.d.ts +4 -1
- package/lib/src/brand-page-maker/models/content-settings.js +47 -1
- package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.d.ts +7 -6
- package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.js +52 -5
- package/lib/src/brand-page-maker/utils/apply-color-strategy.js +45 -17
- package/lib/src/brand-page-maker/utils/rich-text-editor.util.d.ts +6 -0
- package/lib/src/brand-page-maker/utils/rich-text-editor.util.js +24 -1
- package/lib/src/brand-page-maker/validators/field.validator.js +2 -0
- package/lib/src/{bundled-translations-zfiA5Tsw.js → bundled-translations-CUJ-udgD.js} +17 -17
- package/lib/src/{bundled-translations.de-DE-ChsdSyAP.js → bundled-translations.de-DE-Ch7Y_CCO.js} +22 -22
- package/lib/src/{bundled-translations.es-ES-DflsWQK0.js → bundled-translations.es-ES-B4CWkXkC.js} +30 -30
- package/lib/src/{bundled-translations.fr-CA-fpDRuZ52.js → bundled-translations.fr-CA-Drtb5hJ2.js} +9 -9
- package/lib/src/{bundled-translations.fr-FR-Bub73Zt-.js → bundled-translations.fr-FR-CImFpWT4.js} +29 -29
- package/lib/src/{bundled-translations.pt-BR-BlnWE9TB.js → bundled-translations.pt-BR-BHluaLc_.js} +15 -15
- package/lib/src/{bundled-translations.pt-PT-DmzXlnaS.js → bundled-translations.pt-PT-BxL2VvW4.js} +37 -37
- package/lib/src/bundles/bundled-translations.de-DE.json +13 -5
- package/lib/src/bundles/bundled-translations.es-ES.json +14 -6
- package/lib/src/bundles/bundled-translations.fr-CA.json +14 -6
- package/lib/src/bundles/bundled-translations.fr-FR.json +14 -6
- package/lib/src/bundles/bundled-translations.json +9 -1
- package/lib/src/bundles/bundled-translations.pt-BR.json +13 -5
- package/lib/src/bundles/bundled-translations.pt-PT.json +13 -5
- package/lib/src/composables/useTranslate.d.ts +1 -1
- package/lib/src/composables/useTranslate.js +1 -1
- package/lib/src/css/library.brand-page-brandCrowd.min.css +164 -53
- package/lib/src/css/library.brand-page-brandPage.min.css +164 -53
- package/lib/src/css/library.brand-page-designCom.min.css +164 -53
- package/lib/src/css/library.brand-page-preview.min.css +164 -53
- package/lib/src/index.mjs +161 -160
- package/lib/src/{lib-Ca7GMpcR.js → lib-nAkVtlza.js} +34006 -33265
- package/lib/src/metadata-builder/parsers/section-tool-arguments.d.ts +1 -1
- package/lib/src/shared/color-strategies/color-strategies.js +4 -0
- package/lib/src/shared/color-strategies/rte-field-pairs.d.ts +12 -0
- package/lib/src/shared/color-strategies/rte-field-pairs.js +10 -0
- package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +3 -0
- package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +4 -1
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +3 -0
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +3 -0
- package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.d.ts +3 -0
- package/lib/src/shared/content-settings/components/items-field/ItemsField.mixin.d.ts +12 -0
- package/lib/src/shared/content-settings/components/items-field/ItemsField.mixin.js +8 -0
- package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +6 -5
- package/lib/src/shared/content-settings/components/textarea-field/TextareaField.mixin.d.ts +12 -0
- package/lib/src/shared/content-settings/components/textarea-field/TextareaField.mixin.js +5 -0
- package/lib/src/shared/content-settings/models.d.ts +6 -0
- package/lib/src/shared/content-settings/store/content-settings-store.d.ts +5 -1
- package/lib/src/shared/content-settings/store/content-settings-store.js +12 -0
- package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +6 -5
- package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +9 -5
- package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +9 -5
- package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +6 -5
- package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +6 -5
- package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +6 -5
- package/package.json +2 -2
- package/src/brand-page/components/faq-section/FaqSection.test.ts +403 -0
- package/src/brand-page/components/faq-section/FaqSection.vue +315 -0
- package/src/brand-page/components/navigation/navigation-carousel/NavigationCarousel.vue +1 -0
- package/src/brand-page/components/page/PageComponent.vue +2 -0
- package/src/brand-page/constants/misc.constants.ts +12 -0
- package/src/brand-page/constants/styles.constants.ts +2 -0
- package/src/brand-page/models/content.model.ts +1 -0
- package/src/brand-page/models/index.ts +24 -0
- package/src/brand-page/utils/content-callback-util.ts +5 -0
- package/src/brand-page/utils/view-model.util.test.ts +102 -0
- package/src/brand-page/utils/view-model.util.ts +43 -0
- package/src/brand-page/view-models.ts +10 -1
- package/src/brand-page-maker/assessors/faq-accordion-color-field-visibility.assessor.ts +9 -0
- package/src/brand-page-maker/assessors/index.ts +1 -0
- package/src/brand-page-maker/components/brandpage-settings/BrandPageSettings.test.ts +323 -0
- package/src/brand-page-maker/components/brandpage-settings/BrandPageSettings.vue +3 -3
- package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.test.ts +165 -0
- package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.vue +11 -4
- package/src/brand-page-maker/components/sensitive-content/SensitiveContent.vue +23 -3
- package/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.ts +5 -0
- package/src/brand-page-maker/components/seo-settings/SeoPageSettings.vue +2 -0
- package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +48 -12
- package/src/brand-page-maker/constants/config-settings-constant.ts +107 -1
- package/src/brand-page-maker/constants/faq-section-config.test.ts +108 -0
- package/src/brand-page-maker/convertors/faq-display-style.convertor.ts +61 -0
- package/src/brand-page-maker/convertors/i18n/converter.de-DE.json +23 -23
- package/src/brand-page-maker/convertors/i18n/converter.es-ES.json +23 -23
- package/src/brand-page-maker/convertors/i18n/converter.fr-CA.json +23 -23
- package/src/brand-page-maker/convertors/i18n/converter.fr-FR.json +23 -23
- package/src/brand-page-maker/convertors/i18n/converter.pt-BR.json +23 -23
- package/src/brand-page-maker/convertors/i18n/converter.pt-PT.json +23 -23
- package/src/brand-page-maker/models/content-settings-configs.ts +1 -0
- package/src/brand-page-maker/models/content-settings.ts +59 -0
- package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.save.test.ts +332 -1
- package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.ts +83 -5
- package/src/brand-page-maker/utils/__snapshots__/apply-color-strategy.golden.test.ts.snap +3820 -300
- package/src/brand-page-maker/utils/apply-color-strategy.test.ts +123 -2
- package/src/brand-page-maker/utils/apply-color-strategy.ts +73 -19
- package/src/brand-page-maker/utils/rich-text-editor.util.test.ts +110 -0
- package/src/brand-page-maker/utils/rich-text-editor.util.ts +66 -0
- package/src/brand-page-maker/validators/field.validator.ts +2 -0
- package/src/bundles/bundled-translations.de-DE.json +13 -5
- package/src/bundles/bundled-translations.es-ES.json +14 -6
- package/src/bundles/bundled-translations.fr-CA.json +14 -6
- package/src/bundles/bundled-translations.fr-FR.json +14 -6
- package/src/bundles/bundled-translations.json +9 -1
- package/src/bundles/bundled-translations.pt-BR.json +13 -5
- package/src/bundles/bundled-translations.pt-PT.json +13 -5
- package/src/composables/useTranslate.ts +2 -1
- package/src/metadata-builder/builders/item-id-utils.test.ts +24 -0
- package/src/metadata-builder/parsers/section-tool-arguments.ts +2 -1
- package/src/shared/color-picker/components/i18n/color-picker.de-DE.json +12 -11
- package/src/shared/color-picker/components/i18n/color-picker.es-ES.json +12 -11
- package/src/shared/color-picker/components/i18n/color-picker.fr-CA.json +12 -11
- package/src/shared/color-picker/components/i18n/color-picker.fr-FR.json +12 -11
- package/src/shared/color-picker/components/i18n/color-picker.pt-BR.json +12 -11
- package/src/shared/color-picker/components/i18n/color-picker.pt-PT.json +12 -11
- package/src/shared/color-strategies/color-strategies.ts +4 -0
- package/src/shared/color-strategies/rte-field-pairs.test.ts +2 -0
- package/src/shared/color-strategies/rte-field-pairs.ts +23 -0
- package/src/shared/content-settings/components/color-field/ColorField.test.ts +29 -0
- package/src/shared/content-settings/components/content-settings/i18n/content-settings.de-DE.json +10 -1
- package/src/shared/content-settings/components/content-settings/i18n/content-settings.es-ES.json +10 -1
- package/src/shared/content-settings/components/content-settings/i18n/content-settings.fr-CA.json +10 -1
- package/src/shared/content-settings/components/content-settings/i18n/content-settings.fr-FR.json +10 -1
- package/src/shared/content-settings/components/content-settings/i18n/content-settings.json +10 -1
- package/src/shared/content-settings/components/content-settings/i18n/content-settings.pt-BR.json +10 -1
- package/src/shared/content-settings/components/content-settings/i18n/content-settings.pt-PT.json +10 -1
- package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.vue +2 -0
- package/src/shared/content-settings/components/faq-items-field/FaqItemsField.test.ts +357 -0
- package/src/shared/content-settings/components/faq-items-field/FaqItemsField.vue +274 -0
- package/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.vue +1 -0
- package/src/shared/content-settings/components/items-field/ItemsField.mixin.ts +8 -0
- package/src/shared/content-settings/components/items-field/ItemsField.test.ts +117 -0
- package/src/shared/content-settings/components/items-field/ItemsField.vue +9 -3
- package/src/shared/content-settings/components/textarea-field/TextareaField.mixin.ts +6 -0
- package/src/shared/content-settings/components/textarea-field/TextareaField.vue +1 -0
- package/src/shared/content-settings/models.ts +7 -0
- package/src/shared/content-settings/store/content-settings-store.test.ts +49 -0
- package/src/shared/content-settings/store/content-settings-store.ts +28 -0
- package/src/utils/minify-brand-page-metadata.test.ts +35 -0
|
@@ -24,6 +24,18 @@ export const useExternalRichTextEditor = () => {
|
|
|
24
24
|
externalEditor,
|
|
25
25
|
};
|
|
26
26
|
};
|
|
27
|
+
/**
|
|
28
|
+
* Saves a field's style. An editor bound to a list item (`itemStyleTarget`) saves to that
|
|
29
|
+
* item's own style instead of the section's `${name}Style`.
|
|
30
|
+
*/
|
|
31
|
+
export const updateFieldTextStyles = (store, itemStyleTarget, payload) => {
|
|
32
|
+
if (itemStyleTarget) {
|
|
33
|
+
store.updateListItemTextStyles({ ...payload, target: itemStyleTarget });
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
store.updateTextStyles(payload);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
27
39
|
export const useRichTextEditor = (model, props, emit, fontSettings, fontStyleDropdownRef,
|
|
28
40
|
// One entry of `textStyleOptions`; `undefined` when the selection is "none".
|
|
29
41
|
selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyleTypeOptions, markedText, isHyperlinkPopupOpen, selectedLinkTypeValue) => {
|
|
@@ -204,6 +216,21 @@ selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyle
|
|
|
204
216
|
});
|
|
205
217
|
}
|
|
206
218
|
});
|
|
219
|
+
// Set while a toolbar command runs. The toolbar has taken focus by then, so
|
|
220
|
+
// `isFocused` alone would tag the command's write as hydration and fold it into
|
|
221
|
+
// the previous undo entry — hidden only when a style write rides along and opens
|
|
222
|
+
// an entry of its own. Synchronous commands only: the spacing sliders dispatch
|
|
223
|
+
// after a debounce and are not covered.
|
|
224
|
+
let isRunningToolbarCommand = false;
|
|
225
|
+
const runAsToolbarCommand = (command) => {
|
|
226
|
+
isRunningToolbarCommand = true;
|
|
227
|
+
try {
|
|
228
|
+
return command();
|
|
229
|
+
}
|
|
230
|
+
finally {
|
|
231
|
+
isRunningToolbarCommand = false;
|
|
232
|
+
}
|
|
233
|
+
};
|
|
207
234
|
// Update model when editor content changes. RTE content is stored as Tiptap
|
|
208
235
|
// JSON (BP-5787). getJSON() is already in hand (the editor holds the doc) and
|
|
209
236
|
// is sanitised natively — no getHTML(), no DOMPurify, no extra editor — so
|
|
@@ -217,15 +244,9 @@ selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyle
|
|
|
217
244
|
// field → store chain and arms the history merge at the moment of the
|
|
218
245
|
// store write — arming here at emit time would lapse before the
|
|
219
246
|
// debounce fires. Genuine edits happen while focused and commit
|
|
220
|
-
// normally.
|
|
221
|
-
//
|
|
222
|
-
// Known limitation: a programmatic toolbar command run on an editor the
|
|
223
|
-
// user hasn't focused yet would also merge (losing that undo step). Today
|
|
224
|
-
// the RTE only mounts inside an already-open settings drawer and the user
|
|
225
|
-
// focuses it before formatting, so this doesn't occur — revisit if a
|
|
226
|
-
// consumer ever drives toolbar actions on an unfocused editor.
|
|
247
|
+
// normally, and so do synchronous toolbar commands (isRunningToolbarCommand).
|
|
227
248
|
emit('update:modelValue', sanitizeRteJson(editor.getJSON()), {
|
|
228
|
-
isHydrationWrite: !editor.isFocused,
|
|
249
|
+
isHydrationWrite: !editor.isFocused && !isRunningToolbarCommand,
|
|
229
250
|
});
|
|
230
251
|
});
|
|
231
252
|
editor.on('selectionUpdate', () => {
|
|
@@ -303,7 +324,7 @@ selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyle
|
|
|
303
324
|
// write lands ~100ms BEFORE the editor's canonical text write-back, and
|
|
304
325
|
// an unflagged write here would open a plain capture burst that
|
|
305
326
|
// swallows the flagged text write into a phantom entry (BP-5810).
|
|
306
|
-
contentSettingStore.
|
|
327
|
+
updateFieldTextStyles(contentSettingStore, props.itemStyleTarget, {
|
|
307
328
|
id: props.rawId,
|
|
308
329
|
name: props.name,
|
|
309
330
|
value: {
|
|
@@ -488,7 +509,7 @@ selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyle
|
|
|
488
509
|
});
|
|
489
510
|
}
|
|
490
511
|
else {
|
|
491
|
-
contentSettingStore.
|
|
512
|
+
updateFieldTextStyles(contentSettingStore, props.itemStyleTarget, {
|
|
492
513
|
id: props.rawId,
|
|
493
514
|
name: props.name,
|
|
494
515
|
value: {
|
|
@@ -584,7 +605,7 @@ selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyle
|
|
|
584
605
|
editor,
|
|
585
606
|
onFocus,
|
|
586
607
|
onBlur,
|
|
587
|
-
triggerEditorStyleChange,
|
|
608
|
+
triggerEditorStyleChange: (editorOption) => runAsToolbarCommand(() => triggerEditorStyleChange(editorOption)),
|
|
588
609
|
toggleBold,
|
|
589
610
|
toggleItalic,
|
|
590
611
|
toggleUnderline,
|
|
@@ -601,7 +622,7 @@ selectedGlobalTextStyles, onSelectTextStyleType, updateRichTextEditor, textStyle
|
|
|
601
622
|
setInitialStyleSettings,
|
|
602
623
|
copyGlobalStyleSettings,
|
|
603
624
|
unsetAllMarks,
|
|
604
|
-
handleHyperlink,
|
|
625
|
+
handleHyperlink: (...args) => runAsToolbarCommand(() => handleHyperlink(...args)),
|
|
605
626
|
hyperlinkValue,
|
|
606
627
|
setHyperlinkUrlValue,
|
|
607
628
|
shouldShow,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LogoContent, FacebookContent, GeneralLinkContent, PhoneContent, EmailContent, ImageContent, InstagramContent, LinkedInContent, PinterestContent, ProfileContent, TextContent, TiktokContent, TwitchContent, XContent, VideoContent, WebsiteContent, YoutubeContent, ContentType, MapContent, ImageGalleryContent, MailingListContent, RequestPaymentContent, SupportMeContent, ContactFormContent, BannerSectionContent, SocialLinksContent, ImagesSectionContent, TestimonialSectionContent, AboutSectionContent, DividerSectionContent, ShapesSectionContent, ShopContent, BookingSectionContent } from '@brand-page';
|
|
1
|
+
import type { LogoContent, FacebookContent, GeneralLinkContent, PhoneContent, EmailContent, ImageContent, InstagramContent, LinkedInContent, PinterestContent, ProfileContent, TextContent, TiktokContent, TwitchContent, XContent, VideoContent, WebsiteContent, YoutubeContent, ContentType, MapContent, ImageGalleryContent, MailingListContent, RequestPaymentContent, SupportMeContent, ContactFormContent, BannerSectionContent, SocialLinksContent, ImagesSectionContent, TestimonialSectionContent, AboutSectionContent, DividerSectionContent, ShapesSectionContent, ShopContent, BookingSectionContent, FaqSectionContent } from '@brand-page';
|
|
2
2
|
import type { ContentSettingsConfig, ContentSettingsField, ContentSettingsMultiField } from '../models';
|
|
3
3
|
export declare const LOGO_SETTINGS_CONFIG: () => ContentSettingsConfig<Omit<LogoContent, "version" | "logoVariation" | "logoImageHeight" | "logoImageWidth" | "logoLastUpdate" | "logoImageBase64Url">>;
|
|
4
4
|
export declare const GENERAL_LINK_CONTENT_SETTINGS_CONFIG: () => ContentSettingsConfig<GeneralLinkContent>;
|
|
@@ -51,4 +51,5 @@ export declare const SHOP_SECTION_SETTINGS_CONFIG: () => ContentSettingsConfig<S
|
|
|
51
51
|
isShippingEnabled: boolean;
|
|
52
52
|
}>;
|
|
53
53
|
export declare const BOOKING_SECTION_SETTINGS_CONFIG: () => ContentSettingsConfig<BookingSectionContent>;
|
|
54
|
+
export declare const FAQ_SECTION_SETTINGS_CONFIG: () => ContentSettingsConfig<FaqSectionContent>;
|
|
54
55
|
export declare const CONTENT_SETTINGS_CONFIGS: () => Record<ContentType, ContentSettingsConfig<any>>;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { SOCIAL_LINKS_ICON_DISPLAY_STYLES, BRAND_PAGE_TYPES, DIVIDER_STYLES, MEDIA_TYPES, BUTTON_LINK_TYPE, FONT_SIZE_BODY, LINE_HEIGHT_BODY, MIN_TEXT_SIZE_PX, MAX_TEXT_SIZE_PX, TEXT_COLUMNS, DEFAULT_SHAPE_SIZE, PAYMENT_OPTION_DISPLAY_TYPES, PAYMENT_OPTION_IMAGE_TYPES, GettyVideoMedia, } from '@brand-page';
|
|
2
|
-
import { createInitialButtonContent, createInitialImageContent, createInitialProfileContent, createInitialTextContent, createInitialVideoContent, createInitialLogoContent, createInitialMapContent, createInitialImageGalleryContent, createInitialGeneralLinkContent, createInitialMailingListContent, createInitialRequestPaymentContent, createInitialSupportMeContent, createInitialContactFormContent, CONTENT_SETTINGS_DISPLAY_MODES, createInitialBannerSectionContent, createInitialSocialLinksContent, createInitialImagesSectionContent, createInitialTestimonialSectionContent, createInitialAboutSectionContent, createInitialDividerSectionContent, createInitialShapesSectionContent, VARIANT_DISPLAY_MODES, createInitialShopContent, createInitialBookingSectionContent, } from '../models';
|
|
1
|
+
import { FAQ_DISPLAY_STYLES, SOCIAL_LINKS_ICON_DISPLAY_STYLES, BRAND_PAGE_TYPES, DIVIDER_STYLES, MEDIA_TYPES, BUTTON_LINK_TYPE, FONT_SIZE_BODY, LINE_HEIGHT_BODY, MIN_TEXT_SIZE_PX, MAX_TEXT_SIZE_PX, TEXT_COLUMNS, DEFAULT_SHAPE_SIZE, PAYMENT_OPTION_DISPLAY_TYPES, PAYMENT_OPTION_IMAGE_TYPES, GettyVideoMedia, } from '@brand-page';
|
|
2
|
+
import { createInitialButtonContent, createInitialImageContent, createInitialProfileContent, createInitialTextContent, createInitialVideoContent, createInitialLogoContent, createInitialMapContent, createInitialImageGalleryContent, createInitialGeneralLinkContent, createInitialMailingListContent, createInitialRequestPaymentContent, createInitialSupportMeContent, createInitialContactFormContent, CONTENT_SETTINGS_DISPLAY_MODES, createInitialBannerSectionContent, createInitialSocialLinksContent, createInitialImagesSectionContent, createInitialTestimonialSectionContent, createInitialAboutSectionContent, createInitialDividerSectionContent, createInitialShapesSectionContent, VARIANT_DISPLAY_MODES, createInitialShopContent, createInitialBookingSectionContent, createInitialFaqSectionContent, } from '../models';
|
|
3
3
|
import * as uuid from 'uuid';
|
|
4
4
|
import { colorConvertor, backgroundColorConvertor, borderColorConvertor, displayStyleConvertor, galleryTypeConvertor, imageAspectRatioConvertor, textAlignmentOptionsConvertor, videoContentStateConvertor, fillColorConvertor, bannerAlignDisplayStyleConvertor, aboutDisplayStyleConvertor, dividerStyleConvertor, shapeSizeOptionsConvertor, buttonLinkStyleConvertor, textSizeValueConvertor, textColumnStyleConvertor, contactLayoutStyleConvertor, paymentLinkDisplayStyleConvertor, shopDisplayConvertor, shopAspectRatioConvertor, } from '../convertors';
|
|
5
5
|
import { ALIGN_CENTERED, DISPLAY_STYLE_COLLAPSED, DISPLAY_STYLE_PREVIEW, } from '@brand-page';
|
|
6
|
-
import { imageFieldVisibilityAssessor, imageOptionVisibilityAssessor, imageGalleryFieldVisibilityAssessor, cardFillVisibilityAssessor, mediaSectionItemsFieldTypeAssessor, dividerToggleFieldVisibilityAssessor, shapeSectionItemsFieldTypeAssessor, colorReplacementVisibilityTypeAssessor, colorReplacementProfileVisibilityTypeAssessor, colorReplacementIconVisibilityTypeAssessor, imagesSectionCardStyleVisibilityAssessor, contactCardColorVisibilityAssessor, imageUrlVisibilityAssessor, displayTypeVisibilityAssessor, logoFieldVisibilityAssessor, shapesSectionCardStyleVisibilityAssessor, shopImageOptionVisibilityAssessor, shopItemColorVisibility, personalisationOverrideVisibility, } from '../assessors';
|
|
6
|
+
import { imageFieldVisibilityAssessor, imageOptionVisibilityAssessor, imageGalleryFieldVisibilityAssessor, cardFillVisibilityAssessor, mediaSectionItemsFieldTypeAssessor, dividerToggleFieldVisibilityAssessor, faqAccordionColorFieldVisibilityAssessor, shapeSectionItemsFieldTypeAssessor, colorReplacementVisibilityTypeAssessor, colorReplacementProfileVisibilityTypeAssessor, colorReplacementIconVisibilityTypeAssessor, imagesSectionCardStyleVisibilityAssessor, contactCardColorVisibilityAssessor, imageUrlVisibilityAssessor, displayTypeVisibilityAssessor, logoFieldVisibilityAssessor, shapesSectionCardStyleVisibilityAssessor, shopImageOptionVisibilityAssessor, shopItemColorVisibility, personalisationOverrideVisibility, } from '../assessors';
|
|
7
7
|
import { contactFormCardColorDefaultGetter, paymentFillColorFieldDefaultGetter, paymentTextAndBorderColorFieldDefaultGetter, shopBorderColorFieldDefaultGetter, shopFillColorFieldDefaultGetter, textColorFieldDefaultGetter, } from '../default-getters';
|
|
8
8
|
import { socialLinksIconDisplayStyleConvertor } from '../convertors/social-links-icon-display-style.convertor';
|
|
9
9
|
import { getTextMediaOptionsConverterByMediaType } from '../convertors/text-image-display-style.convertor';
|
|
10
10
|
import { testimonialDisplayStyleConvertor } from '../convertors/testimonial-display-style-convertor';
|
|
11
|
+
import { faqDisplayStyleConvertor } from '../convertors/faq-display-style.convertor';
|
|
11
12
|
import { pageValidator, urlValidator } from '../validators';
|
|
12
13
|
import { imagesSectionAspectRatioVisibilityAssessor } from '../assessors/images-section-aspect-ratio-visibility.assessor';
|
|
13
14
|
import { bannerLinkTypeVisibilityAssessor, bannerSectionPageVisibilityAssessor, bannerSectionUrlVisibilityAssessor, bannerDisplayTypeVisibilityAssessor, bannerOverlayOptionsVisibilityAssessor, } from '../assessors/banner-section-description-visibility.assessor';
|
|
@@ -15,7 +16,7 @@ import { imagesSectionTextStyleVisibilityAssessor } from '../assessors/images-se
|
|
|
15
16
|
import { bannerPlaceholderFieldTypeAssessor, bannerSectionFieldTypeAssessor, bannerSectionRoleTypeAssessor, } from '../assessors/banner-section-field.assessor';
|
|
16
17
|
import { isValidSvgUrl } from '@brand-page/utils';
|
|
17
18
|
import { brandPageOrbrandContactTypeVisibilityAssessor, brandSiteTypeVisibilityAssessor, } from '../assessors/brand-page-type-visibility.assessor';
|
|
18
|
-
import { contentSettingsTr } from '@src/composables/useTranslate';
|
|
19
|
+
import { commonTr, contentSettingsTr } from '@src/composables/useTranslate';
|
|
19
20
|
const MediaFieldNames = {
|
|
20
21
|
aspectRatio: 'aspectRatio',
|
|
21
22
|
iconUrl: 'iconUrl',
|
|
@@ -2807,6 +2808,103 @@ export const BOOKING_SECTION_SETTINGS_CONFIG = () => ({
|
|
|
2807
2808
|
isEnabled: true,
|
|
2808
2809
|
isLocked: false,
|
|
2809
2810
|
});
|
|
2811
|
+
const FAQ_FIELD_GROUP_IDS = {
|
|
2812
|
+
settings: 'settings',
|
|
2813
|
+
items: 'items',
|
|
2814
|
+
style: 'style',
|
|
2815
|
+
};
|
|
2816
|
+
export const FAQ_SECTION_SETTINGS_CONFIG = () => ({
|
|
2817
|
+
type: 'faq-section',
|
|
2818
|
+
category: 'general',
|
|
2819
|
+
createInitialContent: createInitialFaqSectionContent,
|
|
2820
|
+
displayMode: CONTENT_SETTINGS_DISPLAY_MODES.focused,
|
|
2821
|
+
defaultIconName: 'question-circle-filled',
|
|
2822
|
+
displayName: contentSettingsTr(`faqSectionDisplayName`),
|
|
2823
|
+
fieldGroups: [
|
|
2824
|
+
{
|
|
2825
|
+
id: FAQ_FIELD_GROUP_IDS.settings,
|
|
2826
|
+
displayName: contentSettingsTr(`settingsDisplayName`),
|
|
2827
|
+
isCollapsed: false,
|
|
2828
|
+
},
|
|
2829
|
+
{
|
|
2830
|
+
id: FAQ_FIELD_GROUP_IDS.items,
|
|
2831
|
+
displayName: contentSettingsTr(`faqItemsDisplayName`),
|
|
2832
|
+
isCollapsed: false,
|
|
2833
|
+
},
|
|
2834
|
+
{
|
|
2835
|
+
id: FAQ_FIELD_GROUP_IDS.style,
|
|
2836
|
+
displayName: contentSettingsTr(`styleDisplayName`),
|
|
2837
|
+
isCollapsed: true,
|
|
2838
|
+
},
|
|
2839
|
+
],
|
|
2840
|
+
fields: {
|
|
2841
|
+
titleStyle: DEFAULT_TITLE_STYLE_SETTINGS_FILED_WITH_TITLE(),
|
|
2842
|
+
descriptionStyle: DEFAULT_DESCRIPTION_STYLE_FILED(),
|
|
2843
|
+
title: {
|
|
2844
|
+
type: 'text',
|
|
2845
|
+
placeholder: contentSettingsTr(`titlePlaceholder`),
|
|
2846
|
+
title: contentSettingsTr(`titleTitle`),
|
|
2847
|
+
groupId: FAQ_FIELD_GROUP_IDS.settings,
|
|
2848
|
+
maxLength: 200,
|
|
2849
|
+
},
|
|
2850
|
+
description: {
|
|
2851
|
+
type: 'textarea',
|
|
2852
|
+
placeholder: contentSettingsTr(`descriptionPlaceholder`),
|
|
2853
|
+
title: contentSettingsTr(`descriptionTitle`),
|
|
2854
|
+
groupId: FAQ_FIELD_GROUP_IDS.settings,
|
|
2855
|
+
maxLength: 1000,
|
|
2856
|
+
},
|
|
2857
|
+
// FaqItemsField owns the question/answer inputs and the FAQ_MAX_ITEMS cap.
|
|
2858
|
+
items: {
|
|
2859
|
+
type: 'faq-items',
|
|
2860
|
+
defaultValue: [],
|
|
2861
|
+
groupId: FAQ_FIELD_GROUP_IDS.items,
|
|
2862
|
+
},
|
|
2863
|
+
displayStyle: {
|
|
2864
|
+
type: 'radio',
|
|
2865
|
+
role: 'multi',
|
|
2866
|
+
defaultValue: FAQ_DISPLAY_STYLES.centered,
|
|
2867
|
+
title: contentSettingsTr(`displayStyleTitle`),
|
|
2868
|
+
optionsConvertor: faqDisplayStyleConvertor,
|
|
2869
|
+
groupId: FAQ_FIELD_GROUP_IDS.style,
|
|
2870
|
+
variant: 'icon',
|
|
2871
|
+
},
|
|
2872
|
+
...PADDING_CONTROL_FIELDS(FAQ_FIELD_GROUP_IDS.style),
|
|
2873
|
+
iconColor: {
|
|
2874
|
+
type: 'color',
|
|
2875
|
+
groupId: FAQ_FIELD_GROUP_IDS.style,
|
|
2876
|
+
defaultValue: {},
|
|
2877
|
+
isInline: true,
|
|
2878
|
+
showToggle: false,
|
|
2879
|
+
disableTransparent: true,
|
|
2880
|
+
visibilityAssessor: faqAccordionColorFieldVisibilityAssessor,
|
|
2881
|
+
title: commonTr(`iconColor`),
|
|
2882
|
+
valueConvertor: colorConvertor,
|
|
2883
|
+
},
|
|
2884
|
+
// Transparent allowed on purpose (it hides the line), unlike the Divider section's field.
|
|
2885
|
+
dividerColor: {
|
|
2886
|
+
type: 'color',
|
|
2887
|
+
groupId: FAQ_FIELD_GROUP_IDS.style,
|
|
2888
|
+
defaultValue: {},
|
|
2889
|
+
isInline: true,
|
|
2890
|
+
showToggle: false,
|
|
2891
|
+
visibilityAssessor: faqAccordionColorFieldVisibilityAssessor,
|
|
2892
|
+
title: contentSettingsTr(`dividerColorTitle`),
|
|
2893
|
+
valueConvertor: backgroundColorConvertor,
|
|
2894
|
+
},
|
|
2895
|
+
backgroundStyle: {
|
|
2896
|
+
type: 'color',
|
|
2897
|
+
groupId: FAQ_FIELD_GROUP_IDS.style,
|
|
2898
|
+
defaultValue: {},
|
|
2899
|
+
isInline: true,
|
|
2900
|
+
showToggle: false,
|
|
2901
|
+
title: contentSettingsTr(`backgroundColorTitle`),
|
|
2902
|
+
valueConvertor: backgroundColorConvertor,
|
|
2903
|
+
},
|
|
2904
|
+
},
|
|
2905
|
+
isEnabled: true,
|
|
2906
|
+
isLocked: false,
|
|
2907
|
+
});
|
|
2810
2908
|
export const CONTENT_SETTINGS_CONFIGS = () => ({
|
|
2811
2909
|
logo: LOGO_SETTINGS_CONFIG(),
|
|
2812
2910
|
'general-link': GENERAL_LINK_CONTENT_SETTINGS_CONFIG(),
|
|
@@ -2840,4 +2938,5 @@ export const CONTENT_SETTINGS_CONFIGS = () => ({
|
|
|
2840
2938
|
'shapes-section': SHAPES_SECTION_SETTINGS_CONFIG(),
|
|
2841
2939
|
'shop-section': SHOP_SECTION_SETTINGS_CONFIG(),
|
|
2842
2940
|
'booking-section': BOOKING_SECTION_SETTINGS_CONFIG(),
|
|
2941
|
+
'faq-section': FAQ_SECTION_SETTINGS_CONFIG(),
|
|
2843
2942
|
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { FAQ_DISPLAY_STYLES } from '@brand-page/constants';
|
|
2
|
+
const ICON_VIEW_BOX = '0 0 96 56';
|
|
3
|
+
export const faqDisplayStyleConvertor = {
|
|
4
|
+
convertBackToMultipleValues: true,
|
|
5
|
+
convert(value) {
|
|
6
|
+
return {
|
|
7
|
+
options: [
|
|
8
|
+
// An empty title suppresses ButtonGroup's label-under-icon paragraph.
|
|
9
|
+
{
|
|
10
|
+
title: '',
|
|
11
|
+
value: FAQ_DISPLAY_STYLES.centered,
|
|
12
|
+
isSelected: value === FAQ_DISPLAY_STYLES.centered,
|
|
13
|
+
iconName: 'display-style-faq-1',
|
|
14
|
+
iconViewBox: ICON_VIEW_BOX,
|
|
15
|
+
dataAttribute: 'data-test-btn-faq-centered',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
title: '',
|
|
19
|
+
value: FAQ_DISPLAY_STYLES.split,
|
|
20
|
+
isSelected: value === FAQ_DISPLAY_STYLES.split,
|
|
21
|
+
iconName: 'display-style-faq-2',
|
|
22
|
+
iconViewBox: ICON_VIEW_BOX,
|
|
23
|
+
dataAttribute: 'data-test-btn-faq-split',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
title: '',
|
|
27
|
+
value: FAQ_DISPLAY_STYLES.grid,
|
|
28
|
+
isSelected: value === FAQ_DISPLAY_STYLES.grid,
|
|
29
|
+
iconName: 'display-style-faq-3',
|
|
30
|
+
iconViewBox: ICON_VIEW_BOX,
|
|
31
|
+
dataAttribute: 'data-test-btn-faq-grid',
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
// Label-less buttons only fill their slot in ButtonGroup's grid mode.
|
|
35
|
+
columns: 3,
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
// The heading sits left beside the accordion in split, centred above it otherwise.
|
|
39
|
+
convertBack(config) {
|
|
40
|
+
const displayStyle = config.options.find((v) => v.isSelected)?.value ??
|
|
41
|
+
FAQ_DISPLAY_STYLES.centered;
|
|
42
|
+
const textAlign = displayStyle === FAQ_DISPLAY_STYLES.split ? 'left' : 'center';
|
|
43
|
+
return {
|
|
44
|
+
displayStyle,
|
|
45
|
+
titleStyle: { textAlign },
|
|
46
|
+
descriptionStyle: { textAlign },
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
};
|
|
@@ -52,6 +52,7 @@ export declare const ITEM_FIELD_TYPES: {
|
|
|
52
52
|
readonly 'color-replacements': "color-replacements";
|
|
53
53
|
readonly 'testimonial-items': "testimonial-items";
|
|
54
54
|
readonly 'text-items': "text-items";
|
|
55
|
+
readonly 'faq-items': "faq-items";
|
|
55
56
|
readonly 'page-dropdown': "page-dropdown";
|
|
56
57
|
readonly 'personalisation-override': "personalisation-override";
|
|
57
58
|
};
|
|
@@ -55,6 +55,7 @@ export const ITEM_FIELD_TYPES = {
|
|
|
55
55
|
'color-replacements': 'color-replacements',
|
|
56
56
|
'testimonial-items': 'testimonial-items',
|
|
57
57
|
'text-items': 'text-items',
|
|
58
|
+
'faq-items': 'faq-items',
|
|
58
59
|
'page-dropdown': 'page-dropdown',
|
|
59
60
|
'personalisation-override': 'personalisation-override',
|
|
60
61
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BrandPageModel } from '@brand-page';
|
|
2
|
-
import type { ButtonContent, ContentType, ImageContent, ProfileContent, TextContent, VideoContent, LogoContent, LogoTheme, MapContent, ImageGalleryContent, GeneralLinkContent, MailingListContent, RequestPaymentContent, ContactFormContent, BannerSectionContent, SocialLinksContent, ImagesSectionContent, TestimonialSectionContent, AboutSectionContent, DividerSectionContent, ShapesSectionContent, BrandPageType, SupportMeContent, ShopContent, BookingSectionContent } from '@brand-page';
|
|
2
|
+
import type { ButtonContent, ContentType, ImageContent, ProfileContent, TextContent, VideoContent, LogoContent, LogoTheme, MapContent, ImageGalleryContent, GeneralLinkContent, MailingListContent, RequestPaymentContent, ContactFormContent, BannerSectionContent, SocialLinksContent, ImagesSectionContent, TestimonialSectionContent, AboutSectionContent, DividerSectionContent, ShapesSectionContent, BrandPageType, SupportMeContent, ShopContent, BookingSectionContent, TextStyleDeclaration, FaqSectionContent } from '@brand-page';
|
|
3
3
|
import type { CreateInitialContentFunction } from './content-settings-configs';
|
|
4
4
|
import type { CreateInitialContentOptions } from '@shared/content-settings/models';
|
|
5
5
|
export declare const createInitialButtonContent: (type: ContentType, iconUrl: string, options?: CreateInitialContentOptions) => () => ButtonContent;
|
|
@@ -18,6 +18,9 @@ export declare const createInitialSupportMeContent: (options?: CreateInitialCont
|
|
|
18
18
|
export declare const createInitialContactFormContent: CreateInitialContentFunction<ContactFormContent>;
|
|
19
19
|
export declare const createInitialBannerSectionContent: CreateInitialContentFunction<BannerSectionContent>;
|
|
20
20
|
export declare const createInitialBookingSectionContent: CreateInitialContentFunction<BookingSectionContent>;
|
|
21
|
+
export declare const createInitialFaqQuestionStyle: (applyAutoScale?: boolean) => TextStyleDeclaration;
|
|
22
|
+
export declare const createInitialFaqAnswerStyle: (applyAutoScale?: boolean) => TextStyleDeclaration;
|
|
23
|
+
export declare const createInitialFaqSectionContent: CreateInitialContentFunction<FaqSectionContent>;
|
|
21
24
|
export declare const createInitialImagesSectionContent: CreateInitialContentFunction<ImagesSectionContent>;
|
|
22
25
|
export declare const createInitialTestimonialSectionContent: CreateInitialContentFunction<TestimonialSectionContent>;
|
|
23
26
|
export declare const createInitialAboutSectionContent: CreateInitialContentFunction<AboutSectionContent>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BrandPageModel, PageStyles, FORM_FIELD_IDS, PAYMENT_OPTION_DISPLAY_TYPES, PAYMENT_OPTION_IMAGE_TYPES, SOCIAL_LINKS_ICON_DISPLAY_STYLES, PageHeaderMobile, PageHeaderDesktop, PageFooterMobile, PageFooterDesktop, MEDIA_TYPES, BUTTON_LINK_TYPE, DISPLAY_STYLE_PREVIEW, SUPPORT_ME_CUSTOM_PRODUCT_NAME, DEFAULT_LOGO_HEIGHT, DEFAULT_LOGO_WIDTH, FONT_SIZE_BODY, LINE_HEIGHT_BODY, TEXT_STYLE_TYPES, TEXT_COLUMNS, DEFAULT_LOGO_BACKGROUND_COLOR_RGB, DEFAULT_LOGO_TEXT_COLOR_RGB, EMPTY_LOGO_IMAGE_MODEL, BRAND_PAGE_TYPES, SENSITIVE_CONTENT_TYPES, CONTACT_FORM_LAYOUT_DEFAULT_PADDING, TESTIMONIAL_DEFAULT_PADDING, } from '@brand-page';
|
|
1
|
+
import { BrandPageModel, PageStyles, FORM_FIELD_IDS, PAYMENT_OPTION_DISPLAY_TYPES, PAYMENT_OPTION_IMAGE_TYPES, SOCIAL_LINKS_ICON_DISPLAY_STYLES, PageHeaderMobile, PageHeaderDesktop, PageFooterMobile, PageFooterDesktop, MEDIA_TYPES, BUTTON_LINK_TYPE, DISPLAY_STYLE_PREVIEW, SUPPORT_ME_CUSTOM_PRODUCT_NAME, DEFAULT_LOGO_HEIGHT, DEFAULT_LOGO_WIDTH, FONT_SIZE_BODY, LINE_HEIGHT_BODY, TEXT_STYLE_TYPES, TEXT_COLUMNS, DEFAULT_LOGO_BACKGROUND_COLOR_RGB, DEFAULT_LOGO_TEXT_COLOR_RGB, EMPTY_LOGO_IMAGE_MODEL, BRAND_PAGE_TYPES, SENSITIVE_CONTENT_TYPES, CONTACT_FORM_LAYOUT_DEFAULT_PADDING, TESTIMONIAL_DEFAULT_PADDING, FAQ_DISPLAY_STYLES, } from '@brand-page';
|
|
2
2
|
import * as uuid from 'uuid';
|
|
3
3
|
import { getColorShades, DEFAULT_CARD_SURFACE_REFERENCE, } from '@brand-page/utils';
|
|
4
4
|
import { contentSettingsTr } from '@src/composables/useTranslate';
|
|
@@ -556,6 +556,52 @@ export const createInitialBookingSectionContent = (options) => {
|
|
|
556
556
|
},
|
|
557
557
|
};
|
|
558
558
|
};
|
|
559
|
+
// Questions follow the Headings role, answers the Paragraphs role.
|
|
560
|
+
export const createInitialFaqQuestionStyle = (applyAutoScale = false) => ({
|
|
561
|
+
applyAutoScale,
|
|
562
|
+
textStyleType: TEXT_STYLE_TYPES.headings,
|
|
563
|
+
textAlign: 'left',
|
|
564
|
+
});
|
|
565
|
+
export const createInitialFaqAnswerStyle = (applyAutoScale = false) => ({
|
|
566
|
+
applyAutoScale,
|
|
567
|
+
textStyleType: TEXT_STYLE_TYPES.paragraphs,
|
|
568
|
+
textAlign: 'left',
|
|
569
|
+
});
|
|
570
|
+
export const createInitialFaqSectionContent = (options) => {
|
|
571
|
+
const applyAutoScale = options?.brandPageType === BRAND_PAGE_TYPES.brandSite;
|
|
572
|
+
return {
|
|
573
|
+
id: uuid.v4(),
|
|
574
|
+
type: 'faq-section',
|
|
575
|
+
title: contentSettingsTr(`defaultFaqTitle`),
|
|
576
|
+
description: contentSettingsTr(`defaultFaqDescription`),
|
|
577
|
+
displayStyle: FAQ_DISPLAY_STYLES.centered,
|
|
578
|
+
topPadding: 32,
|
|
579
|
+
bottomPadding: 32,
|
|
580
|
+
// One sample item; the design's four are only there to show a longer list.
|
|
581
|
+
items: [
|
|
582
|
+
{
|
|
583
|
+
id: uuid.v4(),
|
|
584
|
+
question: contentSettingsTr(`defaultFaqQuestion`),
|
|
585
|
+
questionStyle: createInitialFaqQuestionStyle(applyAutoScale),
|
|
586
|
+
answer: contentSettingsTr(`defaultFaqAnswer`),
|
|
587
|
+
answerStyle: createInitialFaqAnswerStyle(applyAutoScale),
|
|
588
|
+
},
|
|
589
|
+
],
|
|
590
|
+
titleStyle: {
|
|
591
|
+
applyAutoScale,
|
|
592
|
+
textStyleType: TEXT_STYLE_TYPES.titles,
|
|
593
|
+
textAlign: 'center',
|
|
594
|
+
},
|
|
595
|
+
descriptionStyle: {
|
|
596
|
+
applyAutoScale,
|
|
597
|
+
textStyleType: TEXT_STYLE_TYPES.paragraphs,
|
|
598
|
+
textAlign: 'center',
|
|
599
|
+
},
|
|
600
|
+
backgroundStyle: {},
|
|
601
|
+
iconColor: { color: '#555555' },
|
|
602
|
+
dividerColor: { backgroundColor: '#dcdcdc' },
|
|
603
|
+
};
|
|
604
|
+
};
|
|
559
605
|
export const createInitialImagesSectionContent = (options) => {
|
|
560
606
|
return {
|
|
561
607
|
id: uuid.v4(),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type getWebsiteContextualUpgradeResponse } from '../../../clients/brand-page-client';
|
|
2
2
|
import { type LogoDraftAsset, type LogoTemplateAsset } from '@brand-page-maker/stores';
|
|
3
3
|
import type { CustomDomainConfigModel, CustomDomainModel } from '@brand-page-maker/models';
|
|
4
|
-
import { type AbTest } from '@brand-page';
|
|
4
|
+
import { type AbTest, type SensitiveContent } from '@brand-page';
|
|
5
5
|
import type { WebsiteSlugCheckResponse } from '@brand-page-maker/models/api.model';
|
|
6
6
|
import { WEBSITE_UPGRADE_CONTEXT_TYPES } from '@designcrowd/fe-shared-lib';
|
|
7
7
|
import { type OnSearchTermChangedCallback } from '@shared/template-settings/store';
|
|
@@ -418,13 +418,14 @@ export declare const useBrandPageContainerStore: import("pinia").StoreDefinition
|
|
|
418
418
|
startBrandPageSlugEditMode(): void;
|
|
419
419
|
triggerLockedContentClickedEvent(contentType: string): Promise<void>;
|
|
420
420
|
unpublishBrandPage(): Promise<void>;
|
|
421
|
-
updateBrandPageSettings(
|
|
422
|
-
description:
|
|
423
|
-
title:
|
|
421
|
+
updateBrandPageSettings(payload: {
|
|
422
|
+
description: string;
|
|
423
|
+
title: string;
|
|
424
424
|
}): Promise<void>;
|
|
425
|
-
updateSensitiveContent(
|
|
426
|
-
sensitiveContent:
|
|
425
|
+
updateSensitiveContent(payload: {
|
|
426
|
+
sensitiveContent: SensitiveContent;
|
|
427
427
|
}): Promise<void>;
|
|
428
|
+
saveSiteBeforeFirstSettingsWrite(): Promise<boolean>;
|
|
428
429
|
createBrandPageCustomDomain({ domainName }: {
|
|
429
430
|
domainName: any;
|
|
430
431
|
}): Promise<false | undefined>;
|
|
@@ -863,13 +863,17 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
|
|
|
863
863
|
console.error(err);
|
|
864
864
|
}
|
|
865
865
|
},
|
|
866
|
-
async updateBrandPageSettings(
|
|
866
|
+
async updateBrandPageSettings(payload) {
|
|
867
|
+
if (!this.designDraftToken &&
|
|
868
|
+
!(await this.saveSiteBeforeFirstSettingsWrite())) {
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
867
871
|
const brandPageMakerStore = useBrandPageMakerStore();
|
|
868
872
|
try {
|
|
869
873
|
this.setIsPublishing({ isPublishing: true });
|
|
870
874
|
const result = await brandPageClient.updateBrandPageMetaAsync(brandPageMakerStore.brandPageType, this.designDraftToken, {
|
|
871
|
-
pageDescription: description,
|
|
872
|
-
pageTitle: title,
|
|
875
|
+
pageDescription: payload.description,
|
|
876
|
+
pageTitle: payload.title,
|
|
873
877
|
metaKeywords: [],
|
|
874
878
|
});
|
|
875
879
|
if (!result) {
|
|
@@ -893,12 +897,16 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
|
|
|
893
897
|
await brandPageMakerStore.showNextNotificationMessage();
|
|
894
898
|
}
|
|
895
899
|
},
|
|
896
|
-
async updateSensitiveContent(
|
|
900
|
+
async updateSensitiveContent(payload) {
|
|
901
|
+
if (!this.designDraftToken &&
|
|
902
|
+
!(await this.saveSiteBeforeFirstSettingsWrite())) {
|
|
903
|
+
return;
|
|
904
|
+
}
|
|
897
905
|
const brandPageMakerStore = useBrandPageMakerStore();
|
|
898
906
|
try {
|
|
899
907
|
this.setIsPublishing({ isPublishing: true });
|
|
900
908
|
const result = await brandPageClient.updateSensitiveContentAsync(brandPageMakerStore.brandPageType, this.designDraftToken, {
|
|
901
|
-
sensitiveContentType: sensitiveContent,
|
|
909
|
+
sensitiveContentType: payload.sensitiveContent,
|
|
902
910
|
});
|
|
903
911
|
if (!result) {
|
|
904
912
|
await brandPageMakerStore.enqueueErrorMessage();
|
|
@@ -921,6 +929,45 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
|
|
|
921
929
|
await brandPageMakerStore.showNextNotificationMessage();
|
|
922
930
|
}
|
|
923
931
|
},
|
|
932
|
+
// Pre-purchase drafts are saved by the host, never the maker — save-publish.md.
|
|
933
|
+
async saveSiteBeforeFirstSettingsWrite() {
|
|
934
|
+
if (this.isAdminMaker) {
|
|
935
|
+
return false;
|
|
936
|
+
}
|
|
937
|
+
const brandPageMakerStore = useBrandPageMakerStore();
|
|
938
|
+
if (this.isPrePurchase) {
|
|
939
|
+
window.dispatchEvent(new Event('SAVE_PROGRESS_CLICKED'));
|
|
940
|
+
// The host's saveDesign sets isSaving synchronously on the dispatch; if it
|
|
941
|
+
// didn't, no listener is wired and the click would otherwise go silent.
|
|
942
|
+
if (!this.isSaving) {
|
|
943
|
+
await brandPageMakerStore.enqueueErrorMessage();
|
|
944
|
+
await brandPageMakerStore.showNextNotificationMessage();
|
|
945
|
+
}
|
|
946
|
+
return false;
|
|
947
|
+
}
|
|
948
|
+
if (this.isSaving || this.isPublishing) {
|
|
949
|
+
await brandPageMakerStore.enqueueErrorMessage();
|
|
950
|
+
await brandPageMakerStore.showNextNotificationMessage();
|
|
951
|
+
return false;
|
|
952
|
+
}
|
|
953
|
+
this.setIsPublishing({ isPublishing: true });
|
|
954
|
+
// saveBrandPage enqueues its own error on a throw but not on an empty response.
|
|
955
|
+
const messagesBeforeSave = [
|
|
956
|
+
...brandPageMakerStore.notificationMessageQueue,
|
|
957
|
+
];
|
|
958
|
+
const result = await this.saveBrandPage({ saveOnly: true });
|
|
959
|
+
if (!result || !result.saved) {
|
|
960
|
+
const hasErrorQueued = brandPageMakerStore.notificationMessageQueue.some((message) => message.type === 'error' && !messagesBeforeSave.includes(message));
|
|
961
|
+
if (!hasErrorQueued) {
|
|
962
|
+
await brandPageMakerStore.enqueueErrorMessage();
|
|
963
|
+
}
|
|
964
|
+
this.setIsPublishing({ isPublishing: false });
|
|
965
|
+
await brandPageMakerStore.showNextNotificationMessage();
|
|
966
|
+
return false;
|
|
967
|
+
}
|
|
968
|
+
this.setTriggerSaveSuccessMessage({ triggerSaveSuccessMessage: false });
|
|
969
|
+
return true;
|
|
970
|
+
},
|
|
924
971
|
async createBrandPageCustomDomain({ domainName }) {
|
|
925
972
|
const brandPageMakerStore = useBrandPageMakerStore();
|
|
926
973
|
const customDomainResponse = await brandPageClient.createBrandPageCustomDomainAsync(brandPageMakerStore.brandPageType, this.designDraftToken, domainName, false);
|
|
@@ -2,7 +2,8 @@ import { BRAND_PAGE_TYPES } from '@brand-page';
|
|
|
2
2
|
import { FIELD_SLOT_MAP, raisedLayerFor, strategyRoleRefForField, } from '@shared/color-strategies/color-strategies';
|
|
3
3
|
import { isTransparentDisabled, } from '@shared/content-settings/disable-transparent.util';
|
|
4
4
|
import { setRteTextColor } from '@shared/color-strategies/rte-color';
|
|
5
|
-
import {
|
|
5
|
+
import { isTiptapDocument } from '@brand-page-maker/utils/rte-shape';
|
|
6
|
+
import { pairedRteTextField, RTE_ITEM_FIELD_PAIRS, } from '@shared/color-strategies/rte-field-pairs';
|
|
6
7
|
/**
|
|
7
8
|
* Field types a strategy can assign. `color` fields hold nothing but a colour and are
|
|
8
9
|
* REPLACED via their `valueConvertor`; `text-style` fields hold typography *and* a
|
|
@@ -62,6 +63,17 @@ const sectionLayers = (assignable, content, context) => {
|
|
|
62
63
|
surfaceFields.every(([, field]) => !isTransparentDisabled(field.disableTransparent, context?.brandPageType ?? BRAND_PAGE_TYPES.default)),
|
|
63
64
|
};
|
|
64
65
|
};
|
|
66
|
+
/**
|
|
67
|
+
* The strategy's text treatment for one text-style field: `color` set, text background
|
|
68
|
+
* cleared (matching the highlight strip in `setRteTextColor` — the toolbar writes both).
|
|
69
|
+
* The key is deleted rather than set undefined so `'backgroundColor' in style` checks
|
|
70
|
+
* downstream stay honest.
|
|
71
|
+
*/
|
|
72
|
+
const withStrategyTextStyle = (current, ref) => {
|
|
73
|
+
const nextStyle = { ...(current ?? {}), color: ref };
|
|
74
|
+
delete nextStyle.backgroundColor;
|
|
75
|
+
return nextStyle;
|
|
76
|
+
};
|
|
65
77
|
/**
|
|
66
78
|
* Build the per-field colour writes a strategy stamps onto a section. Pure — reads the
|
|
67
79
|
* section config + current content and returns a `{ fieldName: value }` partial. Each
|
|
@@ -97,16 +109,7 @@ export const buildColorStrategyValues = (config, content, strategyId, context, a
|
|
|
97
109
|
}
|
|
98
110
|
if (field.type === 'text-style') {
|
|
99
111
|
const current = contentRecord[name];
|
|
100
|
-
|
|
101
|
-
...(current ?? {}),
|
|
102
|
-
color: ref,
|
|
103
|
-
};
|
|
104
|
-
// A strategy owns the text treatment, so it clears the text background colour
|
|
105
|
-
// too — matching the highlight strip in `setRteTextColor` (the toolbar writes
|
|
106
|
-
// both). Delete the key rather than set it undefined so `'backgroundColor' in
|
|
107
|
-
// style` checks downstream stay honest.
|
|
108
|
-
delete nextStyle.backgroundColor;
|
|
109
|
-
values[name] = nextStyle;
|
|
112
|
+
values[name] = withStrategyTextStyle(current, ref);
|
|
110
113
|
// Also stamp the colour into the paired RTE document, if this field drives one.
|
|
111
114
|
// `setRteTextColor` returns undefined for a plain string or legacy HTML RTE, so
|
|
112
115
|
// that doubles as the "nothing to do" test — no separate type guard here.
|
|
@@ -133,6 +136,28 @@ export const buildColorStrategyValues = (config, content, strategyId, context, a
|
|
|
133
136
|
}
|
|
134
137
|
values[name] = field.valueConvertor.convertBack(ref);
|
|
135
138
|
});
|
|
139
|
+
// Item-level RTE fields (each FAQ question) carry their own style and document, so
|
|
140
|
+
// the section's field loop above never sees them. Same two halves, per item, written
|
|
141
|
+
// back as one new list.
|
|
142
|
+
const itemPairs = typeof contentRecord.type === 'string'
|
|
143
|
+
? (RTE_ITEM_FIELD_PAIRS[contentRecord.type] ?? [])
|
|
144
|
+
: [];
|
|
145
|
+
itemPairs.forEach((pair) => {
|
|
146
|
+
const ref = strategyRoleRefForField(strategyId, pair.styleField, content, context, layers, anchors);
|
|
147
|
+
const items = (values[pair.itemsField] ??
|
|
148
|
+
contentRecord[pair.itemsField]);
|
|
149
|
+
if (!ref || !Array.isArray(items)) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
values[pair.itemsField] = items.map((item) => {
|
|
153
|
+
const nextDoc = setRteTextColor(item[pair.textField], ref);
|
|
154
|
+
return {
|
|
155
|
+
...item,
|
|
156
|
+
[pair.styleField]: withStrategyTextStyle(item[pair.styleField], ref),
|
|
157
|
+
...(nextDoc ? { [pair.textField]: nextDoc } : {}),
|
|
158
|
+
};
|
|
159
|
+
});
|
|
160
|
+
});
|
|
136
161
|
return values;
|
|
137
162
|
};
|
|
138
163
|
/**
|
|
@@ -147,12 +172,15 @@ export const applyColorStrategyToItem = (store, { id, config, content, strategyI
|
|
|
147
172
|
Object.entries(values).forEach(([name, value]) => {
|
|
148
173
|
store.updateItemValue({ id, name, value });
|
|
149
174
|
});
|
|
150
|
-
// A recoloured RTE field is emitted as a whole Tiptap document
|
|
151
|
-
//
|
|
152
|
-
// to re-seed, so signal it just
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
value
|
|
175
|
+
// A recoloured RTE field is emitted as a whole Tiptap document (at the top level,
|
|
176
|
+
// or inside a rewritten item list); the paired style-object writes are plain
|
|
177
|
+
// objects. Only the former needs the live editor to re-seed, so signal it just
|
|
178
|
+
// when a doc was among the writes.
|
|
179
|
+
const replacedRteDoc = Object.values(values).some((value) => isTiptapDocument(value) ||
|
|
180
|
+
(Array.isArray(value) &&
|
|
181
|
+
value.some((item) => typeof item === 'object' &&
|
|
182
|
+
item !== null &&
|
|
183
|
+
Object.values(item).some(isTiptapDocument))));
|
|
156
184
|
if (replacedRteDoc) {
|
|
157
185
|
markRteResync?.();
|
|
158
186
|
}
|
|
@@ -36,6 +36,12 @@ export declare const getPlainTextFromRTE: (content: unknown) => string;
|
|
|
36
36
|
*/
|
|
37
37
|
export declare const getRteTextLength: (value: RichTextValue | null | undefined) => number;
|
|
38
38
|
export declare const replaceTextInRTE: (existingHtml: string, newText: string) => string;
|
|
39
|
+
/**
|
|
40
|
+
* Convert a new list item's plain text to RTE, as adding its section would. Goes through
|
|
41
|
+
* `transformRTEField` (element-first colour), so an item that copied a sibling's
|
|
42
|
+
* strategy-coloured style bakes that colour rather than the linked global one.
|
|
43
|
+
*/
|
|
44
|
+
export declare const switchRteItemFieldsToRTE: (sectionType: string, item: Record<string, unknown>, externalEditor: Editor, uiStyleSettingsStore?: StyleSettingsState) => void;
|
|
39
45
|
export declare const transformToRTE: (uiPageSettingStore: PageSettingsState, externalEditor: Editor, uiStyleSettingsStore?: StyleSettingsState, newContent?: Content, type?: TextStyleType, newStyle?: TextStyleDeclaration) => void;
|
|
40
46
|
export declare const switchAllContentToRTE: (uiPageSettingStore: PageSettingsState, externalEditor: Editor, uiStyleSettingsStore?: StyleSettingsState) => void;
|
|
41
47
|
export declare const getUpdatedHTMLFromEditor: (externalEditor: Editor, contentText: RichTextValue, newContentStyle: TextStyleDeclaration) => string | import("@tiptap/core").DocumentType<Record<string, any> | undefined, import("@tiptap/core").NodeType<string, Record<string, any> | undefined, any, (import("@tiptap/core").NodeType<any, any, any, any> | import("@tiptap/core").TextType<import("@tiptap/core").MarkType<any, any>>)[]>[]>;
|