@designcrowd/library.brand-page 5.17.28 → 5.18.0
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-CJZpKPNH.js → CreatedOnBrandCrowd-de-de-xmkupPus.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-DkIa7iEb.js → CreatedOnBrandCrowd-en-us-Ck7EdTtb.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-CE2p6XHz.js → CreatedOnBrandCrowd-es-es-BC8sJuDH.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-BBjOZS3M.js → CreatedOnBrandCrowd-fr-ca-CN-UBe1q.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-BBjOZS3M.js → CreatedOnBrandCrowd-fr-fr-CN-UBe1q.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-Dayzl4BZ.js → CreatedOnBrandCrowd-pt-br-CajQyNkx.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-Dayzl4BZ.js → CreatedOnBrandCrowd-pt-pt-CajQyNkx.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-CFzDqfCb.js → CreatedOnDcom-de-de-BRCNMmDq.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-C2jIPBDY.js → CreatedOnDcom-en-us-BzQDtZhc.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-qejpzqho.js → CreatedOnDcom-es-es-D-qAM4Cd.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-DMO9Ld7K.js → CreatedOnDcom-fr-ca-CZ1irFOc.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-BFWN9qTP.js → CreatedOnDcom-fr-fr-Gb5BCF0N.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-CneD3ghF.js → CreatedOnDcom-pt-br-CAQV0q6o.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-Cg1B7s0o.js → CreatedOnDcom-pt-pt-D6tQdQFh.js} +1 -1
- package/lib/src/brand-page/components/image-gallery/ImageGalleryModal.mixin.js +2 -2
- package/lib/src/brand-page/models/brand-page-context.model.d.ts +0 -2
- package/lib/src/brand-page/models/brand-page-context.model.js +1 -11
- package/lib/src/brand-page/models/index.d.ts +1 -0
- package/lib/src/brand-page/models/index.js +1 -0
- package/lib/src/brand-page/utils/color.util.js +23 -3
- package/lib/src/brand-page/utils/raygun.util.d.ts +5 -1
- package/lib/src/brand-page/utils/raygun.util.js +7 -2
- package/lib/src/brand-page/utils/svg-color.util.js +1 -2
- package/lib/src/brand-page/utils/view-model.util.js +1 -1
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +1 -31
- package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.js +0 -2
- package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +2 -31
- package/lib/src/brand-page-maker/components/preview/Preview.mixin.d.ts +0 -14
- package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +0 -28
- package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +0 -28
- package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +0 -28
- package/lib/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.mixin.d.ts +0 -28
- package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +0 -28
- package/lib/src/brand-page-maker/components/upgrade-to-premium-button/UpgradeToPremiumButton.mixin.d.ts +0 -28
- package/lib/src/brand-page-maker/composables/ai-chat/aiErrorCopy.d.ts +35 -0
- package/lib/src/brand-page-maker/composables/ai-chat/aiErrorCopy.js +108 -0
- package/lib/src/brand-page-maker/composables/ai-chat/{useAiChat.d.ts → types.d.ts} +5 -13
- package/lib/src/brand-page-maker/composables/ai-chat/types.js +1 -0
- package/lib/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.d.ts +19 -0
- package/lib/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.js +1 -0
- package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.d.ts +1 -1
- package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +488 -82
- package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +5 -5
- package/lib/src/brand-page-maker/composables/useEventTracker.d.ts +6 -16
- package/lib/src/brand-page-maker/composables/useEventTracker.js +19 -21
- package/lib/src/brand-page-maker/constants/sidebar-constant.d.ts +0 -1
- package/lib/src/brand-page-maker/constants/sidebar-constant.js +7 -15
- package/lib/src/brand-page-maker/convertors/image-aspect-ratio.convertor.js +2 -2
- package/lib/src/brand-page-maker/convertors/text-size-value.convertor.js +3 -1
- package/lib/src/brand-page-maker/stores/ai-checkpoint/ai-checkpoint-store.d.ts +30660 -0
- package/lib/src/brand-page-maker/stores/ai-checkpoint/ai-checkpoint-store.js +34 -0
- package/lib/src/brand-page-maker/stores/ai-thread/ai-website-builder-thread-store.d.ts +1 -1
- package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.d.ts +0 -28
- package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +42 -2
- package/lib/src/brand-page-maker/stores/index.d.ts +1 -1
- package/lib/src/brand-page-maker/stores/index.js +1 -1
- package/lib/src/brand-page-maker/stores/user/user-store.js +0 -1
- package/lib/src/bundled-translations-CnareLWC.js +175 -0
- package/lib/src/bundled-translations.de-DE-2Ys7epLO.js +175 -0
- package/lib/src/bundled-translations.es-ES-Cjp-G8rT.js +175 -0
- package/lib/src/bundled-translations.fr-CA-CsaW4Oae.js +175 -0
- package/lib/src/bundled-translations.fr-FR-DIT2dd8J.js +175 -0
- package/lib/src/bundled-translations.pt-BR-BamoBpDW.js +175 -0
- package/lib/src/bundled-translations.pt-PT-C9A4hY_e.js +175 -0
- package/lib/src/bundles/bundled-translations.de-DE.json +1 -20
- package/lib/src/bundles/bundled-translations.es-ES.json +1 -20
- package/lib/src/bundles/bundled-translations.fr-CA.json +1 -20
- package/lib/src/bundles/bundled-translations.fr-FR.json +1 -20
- package/lib/src/bundles/bundled-translations.json +1 -20
- package/lib/src/bundles/bundled-translations.pt-BR.json +1 -20
- package/lib/src/bundles/bundled-translations.pt-PT.json +1 -20
- package/lib/src/clients/ai-assistant-client.d.ts +30 -29
- package/lib/src/clients/ai-assistant-client.js +16 -16
- package/lib/src/clients/design-template-client.d.ts +0 -2
- package/lib/src/clients/design-template-client.js +0 -38
- package/lib/src/clients/websocket-gateway-client.d.ts +9 -1
- package/lib/src/composables/useTranslate.d.ts +2 -1
- package/lib/src/composables/useTranslate.js +2 -1
- package/lib/src/constants/ui.d.ts +0 -1
- package/lib/src/css/library.brand-page-brandCrowd.min.css +225 -134
- package/lib/src/css/library.brand-page-brandPage.min.css +227 -121
- package/lib/src/css/library.brand-page-designCom.min.css +225 -134
- package/lib/src/css/library.brand-page-preview.min.css +225 -118
- package/lib/src/index.d.ts +1 -1
- package/lib/src/index.mjs +1 -1
- package/lib/src/{lib-33w_DBny.js → lib-CSRUPpSo.js} +30887 -29395
- package/lib/src/metadata-builder/ai-metadata-executor.d.ts +21 -0
- package/lib/src/metadata-builder/ai-metadata-executor.js +56 -3
- package/lib/src/metadata-builder/builders/add-page-builder.d.ts +2 -4
- package/lib/src/metadata-builder/builders/add-page-builder.js +5 -8
- package/lib/src/metadata-builder/builders/footer-builder.d.ts +11 -0
- package/lib/src/metadata-builder/builders/footer-builder.js +151 -0
- package/lib/src/metadata-builder/builders/global-styles-builder.d.ts +15 -0
- package/lib/src/metadata-builder/builders/global-styles-builder.js +129 -0
- package/lib/src/metadata-builder/builders/header-builder.d.ts +11 -0
- package/lib/src/metadata-builder/builders/header-builder.js +167 -0
- package/lib/src/metadata-builder/builders/rename-page-builder.d.ts +12 -0
- package/lib/src/metadata-builder/builders/rename-page-builder.js +49 -0
- package/lib/src/metadata-builder/builders/section-builders/about-section-builder.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-builders/about-section-builder.js +44 -4
- package/lib/src/metadata-builder/builders/section-builders/banner-section-builder.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-builders/banner-section-builder.js +70 -6
- package/lib/src/metadata-builder/builders/section-builders/base-section-builder.d.ts +36 -4
- package/lib/src/metadata-builder/builders/section-builders/base-section-builder.js +102 -12
- package/lib/src/metadata-builder/builders/section-builders/booking-section-builder.d.ts +8 -0
- package/lib/src/metadata-builder/builders/section-builders/booking-section-builder.js +50 -0
- package/lib/src/metadata-builder/builders/section-builders/button-section-builder.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-builders/button-section-builder.js +5 -1
- package/lib/src/metadata-builder/builders/section-builders/contact-form-builder.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-builders/contact-form-builder.js +47 -3
- package/lib/src/metadata-builder/builders/section-builders/delete-section-builder.d.ts +2 -1
- package/lib/src/metadata-builder/builders/section-builders/delete-section-builder.js +5 -2
- package/lib/src/metadata-builder/builders/section-builders/divider-section-builder.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-builders/divider-section-builder.js +11 -1
- package/lib/src/metadata-builder/builders/section-builders/image-gallery-builder.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-builders/image-gallery-builder.js +52 -13
- package/lib/src/metadata-builder/builders/section-builders/images-section-builder.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-builders/images-section-builder.js +47 -17
- package/lib/src/metadata-builder/builders/section-builders/index.d.ts +1 -0
- package/lib/src/metadata-builder/builders/section-builders/index.js +1 -0
- package/lib/src/metadata-builder/builders/section-builders/mailing-list-builder.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-builders/mailing-list-builder.js +20 -2
- package/lib/src/metadata-builder/builders/section-builders/mailing-list-section-builder.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-builders/mailing-list-section-builder.js +20 -2
- package/lib/src/metadata-builder/builders/section-builders/profile-section-builder.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-builders/profile-section-builder.js +36 -2
- package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.js +70 -27
- package/lib/src/metadata-builder/builders/section-builders/social-links-builder.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-builders/social-links-builder.js +7 -2
- package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.js +91 -26
- package/lib/src/metadata-builder/builders/section-builders/text-section-builder.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-builders/text-section-builder.js +69 -31
- package/lib/src/metadata-builder/builders/section-content-factory.d.ts +2 -2
- package/lib/src/metadata-builder/builders/section-content-factory.js +8 -2
- package/lib/src/metadata-builder/builders/section-field-maps.js +30 -2
- package/lib/src/metadata-builder/builders/section-field-utils.d.ts +46 -7
- package/lib/src/metadata-builder/builders/section-field-utils.js +86 -62
- package/lib/src/metadata-builder/builders/section-rules/about-section.rules.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-rules/about-section.rules.js +20 -0
- package/lib/src/metadata-builder/builders/section-rules/add-page.rules.d.ts +7 -0
- package/lib/src/metadata-builder/builders/section-rules/add-page.rules.js +8 -0
- package/lib/src/metadata-builder/builders/section-rules/banner-section.rules.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-rules/banner-section.rules.js +27 -0
- package/lib/src/metadata-builder/builders/section-rules/booking-section.rules.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-rules/booking-section.rules.js +16 -0
- package/lib/src/metadata-builder/builders/section-rules/button-section.rules.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-rules/button-section.rules.js +13 -0
- package/lib/src/metadata-builder/builders/section-rules/contact-form.rules.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-rules/contact-form.rules.js +16 -0
- package/lib/src/metadata-builder/builders/section-rules/divider-section.rules.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-rules/divider-section.rules.js +7 -0
- package/lib/src/metadata-builder/builders/section-rules/footer.rules.d.ts +4 -0
- package/lib/src/metadata-builder/builders/section-rules/footer.rules.js +5 -0
- package/lib/src/metadata-builder/builders/section-rules/global-styles.rules.d.ts +6 -0
- package/lib/src/metadata-builder/builders/section-rules/global-styles.rules.js +26 -0
- package/lib/src/metadata-builder/builders/section-rules/header.rules.d.ts +4 -0
- package/lib/src/metadata-builder/builders/section-rules/header.rules.js +41 -0
- package/lib/src/metadata-builder/builders/section-rules/image-gallery.rules.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-rules/image-gallery.rules.js +10 -0
- package/lib/src/metadata-builder/builders/section-rules/images-section.rules.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-rules/images-section.rules.js +31 -0
- package/lib/src/metadata-builder/builders/section-rules/mailing-list.rules.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-rules/mailing-list.rules.js +11 -0
- package/lib/src/metadata-builder/builders/section-rules/profile.rules.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-rules/profile.rules.js +14 -0
- package/lib/src/metadata-builder/builders/section-rules/rename-page.rules.d.ts +7 -0
- package/lib/src/metadata-builder/builders/section-rules/rename-page.rules.js +8 -0
- package/lib/src/metadata-builder/builders/section-rules/shapes-section.rules.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-rules/shapes-section.rules.js +27 -0
- package/lib/src/metadata-builder/builders/section-rules/social-links.rules.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-rules/social-links.rules.js +9 -0
- package/lib/src/metadata-builder/builders/section-rules/testimonial-section.rules.d.ts +7 -0
- package/lib/src/metadata-builder/builders/section-rules/testimonial-section.rules.js +26 -0
- package/lib/src/metadata-builder/builders/section-rules/text-section.rules.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-rules/text-section.rules.js +14 -0
- package/lib/src/metadata-builder/builders/shape-color-utils.d.ts +26 -0
- package/lib/src/metadata-builder/builders/shape-color-utils.js +52 -0
- package/lib/src/metadata-builder/builders/undo-builder.d.ts +48 -0
- package/lib/src/metadata-builder/builders/undo-builder.js +58 -0
- package/lib/src/metadata-builder/builders/update-content-text-style-builder.js +5 -1
- package/lib/src/metadata-builder/helpers/rte.helpers.d.ts +15 -4
- package/lib/src/metadata-builder/helpers/rte.helpers.js +24 -10
- package/lib/src/metadata-builder/metadata-executor.d.ts +2 -1
- package/lib/src/metadata-builder/metadata-executor.js +32 -5
- package/lib/src/metadata-builder/models.d.ts +26 -1
- package/lib/src/metadata-builder/models.js +14 -1
- package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +144 -0
- package/lib/src/metadata-builder/parsers/ai-toolcall-parser.js +17 -0
- package/lib/src/metadata-builder/parsers/section-tool-arguments.d.ts +113 -24
- package/lib/src/metadata-builder/parsers/section-tool-arguments.js +5 -1
- package/lib/src/metadata-builder/sanitizers/rte-schema-check.d.ts +22 -0
- package/lib/src/metadata-builder/sanitizers/rte-schema-check.js +84 -0
- package/lib/src/metadata-builder/sanitizers/sanitizer-rules.d.ts +47 -0
- package/lib/src/metadata-builder/sanitizers/sanitizer-rules.js +60 -0
- package/lib/src/metadata-builder/sanitizers/section-args-validator.d.ts +41 -0
- package/lib/src/metadata-builder/sanitizers/section-args-validator.js +274 -0
- package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +2 -1
- package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.js +2 -16
- package/lib/src/shared/content-settings/components/content-settings/ContentSettings.stories.js +0 -1
- package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +2 -1
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +2 -3
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +0 -4
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.js +6 -8
- package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +0 -28
- package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +2 -1
- package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +0 -28
- package/lib/src/shared/navigation-style-settings/store/index.js +1 -0
- package/lib/src/shared/page-navigation/store/page-navigation-store.js +1 -20
- package/lib/src/shared/page-navigation/utils/nav-order-utils.d.ts +3 -0
- package/lib/src/shared/page-navigation/utils/nav-order-utils.js +20 -0
- package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +2 -30
- package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +0 -28
- package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +2 -43
- package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +0 -30
- package/lib/src/shared/side-bar/components/SideBarTabButton.mixin.d.ts +2 -3
- package/lib/src/shared/side-bar/store/side-bar-store.d.ts +0 -12
- package/lib/src/shared/side-bar/store/side-bar-store.js +0 -7
- package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +2 -29
- package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.d.ts +2 -1
- package/lib/src/utils/build-asset-manifest.d.ts +26 -0
- package/lib/src/utils/build-asset-manifest.js +114 -0
- package/lib/src/utils/minify-brand-page-metadata.d.ts +49 -1
- package/lib/src/utils/minify-brand-page-metadata.js +216 -129
- package/package.json +1 -1
- package/src/brand-page/components/banner-section/BannerSection.vue +1 -1
- package/src/brand-page/components/contact-form/ContactForm.vue +29 -26
- package/src/brand-page/components/image-gallery/ImageGalleryModal.mixin.ts +6 -2
- package/src/brand-page/components/text-media-section/TextMediaSection.vue +1 -5
- package/src/brand-page/models/brand-page-context.model.ts +1 -25
- package/src/brand-page/models/index.ts +1 -0
- package/src/brand-page/utils/color.util.test.ts +48 -0
- package/src/brand-page/utils/color.util.ts +29 -4
- package/src/brand-page/utils/raygun.util.ts +11 -2
- package/src/brand-page/utils/svg-color.util.ts +1 -3
- package/src/brand-page/utils/view-model.util.ts +1 -4
- package/src/brand-page-maker/components/ai-text-edit/AiChatbox.vue +2 -2
- package/src/brand-page-maker/components/ai-text-edit/AiProgressFeed.vue +162 -0
- package/src/brand-page-maker/components/ai-text-edit/TextBubble.vue +57 -5
- package/src/brand-page-maker/components/ai-text-edit/i18n/generate-ai.de-DE.json +0 -20
- package/src/brand-page-maker/components/ai-text-edit/i18n/generate-ai.es-ES.json +0 -20
- package/src/brand-page-maker/components/ai-text-edit/i18n/generate-ai.fr-CA.json +0 -20
- package/src/brand-page-maker/components/ai-text-edit/i18n/generate-ai.fr-FR.json +0 -20
- package/src/brand-page-maker/components/ai-text-edit/i18n/generate-ai.json +0 -20
- package/src/brand-page-maker/components/ai-text-edit/i18n/generate-ai.pt-BR.json +0 -20
- package/src/brand-page-maker/components/ai-text-edit/i18n/generate-ai.pt-PT.json +0 -20
- package/src/brand-page-maker/components/ai-website-builder/AiWebsiteBuilder.vue +1 -2
- package/src/brand-page-maker/components/ai-website-builder/i18n/ai-website-builder.de-DE.json +3 -0
- package/src/brand-page-maker/components/ai-website-builder/i18n/ai-website-builder.es-ES.json +3 -0
- package/src/brand-page-maker/components/ai-website-builder/i18n/ai-website-builder.fr-CA.json +3 -0
- package/src/brand-page-maker/components/ai-website-builder/i18n/ai-website-builder.fr-FR.json +3 -0
- package/src/brand-page-maker/components/ai-website-builder/i18n/ai-website-builder.json +3 -0
- package/src/brand-page-maker/components/ai-website-builder/i18n/ai-website-builder.pt-BR.json +3 -0
- package/src/brand-page-maker/components/ai-website-builder/i18n/ai-website-builder.pt-PT.json +3 -0
- package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.vue +3 -28
- package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.ts +0 -2
- package/src/brand-page-maker/composables/ai-chat/aiErrorCopy.test.ts +229 -0
- package/src/brand-page-maker/composables/ai-chat/aiErrorCopy.ts +164 -0
- package/src/brand-page-maker/composables/ai-chat/types.ts +49 -0
- package/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.ts +20 -0
- package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +651 -94
- package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +9 -9
- package/src/brand-page-maker/composables/useEventTracker.ts +31 -25
- package/src/brand-page-maker/constants/sidebar-constant.ts +7 -15
- package/src/brand-page-maker/convertors/image-aspect-ratio.convertor.ts +2 -2
- package/src/brand-page-maker/convertors/text-size-value.convertor.ts +3 -3
- package/src/brand-page-maker/stores/ai-checkpoint/ai-checkpoint-store.ts +54 -0
- package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +76 -0
- package/src/brand-page-maker/stores/index.ts +1 -1
- package/src/brand-page-maker/stores/user/user-store.ts +0 -1
- package/src/bundles/bundled-translations.de-DE.json +1 -20
- package/src/bundles/bundled-translations.es-ES.json +1 -20
- package/src/bundles/bundled-translations.fr-CA.json +1 -20
- package/src/bundles/bundled-translations.fr-FR.json +1 -20
- package/src/bundles/bundled-translations.json +1 -20
- package/src/bundles/bundled-translations.pt-BR.json +1 -20
- package/src/bundles/bundled-translations.pt-PT.json +1 -20
- package/src/clients/ai-assistant-client.ts +59 -46
- package/src/clients/design-template-client.ts +0 -66
- package/src/clients/websocket-gateway-client.ts +17 -1
- package/src/composables/useTranslate.ts +3 -0
- package/src/constants/ui.ts +0 -1
- package/src/lib.ts +1 -0
- package/src/metadata-builder/ai-metadata-executor.ts +94 -1
- package/src/metadata-builder/builders/add-page-builder.ts +9 -13
- package/src/metadata-builder/builders/footer-builder.test.ts +76 -0
- package/src/metadata-builder/builders/footer-builder.ts +226 -0
- package/src/metadata-builder/builders/global-styles-builder.ts +187 -0
- package/src/metadata-builder/builders/header-builder.test.ts +106 -0
- package/src/metadata-builder/builders/header-builder.ts +254 -0
- package/src/metadata-builder/builders/rename-page-builder.ts +79 -0
- package/src/metadata-builder/builders/section-builders/about-section-builder.ts +73 -5
- package/src/metadata-builder/builders/section-builders/banner-section-builder.ts +112 -7
- package/src/metadata-builder/builders/section-builders/base-section-builder.ts +149 -11
- package/src/metadata-builder/builders/section-builders/booking-section-builder.ts +87 -0
- package/src/metadata-builder/builders/section-builders/button-section-builder.ts +6 -1
- package/src/metadata-builder/builders/section-builders/contact-form-builder.ts +74 -4
- package/src/metadata-builder/builders/section-builders/delete-section-builder.ts +15 -1
- package/src/metadata-builder/builders/section-builders/divider-section-builder.ts +13 -1
- package/src/metadata-builder/builders/section-builders/image-gallery-builder.ts +91 -31
- package/src/metadata-builder/builders/section-builders/images-section-builder.ts +102 -48
- package/src/metadata-builder/builders/section-builders/index.ts +1 -0
- package/src/metadata-builder/builders/section-builders/mailing-list-builder.ts +38 -2
- package/src/metadata-builder/builders/section-builders/mailing-list-section-builder.ts +38 -2
- package/src/metadata-builder/builders/section-builders/profile-section-builder.ts +55 -3
- package/src/metadata-builder/builders/section-builders/shapes-section-builder.ts +170 -77
- package/src/metadata-builder/builders/section-builders/social-links-builder.test.ts +119 -0
- package/src/metadata-builder/builders/section-builders/social-links-builder.ts +13 -2
- package/src/metadata-builder/builders/section-builders/testimonial-section-builder.ts +178 -57
- package/src/metadata-builder/builders/section-builders/text-section-builder.ts +130 -30
- package/src/metadata-builder/builders/section-content-factory.ts +15 -2
- package/src/metadata-builder/builders/section-field-maps.ts +34 -1
- package/src/metadata-builder/builders/section-field-utils.ts +131 -72
- package/src/metadata-builder/builders/section-rules/about-section.rules.ts +38 -0
- package/src/metadata-builder/builders/section-rules/add-page.rules.ts +17 -0
- package/src/metadata-builder/builders/section-rules/banner-section.rules.ts +49 -0
- package/src/metadata-builder/builders/section-rules/booking-section.rules.ts +34 -0
- package/src/metadata-builder/builders/section-rules/button-section.rules.ts +22 -0
- package/src/metadata-builder/builders/section-rules/contact-form.rules.ts +30 -0
- package/src/metadata-builder/builders/section-rules/divider-section.rules.ts +17 -0
- package/src/metadata-builder/builders/section-rules/footer.rules.ts +21 -0
- package/src/metadata-builder/builders/section-rules/global-styles.rules.ts +44 -0
- package/src/metadata-builder/builders/section-rules/header.rules.ts +75 -0
- package/src/metadata-builder/builders/section-rules/image-gallery.rules.ts +22 -0
- package/src/metadata-builder/builders/section-rules/images-section.rules.ts +55 -0
- package/src/metadata-builder/builders/section-rules/mailing-list.rules.ts +21 -0
- package/src/metadata-builder/builders/section-rules/profile.rules.ts +27 -0
- package/src/metadata-builder/builders/section-rules/rename-page.rules.ts +17 -0
- package/src/metadata-builder/builders/section-rules/shapes-section.rules.ts +51 -0
- package/src/metadata-builder/builders/section-rules/social-links.rules.ts +27 -0
- package/src/metadata-builder/builders/section-rules/testimonial-section.rules.ts +48 -0
- package/src/metadata-builder/builders/section-rules/text-section.rules.ts +28 -0
- package/src/metadata-builder/builders/shape-color-utils.test.ts +115 -0
- package/src/metadata-builder/builders/shape-color-utils.ts +75 -0
- package/src/metadata-builder/builders/undo-builder.ts +105 -0
- package/src/metadata-builder/builders/update-content-text-style-builder.ts +4 -1
- package/src/metadata-builder/helpers/rte.helpers.ts +27 -13
- package/src/metadata-builder/metadata-executor.ts +42 -2
- package/src/metadata-builder/models.ts +39 -1
- package/src/metadata-builder/parsers/ai-toolcall-parser.ts +152 -0
- package/src/metadata-builder/parsers/section-tool-arguments.ts +138 -24
- package/src/metadata-builder/sanitizers/__tests__/section-args-validator.test.ts +659 -0
- package/src/metadata-builder/sanitizers/rte-schema-check.ts +99 -0
- package/src/metadata-builder/sanitizers/sanitizer-rules.ts +97 -0
- package/src/metadata-builder/sanitizers/section-args-validator.ts +445 -0
- package/src/shared/content-settings/components/content-settings/ContentSettings.mixin.ts +10 -16
- package/src/shared/content-settings/components/content-settings/ContentSettings.stories.ts +0 -1
- package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.ts +6 -10
- package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.vue +1 -23
- package/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.vue +0 -15
- package/src/shared/content-settings/components/text-items-field/TextItemsField.vue +0 -15
- package/src/shared/navigation-style-settings/store/index.ts +5 -0
- package/src/shared/page-navigation/store/page-navigation-store.ts +4 -31
- package/src/shared/page-navigation/utils/nav-order-utils.ts +32 -0
- package/src/shared/side-bar/components/SideBar.vue +14 -1
- package/src/shared/side-bar/store/side-bar-store.ts +0 -20
- package/src/utils/build-asset-manifest.ts +153 -0
- package/src/utils/minify-brand-page-metadata.ts +362 -130
- package/lib/src/brand-page-maker/composables/ai-chat/useAiChat.js +0 -368
- package/lib/src/brand-page-maker/composables/ai-chat/useAiTextEditPrompts.d.ts +0 -18
- package/lib/src/brand-page-maker/composables/ai-chat/useAiTextEditPrompts.js +0 -144
- package/lib/src/brand-page-maker/stores/ai-thread/ai-thread-store.d.ts +0 -155
- package/lib/src/brand-page-maker/stores/ai-thread/ai-thread-store.js +0 -25
- package/lib/src/brand-page-maker/utils/mixpanel.util.d.ts +0 -1
- package/lib/src/brand-page-maker/utils/mixpanel.util.js +0 -29
- package/lib/src/bundled-translations-CNK7l6_v.js +0 -173
- package/lib/src/bundled-translations.de-DE-BLE4_y0H.js +0 -173
- package/lib/src/bundled-translations.es-ES-thO9osbg.js +0 -173
- package/lib/src/bundled-translations.fr-CA-BZkhiNgU.js +0 -173
- package/lib/src/bundled-translations.fr-FR-bhDLPKgZ.js +0 -173
- package/lib/src/bundled-translations.pt-BR-CI9a5Bq1.js +0 -173
- package/lib/src/bundled-translations.pt-PT-DBoErBaq.js +0 -173
- package/src/brand-page-maker/components/ai-text-edit/AiTextEdit.vue +0 -154
- package/src/brand-page-maker/composables/ai-chat/useAiChat.ts +0 -562
- package/src/brand-page-maker/composables/ai-chat/useAiTextEditPrompts.ts +0 -196
- package/src/brand-page-maker/stores/ai-thread/ai-thread-store.ts +0 -31
- package/src/brand-page-maker/utils/mixpanel.util.ts +0 -42
- package/src/shared/content-settings/components/generate-ai-button/GenerateAiButton.vue +0 -114
- package/src/shared/content-settings/components/generate-ai-modal/GenerateAiModal.vue +0 -761
|
@@ -0,0 +1,99 @@
|
|
|
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';
|
|
14
|
+
import { isTiptapDocument } from '../parsers/section-tool-arguments';
|
|
15
|
+
import {
|
|
16
|
+
rteStyleCheck,
|
|
17
|
+
textCheck,
|
|
18
|
+
type SectionCheck,
|
|
19
|
+
} from './section-args-validator';
|
|
20
|
+
|
|
21
|
+
/**
|
|
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.
|
|
27
|
+
*/
|
|
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
|
+
});
|
|
50
|
+
|
|
51
|
+
/**
|
|
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).
|
|
57
|
+
*
|
|
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.
|
|
61
|
+
*/
|
|
62
|
+
export const rteSchemaCheck =
|
|
63
|
+
(field: string): SectionCheck =>
|
|
64
|
+
(record) => {
|
|
65
|
+
const value = record[field];
|
|
66
|
+
|
|
67
|
+
if (!isTiptapDocument(value)) return null;
|
|
68
|
+
|
|
69
|
+
const editor = buildHeadlessEditor();
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
editor.schema.nodeFromJSON(value);
|
|
73
|
+
|
|
74
|
+
return null;
|
|
75
|
+
} catch (err) {
|
|
76
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
77
|
+
|
|
78
|
+
return `"${field}" is not valid Tiptap JSON: ${detail}`;
|
|
79
|
+
} finally {
|
|
80
|
+
editor.destroy();
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Returns [rteSchemaCheck(field), textCheck(field, max), rteStyleCheck(field)].
|
|
86
|
+
* Use with spread in a CHECKS array to validate the Tiptap doc structure
|
|
87
|
+
* (against the editor's real ProseMirror schema), plain text length, and
|
|
88
|
+
* inline RTE mark styles for the same field. Schema check runs first so
|
|
89
|
+
* a malformed doc surfaces an actionable error to the AI retry loop
|
|
90
|
+
* before the renderer can silently swallow it.
|
|
91
|
+
*/
|
|
92
|
+
export const textAndRteChecks = (
|
|
93
|
+
field: string,
|
|
94
|
+
max: number,
|
|
95
|
+
): SectionCheck[] => [
|
|
96
|
+
rteSchemaCheck(field),
|
|
97
|
+
textCheck(field, max),
|
|
98
|
+
rteStyleCheck(field),
|
|
99
|
+
];
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sanitizer-rules.ts
|
|
3
|
+
*
|
|
4
|
+
* Shared style/logo/page constraint rules and the SectionRules interface.
|
|
5
|
+
* Per-section rules live colocated with each builder (e.g. banner-section.rules.ts).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
MIN_TEXT_SIZE_PX,
|
|
10
|
+
MAX_TEXT_SIZE_PX,
|
|
11
|
+
MIN_LINE_HEIGHT,
|
|
12
|
+
MAX_LINE_HEIGHT,
|
|
13
|
+
MIN_LETTER_SPACING_PERCENT,
|
|
14
|
+
MAX_LETTER_SPACING_PERCENT,
|
|
15
|
+
FONT_FAMILY_CONFIGS,
|
|
16
|
+
FONT_FAMILY_KEYS,
|
|
17
|
+
} from '../../brand-page/constants/font.constants';
|
|
18
|
+
import {
|
|
19
|
+
MAX_PAGE_TITLE_LENGTH,
|
|
20
|
+
MAX_SUBPAGE_TITLE_LENGTH,
|
|
21
|
+
} from '../../shared/page-settings/utils';
|
|
22
|
+
import {
|
|
23
|
+
LOGO_SLIDER_DESKTOP_MIN,
|
|
24
|
+
LOGO_SLIDER_DESKTOP_MAX,
|
|
25
|
+
LOGO_SLIDER_MOBILE_MIN,
|
|
26
|
+
LOGO_SLIDER_MOBILE_MAX,
|
|
27
|
+
} from '../../brand-page/constants/styles.constants';
|
|
28
|
+
import { pxToEm } from '../../brand-page-maker/utils/text.util';
|
|
29
|
+
|
|
30
|
+
// ─── 1. Style property rules ──────────────────────────────────────────────────
|
|
31
|
+
// Applies to any TextStyleArguments object (section styles, global styles,
|
|
32
|
+
// header/footer viewport overrides).
|
|
33
|
+
//
|
|
34
|
+
// fontFamilyNames / fontFamilyKeys use Set (not readonly arrays) because both
|
|
35
|
+
// are derived dynamically from FONT_FAMILY_CONFIGS at runtime — as const
|
|
36
|
+
// literal narrowing is not possible. Consumers call .has(value).
|
|
37
|
+
|
|
38
|
+
export const STYLE_RULES = {
|
|
39
|
+
// fontSize bounds are in px (natural unit for clamping).
|
|
40
|
+
// Flow: parse input unit → convert to px → clamp → pxToEm(clampedPx)
|
|
41
|
+
fontUnit: {
|
|
42
|
+
allowedUnits: ['em'] as const,
|
|
43
|
+
},
|
|
44
|
+
fontSize: {
|
|
45
|
+
minEm: pxToEm(String(MIN_TEXT_SIZE_PX)),
|
|
46
|
+
maxEm: pxToEm(String(MAX_TEXT_SIZE_PX)),
|
|
47
|
+
},
|
|
48
|
+
lineHeight: {
|
|
49
|
+
min: MIN_LINE_HEIGHT,
|
|
50
|
+
max: MAX_LINE_HEIGHT,
|
|
51
|
+
},
|
|
52
|
+
letterSpacing: {
|
|
53
|
+
min: MIN_LETTER_SPACING_PERCENT,
|
|
54
|
+
max: MAX_LETTER_SPACING_PERCENT,
|
|
55
|
+
},
|
|
56
|
+
// Two separate sets because the format differs by context:
|
|
57
|
+
// TextStyleArguments.fontFamily → display name (e.g. 'Playfair Display')
|
|
58
|
+
// UpdateGlobalStylesArguments.textFontFamily → camelCase key (e.g. 'playfairDisplay')
|
|
59
|
+
fontFamilyNames: new Set(
|
|
60
|
+
Object.values(FONT_FAMILY_CONFIGS).map((c) =>
|
|
61
|
+
// Some font names are stored with surrounding single-quotes (e.g. "'Exo 2'").
|
|
62
|
+
// Strip them so the Set matches the bare names the AI sends.
|
|
63
|
+
c.name.replace(/^'(.*)'$/, '$1'),
|
|
64
|
+
),
|
|
65
|
+
),
|
|
66
|
+
fontFamilyKeys: new Set(Object.keys(FONT_FAMILY_KEYS)),
|
|
67
|
+
} as const;
|
|
68
|
+
|
|
69
|
+
// ─── 2. Logo size rules ───────────────────────────────────────────────────────
|
|
70
|
+
// Applies to logo_image_height / logo_image_width in UpdateHeaderArguments and
|
|
71
|
+
// UpdateFooterArguments viewport overrides. Values are in rem units.
|
|
72
|
+
|
|
73
|
+
export const LOGO_SIZE_RULES = {
|
|
74
|
+
unit: 'rem' as const,
|
|
75
|
+
desktop: { min: LOGO_SLIDER_DESKTOP_MIN, max: LOGO_SLIDER_DESKTOP_MAX },
|
|
76
|
+
mobile: { min: LOGO_SLIDER_MOBILE_MIN, max: LOGO_SLIDER_MOBILE_MAX },
|
|
77
|
+
} as const;
|
|
78
|
+
|
|
79
|
+
// ─── 3. Page rules ────────────────────────────────────────────────────────────
|
|
80
|
+
// Applies to add_page (page_name), rename_page (page_name), and update_header
|
|
81
|
+
// (nav_routes[].display_name).
|
|
82
|
+
|
|
83
|
+
export const PAGE_RULES = {
|
|
84
|
+
pageName: MAX_PAGE_TITLE_LENGTH,
|
|
85
|
+
subPageName: MAX_SUBPAGE_TITLE_LENGTH,
|
|
86
|
+
navDisplayName: MAX_PAGE_TITLE_LENGTH,
|
|
87
|
+
} as const;
|
|
88
|
+
|
|
89
|
+
// ─── 4. Item cap rule ─────────────────────────────────────────────────────────
|
|
90
|
+
// Parameter type for itemCapCheck() in section-args-validator.ts.
|
|
91
|
+
|
|
92
|
+
export interface ItemCapRule {
|
|
93
|
+
brandSite: number;
|
|
94
|
+
brandPage: number;
|
|
95
|
+
/** The args field name that holds the items array (e.g. 'items', 'links'). */
|
|
96
|
+
arrayField: string;
|
|
97
|
+
}
|
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isTiptapDocument,
|
|
3
|
+
type TextStyleArguments,
|
|
4
|
+
type TiptapDocument,
|
|
5
|
+
type TiptapMark,
|
|
6
|
+
} from '../parsers/section-tool-arguments';
|
|
7
|
+
import {
|
|
8
|
+
LOGO_SIZE_RULES,
|
|
9
|
+
STYLE_RULES,
|
|
10
|
+
type ItemCapRule,
|
|
11
|
+
} from './sanitizer-rules';
|
|
12
|
+
|
|
13
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
function extractPlainText(value: string | TiptapDocument): string {
|
|
16
|
+
if (typeof value === 'string') return value;
|
|
17
|
+
|
|
18
|
+
return value.content
|
|
19
|
+
.flatMap((block) => block.content ?? [])
|
|
20
|
+
.filter((node) => node.type === 'text')
|
|
21
|
+
.map((node) => node.text)
|
|
22
|
+
.join('');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ─── Style property checks (compiled from STYLE_RULES at module init) ─────────
|
|
26
|
+
//
|
|
27
|
+
// Each check takes (fieldLabel, style) → string | null.
|
|
28
|
+
// STYLE_RULES is the base — no if-conditions in validateStyleArgs itself.
|
|
29
|
+
//
|
|
30
|
+
// TiptapDocument inline mark styles (textStyle marks within RTE content) are
|
|
31
|
+
// validated by validateRteMarkStyle / validateRteDocument below.
|
|
32
|
+
|
|
33
|
+
type StylePropertyCheck = (
|
|
34
|
+
fieldLabel: string,
|
|
35
|
+
style: TextStyleArguments,
|
|
36
|
+
) => string | null;
|
|
37
|
+
|
|
38
|
+
const { fontUnit, fontSize, lineHeight, letterSpacing, fontFamilyNames } =
|
|
39
|
+
STYLE_RULES;
|
|
40
|
+
|
|
41
|
+
const STYLE_PROPERTY_CHECKS: StylePropertyCheck[] = [
|
|
42
|
+
(fieldLabel, style) => {
|
|
43
|
+
if (style.fontSize == null) return null;
|
|
44
|
+
|
|
45
|
+
const raw = style.fontSize.trim().toLowerCase();
|
|
46
|
+
const unit = fontUnit.allowedUnits[0];
|
|
47
|
+
const match = raw.match(new RegExp(`^(\\d+(?:\\.\\d+)?)${unit}$`));
|
|
48
|
+
|
|
49
|
+
if (!match) {
|
|
50
|
+
return `"${fieldLabel}.fontSize" must use "${unit}" units (got "${style.fontSize}")`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const val = parseFloat(match[1]);
|
|
54
|
+
const min = parseFloat(fontSize.minEm);
|
|
55
|
+
const max = parseFloat(fontSize.maxEm);
|
|
56
|
+
|
|
57
|
+
return isNaN(val) || val < min || val > max
|
|
58
|
+
? `"${fieldLabel}.fontSize" "${style.fontSize}" is out of bounds (${fontSize.minEm}–${fontSize.maxEm})`
|
|
59
|
+
: null;
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
(fieldLabel, style) => {
|
|
63
|
+
if (style.lineHeight == null) return null;
|
|
64
|
+
|
|
65
|
+
const { min, max } = lineHeight;
|
|
66
|
+
const val = parseFloat(String(style.lineHeight));
|
|
67
|
+
|
|
68
|
+
return isNaN(val) || val < min || val > max
|
|
69
|
+
? `"${fieldLabel}.lineHeight" ${style.lineHeight} is out of bounds (${min}–${max})`
|
|
70
|
+
: null;
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
(fieldLabel, style) => {
|
|
74
|
+
if (style.letterSpacing == null) return null;
|
|
75
|
+
|
|
76
|
+
const { min, max } = letterSpacing;
|
|
77
|
+
const val = parseFloat(String(style.letterSpacing));
|
|
78
|
+
|
|
79
|
+
return isNaN(val) || val < min || val > max
|
|
80
|
+
? `"${fieldLabel}.letterSpacing" ${style.letterSpacing} is out of bounds (${min}–${max})`
|
|
81
|
+
: null;
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
(fieldLabel, style) => {
|
|
85
|
+
if (style.fontFamily == null) return null;
|
|
86
|
+
|
|
87
|
+
return !fontFamilyNames.has(style.fontFamily)
|
|
88
|
+
? `"${fieldLabel}.fontFamily" "${style.fontFamily}" is not a recognized font family`
|
|
89
|
+
: null;
|
|
90
|
+
},
|
|
91
|
+
];
|
|
92
|
+
|
|
93
|
+
function validateStyleArgs(
|
|
94
|
+
fieldLabel: string,
|
|
95
|
+
style: TextStyleArguments,
|
|
96
|
+
): string[] {
|
|
97
|
+
return STYLE_PROPERTY_CHECKS.flatMap((check) => {
|
|
98
|
+
const err = check(fieldLabel, style);
|
|
99
|
+
|
|
100
|
+
return err ? [err] : [];
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ─── RTE mark style validation ───────────────────────────────────────────────
|
|
105
|
+
//
|
|
106
|
+
// Mark attrs are all strings, unlike TextStyleArguments which uses numbers for
|
|
107
|
+
// lineHeight and letterSpacing. Key format differences:
|
|
108
|
+
// lineHeight → unitless string "1.5" (not a number)
|
|
109
|
+
// letterSpacing → em string "0.05em" (percent / 100; range: [0em, 1em])
|
|
110
|
+
|
|
111
|
+
type RteMarkCheck = (
|
|
112
|
+
path: string,
|
|
113
|
+
attrs: NonNullable<TiptapMark['attrs']>,
|
|
114
|
+
) => string | null;
|
|
115
|
+
|
|
116
|
+
const RTE_MARK_PROPERTY_CHECKS: RteMarkCheck[] = [
|
|
117
|
+
(path, attrs) => {
|
|
118
|
+
if (attrs.fontSize == null) return null;
|
|
119
|
+
|
|
120
|
+
const raw = attrs.fontSize.trim().toLowerCase();
|
|
121
|
+
const unit = fontUnit.allowedUnits[0];
|
|
122
|
+
const match = raw.match(new RegExp(`^(\\d+(?:\\.\\d+)?)${unit}$`));
|
|
123
|
+
|
|
124
|
+
if (!match) {
|
|
125
|
+
return `"${path}.fontSize" must use "em" units (got "${attrs.fontSize}")`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const val = parseFloat(match[1]);
|
|
129
|
+
const min = parseFloat(fontSize.minEm);
|
|
130
|
+
const max = parseFloat(fontSize.maxEm);
|
|
131
|
+
|
|
132
|
+
return isNaN(val) || val < min || val > max
|
|
133
|
+
? `"${path}.fontSize" "${attrs.fontSize}" is out of bounds (${fontSize.minEm}–${fontSize.maxEm})`
|
|
134
|
+
: null;
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
(path, attrs) => {
|
|
138
|
+
if (attrs.fontFamily == null) return null;
|
|
139
|
+
|
|
140
|
+
return !fontFamilyNames.has(attrs.fontFamily)
|
|
141
|
+
? `"${path}.fontFamily" "${attrs.fontFamily}" is not a recognized font family`
|
|
142
|
+
: null;
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
(path, attrs) => {
|
|
146
|
+
if (attrs.lineHeight == null) return null;
|
|
147
|
+
|
|
148
|
+
const val = parseFloat(attrs.lineHeight);
|
|
149
|
+
const isUnitless = !isNaN(val) && attrs.lineHeight.trim() === String(val);
|
|
150
|
+
|
|
151
|
+
if (!isUnitless) {
|
|
152
|
+
return `"${path}.lineHeight" must be a unitless number (got "${attrs.lineHeight}")`;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return val < lineHeight.min || val > lineHeight.max
|
|
156
|
+
? `"${path}.lineHeight" ${val} is out of bounds (${lineHeight.min}–${lineHeight.max})`
|
|
157
|
+
: null;
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
(path, attrs) => {
|
|
161
|
+
if (attrs.letterSpacing == null) return null;
|
|
162
|
+
|
|
163
|
+
const raw = attrs.letterSpacing.trim().toLowerCase();
|
|
164
|
+
|
|
165
|
+
// "0" is valid CSS without units — treat as 0em.
|
|
166
|
+
if (raw === '0') return null;
|
|
167
|
+
|
|
168
|
+
const match = raw.match(/^(\d+(?:\.\d+)?)em$/);
|
|
169
|
+
|
|
170
|
+
if (!match) {
|
|
171
|
+
return `"${path}.letterSpacing" must use "em" units (got "${attrs.letterSpacing}")`;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const val = parseFloat(match[1]);
|
|
175
|
+
const minEm = letterSpacing.min / 100;
|
|
176
|
+
const maxEm = letterSpacing.max / 100;
|
|
177
|
+
|
|
178
|
+
return val < minEm || val > maxEm
|
|
179
|
+
? `"${path}.letterSpacing" ${attrs.letterSpacing} is out of bounds (${minEm}em–${maxEm}em)`
|
|
180
|
+
: null;
|
|
181
|
+
},
|
|
182
|
+
];
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Validates CSS string-format style attrs (fontSize em, fontFamily name,
|
|
186
|
+
* lineHeight unitless, letterSpacing em) against STYLE_RULES bounds.
|
|
187
|
+
* Used for both RTE textStyle mark attrs and GlobalStyles textStyleOptions.
|
|
188
|
+
* Returns the first error string, or null if all attrs are valid / absent.
|
|
189
|
+
*/
|
|
190
|
+
export function validateStringStyleAttrs(
|
|
191
|
+
path: string,
|
|
192
|
+
attrs: {
|
|
193
|
+
fontSize?: string | null;
|
|
194
|
+
fontFamily?: string | null;
|
|
195
|
+
lineHeight?: string | null;
|
|
196
|
+
letterSpacing?: string | null;
|
|
197
|
+
},
|
|
198
|
+
): string | null {
|
|
199
|
+
for (const check of RTE_MARK_PROPERTY_CHECKS) {
|
|
200
|
+
const err = check(path, attrs as NonNullable<TiptapMark['attrs']>);
|
|
201
|
+
|
|
202
|
+
if (err) return err;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function validateRteMarkStyle(
|
|
209
|
+
path: string,
|
|
210
|
+
attrs: NonNullable<TiptapMark['attrs']>,
|
|
211
|
+
): string | null {
|
|
212
|
+
return validateStringStyleAttrs(path, attrs);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function validateRteDocument(
|
|
216
|
+
fieldLabel: string,
|
|
217
|
+
doc: TiptapDocument,
|
|
218
|
+
): string | null {
|
|
219
|
+
for (const block of doc.content) {
|
|
220
|
+
for (const node of block.content ?? []) {
|
|
221
|
+
if (node.type !== 'text') continue;
|
|
222
|
+
|
|
223
|
+
for (const mark of node.marks ?? []) {
|
|
224
|
+
if (mark.type !== 'textStyle' || !mark.attrs) continue;
|
|
225
|
+
|
|
226
|
+
const err = validateRteMarkStyle(fieldLabel, mark.attrs);
|
|
227
|
+
|
|
228
|
+
if (err) return err;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// ─── Public check API ─────────────────────────────────────────────────────────
|
|
237
|
+
|
|
238
|
+
export interface ValidationContext {
|
|
239
|
+
brandPageType?: string;
|
|
240
|
+
mode?: 'create' | 'update';
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* A pure validation check: record + context → one error string or null.
|
|
245
|
+
* All checks operate on Record<string, unknown> — no concrete section type casting.
|
|
246
|
+
*/
|
|
247
|
+
export type SectionCheck = (
|
|
248
|
+
record: Record<string, unknown>,
|
|
249
|
+
ctx: ValidationContext,
|
|
250
|
+
) => string | null;
|
|
251
|
+
|
|
252
|
+
// ─── Check factories ──────────────────────────────────────────────────────────
|
|
253
|
+
|
|
254
|
+
export const textCheck =
|
|
255
|
+
(field: string, max: number): SectionCheck =>
|
|
256
|
+
(record) => {
|
|
257
|
+
const value = record[field];
|
|
258
|
+
|
|
259
|
+
if (value == null) return null;
|
|
260
|
+
|
|
261
|
+
const text = isTiptapDocument(value)
|
|
262
|
+
? extractPlainText(value)
|
|
263
|
+
: String(value);
|
|
264
|
+
|
|
265
|
+
return text.length > max
|
|
266
|
+
? `"${field}" exceeds the maximum length of ${max} characters (got ${text.length})`
|
|
267
|
+
: null;
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
export const styleCheck =
|
|
271
|
+
(field: string): SectionCheck =>
|
|
272
|
+
(record) => {
|
|
273
|
+
const value = record[field];
|
|
274
|
+
|
|
275
|
+
if (value == null || typeof value !== 'object') return null;
|
|
276
|
+
|
|
277
|
+
const errs = validateStyleArgs(field, value as TextStyleArguments);
|
|
278
|
+
|
|
279
|
+
return errs[0] ?? null;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
export const rteStyleCheck =
|
|
283
|
+
(field: string): SectionCheck =>
|
|
284
|
+
(record) => {
|
|
285
|
+
const value = record[field];
|
|
286
|
+
|
|
287
|
+
if (!isTiptapDocument(value)) return null;
|
|
288
|
+
|
|
289
|
+
return validateRteDocument(field, value);
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
export const itemTextCheck =
|
|
293
|
+
(arrayField: string, itemField: string, max: number): SectionCheck =>
|
|
294
|
+
(record) => {
|
|
295
|
+
const items = record[arrayField];
|
|
296
|
+
|
|
297
|
+
if (!Array.isArray(items)) return null;
|
|
298
|
+
|
|
299
|
+
for (let i = 0; i < items.length; i++) {
|
|
300
|
+
const value = (items[i] as Record<string, unknown>)[itemField];
|
|
301
|
+
|
|
302
|
+
if (value == null) continue;
|
|
303
|
+
|
|
304
|
+
const text = isTiptapDocument(value)
|
|
305
|
+
? extractPlainText(value)
|
|
306
|
+
: String(value);
|
|
307
|
+
|
|
308
|
+
if (text.length > max) {
|
|
309
|
+
return `"${arrayField}[${i}].${itemField}" exceeds the maximum length of ${max} characters (got ${text.length})`;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return null;
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
export const itemStyleCheck =
|
|
317
|
+
(arrayField: string, itemField: string): SectionCheck =>
|
|
318
|
+
(record) => {
|
|
319
|
+
const items = record[arrayField];
|
|
320
|
+
|
|
321
|
+
if (!Array.isArray(items)) return null;
|
|
322
|
+
|
|
323
|
+
for (let i = 0; i < items.length; i++) {
|
|
324
|
+
const value = (items[i] as Record<string, unknown>)[itemField];
|
|
325
|
+
|
|
326
|
+
if (value == null || typeof value !== 'object') continue;
|
|
327
|
+
|
|
328
|
+
const errs = validateStyleArgs(
|
|
329
|
+
`${arrayField}[${i}].${itemField}`,
|
|
330
|
+
value as TextStyleArguments,
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
if (errs[0]) return errs[0];
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return null;
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
export const itemRteStyleCheck =
|
|
340
|
+
(arrayField: string, itemField: string): SectionCheck =>
|
|
341
|
+
(record) => {
|
|
342
|
+
const items = record[arrayField];
|
|
343
|
+
|
|
344
|
+
if (!Array.isArray(items)) return null;
|
|
345
|
+
|
|
346
|
+
for (let i = 0; i < items.length; i++) {
|
|
347
|
+
const value = (items[i] as Record<string, unknown>)[itemField];
|
|
348
|
+
|
|
349
|
+
if (!isTiptapDocument(value)) continue;
|
|
350
|
+
|
|
351
|
+
const err = validateRteDocument(
|
|
352
|
+
`${arrayField}[${i}].${itemField}`,
|
|
353
|
+
value,
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
if (err) return err;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return null;
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
export const enumCheck =
|
|
363
|
+
(field: string, allowed: readonly string[], label?: string): SectionCheck =>
|
|
364
|
+
(record) => {
|
|
365
|
+
const value = record[field];
|
|
366
|
+
|
|
367
|
+
if (value == null) return null;
|
|
368
|
+
|
|
369
|
+
return !allowed.includes(value as string)
|
|
370
|
+
? `"${field}" value "${value}" is not valid${label ? ` for "${label}"` : ''}. Valid values: ${allowed.join(', ')}`
|
|
371
|
+
: null;
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
export const itemCapCheck =
|
|
375
|
+
(cap: ItemCapRule, label?: string): SectionCheck =>
|
|
376
|
+
(record, ctx) => {
|
|
377
|
+
if (ctx.brandPageType == null) return null;
|
|
378
|
+
|
|
379
|
+
const shouldCheck =
|
|
380
|
+
ctx.mode === 'create' ||
|
|
381
|
+
(ctx.mode === 'update' &&
|
|
382
|
+
(record['_replace_items'] as boolean | undefined));
|
|
383
|
+
|
|
384
|
+
if (!shouldCheck) return null;
|
|
385
|
+
|
|
386
|
+
const items = record[cap.arrayField];
|
|
387
|
+
const limit =
|
|
388
|
+
ctx.brandPageType === 'brandSite' ? cap.brandSite : cap.brandPage;
|
|
389
|
+
|
|
390
|
+
return Array.isArray(items) && items.length > limit
|
|
391
|
+
? `"${cap.arrayField}" has ${items.length} items but "${label ?? 'section'}" supports a maximum of ${limit}`
|
|
392
|
+
: null;
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Runs an array of SectionChecks against the given args and context.
|
|
397
|
+
* Returns all non-null error strings.
|
|
398
|
+
*/
|
|
399
|
+
export function runChecks(
|
|
400
|
+
checks: SectionCheck[],
|
|
401
|
+
args: Record<string, unknown>,
|
|
402
|
+
ctx: ValidationContext,
|
|
403
|
+
): string[] {
|
|
404
|
+
return checks.flatMap((check) => {
|
|
405
|
+
const err = check(args, ctx);
|
|
406
|
+
|
|
407
|
+
return err ? [err] : [];
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// ─── Logo size regex (compiled once at module init) ───────────────────────────
|
|
412
|
+
|
|
413
|
+
const LOGO_SIZE_REGEX = new RegExp(
|
|
414
|
+
`^(\\d+(?:\\.\\d+)?)${LOGO_SIZE_RULES.unit}$`,
|
|
415
|
+
);
|
|
416
|
+
|
|
417
|
+
// ─── Shared field validators ──────────────────────────────────────────────────
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Validates a logo size value against LOGO_SIZE_RULES for the given viewport.
|
|
421
|
+
* The value must use "rem" units and fall within the viewport-specific bounds.
|
|
422
|
+
* Returns an error string, or null if valid / absent.
|
|
423
|
+
*/
|
|
424
|
+
export function validateLogoSize(
|
|
425
|
+
fieldLabel: string,
|
|
426
|
+
value: string | undefined | null,
|
|
427
|
+
viewport: 'desktop' | 'mobile',
|
|
428
|
+
): string | null {
|
|
429
|
+
if (value == null) return null;
|
|
430
|
+
|
|
431
|
+
const match = value.trim().toLowerCase().match(LOGO_SIZE_REGEX);
|
|
432
|
+
|
|
433
|
+
if (!match) {
|
|
434
|
+
return `"${fieldLabel}" must use "${LOGO_SIZE_RULES.unit}" units (got "${value}")`;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const num = parseFloat(match[1]);
|
|
438
|
+
const { min, max } = LOGO_SIZE_RULES[viewport];
|
|
439
|
+
|
|
440
|
+
if (num < min || num > max) {
|
|
441
|
+
return `"${fieldLabel}" ${value} is out of bounds (${min}rem–${max}rem)`;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
return null;
|
|
445
|
+
}
|
|
@@ -146,14 +146,11 @@ export default defineComponent({
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
// Send MixPanel add event
|
|
149
|
-
this.eventTracker.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
select_location: SELECT_LOCATIONS.SIDEBAR,
|
|
155
|
-
},
|
|
156
|
-
});
|
|
149
|
+
this.eventTracker.sendAddContentEvent(
|
|
150
|
+
option.type,
|
|
151
|
+
SELECT_LOCATIONS.SIDEBAR,
|
|
152
|
+
option.category,
|
|
153
|
+
);
|
|
157
154
|
|
|
158
155
|
if (option.displayMode === 'focused') {
|
|
159
156
|
this.contentSettingsStore.pushMode({
|
|
@@ -212,14 +209,11 @@ export default defineComponent({
|
|
|
212
209
|
this.contentSettingsStore.deleteItem(payload);
|
|
213
210
|
|
|
214
211
|
// Send MixPanel remove event
|
|
215
|
-
this.eventTracker.
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
select_location: SELECT_LOCATIONS.SIDEBAR,
|
|
221
|
-
},
|
|
222
|
-
});
|
|
212
|
+
this.eventTracker.sendRemoveContentEvent(
|
|
213
|
+
type,
|
|
214
|
+
SELECT_LOCATIONS.SIDEBAR,
|
|
215
|
+
this.contentSettingsStore.getContentCategory(type),
|
|
216
|
+
);
|
|
223
217
|
},
|
|
224
218
|
onManagePageButtonClick(): void {
|
|
225
219
|
this.contentSettingsStore.pushMode({
|