@designcrowd/library.brand-page 5.17.6 → 5.17.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/src/{CreatedOnBrandCrowd-de-de-BI2KuOEF.js → CreatedOnBrandCrowd-de-de-BUQFMhZb.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-BYLJCjLJ.js → CreatedOnBrandCrowd-en-us-QS-5r4XI.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-Y_D6cuGE.js → CreatedOnBrandCrowd-es-es-CP2iH-n0.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-CqCBRjYh.js → CreatedOnBrandCrowd-fr-ca-qfD4NmQZ.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-CqCBRjYh.js → CreatedOnBrandCrowd-fr-fr-qfD4NmQZ.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-Bt0YF6DA.js → CreatedOnBrandCrowd-pt-br-CfmaB7zE.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-Bt0YF6DA.js → CreatedOnBrandCrowd-pt-pt-CfmaB7zE.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-CEk8FBEG.js → CreatedOnDcom-de-de-BxSUWfGN.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-DWw4Tm2L.js → CreatedOnDcom-en-us-CSeUdR6v.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-DpG-8o98.js → CreatedOnDcom-es-es-g7rCfAtP.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-CEla7RmR.js → CreatedOnDcom-fr-ca-Bh_BTb-O.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-DRXeVTlV.js → CreatedOnDcom-fr-fr-Clgd_Ujm.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-Bzu_phZc.js → CreatedOnDcom-pt-br-Dlgk0myX.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-DWax8Er7.js → CreatedOnDcom-pt-pt-B14APfrn.js} +1 -1
- package/lib/src/brand-page/models/brand-page-context.model.d.ts +2 -1
- package/lib/src/brand-page/models/brand-page-context.model.js +5 -0
- package/lib/src/brand-page/models/index.d.ts +1 -0
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +62 -2
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +1 -0
- package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +60 -2
- package/lib/src/brand-page-maker/components/preview/Preview.mixin.d.ts +30 -1
- package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +60 -2
- package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +60 -2
- package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +60 -2
- package/lib/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.mixin.d.ts +60 -2
- package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +60 -2
- package/lib/src/brand-page-maker/components/upgrade-to-premium-button/UpgradeToPremiumButton.mixin.d.ts +60 -2
- package/lib/src/brand-page-maker/composables/ai-chat/useAiChat.js +3 -1
- package/lib/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.d.ts +1 -1
- package/lib/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.js +6 -6
- package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.d.ts +2 -0
- package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +258 -0
- package/lib/src/brand-page-maker/constants/sidebar-constant.d.ts +1 -0
- package/lib/src/brand-page-maker/constants/sidebar-constant.js +8 -0
- package/lib/src/brand-page-maker/stores/ai-thread/ai-website-builder-thread-store.d.ts +16 -0
- package/lib/src/brand-page-maker/stores/ai-thread/ai-website-builder-thread-store.js +14 -0
- package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.d.ts +62 -3
- package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +2 -0
- package/lib/src/brand-page-maker/stores/index.d.ts +1 -0
- package/lib/src/brand-page-maker/stores/index.js +1 -0
- package/lib/src/brand-page-maker/stores/snapshot/snapshot-store.d.ts +2 -0
- package/lib/src/brand-page-maker/stores/snapshot/snapshot-store.js +9 -0
- package/lib/src/clients/ai-assistant-client.d.ts +8 -0
- package/lib/src/clients/ai-assistant-client.js +11 -1
- package/lib/src/composables/useSnapshot.js +33 -0
- package/lib/src/css/library.brand-page-brandCrowd.min.css +19 -6
- package/lib/src/css/library.brand-page-brandPage.min.css +19 -6
- package/lib/src/css/library.brand-page-designCom.min.css +19 -6
- package/lib/src/css/library.brand-page-preview.min.css +19 -6
- package/lib/src/index.d.ts +1 -0
- package/lib/src/index.mjs +42 -41
- package/lib/src/{lib-DODSa6QK.js → lib-pOkCQP0J.js} +28820 -26841
- package/lib/src/lib.js +1 -0
- package/lib/src/metadata-builder/ai-metadata-executor.d.ts +1 -1
- package/lib/src/metadata-builder/ai-metadata-executor.js +68 -7
- package/lib/src/metadata-builder/builders/add-page-builder.d.ts +14 -0
- package/lib/src/metadata-builder/builders/add-page-builder.js +66 -0
- package/lib/src/metadata-builder/builders/remove-page-builder.d.ts +13 -0
- package/lib/src/metadata-builder/builders/remove-page-builder.js +50 -0
- package/lib/src/metadata-builder/builders/section-builders/about-section-builder.d.ts +6 -0
- package/lib/src/metadata-builder/builders/section-builders/about-section-builder.js +17 -0
- package/lib/src/metadata-builder/builders/section-builders/banner-section-builder.d.ts +6 -0
- package/lib/src/metadata-builder/builders/section-builders/banner-section-builder.js +25 -0
- package/lib/src/metadata-builder/builders/section-builders/base-section-builder.d.ts +40 -0
- package/lib/src/metadata-builder/builders/section-builders/base-section-builder.js +108 -0
- package/lib/src/metadata-builder/builders/section-builders/button-section-builder.d.ts +6 -0
- package/lib/src/metadata-builder/builders/section-builders/button-section-builder.js +16 -0
- package/lib/src/metadata-builder/builders/section-builders/contact-form-builder.d.ts +6 -0
- package/lib/src/metadata-builder/builders/section-builders/contact-form-builder.js +27 -0
- package/lib/src/metadata-builder/builders/section-builders/delete-section-builder.d.ts +13 -0
- package/lib/src/metadata-builder/builders/section-builders/delete-section-builder.js +37 -0
- package/lib/src/metadata-builder/builders/section-builders/divider-section-builder.d.ts +6 -0
- package/lib/src/metadata-builder/builders/section-builders/divider-section-builder.js +16 -0
- package/lib/src/metadata-builder/builders/section-builders/image-gallery-builder.d.ts +6 -0
- package/lib/src/metadata-builder/builders/section-builders/image-gallery-builder.js +76 -0
- package/lib/src/metadata-builder/builders/section-builders/image-section-builder.d.ts +6 -0
- package/lib/src/metadata-builder/builders/section-builders/image-section-builder.js +16 -0
- package/lib/src/metadata-builder/builders/section-builders/images-section-builder.d.ts +6 -0
- package/lib/src/metadata-builder/builders/section-builders/images-section-builder.js +158 -0
- package/lib/src/metadata-builder/builders/section-builders/index.d.ts +17 -0
- package/lib/src/metadata-builder/builders/section-builders/index.js +17 -0
- package/lib/src/metadata-builder/builders/section-builders/mailing-list-builder.d.ts +6 -0
- package/lib/src/metadata-builder/builders/section-builders/mailing-list-builder.js +17 -0
- package/lib/src/metadata-builder/builders/section-builders/mailing-list-section-builder.d.ts +6 -0
- package/lib/src/metadata-builder/builders/section-builders/mailing-list-section-builder.js +16 -0
- package/lib/src/metadata-builder/builders/section-builders/move-section-builder.d.ts +15 -0
- package/lib/src/metadata-builder/builders/section-builders/move-section-builder.js +62 -0
- package/lib/src/metadata-builder/builders/section-builders/profile-section-builder.d.ts +6 -0
- package/lib/src/metadata-builder/builders/section-builders/profile-section-builder.js +16 -0
- package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.d.ts +6 -0
- package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.js +162 -0
- package/lib/src/metadata-builder/builders/section-builders/social-links-builder.d.ts +6 -0
- package/lib/src/metadata-builder/builders/section-builders/social-links-builder.js +50 -0
- package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.d.ts +6 -0
- package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.js +133 -0
- package/lib/src/metadata-builder/builders/section-builders/text-section-builder.d.ts +6 -0
- package/lib/src/metadata-builder/builders/section-builders/text-section-builder.js +154 -0
- package/lib/src/metadata-builder/builders/section-content-factory.d.ts +3 -0
- package/lib/src/metadata-builder/builders/section-content-factory.js +13 -0
- package/lib/src/metadata-builder/builders/section-field-maps.d.ts +12 -0
- package/lib/src/metadata-builder/builders/section-field-maps.js +180 -0
- package/lib/src/metadata-builder/builders/section-field-utils.d.ts +11 -0
- package/lib/src/metadata-builder/builders/section-field-utils.js +109 -0
- package/lib/src/metadata-builder/helpers/rte.helpers.d.ts +6 -0
- package/lib/src/metadata-builder/helpers/rte.helpers.js +16 -1
- package/lib/src/metadata-builder/metadata-executor.js +71 -1
- package/lib/src/metadata-builder/models.d.ts +54 -0
- package/lib/src/metadata-builder/models.js +58 -0
- package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +51 -3
- package/lib/src/metadata-builder/parsers/ai-toolcall-parser.js +110 -13
- package/lib/src/metadata-builder/parsers/section-tool-arguments.d.ts +285 -0
- package/lib/src/metadata-builder/parsers/section-tool-arguments.js +7 -0
- package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +60 -2
- package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +60 -2
- package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +60 -2
- package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +60 -2
- package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +90 -3
- package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +61 -2
- package/lib/src/shared/side-bar/components/SideBar.mixin.js +6 -0
- package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +60 -2
- package/lib/src/utils/minify-brand-page-metadata.d.ts +22 -0
- package/lib/src/utils/minify-brand-page-metadata.js +344 -0
- package/package.json +1 -1
- package/src/brand-page/models/brand-page-context.model.ts +12 -3
- package/src/brand-page/models/index.ts +1 -0
- package/src/brand-page-maker/components/ai-website-builder/AiWebsiteBuilder.vue +80 -0
- package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +4 -0
- package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.vue +9 -2
- package/src/brand-page-maker/composables/ai-chat/useAiChat.ts +4 -1
- package/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.ts +6 -6
- package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +363 -0
- package/src/brand-page-maker/constants/sidebar-constant.ts +8 -0
- package/src/brand-page-maker/stores/ai-thread/ai-website-builder-thread-store.ts +19 -0
- package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.ts +3 -1
- package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +4 -0
- package/src/brand-page-maker/stores/index.ts +1 -0
- package/src/brand-page-maker/stores/snapshot/snapshot-store.ts +12 -0
- package/src/clients/ai-assistant-client.ts +17 -1
- package/src/composables/useSnapshot.ts +47 -0
- package/src/lib.ts +4 -0
- package/src/metadata-builder/ai-metadata-executor.ts +116 -26
- package/src/metadata-builder/builders/add-page-builder.ts +98 -0
- package/src/metadata-builder/builders/remove-page-builder.ts +83 -0
- package/src/metadata-builder/builders/section-builders/about-section-builder.ts +28 -0
- package/src/metadata-builder/builders/section-builders/banner-section-builder.ts +45 -0
- package/src/metadata-builder/builders/section-builders/base-section-builder.ts +160 -0
- package/src/metadata-builder/builders/section-builders/button-section-builder.ts +24 -0
- package/src/metadata-builder/builders/section-builders/contact-form-builder.ts +43 -0
- package/src/metadata-builder/builders/section-builders/delete-section-builder.ts +63 -0
- package/src/metadata-builder/builders/section-builders/divider-section-builder.ts +27 -0
- package/src/metadata-builder/builders/section-builders/image-gallery-builder.ts +111 -0
- package/src/metadata-builder/builders/section-builders/image-section-builder.ts +24 -0
- package/src/metadata-builder/builders/section-builders/images-section-builder.ts +223 -0
- package/src/metadata-builder/builders/section-builders/index.ts +21 -0
- package/src/metadata-builder/builders/section-builders/mailing-list-builder.ts +29 -0
- package/src/metadata-builder/builders/section-builders/mailing-list-section-builder.ts +27 -0
- package/src/metadata-builder/builders/section-builders/move-section-builder.ts +100 -0
- package/src/metadata-builder/builders/section-builders/profile-section-builder.ts +27 -0
- package/src/metadata-builder/builders/section-builders/shapes-section-builder.ts +231 -0
- package/src/metadata-builder/builders/section-builders/social-links-builder.ts +79 -0
- package/src/metadata-builder/builders/section-builders/testimonial-section-builder.ts +194 -0
- package/src/metadata-builder/builders/section-builders/text-section-builder.ts +234 -0
- package/src/metadata-builder/builders/section-content-factory.ts +20 -0
- package/src/metadata-builder/builders/section-field-maps.ts +235 -0
- package/src/metadata-builder/builders/section-field-utils.ts +157 -0
- package/src/metadata-builder/helpers/rte.helpers.ts +23 -1
- package/src/metadata-builder/metadata-executor.ts +96 -4
- package/src/metadata-builder/models.ts +62 -0
- package/src/metadata-builder/parsers/ai-toolcall-parser.ts +141 -17
- package/src/metadata-builder/parsers/section-tool-arguments.ts +417 -0
- package/src/shared/side-bar/components/SideBar.mixin.ts +10 -0
- package/src/utils/minify-brand-page-metadata.ts +407 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import type { BuilderResult } from '../../models';
|
|
2
|
+
import type {
|
|
3
|
+
TextContent,
|
|
4
|
+
TextItem,
|
|
5
|
+
TextStyleDeclaration,
|
|
6
|
+
BrandPageModel,
|
|
7
|
+
} from '../../../brand-page/models';
|
|
8
|
+
import { updateRTEText } from '../../helpers/rte.helpers';
|
|
9
|
+
import type {
|
|
10
|
+
TextSectionArguments,
|
|
11
|
+
TextSectionItem,
|
|
12
|
+
} from '../../parsers/section-tool-arguments';
|
|
13
|
+
import { applyScalarFields, applyStyleFields } from '../section-field-utils';
|
|
14
|
+
import { BaseSectionBuilder } from './base-section-builder';
|
|
15
|
+
|
|
16
|
+
const createTextItem = (
|
|
17
|
+
item: TextSectionItem,
|
|
18
|
+
baseStyle: TextStyleDeclaration,
|
|
19
|
+
): TextItem => {
|
|
20
|
+
const textStyle = (
|
|
21
|
+
item.text_style ? { ...baseStyle, ...item.text_style } : { ...baseStyle }
|
|
22
|
+
) as TextStyleDeclaration;
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
text: item.text || '',
|
|
26
|
+
textStyle,
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const applyTextItems = (
|
|
31
|
+
content: TextContent,
|
|
32
|
+
items: TextSectionItem[],
|
|
33
|
+
): void => {
|
|
34
|
+
content.textItems = items.map((item) =>
|
|
35
|
+
createTextItem(item, content.textStyle || {}),
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const mergeTextItems = (
|
|
40
|
+
content: TextContent,
|
|
41
|
+
items: TextSectionItem[],
|
|
42
|
+
replaceAll: boolean,
|
|
43
|
+
): void => {
|
|
44
|
+
const hasIndexedItems = items.some((item) => item.item_index !== undefined);
|
|
45
|
+
|
|
46
|
+
if (hasIndexedItems) {
|
|
47
|
+
for (const item of items) {
|
|
48
|
+
const targetIndex = item.item_index;
|
|
49
|
+
|
|
50
|
+
if (
|
|
51
|
+
targetIndex === undefined ||
|
|
52
|
+
targetIndex < 0 ||
|
|
53
|
+
!content.textItems?.[targetIndex]
|
|
54
|
+
)
|
|
55
|
+
continue;
|
|
56
|
+
|
|
57
|
+
const existing = content.textItems[targetIndex];
|
|
58
|
+
|
|
59
|
+
if (item.text !== undefined) existing.text = item.text;
|
|
60
|
+
|
|
61
|
+
if (item.text_style && typeof item.text_style === 'object') {
|
|
62
|
+
const mergedStyle = (
|
|
63
|
+
item.text_style
|
|
64
|
+
? { ...(existing.textStyle || {}), ...item.text_style }
|
|
65
|
+
: existing.textStyle || {}
|
|
66
|
+
) as TextStyleDeclaration;
|
|
67
|
+
|
|
68
|
+
existing.textStyle = mergedStyle;
|
|
69
|
+
existing.text = updateRTEText(existing.text, mergedStyle);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const updatedItems = items.map((item, index) => {
|
|
77
|
+
const existing = content.textItems?.[index];
|
|
78
|
+
const baseStyle = existing?.textStyle || content.textStyle || {};
|
|
79
|
+
|
|
80
|
+
const mergedStyle = (
|
|
81
|
+
item.text_style ? { ...baseStyle, ...item.text_style } : baseStyle
|
|
82
|
+
) as TextStyleDeclaration;
|
|
83
|
+
|
|
84
|
+
const text = item.text ?? existing?.text ?? '';
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
text: item.text_style ? updateRTEText(text, mergedStyle) : text,
|
|
88
|
+
textStyle: mergedStyle,
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
if (
|
|
93
|
+
!replaceAll &&
|
|
94
|
+
content.textItems &&
|
|
95
|
+
content.textItems.length > items.length
|
|
96
|
+
) {
|
|
97
|
+
updatedItems.push(...content.textItems.slice(items.length));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
content.textItems = updatedItems;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Handles the single `text` + `text_style` fields (BrandPage/BrandContact
|
|
105
|
+
* or shorthand for the first item).
|
|
106
|
+
*/
|
|
107
|
+
const applySingleTextField = (
|
|
108
|
+
content: TextContent,
|
|
109
|
+
args: TextSectionArguments,
|
|
110
|
+
): void => {
|
|
111
|
+
if (typeof args.text === 'string') {
|
|
112
|
+
if (Array.isArray(content.textItems) && content.textItems.length > 0) {
|
|
113
|
+
content.textItems[0] = {
|
|
114
|
+
...content.textItems[0],
|
|
115
|
+
text: args.text,
|
|
116
|
+
};
|
|
117
|
+
} else {
|
|
118
|
+
content.textItems = [
|
|
119
|
+
{
|
|
120
|
+
text: args.text,
|
|
121
|
+
textStyle: { ...(content.textStyle || {}) },
|
|
122
|
+
},
|
|
123
|
+
];
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (
|
|
128
|
+
args.text_style &&
|
|
129
|
+
typeof args.text_style === 'object' &&
|
|
130
|
+
Array.isArray(content.textItems) &&
|
|
131
|
+
content.textItems.length > 0
|
|
132
|
+
) {
|
|
133
|
+
const mergedStyle = {
|
|
134
|
+
...(content.textItems[0].textStyle || {}),
|
|
135
|
+
...(content.textStyle || {}),
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
content.textItems[0] = {
|
|
139
|
+
...content.textItems[0],
|
|
140
|
+
textStyle: mergedStyle,
|
|
141
|
+
text: updateRTEText(content.textItems[0].text, mergedStyle),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export class TextSectionBuilder extends BaseSectionBuilder<TextContent> {
|
|
147
|
+
async buildAsync(model: BrandPageModel): Promise<BuilderResult> {
|
|
148
|
+
this.log('Build called');
|
|
149
|
+
|
|
150
|
+
const validation = await this.validateAsync();
|
|
151
|
+
|
|
152
|
+
if (validation.errors.length) {
|
|
153
|
+
return { request: this.request, model, errors: validation.errors };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const resolved = this.resolveContent(model);
|
|
157
|
+
|
|
158
|
+
if ('error' in resolved) return resolved.error;
|
|
159
|
+
|
|
160
|
+
const content = resolved.content;
|
|
161
|
+
|
|
162
|
+
applyScalarFields(content, this.args, this.sectionType);
|
|
163
|
+
applyStyleFields(content, this.args, this.sectionType);
|
|
164
|
+
|
|
165
|
+
const args = this.args as TextSectionArguments;
|
|
166
|
+
|
|
167
|
+
if (args.items && Array.isArray(args.items)) {
|
|
168
|
+
if (this.mode === 'create') {
|
|
169
|
+
applyTextItems(content, args.items);
|
|
170
|
+
} else {
|
|
171
|
+
mergeTextItems(content, args.items, !!args._replace_items);
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
applySingleTextField(content, args);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Phase 2: Item operations (remove, insert, reorder)
|
|
178
|
+
if (args._remove_item_indices?.length && content.textItems) {
|
|
179
|
+
const sorted = [...args._remove_item_indices].sort((a, b) => b - a);
|
|
180
|
+
|
|
181
|
+
for (const idx of sorted) {
|
|
182
|
+
if (idx >= 0 && idx < content.textItems.length) {
|
|
183
|
+
content.textItems.splice(idx, 1);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (args.items && Array.isArray(args.items)) {
|
|
189
|
+
const insertItems = args.items.filter(
|
|
190
|
+
(item) => item.insert_at !== undefined && item.item_index === undefined,
|
|
191
|
+
);
|
|
192
|
+
const sortedInserts = [...insertItems].sort(
|
|
193
|
+
(a, b) => (b.insert_at ?? 0) - (a.insert_at ?? 0),
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
for (const item of sortedInserts) {
|
|
197
|
+
const pos = Math.max(
|
|
198
|
+
0,
|
|
199
|
+
Math.min(item.insert_at ?? 0, content.textItems?.length ?? 0),
|
|
200
|
+
);
|
|
201
|
+
const baseStyle = content.textStyle || {};
|
|
202
|
+
const textStyle = (
|
|
203
|
+
item.text_style
|
|
204
|
+
? { ...baseStyle, ...item.text_style }
|
|
205
|
+
: { ...baseStyle }
|
|
206
|
+
) as TextStyleDeclaration;
|
|
207
|
+
const newItem: TextItem = {
|
|
208
|
+
text: item.text ?? '',
|
|
209
|
+
textStyle,
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
content.textItems = content.textItems ?? [];
|
|
213
|
+
content.textItems.splice(pos, 0, newItem);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (args._reorder_items?.length && content.textItems) {
|
|
218
|
+
const newOrder = args._reorder_items;
|
|
219
|
+
const unique = new Set(newOrder);
|
|
220
|
+
|
|
221
|
+
if (unique.size === newOrder.length) {
|
|
222
|
+
const reordered = newOrder
|
|
223
|
+
.filter((idx) => idx >= 0 && idx < content.textItems!.length)
|
|
224
|
+
.map((idx) => content.textItems![idx]);
|
|
225
|
+
|
|
226
|
+
if (reordered.length === content.textItems.length) {
|
|
227
|
+
content.textItems = reordered;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return { request: this.request, model };
|
|
233
|
+
}
|
|
234
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory that creates default Content objects for each section type.
|
|
3
|
+
* Used by BaseSectionBuilder when adding a new section to a page.
|
|
4
|
+
*/
|
|
5
|
+
import { CONTENT_SETTINGS_CONFIGS } from '../../brand-page-maker/constants/config-settings-constant';
|
|
6
|
+
import type { Content, ContentType } from '../../brand-page/models';
|
|
7
|
+
import type { SectionType } from '../parsers/section-tool-arguments';
|
|
8
|
+
|
|
9
|
+
export const createDefaultSectionContent = (
|
|
10
|
+
sectionType: SectionType,
|
|
11
|
+
): Content | null => {
|
|
12
|
+
const configs = CONTENT_SETTINGS_CONFIGS();
|
|
13
|
+
const config = configs[sectionType as ContentType];
|
|
14
|
+
|
|
15
|
+
if (!config) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return config.createInitialContent() as Content;
|
|
20
|
+
};
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps AI tool call argument names → BrandPageModel content field names
|
|
3
|
+
* per section type.
|
|
4
|
+
*
|
|
5
|
+
* Reference: service.ai-pipelines/src/agents/website/section_schemas.py
|
|
6
|
+
* Reference: library.brand-page/src/brand-page/models/index.ts
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type {
|
|
10
|
+
Content,
|
|
11
|
+
BannerSectionContent,
|
|
12
|
+
AboutSectionContent,
|
|
13
|
+
TestimonialSectionContent,
|
|
14
|
+
ImagesSectionContent,
|
|
15
|
+
ShapesSectionContent,
|
|
16
|
+
TextContent,
|
|
17
|
+
ProfileContent,
|
|
18
|
+
ContactFormContent,
|
|
19
|
+
MailingListContent,
|
|
20
|
+
SocialLinksContent,
|
|
21
|
+
DividerSectionContent,
|
|
22
|
+
ImageContent,
|
|
23
|
+
ButtonContent,
|
|
24
|
+
ImageGalleryContent,
|
|
25
|
+
} from '../../brand-page/models';
|
|
26
|
+
|
|
27
|
+
export type SectionFieldMap = Record<string, string>;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Identity function that validates field map values are actual properties
|
|
31
|
+
* of the given Content subtype at compile time.
|
|
32
|
+
*/
|
|
33
|
+
function defineFieldMap<C extends Content>(
|
|
34
|
+
map: Record<string, keyof C & string>,
|
|
35
|
+
): Record<string, keyof C & string> {
|
|
36
|
+
return map;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const bannerFields = defineFieldMap<BannerSectionContent>({
|
|
40
|
+
title: 'title',
|
|
41
|
+
description: 'description',
|
|
42
|
+
button_text: 'buttonText',
|
|
43
|
+
button_url: 'url',
|
|
44
|
+
background_image_url: 'imageUrl',
|
|
45
|
+
display_style: 'displayStyle',
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const aboutFields = defineFieldMap<AboutSectionContent>({
|
|
49
|
+
title: 'title',
|
|
50
|
+
paragraph: 'paragraph',
|
|
51
|
+
about_image_url: 'imageUrl',
|
|
52
|
+
display_style: 'displayStyle',
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const testimonialFields = defineFieldMap<TestimonialSectionContent>({
|
|
56
|
+
title: 'title',
|
|
57
|
+
display_style: 'displayStyle',
|
|
58
|
+
// items handled separately
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const imagesSectionFields = defineFieldMap<ImagesSectionContent>({
|
|
62
|
+
title: 'title',
|
|
63
|
+
description: 'description',
|
|
64
|
+
display_style: 'displayStyle',
|
|
65
|
+
aspect_ratio: 'aspectRatio',
|
|
66
|
+
are_images_full_width: 'areImagesFullWidth',
|
|
67
|
+
// items handled separately
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const shapesSectionFields = defineFieldMap<ShapesSectionContent>({
|
|
71
|
+
title: 'title',
|
|
72
|
+
description: 'description',
|
|
73
|
+
display_style: 'displayStyle',
|
|
74
|
+
size: 'size',
|
|
75
|
+
// items handled separately
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const textFields = defineFieldMap<TextContent>({
|
|
79
|
+
text: 'text',
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const profileFields = defineFieldMap<ProfileContent>({
|
|
83
|
+
name: 'name',
|
|
84
|
+
title: 'title',
|
|
85
|
+
description: 'description',
|
|
86
|
+
avatar_image_url: 'avatarImageUrl',
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const contactFormFields = defineFieldMap<ContactFormContent>({
|
|
90
|
+
title: 'title',
|
|
91
|
+
description: 'description',
|
|
92
|
+
button_text: 'buttonText',
|
|
93
|
+
success_message: 'successMessage',
|
|
94
|
+
response_email: 'responseEmail',
|
|
95
|
+
header_image_url: 'imageUrl',
|
|
96
|
+
display_style: 'displayStyle',
|
|
97
|
+
layout_style: 'layoutStyle',
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const mailingListFields = defineFieldMap<MailingListContent>({
|
|
101
|
+
title: 'title',
|
|
102
|
+
button_text: 'buttonText',
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const socialLinksFields = defineFieldMap<SocialLinksContent>({
|
|
106
|
+
title: 'title',
|
|
107
|
+
icon_style: 'iconDisplayStyle',
|
|
108
|
+
// links handled separately
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const dividerFields = defineFieldMap<DividerSectionContent>({
|
|
112
|
+
divider_style: 'dividerStyle',
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const imageFields = defineFieldMap<ImageContent>({
|
|
116
|
+
image_url: 'imageUrl',
|
|
117
|
+
image_title: 'imageTitle',
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const imageGalleryFields = defineFieldMap<ImageGalleryContent>({
|
|
121
|
+
// images handled separately
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const buttonWithIconFields = defineFieldMap<ButtonContent>({
|
|
125
|
+
title: 'title',
|
|
126
|
+
url: 'url',
|
|
127
|
+
icon_image_url: 'iconUrl',
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const emailButtonFields = defineFieldMap<ButtonContent>({
|
|
131
|
+
title: 'title',
|
|
132
|
+
email: 'url',
|
|
133
|
+
icon_image_url: 'iconUrl',
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const phoneButtonFields = defineFieldMap<ButtonContent>({
|
|
137
|
+
title: 'title',
|
|
138
|
+
phone_number: 'url',
|
|
139
|
+
icon_image_url: 'iconUrl',
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const socialButtonFields = defineFieldMap<ButtonContent>({
|
|
143
|
+
title: 'title',
|
|
144
|
+
url: 'url',
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
export const SECTION_FIELD_MAPS: Record<string, SectionFieldMap> = {
|
|
148
|
+
'banner-section': bannerFields,
|
|
149
|
+
'about-section': aboutFields,
|
|
150
|
+
'testimonial-section': testimonialFields,
|
|
151
|
+
'images-section': imagesSectionFields,
|
|
152
|
+
'shapes-section': shapesSectionFields,
|
|
153
|
+
text: textFields,
|
|
154
|
+
profile: profileFields,
|
|
155
|
+
'contact-form': contactFormFields,
|
|
156
|
+
'mailing-list': mailingListFields,
|
|
157
|
+
'social-links': socialLinksFields,
|
|
158
|
+
'divider-section': dividerFields,
|
|
159
|
+
image: imageFields,
|
|
160
|
+
'image-gallery': imageGalleryFields,
|
|
161
|
+
'general-link': buttonWithIconFields,
|
|
162
|
+
website: buttonWithIconFields,
|
|
163
|
+
email: emailButtonFields,
|
|
164
|
+
phone: phoneButtonFields,
|
|
165
|
+
facebook: socialButtonFields,
|
|
166
|
+
x: socialButtonFields,
|
|
167
|
+
instagram: socialButtonFields,
|
|
168
|
+
youtube: socialButtonFields,
|
|
169
|
+
linkedin: socialButtonFields,
|
|
170
|
+
pinterest: socialButtonFields,
|
|
171
|
+
twitch: socialButtonFields,
|
|
172
|
+
tiktok: socialButtonFields,
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
export const getSectionFieldMap = (
|
|
176
|
+
sectionType: string,
|
|
177
|
+
): SectionFieldMap | undefined => {
|
|
178
|
+
return SECTION_FIELD_MAPS[sectionType];
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const bannerStyleFields = defineFieldMap<BannerSectionContent>({
|
|
182
|
+
title_style: 'titleStyle',
|
|
183
|
+
description_style: 'descriptionStyle',
|
|
184
|
+
button_text_style: 'buttonTextStyle',
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const aboutStyleFields = defineFieldMap<AboutSectionContent>({
|
|
188
|
+
title_style: 'titleStyle',
|
|
189
|
+
paragraph_style: 'paragraphStyle',
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
const textStyleFields = defineFieldMap<TextContent>({
|
|
193
|
+
text_style: 'textStyle',
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
const testimonialStyleFields = defineFieldMap<TestimonialSectionContent>({
|
|
197
|
+
title_style: 'titleStyle',
|
|
198
|
+
testimonial_style: 'testimonialStyle',
|
|
199
|
+
name_style: 'nameStyle',
|
|
200
|
+
position_style: 'positionStyle',
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
const contactFormStyleFields = defineFieldMap<ContactFormContent>({
|
|
204
|
+
title_style: 'titleStyle',
|
|
205
|
+
description_style: 'descriptionStyle',
|
|
206
|
+
button_text_style: 'buttonTextStyle',
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const imagesSectionStyleFields = defineFieldMap<ImagesSectionContent>({
|
|
210
|
+
title_style: 'titleStyle',
|
|
211
|
+
description_style: 'descriptionStyle',
|
|
212
|
+
heading_style: 'headingStyle',
|
|
213
|
+
paragraph_style: 'paragraphStyle',
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
const shapesSectionStyleFields = defineFieldMap<ShapesSectionContent>({
|
|
217
|
+
title_style: 'titleStyle',
|
|
218
|
+
description_style: 'descriptionStyle',
|
|
219
|
+
heading_style: 'headingStyle',
|
|
220
|
+
paragraph_style: 'paragraphStyle',
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
export const STYLE_FIELD_MAPS: Record<string, SectionFieldMap> = {
|
|
224
|
+
'banner-section': bannerStyleFields,
|
|
225
|
+
'about-section': aboutStyleFields,
|
|
226
|
+
text: textStyleFields,
|
|
227
|
+
'testimonial-section': testimonialStyleFields,
|
|
228
|
+
'contact-form': contactFormStyleFields,
|
|
229
|
+
'images-section': imagesSectionStyleFields,
|
|
230
|
+
'shapes-section': shapesSectionStyleFields,
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
export const getStyleFieldMap = (
|
|
234
|
+
sectionType: string,
|
|
235
|
+
): SectionFieldMap | undefined => STYLE_FIELD_MAPS[sectionType];
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import type { Content, TextStyleDeclaration } from '../../brand-page/models';
|
|
2
|
+
import { RTE_ALLOWED_SECTION_TYPES } from '../../brand-page-maker/utils';
|
|
3
|
+
import { updateRTEText } from '../helpers/rte.helpers';
|
|
4
|
+
import type { SectionToolArguments } from '../parsers/section-tool-arguments';
|
|
5
|
+
import { getSectionFieldMap, getStyleFieldMap } from './section-field-maps';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Content subtypes (BannerSectionContent, TextContent, etc.) extend the base
|
|
9
|
+
* Content interface with additional properties. These utility functions apply
|
|
10
|
+
* fields dynamically via field maps resolved at runtime, so static typing
|
|
11
|
+
* can't know the concrete subtype.
|
|
12
|
+
*
|
|
13
|
+
* IndexableContent captures this: it's Content that can be indexed by string
|
|
14
|
+
* keys — a valid downcast because every Content instance at runtime is a
|
|
15
|
+
* subtype with extra properties beyond the base interface.
|
|
16
|
+
*/
|
|
17
|
+
type IndexableContent = Content & Record<string, unknown>;
|
|
18
|
+
|
|
19
|
+
const isUrlField = (aiKey: string): boolean => aiKey.endsWith('_url');
|
|
20
|
+
|
|
21
|
+
const isValidUrl = (value: unknown): boolean => {
|
|
22
|
+
if (typeof value !== 'string' || !value) return false;
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
new URL(value);
|
|
26
|
+
|
|
27
|
+
return true;
|
|
28
|
+
} catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const applyScalarFields = (
|
|
34
|
+
content: Content,
|
|
35
|
+
args: SectionToolArguments,
|
|
36
|
+
sectionType: string,
|
|
37
|
+
): void => {
|
|
38
|
+
const fieldMap = getSectionFieldMap(sectionType);
|
|
39
|
+
|
|
40
|
+
if (!fieldMap) return;
|
|
41
|
+
|
|
42
|
+
const record = content as IndexableContent;
|
|
43
|
+
|
|
44
|
+
for (const [aiKey, modelKey] of Object.entries(fieldMap)) {
|
|
45
|
+
if (aiKey in args) {
|
|
46
|
+
// Skip invalid URLs — don't overwrite model with malformed values
|
|
47
|
+
if (isUrlField(aiKey) && !isValidUrl(args[aiKey])) continue;
|
|
48
|
+
|
|
49
|
+
record[modelKey] = args[aiKey];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Convert AI-sent style value to the format expected by the model.
|
|
56
|
+
* - letterSpacing: unitless 0-100 → em string (e.g., 50 → '0.5em')
|
|
57
|
+
* - null → '' (explicitly clear/reset the property)
|
|
58
|
+
* - everything else passes through as-is
|
|
59
|
+
*/
|
|
60
|
+
const normalizeStyleValue = (key: string, value: unknown): unknown => {
|
|
61
|
+
if (value === null) return '';
|
|
62
|
+
|
|
63
|
+
if (value === undefined) return undefined;
|
|
64
|
+
|
|
65
|
+
if (key === 'letterSpacing' && typeof value === 'number') {
|
|
66
|
+
return `${value / 100}em`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (key === 'lineHeight' && typeof value === 'number') {
|
|
70
|
+
return String(value);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return value;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const applyStyleFields = (
|
|
77
|
+
content: Content,
|
|
78
|
+
args: SectionToolArguments,
|
|
79
|
+
sectionType: string,
|
|
80
|
+
): void => {
|
|
81
|
+
const styleMap = getStyleFieldMap(sectionType);
|
|
82
|
+
|
|
83
|
+
if (!styleMap) return;
|
|
84
|
+
|
|
85
|
+
const record = content as IndexableContent;
|
|
86
|
+
|
|
87
|
+
for (const [aiKey, modelKey] of Object.entries(styleMap)) {
|
|
88
|
+
if (aiKey in args && args[aiKey] && typeof args[aiKey] === 'object') {
|
|
89
|
+
const existing = (content[modelKey] as Record<string, unknown>) || {};
|
|
90
|
+
const aiStyle = args[aiKey] as Record<string, unknown>;
|
|
91
|
+
|
|
92
|
+
const filtered: Record<string, unknown> = {};
|
|
93
|
+
|
|
94
|
+
for (const [k, v] of Object.entries(aiStyle)) {
|
|
95
|
+
const normalized = normalizeStyleValue(k, v);
|
|
96
|
+
|
|
97
|
+
if (normalized !== undefined) filtered[k] = normalized;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
record[modelKey] = {
|
|
101
|
+
...existing,
|
|
102
|
+
...filtered,
|
|
103
|
+
textStyleType: undefined,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* RTE field → style field pairs for fields that support rich text editing.
|
|
111
|
+
* Matches the RTE_ALLOWED_FIELDS constant from rich-text-editor.util.ts:
|
|
112
|
+
* ['title', 'description', 'text', 'textItems']
|
|
113
|
+
*
|
|
114
|
+
* textItems is excluded here because it requires per-item handling
|
|
115
|
+
* (each TextItem has its own textStyle) — handled by TextSectionBuilder.
|
|
116
|
+
*/
|
|
117
|
+
const RTE_FIELD_STYLE_PAIRS: {
|
|
118
|
+
textField: string;
|
|
119
|
+
styleField: string;
|
|
120
|
+
argKey: string;
|
|
121
|
+
}[] = [
|
|
122
|
+
{ textField: 'title', styleField: 'titleStyle', argKey: 'title_style' },
|
|
123
|
+
{
|
|
124
|
+
textField: 'description',
|
|
125
|
+
styleField: 'descriptionStyle',
|
|
126
|
+
argKey: 'description_style',
|
|
127
|
+
},
|
|
128
|
+
{ textField: 'text', styleField: 'textStyle', argKey: 'text_style' },
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Re-applies merged styles to RTE content fields after applyStyleFields has
|
|
133
|
+
* updated the style objects. Only runs for section types that support RTE
|
|
134
|
+
* (defined by RTE_ALLOWED_SECTION_TYPES) and only touches fields in the
|
|
135
|
+
* RTE_ALLOWED_FIELDS list.
|
|
136
|
+
*/
|
|
137
|
+
export const applyRTEStyles = (
|
|
138
|
+
content: Content,
|
|
139
|
+
args: SectionToolArguments,
|
|
140
|
+
sectionType: string,
|
|
141
|
+
): void => {
|
|
142
|
+
if (!RTE_ALLOWED_SECTION_TYPES.includes(sectionType)) return;
|
|
143
|
+
|
|
144
|
+
const record = content as IndexableContent;
|
|
145
|
+
const argsRecord = args as Record<string, unknown>;
|
|
146
|
+
|
|
147
|
+
for (const { textField, styleField, argKey } of RTE_FIELD_STYLE_PAIRS) {
|
|
148
|
+
if (!argsRecord[argKey]) continue;
|
|
149
|
+
|
|
150
|
+
const text = record[textField];
|
|
151
|
+
const style = record[styleField];
|
|
152
|
+
|
|
153
|
+
if (typeof text === 'string' && style) {
|
|
154
|
+
record[textField] = updateRTEText(text, style as TextStyleDeclaration);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { TextStyleDeclaration } from '../../brand-page';
|
|
2
|
-
import { getRTEColor } from '../../brand-page-maker/utils';
|
|
2
|
+
import { getRTEColor, hasRTEContent } from '../../brand-page-maker/utils';
|
|
3
|
+
import { useExternalRichTextEditor } from '../../brand-page-maker/composables/rich-text-editor/useRichTextEditor';
|
|
3
4
|
import { getRenderText } from '../../brand-page/utils';
|
|
4
5
|
import { ESCAPED_NEWLINE_CHARACTER } from '../../constants/ui';
|
|
5
6
|
import type { Editor } from '@tiptap/vue-3';
|
|
@@ -72,3 +73,24 @@ export const applyStyleToRTEText = (
|
|
|
72
73
|
|
|
73
74
|
return html;
|
|
74
75
|
};
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* If `text` contains RTE markup, re-applies `style` to the RTE content
|
|
79
|
+
* so inline formatting matches the updated TextStyleDeclaration.
|
|
80
|
+
* Returns the original text unchanged when it has no RTE content.
|
|
81
|
+
*/
|
|
82
|
+
export const updateRTEText = (
|
|
83
|
+
text: string,
|
|
84
|
+
style: TextStyleDeclaration,
|
|
85
|
+
): string => {
|
|
86
|
+
if (!text || typeof text !== 'string' || !hasRTEContent(text)) {
|
|
87
|
+
return text;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const { externalEditor } = useExternalRichTextEditor();
|
|
91
|
+
const updatedText = applyStyleToRTEText(externalEditor, text, style);
|
|
92
|
+
|
|
93
|
+
externalEditor.destroy();
|
|
94
|
+
|
|
95
|
+
return updatedText;
|
|
96
|
+
};
|