@designcrowd/library.brand-page 6.1.1-json-prereq-4 → 6.1.1
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-Dk-G3RbI.js → CreatedOnBrandCrowd-de-de-B5B5ThJ6.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-AVAWRjbj.js → CreatedOnBrandCrowd-en-us-a48CaORy.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-C5Xq4Jln.js → CreatedOnBrandCrowd-es-es-xpuZ317-.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-BQXjmcrr.js → CreatedOnBrandCrowd-fr-ca-V-iUMArW.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-BQXjmcrr.js → CreatedOnBrandCrowd-fr-fr-V-iUMArW.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-DRMRc1Zk.js → CreatedOnBrandCrowd-pt-br-DZ0NKSAy.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-DRMRc1Zk.js → CreatedOnBrandCrowd-pt-pt-DZ0NKSAy.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-Dd9-oQ34.js → CreatedOnDcom-de-de-_950cgGp.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-CnDfLzF4.js → CreatedOnDcom-en-us-DogKzH-g.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-bvqvI9gT.js → CreatedOnDcom-es-es-CmGM3IPX.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-BG7UGFe8.js → CreatedOnDcom-fr-ca-BonEDkWZ.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-xdz35O_B.js → CreatedOnDcom-fr-fr-DQHtKrd_.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-CLfHnCkk.js → CreatedOnDcom-pt-br-CtYJSBjs.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-Z7FY0BXt.js → CreatedOnDcom-pt-pt-DoO9r4lA.js} +1 -1
- package/lib/src/brand-page/components/contact-form/ContactForm.mixin.js +7 -8
- package/lib/src/brand-page/components/mailing-list/MailingList.mixin.js +6 -4
- package/lib/src/brand-page/components/page-footer/PageFooter.mixin.d.ts +1 -0
- package/lib/src/brand-page/components/page-footer/PageFooter.mixin.js +4 -1
- package/lib/src/brand-page/components/payment/Payment.mixin.js +4 -3
- package/lib/src/brand-page/components/payment/__fixtures__/request-payment.d.ts +1 -0
- package/lib/src/brand-page/components/payment/__fixtures__/support-me.d.ts +1 -0
- package/lib/src/brand-page/components/payment/request-payment/RequestPayment.mixin.d.ts +1 -0
- package/lib/src/brand-page/components/payment/request-payment/RequestPayment.mixin.js +4 -1
- package/lib/src/brand-page/composables/consent.composable.d.ts +2 -0
- package/lib/src/brand-page/composables/consent.composable.js +9 -3
- package/lib/src/brand-page/models/brand-page-context.model.d.ts +7 -0
- package/lib/src/brand-page/models/index.d.ts +26 -34
- package/lib/src/brand-page/utils/context.util.d.ts +8 -0
- package/lib/src/brand-page/utils/context.util.js +8 -0
- package/lib/src/brand-page/utils/migration.util.js +0 -11
- package/lib/src/brand-page/utils/text.util.d.ts +1 -13
- package/lib/src/brand-page/utils/text.util.js +0 -64
- package/lib/src/brand-page/utils/vcard.util.js +4 -4
- package/lib/src/brand-page/utils/view-model.util.d.ts +0 -1
- package/lib/src/brand-page/utils/view-model.util.js +20 -68
- package/lib/src/brand-page/view-models.d.ts +3 -3
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +1 -1
- package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.js +51 -18
- package/lib/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.d.ts +1 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/bubbleMenu.d.ts +9 -2
- package/lib/src/brand-page-maker/composables/rich-text-editor/bubbleMenu.js +10 -6
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/FontSize.d.ts +20 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/FontSize.js +44 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/LineHeight.d.ts +27 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/LineHeight.js +44 -0
- package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.d.ts +1 -1
- package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +103 -24
- package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.js +8 -0
- package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +9 -3
- package/lib/src/brand-page-maker/stores/ui/ui-store.d.ts +1 -1
- package/lib/src/brand-page-maker/utils/index.d.ts +0 -2
- package/lib/src/brand-page-maker/utils/index.js +0 -2
- package/lib/src/brand-page-maker/utils/rich-text-editor.util.d.ts +5 -36
- package/lib/src/brand-page-maker/utils/rich-text-editor.util.js +5 -65
- package/lib/src/brand-page-maker/validators/field.validator.js +2 -10
- package/lib/src/clients/models.d.ts +2 -0
- package/lib/src/css/library.brand-page-brandCrowd.min.css +99 -102
- package/lib/src/css/library.brand-page-brandPage.min.css +99 -102
- package/lib/src/css/library.brand-page-designCom.min.css +99 -102
- package/lib/src/css/library.brand-page-preview.min.css +99 -102
- package/lib/src/index.d.ts +1 -1
- package/lib/src/index.mjs +219 -221
- package/lib/src/{lib-uYwxz8qR.js → lib-DtalJKI3.js} +71861 -75344
- package/lib/src/lib.js +1 -2
- package/lib/src/metadata-builder/ai-metadata-executor.d.ts +1 -0
- package/lib/src/metadata-builder/ai-metadata-executor.js +19 -0
- package/lib/src/metadata-builder/builders/section-builders/about-section-builder.js +3 -2
- package/lib/src/metadata-builder/builders/section-builders/banner-section-builder.js +3 -2
- package/lib/src/metadata-builder/builders/section-builders/booking-section-builder.js +3 -2
- package/lib/src/metadata-builder/builders/section-builders/contact-form-builder.js +4 -3
- package/lib/src/metadata-builder/builders/section-builders/images-section-builder.js +3 -2
- package/lib/src/metadata-builder/builders/section-builders/mailing-list-builder.js +2 -1
- package/lib/src/metadata-builder/builders/section-builders/mailing-list-section-builder.js +2 -1
- package/lib/src/metadata-builder/builders/section-builders/profile-section-builder.js +4 -3
- package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.js +3 -2
- package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.js +2 -1
- package/lib/src/metadata-builder/builders/section-builders/text-section-builder.js +11 -15
- package/lib/src/metadata-builder/builders/update-content-text-builder.d.ts +17 -0
- package/lib/src/metadata-builder/builders/update-content-text-builder.js +103 -0
- package/lib/src/metadata-builder/builders/update-content-text-style-builder.d.ts +16 -0
- package/lib/src/metadata-builder/builders/update-content-text-style-builder.js +216 -0
- package/lib/src/metadata-builder/helpers/rte.helpers.d.ts +13 -11
- package/lib/src/metadata-builder/helpers/rte.helpers.js +73 -14
- package/lib/src/metadata-builder/metadata-executor.js +4 -0
- package/lib/src/metadata-builder/models.d.ts +2 -0
- package/lib/src/metadata-builder/models.js +2 -0
- package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +19 -0
- package/lib/src/metadata-builder/parsers/ai-toolcall-parser.js +4 -0
- package/lib/src/metadata-builder/sanitizers/rte-schema-check.d.ts +8 -7
- package/lib/src/metadata-builder/sanitizers/rte-schema-check.js +52 -21
- package/lib/src/shared/content-settings/components/GenericTextInput.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/GenericTextInput.mixin.js +10 -35
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.js +3 -12
- package/lib/src/shared/content-settings/components/email-field/EmailField.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/tel-field/TelField.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.mixin.d.ts +2 -3
- package/lib/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.mixin.js +3 -10
- package/lib/src/shared/content-settings/components/text-field/TextField.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.d.ts +1 -2
- package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.js +1 -4
- package/lib/src/shared/content-settings/components/textarea-field/TextareaField.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/url-field/UrlField.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/youtube-video-field/YoutubeVideoField.mixin.d.ts +1 -1
- package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +1 -1
- package/lib/src/shared/logo-versions/LogoVersions.mixin.d.ts +1 -1
- package/lib/src/shared/my-designs/MyDesigns.mixin.d.ts +1 -1
- package/lib/src/shared/my-uploads/MyMedia.mixin.d.ts +1 -1
- package/lib/src/shared/my-uploads/MyUploads.mixin.d.ts +1 -1
- package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +1 -1
- package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +1 -1
- package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +1 -1
- package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.d.ts +1 -1
- package/lib/src/shared/template-settings/store/template-settings-store.d.ts +2 -0
- package/lib/src/shared/template-settings/store/template-settings-store.js +72 -24
- package/lib/src/shared/unsplash-library/UnsplashLibrary.mixin.d.ts +1 -1
- package/lib/src/utils/minify-brand-page-metadata.js +1 -4
- package/package.json +15 -17
- package/src/brand-page/components/contact-form/ContactForm.mixin.ts +9 -7
- package/src/brand-page/components/cookie-consent/CookieConsent.vue +1 -0
- package/src/brand-page/components/mailing-list/MailingList.mixin.ts +8 -3
- package/src/brand-page/components/navigation/navigation-carousel/NavigationCarousel.vue +5 -1
- package/src/brand-page/components/page-footer/PageFooter.mixin.ts +4 -1
- package/src/brand-page/components/page-footer/PageFooter.vue +1 -1
- package/src/brand-page/components/payment/Payment.mixin.ts +4 -3
- package/src/brand-page/components/payment/request-payment/RequestPayment.mixin.ts +8 -1
- package/src/brand-page/components/payment/request-payment/RequestPayment.vue +1 -1
- package/src/brand-page/components/save-contact/SaveContactWidget.vue +2 -1
- package/src/brand-page/components/shop/Shop.vue +6 -3
- package/src/brand-page/components/social-links/SocialLinks.vue +5 -2
- package/src/brand-page/components/text-wrapper/TextWrapper.vue +6 -17
- package/src/brand-page/composables/consent.composable.ts +18 -4
- package/src/brand-page/models/brand-page-context.model.ts +7 -0
- package/src/brand-page/models/index.ts +26 -35
- package/src/brand-page/utils/__snapshots__/migration.util.test.ts.snap +3 -3
- package/src/brand-page/utils/context.util.test.ts +43 -0
- package/src/brand-page/utils/context.util.ts +10 -0
- package/src/brand-page/utils/migration.util.ts +0 -12
- package/src/brand-page/utils/style.util.test.ts +0 -51
- package/src/brand-page/utils/text.util.ts +4 -83
- package/src/brand-page/utils/vcard.util.ts +4 -6
- package/src/brand-page/utils/view-model.util.ts +26 -94
- package/src/brand-page/view-models.ts +2 -3
- package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.vue +4 -5
- package/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.test.ts +135 -0
- package/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.ts +62 -21
- package/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.ts +1 -0
- package/src/brand-page-maker/composables/rich-text-editor/bubbleMenu.ts +10 -6
- package/src/brand-page-maker/composables/rich-text-editor/extensions/FontSize.ts +73 -0
- package/src/brand-page-maker/composables/rich-text-editor/extensions/LineHeight.ts +85 -0
- package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +111 -27
- package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.ts +9 -0
- package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +11 -3
- package/src/brand-page-maker/stores/ui/ui-store.ts +1 -1
- package/src/brand-page-maker/utils/index.ts +0 -2
- package/src/brand-page-maker/utils/rich-text-editor.util.test.ts +3 -62
- package/src/brand-page-maker/utils/rich-text-editor.util.ts +11 -86
- package/src/brand-page-maker/validators/field.validator.ts +2 -10
- package/src/clients/models.ts +3 -0
- package/src/lib.ts +1 -9
- package/src/metadata-builder/ai-metadata-executor.ts +26 -0
- package/src/metadata-builder/builders/section-builders/about-section-builder.ts +3 -2
- package/src/metadata-builder/builders/section-builders/banner-section-builder.ts +3 -2
- package/src/metadata-builder/builders/section-builders/booking-section-builder.ts +5 -2
- package/src/metadata-builder/builders/section-builders/contact-form-builder.ts +4 -3
- package/src/metadata-builder/builders/section-builders/images-section-builder.ts +3 -2
- package/src/metadata-builder/builders/section-builders/mailing-list-builder.ts +2 -1
- package/src/metadata-builder/builders/section-builders/mailing-list-section-builder.ts +2 -1
- package/src/metadata-builder/builders/section-builders/profile-section-builder.ts +6 -3
- package/src/metadata-builder/builders/section-builders/shapes-section-builder.ts +3 -2
- package/src/metadata-builder/builders/section-builders/testimonial-section-builder.ts +2 -1
- package/src/metadata-builder/builders/section-builders/text-section-builder.ts +13 -19
- package/src/metadata-builder/builders/update-content-text-builder.ts +148 -0
- package/src/metadata-builder/builders/update-content-text-style-builder.ts +352 -0
- package/src/metadata-builder/helpers/rte.helpers.ts +101 -15
- package/src/metadata-builder/metadata-executor.ts +5 -0
- package/src/metadata-builder/models.ts +3 -0
- package/src/metadata-builder/parsers/ai-toolcall-parser.ts +27 -0
- package/src/metadata-builder/sanitizers/rte-schema-check.ts +53 -24
- package/src/shared/content-settings/components/GenericTextInput.mixin.ts +11 -42
- package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.ts +3 -16
- package/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.mixin.ts +4 -13
- package/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.vue +4 -6
- package/src/shared/content-settings/components/text-image-field/TextImageField.vue +3 -6
- package/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.ts +1 -6
- package/src/shared/content-settings/components/text-items-field/TextItemsField.vue +1 -1
- package/src/shared/template-settings/store/template-settings-store.ts +93 -27
- package/src/utils/minify-brand-page-metadata.ts +1 -4
- package/lib/src/brand-page/utils/migration/migration-20.d.ts +0 -2
- package/lib/src/brand-page/utils/migration/migration-20.js +0 -66
- package/lib/src/brand-page-maker/__fixtures__/complex-rte.fixture.d.ts +0 -22
- package/lib/src/brand-page-maker/__fixtures__/complex-rte.fixture.js +0 -22
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.d.ts +0 -14
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.js +0 -39
- package/lib/src/brand-page-maker/composables/rich-text-editor/getRteExtensions.d.ts +0 -28
- package/lib/src/brand-page-maker/composables/rich-text-editor/getRteExtensions.js +0 -117
- package/lib/src/brand-page-maker/utils/rte-render.util.d.ts +0 -63
- package/lib/src/brand-page-maker/utils/rte-render.util.js +0 -95
- package/lib/src/brand-page-maker/utils/rte-sanitize.util.d.ts +0 -6
- package/lib/src/brand-page-maker/utils/rte-sanitize.util.js +0 -156
- package/src/brand-page/utils/migration/migration-20.server.test.ts +0 -125
- package/src/brand-page/utils/migration/migration-20.test.ts +0 -72
- package/src/brand-page/utils/migration/migration-20.ts +0 -87
- package/src/brand-page/utils/text.util.test.ts +0 -106
- package/src/brand-page/utils/view-model.pageid-rte.test.ts +0 -104
- package/src/brand-page-maker/__fixtures__/complex-rte.fixture.ts +0 -23
- package/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.test.ts +0 -52
- package/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.ts +0 -42
- package/src/brand-page-maker/composables/rich-text-editor/getRteExtensions.ts +0 -162
- package/src/brand-page-maker/utils/__snapshots__/rte-render-parity.test.ts.snap +0 -202
- package/src/brand-page-maker/utils/rte-features.test.ts +0 -378
- package/src/brand-page-maker/utils/rte-render-parity.test.ts +0 -164
- package/src/brand-page-maker/utils/rte-render.util.ts +0 -165
- package/src/brand-page-maker/utils/rte-sanitize-json.test.ts +0 -172
- package/src/brand-page-maker/utils/rte-sanitize.util.ts +0 -192
- package/src/brand-page-maker/validators/field.validator.test.ts +0 -55
|
@@ -1,6 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import { Editor } from '@tiptap/vue-3';
|
|
2
|
+
import StarterKit from '@tiptap/starter-kit';
|
|
3
|
+
import Underline from '@tiptap/extension-underline';
|
|
4
|
+
import TextStyle from '@tiptap/extension-text-style';
|
|
5
|
+
import TextAlign from '@tiptap/extension-text-align';
|
|
6
|
+
import FontFamily from '@tiptap/extension-font-family';
|
|
7
|
+
import ColorExtension from '@tiptap/extension-color';
|
|
8
|
+
import Highlight from '@tiptap/extension-highlight';
|
|
9
|
+
import Link from '@tiptap/extension-link';
|
|
10
|
+
import { FontSize } from '../../brand-page-maker/composables/rich-text-editor/extensions/FontSize';
|
|
11
|
+
import { LetterSpacing } from '../../brand-page-maker/composables/rich-text-editor/extensions/LetterSpacing';
|
|
12
|
+
import { LineHeight } from '../../brand-page-maker/composables/rich-text-editor/extensions/LineHeight';
|
|
13
|
+
import { AutoLink } from '../../brand-page-maker/composables/rich-text-editor/extensions/AutoLink';
|
|
4
14
|
import { isTiptapDocument } from '../parsers/section-tool-arguments';
|
|
5
15
|
import {
|
|
6
16
|
rteStyleCheck,
|
|
@@ -9,30 +19,45 @@ import {
|
|
|
9
19
|
} from './section-args-validator';
|
|
10
20
|
|
|
11
21
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* We import `getRteExtensions` (a leaf module — @tiptap + prosemirror only), not
|
|
18
|
-
* the maker composable (`useExternalRichTextEditor`), which would pull in the
|
|
19
|
-
* AI executor → section-builders → section-rules graph and re-enter this file
|
|
20
|
-
* before its exports are bound.
|
|
22
|
+
* Constructs a headless Tiptap Editor with the same extension set as
|
|
23
|
+
* `useExternalRichTextEditor` in the maker. We import the Tiptap extension
|
|
24
|
+
* files directly (they are leaf modules) instead of going through the maker
|
|
25
|
+
* composable, which would pull in the AI executor → section-builders →
|
|
26
|
+
* section-rules graph and re-enter this file before its exports are bound.
|
|
21
27
|
*/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
const buildHeadlessEditor = (): Editor =>
|
|
29
|
+
new Editor({
|
|
30
|
+
editable: false,
|
|
31
|
+
extensions: [
|
|
32
|
+
StarterKit,
|
|
33
|
+
Underline,
|
|
34
|
+
TextStyle.configure({ mergeNestedSpanStyles: true }),
|
|
35
|
+
TextAlign.configure({ types: ['heading', 'paragraph'] }),
|
|
36
|
+
FontFamily.configure({ types: ['textStyle'] }),
|
|
37
|
+
FontSize,
|
|
38
|
+
LetterSpacing,
|
|
39
|
+
LineHeight,
|
|
40
|
+
ColorExtension.configure({ types: ['textStyle'] }),
|
|
41
|
+
Highlight.configure({ multicolor: true }),
|
|
42
|
+
Link.configure({
|
|
43
|
+
openOnClick: false,
|
|
44
|
+
defaultProtocol: 'https',
|
|
45
|
+
autolink: true,
|
|
46
|
+
}),
|
|
47
|
+
AutoLink,
|
|
48
|
+
],
|
|
49
|
+
});
|
|
26
50
|
|
|
27
51
|
/**
|
|
28
|
-
* Validates a Tiptap doc against the real ProseMirror
|
|
29
|
-
* (`schema.nodeFromJSON`). Catches malformed AI input — stray
|
|
30
|
-
* in `content`, unknown node types, malformed attrs —
|
|
31
|
-
* and the renderer's silent `setContent` drops
|
|
52
|
+
* Validates a Tiptap doc against the headless editor's real ProseMirror
|
|
53
|
+
* schema (`schema.nodeFromJSON`). Catches malformed AI input — stray
|
|
54
|
+
* non-node children in `content`, unknown node types, malformed attrs —
|
|
55
|
+
* before the builder runs and the renderer's silent `setContent` drops
|
|
56
|
+
* the doc to `<p></p>` (BP-5669).
|
|
32
57
|
*
|
|
33
|
-
* Returns the field-prefixed error string so the AI's tool-call retry
|
|
34
|
-
* it via `BuilderResult.errors` → `tool_result.errorMessage`
|
|
35
|
-
* corrected payload.
|
|
58
|
+
* Returns the field-prefixed error string so the AI's tool-call retry
|
|
59
|
+
* loop reads it via `BuilderResult.errors` → `tool_result.errorMessage`
|
|
60
|
+
* and re-emits a corrected payload.
|
|
36
61
|
*/
|
|
37
62
|
export const rteSchemaCheck =
|
|
38
63
|
(field: string): SectionCheck =>
|
|
@@ -41,14 +66,18 @@ export const rteSchemaCheck =
|
|
|
41
66
|
|
|
42
67
|
if (!isTiptapDocument(value)) return null;
|
|
43
68
|
|
|
69
|
+
const editor = buildHeadlessEditor();
|
|
70
|
+
|
|
44
71
|
try {
|
|
45
|
-
|
|
72
|
+
editor.schema.nodeFromJSON(value);
|
|
46
73
|
|
|
47
74
|
return null;
|
|
48
75
|
} catch (err) {
|
|
49
76
|
const detail = err instanceof Error ? err.message : String(err);
|
|
50
77
|
|
|
51
78
|
return `"${field}" is not valid Tiptap JSON: ${detail}`;
|
|
79
|
+
} finally {
|
|
80
|
+
editor.destroy();
|
|
52
81
|
}
|
|
53
82
|
};
|
|
54
83
|
|
|
@@ -6,7 +6,7 @@ import { TextInput, Textarea } from '@designcrowd/fe-shared-lib';
|
|
|
6
6
|
import type { ContentItemFieldSettings } from '../models';
|
|
7
7
|
import {
|
|
8
8
|
encodeContentText,
|
|
9
|
-
|
|
9
|
+
escapeContentText,
|
|
10
10
|
unescapeContentText,
|
|
11
11
|
} from '@brand-page/utils';
|
|
12
12
|
import { genericTextInputTr } from '@src/composables/useTranslate';
|
|
@@ -107,6 +107,7 @@ export default defineComponent({
|
|
|
107
107
|
_oldValue: '' as string,
|
|
108
108
|
isDirty: false,
|
|
109
109
|
emitChangeDebounce: undefined as DebounceHandle | undefined,
|
|
110
|
+
lengthError: false,
|
|
110
111
|
// Whether every write in the current debounce burst was an RTE
|
|
111
112
|
// hydration write-back (see UpdateItemValuePayload.isHydrationWrite).
|
|
112
113
|
// undefined = no burst pending; any user write downgrades it to false.
|
|
@@ -129,30 +130,6 @@ export default defineComponent({
|
|
|
129
130
|
return this.settings?.isValid;
|
|
130
131
|
},
|
|
131
132
|
|
|
132
|
-
// Derived from the current value + maxLength (not hand-synced in a watcher):
|
|
133
|
-
// stays correct when maxLength or showRichTextEditor change and on first
|
|
134
|
-
// render, and flips the instant `_value` updates rather than after the emit
|
|
135
|
-
// round-trips back through the `value` prop. `>=` (not `>`) because the RTE
|
|
136
|
-
// MaxLength extension hard-gates the length, so "reached the cap" is the
|
|
137
|
-
// signal to surface. Length is measured with getContentTextLength so it
|
|
138
|
-
// matches the editor's own char count (ProseMirror textContent) — NOT
|
|
139
|
-
// escapeContentText, whose space-join over-counts by one per mark boundary
|
|
140
|
-
// (e.g. hyperlinking a word), reporting length+1 at the cap (BP-5787).
|
|
141
|
-
lengthError(): boolean {
|
|
142
|
-
const value = this._value;
|
|
143
|
-
const maxLength = this.maxLength;
|
|
144
|
-
|
|
145
|
-
if (maxLength == null || value === false || value == null) {
|
|
146
|
-
return false;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const length = this.showRichTextEditor
|
|
150
|
-
? getContentTextLength(value)
|
|
151
|
-
: value.length;
|
|
152
|
-
|
|
153
|
-
return length >= maxLength;
|
|
154
|
-
},
|
|
155
|
-
|
|
156
133
|
label(): string {
|
|
157
134
|
return this.name.replace(/./, (c: string) => c.toUpperCase());
|
|
158
135
|
},
|
|
@@ -198,24 +175,16 @@ export default defineComponent({
|
|
|
198
175
|
},
|
|
199
176
|
},
|
|
200
177
|
watch: {
|
|
201
|
-
value(newVal: string | undefined
|
|
202
|
-
// BP-5787: RTE values are Tiptap JSON objects. The parent (TextItemsField)
|
|
203
|
-
// re-clones its items array (cloneDeep) on ANY change — including a sibling
|
|
204
|
-
// field's style sync — yielding a NEW object reference with identical text
|
|
205
|
-
// content. For objects Vue fires this watcher on reference change, so that
|
|
206
|
-
// spurious re-clone would overwrite `_value` and clobber an in-flight edit
|
|
207
|
-
// (a mark applied but not yet debounced to the store), silently dropping
|
|
208
|
-
// the user's formatting. Strings never hit this (same content = same
|
|
209
|
-
// reference = no fire), so mirror that: ignore re-clones whose content is
|
|
210
|
-
// unchanged from the previous prop value.
|
|
211
|
-
if (
|
|
212
|
-
this.showRichTextEditor &&
|
|
213
|
-
JSON.stringify(newVal) === JSON.stringify(oldVal)
|
|
214
|
-
) {
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
|
|
178
|
+
value(newVal: string | undefined) {
|
|
218
179
|
this._value = newVal;
|
|
180
|
+
|
|
181
|
+
if (this.showRichTextEditor) {
|
|
182
|
+
const textValue = escapeContentText(this._value);
|
|
183
|
+
|
|
184
|
+
this.lengthError = textValue && textValue.length >= this.maxLength;
|
|
185
|
+
} else {
|
|
186
|
+
this.lengthError = this._value.length >= this.maxLength;
|
|
187
|
+
}
|
|
219
188
|
},
|
|
220
189
|
|
|
221
190
|
isToggled(newVal: boolean) {
|
|
@@ -21,9 +21,6 @@ import {
|
|
|
21
21
|
replaceTextInRTE,
|
|
22
22
|
RTE_ALLOWED_SECTION_TYPES,
|
|
23
23
|
isRTEManagedStyleField,
|
|
24
|
-
isTiptapDocument,
|
|
25
|
-
renderRteToHtml,
|
|
26
|
-
toRteJson,
|
|
27
24
|
} from '@brand-page-maker/utils';
|
|
28
25
|
import { isDefaultContentText } from '@shared/content-settings/utils';
|
|
29
26
|
import { useUiLogoSettingsStore } from '../../../logo-settings/store';
|
|
@@ -330,20 +327,10 @@ export default defineComponent({
|
|
|
330
327
|
this.isToggled = isToggled;
|
|
331
328
|
},
|
|
332
329
|
onUseGeneratedText(generatedText: string) {
|
|
333
|
-
let formattedText
|
|
330
|
+
let formattedText = generatedText;
|
|
334
331
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
// (cold AI path, shared editor); string fields use it directly.
|
|
338
|
-
if (this.showRichTextEditor) {
|
|
339
|
-
if (isTiptapDocument(this.value)) {
|
|
340
|
-
formattedText =
|
|
341
|
-
toRteJson(
|
|
342
|
-
replaceTextInRTE(renderRteToHtml(this.value), generatedText),
|
|
343
|
-
) ?? generatedText;
|
|
344
|
-
} else if (typeof this.value === 'string') {
|
|
345
|
-
formattedText = replaceTextInRTE(this.value, generatedText);
|
|
346
|
-
}
|
|
332
|
+
if (this.showRichTextEditor && typeof this.value === 'string') {
|
|
333
|
+
formattedText = replaceTextInRTE(this.value, generatedText);
|
|
347
334
|
}
|
|
348
335
|
|
|
349
336
|
this.contentSettingsStore.updateItemValue({
|
|
@@ -4,7 +4,6 @@ import type {
|
|
|
4
4
|
ColorReplacement,
|
|
5
5
|
Content,
|
|
6
6
|
LogoTheme,
|
|
7
|
-
RichTextValue,
|
|
8
7
|
TestimonialItems,
|
|
9
8
|
} from '@brand-page';
|
|
10
9
|
import {
|
|
@@ -18,7 +17,7 @@ import debounce from 'lodash.debounce';
|
|
|
18
17
|
import type { UpdateItemValuePayload } from '../../models';
|
|
19
18
|
import cloneDeep from 'lodash.clonedeep';
|
|
20
19
|
import { useSnapshotStore } from '@brand-page-maker/stores';
|
|
21
|
-
import { getPlainTextFromRTE
|
|
20
|
+
import { getPlainTextFromRTE } from '@brand-page-maker/utils';
|
|
22
21
|
import { isDefaultContentText } from '../../utils';
|
|
23
22
|
import { decodeHtmlEntities } from '@brand-page/utils';
|
|
24
23
|
import { ESCAPED_NEWLINE_CHARACTER } from '../../../../constants/ui';
|
|
@@ -92,10 +91,8 @@ export default defineComponent({
|
|
|
92
91
|
created() {
|
|
93
92
|
this.options = cloneDeep(this.value);
|
|
94
93
|
|
|
95
|
-
// BP-5787: testimonials may be Tiptap JSON (migrated legacy content), so
|
|
96
|
-
// read visible text via getPlainTextFromRTE rather than `.trim()` on a doc.
|
|
97
94
|
this.isEmpty = this.options.map(
|
|
98
|
-
(option) =>
|
|
95
|
+
(option) => option.testimonials.trim().length === 0,
|
|
99
96
|
);
|
|
100
97
|
|
|
101
98
|
if (!this.changeDebounce) {
|
|
@@ -209,17 +206,11 @@ export default defineComponent({
|
|
|
209
206
|
this.options[index][payload.name] = payload.value;
|
|
210
207
|
this.emitChange();
|
|
211
208
|
},
|
|
212
|
-
getItemTextPreview(text:
|
|
213
|
-
// BP-5787: a JSON doc has no `.replace` — take its visible text first.
|
|
214
|
-
const value = typeof text === 'string' ? text : getPlainTextFromRTE(text);
|
|
215
|
-
|
|
209
|
+
getItemTextPreview(text: string): string {
|
|
216
210
|
return decodeHtmlEntities(
|
|
217
|
-
|
|
211
|
+
text.replace(new RegExp(ESCAPED_NEWLINE_CHARACTER, 'g'), ' '),
|
|
218
212
|
);
|
|
219
213
|
},
|
|
220
|
-
rteTextLength(value: RichTextValue): number {
|
|
221
|
-
return getRteTextLength(value);
|
|
222
|
-
},
|
|
223
214
|
getPlainTextValue(index: number): string {
|
|
224
215
|
const text = this.options[index]?.testimonials || '';
|
|
225
216
|
const plainText = getPlainTextFromRTE(text);
|
package/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.vue
CHANGED
|
@@ -26,8 +26,7 @@
|
|
|
26
26
|
:error="
|
|
27
27
|
isEmpty[option.index] ||
|
|
28
28
|
(options[option.index].testimonials &&
|
|
29
|
-
|
|
30
|
-
maxTestimonialLength)
|
|
29
|
+
options[option.index].testimonials.length >= maxTestimonialLength)
|
|
31
30
|
"
|
|
32
31
|
:resize="false"
|
|
33
32
|
class="tw-w-full"
|
|
@@ -43,8 +42,7 @@
|
|
|
43
42
|
<p
|
|
44
43
|
v-else-if="
|
|
45
44
|
options[option.index].testimonials &&
|
|
46
|
-
|
|
47
|
-
maxTestimonialLength
|
|
45
|
+
options[option.index].testimonials.length >= maxTestimonialLength
|
|
48
46
|
"
|
|
49
47
|
class="tw-text-error-500 tw-text-sm"
|
|
50
48
|
>
|
|
@@ -129,7 +127,7 @@
|
|
|
129
127
|
v-if="
|
|
130
128
|
options[option.index] &&
|
|
131
129
|
options[option.index].name &&
|
|
132
|
-
|
|
130
|
+
options[option.index].name.length >= maxTitleLength
|
|
133
131
|
"
|
|
134
132
|
class="tw-text-error-500 tw-text-sm"
|
|
135
133
|
>
|
|
@@ -160,7 +158,7 @@
|
|
|
160
158
|
v-if="
|
|
161
159
|
options[option.index] &&
|
|
162
160
|
options[option.index].position &&
|
|
163
|
-
|
|
161
|
+
options[option.index].position.length >= maxTitleLength
|
|
164
162
|
"
|
|
165
163
|
class="tw-text-error-500 tw-text-sm"
|
|
166
164
|
>
|
|
@@ -97,10 +97,10 @@
|
|
|
97
97
|
:attrs="{
|
|
98
98
|
'data-test-tag': 'image-title-text-input',
|
|
99
99
|
}"
|
|
100
|
-
:error="
|
|
100
|
+
:error="options[option.index].title.length >= titleLength"
|
|
101
101
|
/>
|
|
102
102
|
<p
|
|
103
|
-
v-if="
|
|
103
|
+
v-if="options[option.index].title.length >= titleLength"
|
|
104
104
|
class="tw-text-error-500 tw-text-sm tw-mt-2"
|
|
105
105
|
>
|
|
106
106
|
{{ maxLengthError }}
|
|
@@ -134,9 +134,7 @@
|
|
|
134
134
|
:attrs="{
|
|
135
135
|
'data-test-tag': 'image-description-text-input',
|
|
136
136
|
}"
|
|
137
|
-
:error="
|
|
138
|
-
rteTextLength(options[option.index].paragraph) >= descriptionLength
|
|
139
|
-
"
|
|
137
|
+
:error="options[option.index].paragraph.length >= descriptionLength"
|
|
140
138
|
@update:model-value="onTextAreaTextChange($event, option.index)"
|
|
141
139
|
/>
|
|
142
140
|
<PersonalisationOverrideField
|
|
@@ -313,7 +311,6 @@ import debounce from 'lodash.debounce';
|
|
|
313
311
|
import type { UpdateItemValuePayload } from '../../models';
|
|
314
312
|
import cloneDeep from 'lodash.clonedeep';
|
|
315
313
|
import { isURL } from '../../../../utils/validator.util';
|
|
316
|
-
import { getRteTextLength as rteTextLength } from '@brand-page-maker/utils';
|
|
317
314
|
|
|
318
315
|
const DEBOUNCE_IN_MS = 250;
|
|
319
316
|
|
|
@@ -3,7 +3,6 @@ import type { PropType } from 'vue';
|
|
|
3
3
|
import type {
|
|
4
4
|
Content,
|
|
5
5
|
LogoTheme,
|
|
6
|
-
RichTextValue,
|
|
7
6
|
TextItem,
|
|
8
7
|
TextStyleDeclaration,
|
|
9
8
|
} from '@brand-page/models';
|
|
@@ -20,7 +19,7 @@ import type { UpdateItemValuePayload } from '../../models';
|
|
|
20
19
|
import cloneDeep from 'lodash.clonedeep';
|
|
21
20
|
import { decodeHtmlEntities, escapeContentText } from '@brand-page/utils';
|
|
22
21
|
import { useSnapshotStore } from '@brand-page-maker/stores';
|
|
23
|
-
import { getPlainTextFromRTE
|
|
22
|
+
import { getPlainTextFromRTE } from '@brand-page-maker/utils';
|
|
24
23
|
import { isDefaultContentText } from '../../utils';
|
|
25
24
|
|
|
26
25
|
const DEBOUNCE_IN_MS = 250;
|
|
@@ -235,10 +234,6 @@ export default defineComponent({
|
|
|
235
234
|
this.emitChange();
|
|
236
235
|
},
|
|
237
236
|
|
|
238
|
-
rteTextLength(value: RichTextValue): number {
|
|
239
|
-
return getRteTextLength(value);
|
|
240
|
-
},
|
|
241
|
-
|
|
242
237
|
getPlainTextValue(index: number): string {
|
|
243
238
|
const text = this.options[index]?.text || '';
|
|
244
239
|
const plainText = getPlainTextFromRTE(text);
|
|
@@ -26,7 +26,10 @@ import {
|
|
|
26
26
|
useUiStore,
|
|
27
27
|
} from '@brand-page-maker/stores';
|
|
28
28
|
import { useUiSideBarStore } from '../../side-bar/store';
|
|
29
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
BrandPageModel,
|
|
31
|
+
type UserPersonalisationContent,
|
|
32
|
+
} from '@brand-page/models';
|
|
30
33
|
import { migrateBrandPageModel } from '@brand-page/utils';
|
|
31
34
|
import { getAiContentIndexByTemplateTokenAndNumberOfVariations } from '@brand-page-maker/utils/ai-content-selection.util';
|
|
32
35
|
import {
|
|
@@ -50,6 +53,7 @@ const POST_PURCHASE_PAGE_SECTION_BY_TAB: Record<string, string> = {
|
|
|
50
53
|
|
|
51
54
|
const PRE_PURCHASE_PAGE_SECTION_BY_TAB: Record<string, string> = {
|
|
52
55
|
[TEMPLATE_TABS.all]: 'MakerPrePurchaseSidebarTemplatesAllTab',
|
|
56
|
+
[TEMPLATE_TABS.AI]: 'MakerPrePurchaseSidebarTemplatesAiTab',
|
|
53
57
|
[TEMPLATE_TABS.categories]: 'MakerPrePurchaseSidebarTemplatesCategoryTab',
|
|
54
58
|
};
|
|
55
59
|
const LOAD_PAGE_RETRY_DELAY = 250;
|
|
@@ -76,6 +80,7 @@ export interface TemplatesSettingState {
|
|
|
76
80
|
selectedTab: SelectedTabType;
|
|
77
81
|
selectedCategory: string | undefined;
|
|
78
82
|
searchTerm: string | undefined;
|
|
83
|
+
searchPersonalisationData: UserPersonalisationContent[] | undefined;
|
|
79
84
|
tabsWithTranslations: SelectedTabType[];
|
|
80
85
|
logoChangeWatcherInitialized: boolean;
|
|
81
86
|
initialSearchTerm: string | undefined;
|
|
@@ -98,6 +103,7 @@ export const useUiTemplateSettingsStore = defineStore('uiTemplateSettings', {
|
|
|
98
103
|
displayName: templateSettingsTr(`headerAll`),
|
|
99
104
|
},
|
|
100
105
|
searchTerm: undefined,
|
|
106
|
+
searchPersonalisationData: undefined,
|
|
101
107
|
selectedCategory: undefined,
|
|
102
108
|
templateCategories: [],
|
|
103
109
|
tabsWithTranslations: [
|
|
@@ -321,17 +327,25 @@ export const useUiTemplateSettingsStore = defineStore('uiTemplateSettings', {
|
|
|
321
327
|
const isBrandSite =
|
|
322
328
|
this.templateType === BP_BRAND_SITE_TEMPLATE_TYPE_NAME;
|
|
323
329
|
|
|
324
|
-
//
|
|
325
|
-
//
|
|
326
|
-
//
|
|
327
|
-
|
|
330
|
+
// With no user search, the All tab must still show industry-relevant templates rather than
|
|
331
|
+
// generic ones (searchIndustries alone doesn't rank the non-AI half). Seed searchTerm as an
|
|
332
|
+
// invisible default: pre-purchase has no logo to read an industry from, so it uses the seeded
|
|
333
|
+
// keyword from the URL/cookie (bp-5454); post-purchase falls back to the logo draft's industry
|
|
334
|
+
// (bp-5789). Once the user searches, this.searchTerm takes over. this.searchTerm stays unset
|
|
335
|
+
// here, so AI content-key resolution below is unaffected.
|
|
336
|
+
const useSeededSearchTerm =
|
|
328
337
|
!this.searchTerm &&
|
|
329
338
|
!this.selectedCategory &&
|
|
330
|
-
isPrePurchase &&
|
|
331
339
|
isBrandSite &&
|
|
332
|
-
this.selectedTab.key === TEMPLATE_TABS.all
|
|
333
|
-
|
|
334
|
-
|
|
340
|
+
this.selectedTab.key === TEMPLATE_TABS.all;
|
|
341
|
+
|
|
342
|
+
const seededSearchTerm = isPrePurchase
|
|
343
|
+
? this.initialSearchTerm
|
|
344
|
+
: brandPageMakerStore.industry;
|
|
345
|
+
|
|
346
|
+
const effectiveSearchTerm = useSeededSearchTerm
|
|
347
|
+
? seededSearchTerm
|
|
348
|
+
: this.searchTerm;
|
|
335
349
|
|
|
336
350
|
const pageSection = isBrandSite
|
|
337
351
|
? (isPrePurchase
|
|
@@ -397,6 +411,23 @@ export const useUiTemplateSettingsStore = defineStore('uiTemplateSettings', {
|
|
|
397
411
|
}
|
|
398
412
|
}
|
|
399
413
|
|
|
414
|
+
// searchPersonalisation is a per-search payload established on page 1; only set it there
|
|
415
|
+
// (like abTestValuesToBePushed above) so paginating to page 2+ can't reset it to undefined.
|
|
416
|
+
// Every context change (search/clear/category/logo swap) reloads from page 1, so this still
|
|
417
|
+
// clears stale search content on a new search.
|
|
418
|
+
//
|
|
419
|
+
// Set BEFORE the mapping loop so tiles and the apply path read the same value — reading the
|
|
420
|
+
// per-page `result.searchPersonalisation` here made page-2 tiles fall back to page-load
|
|
421
|
+
// content while applying used page-1 search content.
|
|
422
|
+
//
|
|
423
|
+
// Empty [] is stored as undefined: it wins `??` but fails `?.length`, so it would strand
|
|
424
|
+
// the downstream fallback to uiStore.personalisationData and silently skip the apply.
|
|
425
|
+
if (pageNo === 1) {
|
|
426
|
+
this.searchPersonalisationData = result.searchPersonalisation?.length
|
|
427
|
+
? result.searchPersonalisation
|
|
428
|
+
: undefined;
|
|
429
|
+
}
|
|
430
|
+
|
|
400
431
|
const templates = await Promise.all(
|
|
401
432
|
result.paginatedItems.map(async (item) => {
|
|
402
433
|
try {
|
|
@@ -411,17 +442,20 @@ export const useUiTemplateSettingsStore = defineStore('uiTemplateSettings', {
|
|
|
411
442
|
let personalisationContentIndex: number | undefined;
|
|
412
443
|
let contentKey: string | undefined;
|
|
413
444
|
|
|
414
|
-
|
|
445
|
+
const activePersonalisation =
|
|
446
|
+
this.searchPersonalisationData ?? uiStore.personalisationData;
|
|
447
|
+
|
|
448
|
+
if (activePersonalisation?.length) {
|
|
415
449
|
personalisationContentIndex =
|
|
416
450
|
await getAiContentIndexByTemplateTokenAndNumberOfVariations(
|
|
417
451
|
item.designTemplateToken,
|
|
418
|
-
|
|
452
|
+
activePersonalisation.length,
|
|
419
453
|
);
|
|
420
454
|
|
|
421
455
|
contentKey =
|
|
422
|
-
|
|
456
|
+
activePersonalisation[personalisationContentIndex]
|
|
423
457
|
.contentKey;
|
|
424
|
-
} else if (item.isPersonalisable) {
|
|
458
|
+
} else if (item.isPersonalisable && !this.searchTerm) {
|
|
425
459
|
// Pre-purchase has no personalisationData; personalise AI
|
|
426
460
|
// template previews with the prompt content key (bp-5742).
|
|
427
461
|
contentKey = uiStore.userPromptContentKey;
|
|
@@ -431,10 +465,9 @@ export const useUiTemplateSettingsStore = defineStore('uiTemplateSettings', {
|
|
|
431
465
|
id: item.designTemplateToken,
|
|
432
466
|
isPersonalisable: item.isPersonalisable,
|
|
433
467
|
contentKey,
|
|
434
|
-
//
|
|
435
|
-
//
|
|
436
|
-
//
|
|
437
|
-
// holds placeholders post-purchase (bp-5454).
|
|
468
|
+
// userPromptContentKey signals the content lives in the userPrompt S3
|
|
469
|
+
// bucket (post- or pre-purchase); the preview must resolve via
|
|
470
|
+
// userPromptContentKey, not the regular bucket (bp-5454).
|
|
438
471
|
usesUserPromptContentKey: !!uiStore.userPromptContentKey,
|
|
439
472
|
previewImageUrl: item.previewImageUrl,
|
|
440
473
|
} as TemplateSettingsTemplate;
|
|
@@ -450,13 +483,25 @@ export const useUiTemplateSettingsStore = defineStore('uiTemplateSettings', {
|
|
|
450
483
|
(t): t is TemplateSettingsTemplate => t !== null,
|
|
451
484
|
);
|
|
452
485
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
//
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
486
|
+
let displayTemplates = validTemplates;
|
|
487
|
+
|
|
488
|
+
// The All tab shows backend-interleaved AI templates (gated server-side on the AB
|
|
489
|
+
// variation) even when the dedicated AI tab is hidden — e.g. regular templates
|
|
490
|
+
// pre-purchase (bp-5789). So only strip AI when the AI tab is hidden AND we're not on
|
|
491
|
+
// the All tab; the backend is the interleave gate, control buckets return no AI here.
|
|
492
|
+
if (
|
|
493
|
+
!uiStore.showAiTemplatesTab &&
|
|
494
|
+
this.selectedTab.key !== TEMPLATE_TABS.all
|
|
495
|
+
) {
|
|
496
|
+
displayTemplates = displayTemplates.filter(
|
|
497
|
+
(t) => !t.isPersonalisable,
|
|
498
|
+
);
|
|
499
|
+
} else if (this.selectedTab.key === TEMPLATE_TABS.categories) {
|
|
500
|
+
displayTemplates = displayTemplates.map((t) => ({
|
|
501
|
+
...t,
|
|
502
|
+
isPersonalisable: false,
|
|
503
|
+
}));
|
|
504
|
+
}
|
|
460
505
|
|
|
461
506
|
this._addTemplates({ templates: displayTemplates });
|
|
462
507
|
this._setPageNoLoaded({ pageNoLoaded: pageNo });
|
|
@@ -529,6 +574,11 @@ export const useUiTemplateSettingsStore = defineStore('uiTemplateSettings', {
|
|
|
529
574
|
searchTerm: payload.searchTerm,
|
|
530
575
|
});
|
|
531
576
|
|
|
577
|
+
// Drive AI industry selection from the typed term; fall back to the
|
|
578
|
+
// seeded keyword on clear so the AI tab doesn't go generic (bp-5789).
|
|
579
|
+
this.aiTemplateKeywords =
|
|
580
|
+
payload.searchTerm || this.initialSearchTerm || '';
|
|
581
|
+
|
|
532
582
|
this.onSearchTermChanged?.(payload.searchTerm);
|
|
533
583
|
|
|
534
584
|
await this._setPageNo({ pageNo: 1 });
|
|
@@ -617,7 +667,8 @@ export const useUiTemplateSettingsStore = defineStore('uiTemplateSettings', {
|
|
|
617
667
|
return;
|
|
618
668
|
}
|
|
619
669
|
|
|
620
|
-
//
|
|
670
|
+
// Refetch previews on any logo change (pre- and post-purchase) so the new logo
|
|
671
|
+
// shows in the thumbnails.
|
|
621
672
|
const hasLogoChanged =
|
|
622
673
|
newLogoImage.logoDraftToken !== oldLogoImage.logoDraftToken ||
|
|
623
674
|
newLogoImage.logoVariation !== oldLogoImage.logoVariation;
|
|
@@ -627,8 +678,23 @@ export const useUiTemplateSettingsStore = defineStore('uiTemplateSettings', {
|
|
|
627
678
|
newLogoImage.logoDraftToken &&
|
|
628
679
|
hasLogoChanged
|
|
629
680
|
) {
|
|
630
|
-
|
|
631
|
-
|
|
681
|
+
const uiStore = useUiStore();
|
|
682
|
+
const isPrePurchase = useBrandPageContainerStore().isPrePurchase;
|
|
683
|
+
|
|
684
|
+
uiStore.setUserPersonalisationData({
|
|
685
|
+
personalisationData: undefined,
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
if (
|
|
689
|
+
!isPrePurchase &&
|
|
690
|
+
newLogoImage.logoDraftToken !== oldLogoImage.logoDraftToken
|
|
691
|
+
) {
|
|
692
|
+
uiStore.setUserPromptContentKey({
|
|
693
|
+
userPromptContentKey: undefined,
|
|
694
|
+
});
|
|
695
|
+
uiStore.setShowAiTemplatesTab({ showAiTemplatesTab: false });
|
|
696
|
+
}
|
|
697
|
+
|
|
632
698
|
await this._setTemplates({ templates: [] });
|
|
633
699
|
await this._setPageNoLoaded({ pageNoLoaded: 0 });
|
|
634
700
|
await this._setPageNo({ pageNo: 1 });
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from '../brand-page/models';
|
|
11
11
|
import type { Content, ContentType } from '../brand-page/models/content.model';
|
|
12
12
|
import type { TextStyleDeclaration } from '../brand-page/models/styles.model';
|
|
13
|
-
import { hasRTEContent
|
|
13
|
+
import { hasRTEContent } from '../brand-page-maker/utils';
|
|
14
14
|
import { useExternalRichTextEditor } from '../brand-page-maker/composables/rich-text-editor/useRichTextEditor';
|
|
15
15
|
import type { Editor, JSONContent } from '@tiptap/vue-3';
|
|
16
16
|
import {
|
|
@@ -106,9 +106,6 @@ const convertText = (
|
|
|
106
106
|
value: unknown,
|
|
107
107
|
editor: Editor,
|
|
108
108
|
): RichTextValue | undefined => {
|
|
109
|
-
// Already Tiptap JSON (BP-5787 storage) — keep as-is.
|
|
110
|
-
if (isTiptapDocument(value)) return value;
|
|
111
|
-
|
|
112
109
|
if (typeof value !== 'string' || !value) return undefined;
|
|
113
110
|
|
|
114
111
|
if (hasRTEContent(value)) {
|