@templatical/editor 0.39.0 → 0.39.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -4
- package/dist/{AiChatSidebar-jVlXXND3.js → AiChatSidebar-pOxCZWz9.js} +14 -14
- package/dist/{AiFeatureMenu-C1HCntyQ.js → AiFeatureMenu-Bljk6Qjv.js} +7 -7
- package/dist/{BlockIssueBadge-JhNgcUmZ.js → BlockIssueBadge-D5oGxOQP.js} +5 -5
- package/dist/{BlockPreviewCanvas-C_rA5LJN.js → BlockPreviewCanvas-DXGjUECG.js} +27 -27
- package/dist/{CloudHeaderExtras-DvYyNsPB.js → CloudHeaderExtras-DaocwNmy.js} +5 -5
- package/dist/{CloudPanels-CDPhPVdd.js → CloudPanels-CyZAnSJY.js} +7 -7
- package/dist/{CollaboratorBar-Co9UPoB0.js → CollaboratorBar-C7Zca3g1.js} +4 -4
- package/dist/{CommentsPanel-CRcVN9Ri.js → CommentsPanel-CNOb7YCm.js} +2 -2
- package/dist/{CommentsSidebar-gDU977br.js → CommentsSidebar-VmwjU9va.js} +14 -14
- package/dist/{CountdownBlock-CEzrfe5R.js → CountdownBlock-DSvbf3qU.js} +3 -3
- package/dist/{CountdownToolbar-B00zhkNJ.js → CountdownToolbar-C2kfS6Oy.js} +31 -30
- package/dist/{DesignReferenceSidebar-DedivZZl.js → DesignReferenceSidebar-QC4gEUWp.js} +11 -11
- package/dist/{IssuesPanel-C-PjdmAV.js → IssuesPanel-DL2Xr14_.js} +8 -8
- package/dist/{LoadingTrack-BlTL4zFv.js → LoadingTrack-C2jKCU2d.js} +1 -1
- package/dist/LogicTagInsertButton-D8IwH-9Z.js +1071 -0
- package/dist/MediaEditModal-D4GEq2md.js +3545 -0
- package/dist/{MediaPanels-BpQNY8YX.js → MediaPanels-sapgKtxu.js} +2 -2
- package/dist/MergeTagInput-QI-5KG2R.js +81 -0
- package/dist/{MergeTagModeToggle-DGuzSAdX.js → MergeTagModeToggle-D793Bj_E.js} +14 -55
- package/dist/{ParagraphEditor-jMKLLTa8.js → ParagraphEditor-DkkPSexG.js} +65 -66
- package/dist/{RestoreVersionDialog-DG1jUdBM.js → RestoreVersionDialog-BgueZnZr.js} +5 -5
- package/dist/{RichTextEditorContent-JrNEg0kv.js → RichTextEditorContent-BC5UTVnb.js} +11 -11
- package/dist/{SaveBlockDialog-C0KC-OKs.js → SaveBlockDialog-BuTuVlLr.js} +12 -11
- package/dist/{SavedBlocksBrowserModal-zyOiRgWZ.js → SavedBlocksBrowserModal-Srhix8BB.js} +17 -16
- package/dist/{SavedBlocksPanels-epMd799w.js → SavedBlocksPanels-B2iScCS-.js} +2 -2
- package/dist/{SavedBlocksPickBar-CJqqQ3jd.js → SavedBlocksPickBar-cI7bDQQi.js} +4 -4
- package/dist/{TemplateScoringPanel-m2FOeaai.js → TemplateScoringPanel-C2Rdlyn6.js} +16 -16
- package/dist/TemplateSettings-C_5leDdF.js +245 -0
- package/dist/{TestEmailModal-D58kYkMV.js → TestEmailModal-DJ5q_u4N.js} +10 -10
- package/dist/{TestEmailPanel-BmFVBIQt.js → TestEmailPanel-CP24UGst.js} +2 -2
- package/dist/{TitleEditor-C4BGPXnf.js → TitleEditor-QBBOXtxx.js} +15 -15
- package/dist/ToggleSwitch-JvQ_CmI1.js +102 -0
- package/dist/Toolbar-COD2TW20.js +2426 -0
- package/dist/{TplModal-BIDJw4Kj.js → TplModal-C8xGjC1l.js} +5 -5
- package/dist/{VersionHistoryMenu-dt_aZQfh.js → VersionHistoryMenu-BVQityes.js} +10 -10
- package/dist/{VersionHistoryPanels-B_5SBRrr.js → VersionHistoryPanels-BrK6na4A.js} +2 -2
- package/dist/{VersionPreviewBanner-DttvOkwd.js → VersionPreviewBanner-BaMSgA1O.js} +3 -3
- package/dist/{blockTypeIcons-CzTizYmK.js → blockTypeIcons-CdXugKyV.js} +16 -37
- package/dist/bundle-stats.json +8 -8
- package/dist/{ca-Jx2CDwtn.js → ca-BTf1Zbqb.js} +9 -0
- package/dist/cdn/chunks/{AiChatSidebar-DeZl9Tk0.js → AiChatSidebar-CjSEoK4x.js} +8 -8
- package/dist/cdn/chunks/{AiChatSidebar-DeZl9Tk0.js.map → AiChatSidebar-CjSEoK4x.js.map} +1 -1
- package/dist/cdn/chunks/{AiFeatureMenu-Bv8jMu9p.js → AiFeatureMenu-l0K5TOSn.js} +6 -6
- package/dist/cdn/chunks/{AiFeatureMenu-Bv8jMu9p.js.map → AiFeatureMenu-l0K5TOSn.js.map} +1 -1
- package/dist/cdn/chunks/{BlockIssueBadge-B6PpoOPv.js → BlockIssueBadge-9hHpaXb9.js} +5 -5
- package/dist/cdn/chunks/{BlockIssueBadge-B6PpoOPv.js.map → BlockIssueBadge-9hHpaXb9.js.map} +1 -1
- package/dist/cdn/chunks/{BlockPreviewCanvas-DfEtDosD.js → BlockPreviewCanvas-lQrAdgG3.js} +30 -30
- package/dist/cdn/chunks/{BlockPreviewCanvas-DfEtDosD.js.map → BlockPreviewCanvas-lQrAdgG3.js.map} +1 -1
- package/dist/cdn/chunks/{CloudHeaderExtras-Hk98ub-C.js → CloudHeaderExtras-CXNe7Q-4.js} +5 -5
- package/dist/cdn/chunks/{CloudHeaderExtras-Hk98ub-C.js.map → CloudHeaderExtras-CXNe7Q-4.js.map} +1 -1
- package/dist/cdn/chunks/{CloudPanels-Ba3GLmvF.js → CloudPanels-bHhh9AUA.js} +6 -6
- package/dist/cdn/chunks/{CloudPanels-Ba3GLmvF.js.map → CloudPanels-bHhh9AUA.js.map} +1 -1
- package/dist/cdn/chunks/{CollaboratorBar-D2dCQ9gg.js → CollaboratorBar-DgqcaGGI.js} +5 -5
- package/dist/cdn/chunks/{CollaboratorBar-D2dCQ9gg.js.map → CollaboratorBar-DgqcaGGI.js.map} +1 -1
- package/dist/cdn/chunks/{CommentsPanel-CV2HveQk.js → CommentsPanel-Cy4TlTHC.js} +3 -3
- package/dist/cdn/chunks/{CommentsPanel-CV2HveQk.js.map → CommentsPanel-Cy4TlTHC.js.map} +1 -1
- package/dist/cdn/chunks/{CommentsSidebar-Dok_vaRc.js → CommentsSidebar-C7oAP3Mx.js} +5 -5
- package/dist/cdn/chunks/{CommentsSidebar-Dok_vaRc.js.map → CommentsSidebar-C7oAP3Mx.js.map} +1 -1
- package/dist/cdn/chunks/{CountdownBlock-DGDl3ota.js → CountdownBlock-DdC8Lg5F.js} +4 -4
- package/dist/cdn/chunks/{CountdownBlock-DGDl3ota.js.map → CountdownBlock-DdC8Lg5F.js.map} +1 -1
- package/dist/cdn/chunks/{CountdownToolbar-B9Rin64t.js → CountdownToolbar-CN9h4nlC.js} +22 -21
- package/dist/cdn/chunks/{CountdownToolbar-B9Rin64t.js.map → CountdownToolbar-CN9h4nlC.js.map} +1 -1
- package/dist/cdn/chunks/{DesignReferenceSidebar-eCuTFak2.js → DesignReferenceSidebar-Bjo0M-AY.js} +7 -7
- package/dist/cdn/chunks/{DesignReferenceSidebar-eCuTFak2.js.map → DesignReferenceSidebar-Bjo0M-AY.js.map} +1 -1
- package/dist/cdn/chunks/{IssuesPanel-CP7FEzw7.js → IssuesPanel-DdFk-Blf.js} +6 -6
- package/dist/cdn/chunks/{IssuesPanel-CP7FEzw7.js.map → IssuesPanel-DdFk-Blf.js.map} +1 -1
- package/dist/cdn/chunks/{LoadingTrack-Cm3TDKb3.js → LoadingTrack-Ba5xh5HD.js} +2 -2
- package/dist/cdn/chunks/{LoadingTrack-Cm3TDKb3.js.map → LoadingTrack-Ba5xh5HD.js.map} +1 -1
- package/dist/cdn/chunks/LogicTagInsertButton-DpyPozop.js +1035 -0
- package/dist/cdn/chunks/LogicTagInsertButton-DpyPozop.js.map +1 -0
- package/dist/cdn/chunks/MediaEditModal-BBZRcYKe.js +3529 -0
- package/dist/cdn/chunks/MediaEditModal-BBZRcYKe.js.map +1 -0
- package/dist/cdn/chunks/{MediaPanels-TYrKKHX5.js → MediaPanels-CSBCsFwT.js} +3 -3
- package/dist/cdn/chunks/{MediaPanels-TYrKKHX5.js.map → MediaPanels-CSBCsFwT.js.map} +1 -1
- package/dist/cdn/chunks/MergeTagInput-ERJr7bP_.js +83 -0
- package/dist/cdn/chunks/MergeTagInput-ERJr7bP_.js.map +1 -0
- package/dist/cdn/chunks/{MergeTagModeToggle-QGTUIWWo.js → MergeTagModeToggle-n3nvSNeQ.js} +5 -5
- package/dist/cdn/chunks/{MergeTagModeToggle-QGTUIWWo.js.map → MergeTagModeToggle-n3nvSNeQ.js.map} +1 -1
- package/dist/cdn/chunks/{ParagraphEditor-D1tsPv4v.js → ParagraphEditor-DO4RzP8l.js} +40 -40
- package/dist/cdn/chunks/{ParagraphEditor-D1tsPv4v.js.map → ParagraphEditor-DO4RzP8l.js.map} +1 -1
- package/dist/cdn/chunks/{RestoreVersionDialog-BeCxNPLS.js → RestoreVersionDialog-CzZ_sFnz.js} +5 -5
- package/dist/cdn/chunks/{RestoreVersionDialog-BeCxNPLS.js.map → RestoreVersionDialog-CzZ_sFnz.js.map} +1 -1
- package/dist/cdn/chunks/{RichTextEditorContent-BBxzACFQ.js → RichTextEditorContent-Ch5zeyZ7.js} +8 -8
- package/dist/cdn/chunks/{RichTextEditorContent-BBxzACFQ.js.map → RichTextEditorContent-Ch5zeyZ7.js.map} +1 -1
- package/dist/cdn/chunks/{SaveBlockDialog-CLgh_g7H.js → SaveBlockDialog-LgxYrXyx.js} +10 -9
- package/dist/cdn/chunks/{SaveBlockDialog-CLgh_g7H.js.map → SaveBlockDialog-LgxYrXyx.js.map} +1 -1
- package/dist/cdn/chunks/{SavedBlocksBrowserModal-B4TcUJJe.js → SavedBlocksBrowserModal-CdeSsTpb.js} +9 -9
- package/dist/cdn/chunks/{SavedBlocksBrowserModal-B4TcUJJe.js.map → SavedBlocksBrowserModal-CdeSsTpb.js.map} +1 -1
- package/dist/cdn/chunks/{SavedBlocksPanels-CaBsHoRC.js → SavedBlocksPanels-B5hakNJj.js} +3 -3
- package/dist/cdn/chunks/{SavedBlocksPanels-CaBsHoRC.js.map → SavedBlocksPanels-B5hakNJj.js.map} +1 -1
- package/dist/cdn/chunks/{SavedBlocksPickBar-iG35XCDx.js → SavedBlocksPickBar-Cl6PLwwV.js} +5 -5
- package/dist/cdn/chunks/{SavedBlocksPickBar-iG35XCDx.js.map → SavedBlocksPickBar-Cl6PLwwV.js.map} +1 -1
- package/dist/cdn/chunks/{TemplateScoringPanel-DuQJBykq.js → TemplateScoringPanel--JxR6CsQ.js} +6 -6
- package/dist/cdn/chunks/{TemplateScoringPanel-DuQJBykq.js.map → TemplateScoringPanel--JxR6CsQ.js.map} +1 -1
- package/dist/cdn/chunks/TemplateSettings-DjXiiiNr.js +207 -0
- package/dist/cdn/chunks/TemplateSettings-DjXiiiNr.js.map +1 -0
- package/dist/cdn/chunks/{TestEmailModal-D6Woss3r.js → TestEmailModal-BAuDxJtD.js} +9 -9
- package/dist/cdn/chunks/{TestEmailModal-D6Woss3r.js.map → TestEmailModal-BAuDxJtD.js.map} +1 -1
- package/dist/cdn/chunks/{TestEmailPanel-CWQFB7J3.js → TestEmailPanel-GUGZisLp.js} +3 -3
- package/dist/cdn/chunks/{TestEmailPanel-CWQFB7J3.js.map → TestEmailPanel-GUGZisLp.js.map} +1 -1
- package/dist/cdn/chunks/{TitleEditor-CbY1tgSl.js → TitleEditor-uKu33Nwr.js} +12 -12
- package/dist/cdn/chunks/{TitleEditor-CbY1tgSl.js.map → TitleEditor-uKu33Nwr.js.map} +1 -1
- package/dist/cdn/chunks/ToggleSwitch-CDy8OfcB.js +104 -0
- package/dist/cdn/chunks/ToggleSwitch-CDy8OfcB.js.map +1 -0
- package/dist/cdn/chunks/Toolbar-dxDYwN5E.js +2385 -0
- package/dist/cdn/chunks/Toolbar-dxDYwN5E.js.map +1 -0
- package/dist/cdn/chunks/{TplModal-CGpp-d_r.js → TplModal-DuwS2ifK.js} +5 -5
- package/dist/cdn/chunks/{TplModal-CGpp-d_r.js.map → TplModal-DuwS2ifK.js.map} +1 -1
- package/dist/cdn/chunks/{VersionHistoryMenu-ByVJXDbK.js → VersionHistoryMenu-Dij1pTEb.js} +6 -6
- package/dist/cdn/chunks/{VersionHistoryMenu-ByVJXDbK.js.map → VersionHistoryMenu-Dij1pTEb.js.map} +1 -1
- package/dist/cdn/chunks/{VersionHistoryPanels-CQJ5OggF.js → VersionHistoryPanels-GeR6MStB.js} +3 -3
- package/dist/cdn/chunks/{VersionHistoryPanels-CQJ5OggF.js.map → VersionHistoryPanels-GeR6MStB.js.map} +1 -1
- package/dist/cdn/chunks/{VersionPreviewBanner-G4lLbfr8.js → VersionPreviewBanner-Df3FVlig.js} +4 -4
- package/dist/cdn/chunks/{VersionPreviewBanner-G4lLbfr8.js.map → VersionPreviewBanner-Df3FVlig.js.map} +1 -1
- package/dist/cdn/chunks/{blockTypeIcons-CQY-vxdM.js → blockTypeIcons-raBjStuv.js} +2 -2
- package/dist/cdn/chunks/{blockTypeIcons-CQY-vxdM.js.map → blockTypeIcons-raBjStuv.js.map} +1 -1
- package/dist/cdn/chunks/{ca-Jx2CDwtn.js → ca-BTf1Zbqb.js} +10 -1
- package/dist/cdn/chunks/{ca-Jx2CDwtn.js.map → ca-BTf1Zbqb.js.map} +1 -1
- package/dist/cdn/chunks/{cloud-BLgCKP7Z.js → cloud-eaXyxZ8l.js} +2 -2
- package/dist/cdn/chunks/{cloud-BLgCKP7Z.js.map → cloud-eaXyxZ8l.js.map} +1 -1
- package/dist/cdn/chunks/{createCloudRuntime-ClvtMBF1.js → createCloudRuntime-D5bXzcTe.js} +6 -6
- package/dist/cdn/chunks/{createCloudRuntime-ClvtMBF1.js.map → createCloudRuntime-D5bXzcTe.js.map} +1 -1
- package/dist/{de-Ck0pBGHu.js → cdn/chunks/de-xzrh9PA3.js} +11 -0
- package/dist/cdn/chunks/{de-Ck0pBGHu.js.map → de-xzrh9PA3.js.map} +1 -1
- package/dist/cdn/chunks/{dist-BW6Y49zE.js → dist-BRZhN8qJ.js} +4 -4
- package/dist/cdn/chunks/dist-BRZhN8qJ.js.map +1 -0
- package/dist/cdn/chunks/{dist-CAFTQ6Y2.js → dist-CXB2_kBa.js} +27 -22
- package/dist/cdn/chunks/dist-CXB2_kBa.js.map +1 -0
- package/dist/cdn/chunks/{draggable-kbOhCgnk.js → draggable-IB4x6w2O.js} +1477 -1470
- package/dist/cdn/chunks/draggable-IB4x6w2O.js.map +1 -0
- package/dist/cdn/chunks/editor-modal-C-yBlj2C.js +2700 -0
- package/dist/cdn/chunks/editor-modal-C-yBlj2C.js.map +1 -0
- package/dist/cdn/chunks/en-DYtFUE2l.js +2 -0
- package/dist/cdn/chunks/{es-lagTvUfX.js → es-BT4LSpE2.js} +10 -1
- package/dist/cdn/chunks/{es-lagTvUfX.js.map → es-BT4LSpE2.js.map} +1 -1
- package/dist/cdn/chunks/{extensions-D2YIhF7u.js → extensions-Bhu8UEE5.js} +105 -45
- package/dist/cdn/chunks/extensions-Bhu8UEE5.js.map +1 -0
- package/dist/cdn/chunks/{fr-C4hVl5Lk.js → fr-CI7OJoql.js} +10 -1
- package/dist/cdn/chunks/{fr-C4hVl5Lk.js.map → fr-CI7OJoql.js.map} +1 -1
- package/dist/cdn/chunks/{icons-DdrAicM2.js → icons-BKkJ-5xF.js} +43 -43
- package/dist/cdn/chunks/{icons-DdrAicM2.js.map → icons-BKkJ-5xF.js.map} +1 -1
- package/dist/cdn/chunks/{keys-DXYJTLZF.js → keys-dJbD1QPs.js} +2 -2
- package/dist/cdn/chunks/{keys-DXYJTLZF.js.map → keys-dJbD1QPs.js.map} +1 -1
- package/dist/{nl-CReD7Apd.js → cdn/chunks/nl-D8y5OWGB.js} +11 -0
- package/dist/cdn/chunks/{nl-CReD7Apd.js.map → nl-D8y5OWGB.js.map} +1 -1
- package/dist/cdn/chunks/{pt-BR-BRA0-vGP.js → pt-BR-DMCbUBvJ.js} +10 -1
- package/dist/cdn/chunks/{pt-BR-BRA0-vGP.js.map → pt-BR-DMCbUBvJ.js.map} +1 -1
- package/dist/cdn/chunks/socialIcons-9VrG8X3m.js +1054 -0
- package/dist/cdn/chunks/socialIcons-9VrG8X3m.js.map +1 -0
- package/dist/cdn/chunks/{src-fn7uy1FD.js → src-O5Sp_qJ7.js} +3 -3
- package/dist/cdn/chunks/{src-fn7uy1FD.js.map → src-O5Sp_qJ7.js.map} +1 -1
- package/dist/cdn/chunks/templateSettingsFields-YCFVBVYh.js +36 -0
- package/dist/cdn/chunks/templateSettingsFields-YCFVBVYh.js.map +1 -0
- package/dist/cdn/chunks/{tiptap-Epe8m3Vo.js → tiptap-DhLuKyDc.js} +2776 -2773
- package/dist/cdn/chunks/tiptap-DhLuKyDc.js.map +1 -0
- package/dist/cdn/chunks/{useAliveFlag-CT9gjvO_.js → useAliveFlag-DAlQLbM2.js} +2 -2
- package/dist/cdn/chunks/{useAliveFlag-CT9gjvO_.js.map → useAliveFlag-DAlQLbM2.js.map} +1 -1
- package/dist/cdn/chunks/{useCloudI18n-OezCj0cx.js → useCloudI18n-C09JcFS0.js} +3 -3
- package/dist/cdn/chunks/{useCloudI18n-OezCj0cx.js.map → useCloudI18n-C09JcFS0.js.map} +1 -1
- package/dist/cdn/chunks/useEditorCore-BHmIp1hW.js +2592 -0
- package/dist/cdn/chunks/useEditorCore-BHmIp1hW.js.map +1 -0
- package/dist/cdn/chunks/useEditorRoot-DFx2fXJP.js +10 -0
- package/dist/cdn/chunks/{useEditorRoot-ByHPMqYT.js.map → useEditorRoot-DFx2fXJP.js.map} +1 -1
- package/dist/cdn/chunks/{useI18n-BhE7ndNr.js → useI18n-DTZ9sIcv.js} +3 -3
- package/dist/cdn/chunks/{useI18n-BhE7ndNr.js.map → useI18n-DTZ9sIcv.js.map} +1 -1
- package/dist/cdn/chunks/useLogicTag-E2V0Xdcb.js +38 -0
- package/dist/cdn/chunks/useLogicTag-E2V0Xdcb.js.map +1 -0
- package/dist/cdn/chunks/{useMergeTag-DE2mpy1w.js → useMergeTag-BE8oDoha.js} +3 -3
- package/dist/cdn/chunks/{useMergeTag-DE2mpy1w.js.map → useMergeTag-BE8oDoha.js.map} +1 -1
- package/dist/cdn/chunks/{usePopoverPosition-BPL891uG.js → usePopoverPosition-gB9q-ql7.js} +3 -3
- package/dist/cdn/chunks/{usePopoverPosition-BPL891uG.js.map → usePopoverPosition-gB9q-ql7.js.map} +1 -1
- package/dist/cdn/chunks/{useScrollToBlock-DwF4pVur.js → useScrollToBlock-CtTXwmiU.js} +3 -3
- package/dist/cdn/chunks/{useScrollToBlock-DwF4pVur.js.map → useScrollToBlock-CtTXwmiU.js.map} +1 -1
- package/dist/cdn/editor.css +1 -1
- package/dist/cdn/editor.js +809 -3337
- package/dist/cdn/editor.js.map +1 -1
- package/dist/{check-9xX6RVHz.js → check-eqb2JhqU.js} +1 -1
- package/dist/{chevron-down-J5hFJ6TL.js → chevron-down-Dkr-7Ywl.js} +1 -1
- package/dist/{chevron-right-BJuo5PQ-.js → chevron-right-Bge4XF_B.js} +1 -1
- package/dist/{chevron-up-Qfi5k52_.js → chevron-up-CQAyl0kC.js} +1 -1
- package/dist/{circle-alert-BiArYmkB.js → circle-alert-CYgTHKWr.js} +1 -1
- package/dist/{clock-BkYJZ7Y0.js → clock-BgSJZJP5.js} +1 -1
- package/dist/{cloud-DdidMW6f.js → cloud-C9xWZXhg.js} +1 -1
- package/dist/{copy-BRLUNHwF.js → copy-mw6PVnOJ.js} +1 -1
- package/dist/{createCloudRuntime-CNFXaTNQ.js → createCloudRuntime-BGd5--Bq.js} +5 -5
- package/dist/{createLucideIcon-CDDkF1Tm.js → createLucideIcon-BxY5yz5u.js} +6 -6
- package/dist/{cdn/chunks/de-Ck0pBGHu.js → de-xzrh9PA3.js} +9 -2
- package/dist/{dist-D8i1ixHK.js → dist-8VFzbeu9.js} +3 -3
- package/dist/{dist-DBirAJIs.js → dist-BDuPwOyn.js} +26 -21
- package/dist/{dist-CtF9STPS.js → dist-BJM3eFyT.js} +1 -1
- package/dist/{dist-DkcA6epL.js → dist-BdHF7nyq.js} +3 -3
- package/dist/{dist-ByT5fgKq.js → dist-Bl4rxpX9.js} +1 -1
- package/dist/{dist-BVqAYoRB.js → dist-BmsLcnrO.js} +4 -4
- package/dist/{dist-CtMXAH7a.js → dist-BxVnMgXZ.js} +1 -1
- package/dist/{dist-DC-3T0ED.js → dist-CQSVro7b.js} +1 -1
- package/dist/{dist-f7HXo6j6.js → dist-DQbOebGW.js} +1 -1
- package/dist/{dist-DL9334yz.js → dist-DerFNpDY.js} +3 -3
- package/dist/{dist-D08oVYhr.js → dist-Djmzp6wi.js} +1 -1
- package/dist/{dist-D7WY8VPq.js → dist-DyrEOKEJ.js} +1 -1
- package/dist/{dist-DzdeVn-W.js → dist-EDkj3Ub1.js} +1 -1
- package/dist/{dist-C1tsW_99.js → dist-wyXxj3R1.js} +1 -1
- package/dist/editor-modal-oD1qNz_P.js +2773 -0
- package/dist/en-CM5fTFSo.js +2 -0
- package/dist/{es-lagTvUfX.js → es-BT4LSpE2.js} +9 -0
- package/dist/extensions-DRN-elXT.js +1645 -0
- package/dist/{eye-DwhBOaV8.js → eye-DphkRtAD.js} +1 -1
- package/dist/{fr-C4hVl5Lk.js → fr-CI7OJoql.js} +9 -0
- package/dist/{image-up-CiyQNZBt.js → image-up-Qi2BXD7T.js} +1 -1
- package/dist/{info-D6A1qEiF.js → info-VSyAs02q.js} +1 -1
- package/dist/{keys-DD1rl72F.js → keys-BdoSgsz9.js} +1 -1
- package/dist/{link-tKGmYWsB.js → link-CNuozGqD.js} +1 -1
- package/dist/{list-DjZQRpeI.js → list-BA0I5Wmu.js} +1 -1
- package/dist/{loader-circle-D9ZL3Sv0.js → loader-circle-z5eeqasv.js} +1 -1
- package/dist/{message-circle-KTHxCcpB.js → message-circle-BsQ9hEup.js} +1 -1
- package/dist/{cdn/chunks/nl-CReD7Apd.js → nl-D8y5OWGB.js} +9 -2
- package/dist/package-OkXfuRoO.js +25 -0
- package/dist/{pencil-Bq-nbQ7F.js → pencil-DFVFA7Dj.js} +1 -1
- package/dist/{plus-CRMnR4IG.js → plus-D8bkVjZ7.js} +1 -1
- package/dist/{pt-BR-BRA0-vGP.js → pt-BR-DMCbUBvJ.js} +9 -0
- package/dist/{refresh-cw-D7bYS5tm.js → refresh-cw-DPB7YFuz.js} +1 -1
- package/dist/{runtime-dom.esm-bundler-PnoZU512.js → runtime-dom.esm-bundler-BGbPz4-g.js} +2 -2
- package/dist/{search-DUo0YwPz.js → search-C-dCgqIa.js} +1 -1
- package/dist/{send-DaVMQphu.js → send-Cm2fy2zm.js} +1 -1
- package/dist/{shield-check-DxaaurL9.js → shield-check-COgBYFDF.js} +1 -1
- package/dist/smartphone-v0u_MOEV.js +46 -0
- package/dist/socialIcons-DkGcpEwC.js +1130 -0
- package/dist/{sparkles-D6T6k30e.js → sparkles-Ds0RF8Iu.js} +1 -1
- package/dist/style.css +1 -1
- package/dist/templateSettingsFields-YCFVBVYh.js +34 -0
- package/dist/templatical-editor.js +895 -3498
- package/dist/{text-align-start-vreFpmCX.js → text-align-start-DiavaIm6.js} +1 -1
- package/dist/{trash-DBv8MGY6.js → trash-DnOkfu2V.js} +1 -1
- package/dist/{triangle-alert-CmNS2LLv.js → triangle-alert-DGLAyXnh.js} +1 -1
- package/dist/{upload-DDB9Fs0P.js → upload-BBDme2cy.js} +1 -1
- package/dist/{useAliveFlag-oyByIcjy.js → useAliveFlag-BkKyhkwZ.js} +1 -1
- package/dist/{useCloudI18n-C1wuXik6.js → useCloudI18n-D1iedlP3.js} +2 -2
- package/dist/{useEditorCore-jfwgLThK.js → useEditorCore-C5APBjjV.js} +1140 -2325
- package/dist/{useEditorRoot-eVv4doqZ.js → useEditorRoot-BOxn5EfP.js} +2 -2
- package/dist/{useI18n-VOtdfENx.js → useI18n-Ds_-druD.js} +2 -2
- package/dist/useLogicTag-DoHfc08B.js +36 -0
- package/dist/{useMergeTag-CQM9pFca.js → useMergeTag-DXyum3kG.js} +2 -2
- package/dist/{usePopoverPosition-gZjRywai.js → usePopoverPosition-Du-Ah8E9.js} +2 -2
- package/dist/{useScrollToBlock-C0Ehnyl4.js → useScrollToBlock-DXQYPCnJ.js} +3 -3
- package/dist/{vue.runtime.esm-bundler-DShF3P6k.js → vue.runtime.esm-bundler-CyqhBwpY.js} +1133 -1126
- package/dist/{x-B7sgO_z8.js → x-3BHV3Q6K.js} +1 -1
- package/package.json +14 -14
- package/dist/ColorPicker-BTtN94te.js +0 -501
- package/dist/FieldRow-C8nOknr_.js +0 -128
- package/dist/MergeTagInput-Cw1RoMly.js +0 -509
- package/dist/MergeTagSuggestion-BXO3UIXW.js +0 -1329
- package/dist/cdn/chunks/ColorPicker-BaonTCAQ.js +0 -502
- package/dist/cdn/chunks/ColorPicker-BaonTCAQ.js.map +0 -1
- package/dist/cdn/chunks/FieldRow-D9OJhYeb.js +0 -130
- package/dist/cdn/chunks/FieldRow-D9OJhYeb.js.map +0 -1
- package/dist/cdn/chunks/MergeTagInput-CSIThqkz.js +0 -470
- package/dist/cdn/chunks/MergeTagInput-CSIThqkz.js.map +0 -1
- package/dist/cdn/chunks/MergeTagSuggestion-CY6WK8Eb.js +0 -215
- package/dist/cdn/chunks/MergeTagSuggestion-CY6WK8Eb.js.map +0 -1
- package/dist/cdn/chunks/dist-BW6Y49zE.js.map +0 -1
- package/dist/cdn/chunks/dist-CAFTQ6Y2.js.map +0 -1
- package/dist/cdn/chunks/draggable-kbOhCgnk.js.map +0 -1
- package/dist/cdn/chunks/editor-modal-B6IdQWlf.js +0 -5908
- package/dist/cdn/chunks/editor-modal-B6IdQWlf.js.map +0 -1
- package/dist/cdn/chunks/en-DjunooBz.js +0 -2
- package/dist/cdn/chunks/extensions-D2YIhF7u.js.map +0 -1
- package/dist/cdn/chunks/tiptap-Epe8m3Vo.js.map +0 -1
- package/dist/cdn/chunks/useEditorCore-06PtcUi1.js +0 -3698
- package/dist/cdn/chunks/useEditorCore-06PtcUi1.js.map +0 -1
- package/dist/cdn/chunks/useEditorRoot-ByHPMqYT.js +0 -10
- package/dist/editor-modal-uAEB6xKz.js +0 -5998
- package/dist/en-CQWkDCpm.js +0 -2
- package/dist/extensions-CcGj7OfS.js +0 -470
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TemplateScoringPanel-DuQJBykq.js","names":[],"sources":["../../../src/cloud/utils/scoringStyles.ts","../../../src/cloud/components/TemplateScoringPanel.vue","../../../src/cloud/components/TemplateScoringPanel.vue"],"sourcesContent":["export type ScoringSeverity = \"high\" | \"medium\" | \"low\" | string;\n\nexport function scoreColor(score: number): string {\n if (score >= 80) return \"var(--tpl-success)\";\n if (score >= 60) return \"var(--tpl-warning)\";\n return \"var(--tpl-danger)\";\n}\n\nexport function scoreBgColor(score: number): string {\n if (score >= 80) return \"var(--tpl-success-light)\";\n if (score >= 60) return \"var(--tpl-warning-light)\";\n return \"var(--tpl-danger-light)\";\n}\n\nexport function severityColor(severity: ScoringSeverity): string {\n if (severity === \"high\") return \"var(--tpl-danger)\";\n if (severity === \"medium\") return \"var(--tpl-warning)\";\n return \"var(--tpl-text-muted)\";\n}\n\nexport function severityBgColor(severity: ScoringSeverity): string {\n if (severity === \"high\") return \"var(--tpl-danger-light)\";\n if (severity === \"medium\") return \"var(--tpl-warning-light)\";\n return \"var(--tpl-bg-hover)\";\n}\n","<script setup lang=\"ts\">\nimport LoadingTrack from \"../../components/LoadingTrack.vue\";\nimport {\n EDITOR_KEY,\n SCORING_KEY,\n MERGE_TAGS_KEY,\n NO_MERGE_TAGS,\n requireInject,\n} from \"../../keys\";\nimport {\n scoreColor,\n scoreBgColor,\n severityColor,\n severityBgColor,\n} from \"../utils/scoringStyles\";\nimport { useCloudI18nStrict } from \"../../composables/useCloudI18n\";\nimport type { ScoringCategory, ScoringFinding } from \"@templatical/types\";\nimport {\n CircleAlert,\n TriangleAlert,\n ChevronDown,\n Eye,\n Info,\n LoaderCircle,\n RefreshCw,\n ShieldCheck,\n ShieldX,\n Sparkles,\n X,\n Zap,\n} from \"@lucide/vue\";\nimport { inject, ref, watch } from \"vue\";\n\nconst props = defineProps<{\n visible: boolean;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n}>();\n\nconst { t: cloudT } = useCloudI18nStrict();\nconst editor = requireInject(EDITOR_KEY, \"TemplateScoringPanel\");\nconst scoring = requireInject(SCORING_KEY, \"TemplateScoringPanel\");\nconst mergeTags = inject(MERGE_TAGS_KEY, NO_MERGE_TAGS);\n\nconst expandedCategories = ref<Record<string, boolean>>({\n spam: true,\n readability: true,\n accessibility: true,\n bestPractices: true,\n});\n\nfunction toggleCategory(category: string): void {\n expandedCategories.value[category] = !expandedCategories.value[category];\n}\n\nconst categoryOrder: ScoringCategory[] = [\n \"spam\",\n \"readability\",\n \"accessibility\",\n \"bestPractices\",\n];\n\nconst categoryIcons: Record<ScoringCategory, typeof ShieldCheck> = {\n spam: ShieldX,\n readability: Eye,\n accessibility: Sparkles,\n bestPractices: Zap,\n};\n\nfunction triggerScore(): void {\n scoring.score(editor.content.value, mergeTags.value);\n}\n\nwatch(\n () => props.visible,\n (isVisible) => {\n if (isVisible && !scoring.scoringResult.value && !scoring.isScoring.value) {\n triggerScore();\n }\n },\n);\n\nasync function handleFix(finding: ScoringFinding): Promise<void> {\n if (!finding.blockId) {\n return;\n }\n\n // Get the block content from the editor\n const block = editor.content.value.blocks.find(\n (b) => b.id === finding.blockId,\n );\n if (!block) {\n return;\n }\n\n // Extract HTML content from the block (text blocks have content property)\n const blockContent = (block as unknown as Record<string, unknown>).content as\n string | undefined;\n if (!blockContent) {\n return;\n }\n\n const fixedContent = await scoring.fixFinding(\n blockContent,\n finding,\n mergeTags.value,\n );\n\n if (fixedContent) {\n editor.updateBlock(finding.blockId, { content: fixedContent });\n scoring.removeFinding(finding.category, finding.id);\n }\n}\n\nfunction totalFindings(): number {\n if (!scoring.scoringResult.value) {\n return 0;\n }\n return categoryOrder.reduce((sum, cat) => {\n return (\n sum + (scoring.scoringResult.value?.categories[cat]?.findings.length ?? 0)\n );\n }, 0);\n}\n</script>\n\n<template>\n <Transition\n enter-active-class=\"tpl-scoring-slide-enter-active\"\n enter-from-class=\"tpl:translate-x-full\"\n enter-to-class=\"tpl:translate-x-0\"\n leave-active-class=\"tpl-scoring-slide-leave-active\"\n leave-from-class=\"tpl:translate-x-0\"\n leave-to-class=\"tpl:translate-x-full\"\n >\n <div\n v-if=\"visible\"\n class=\"tpl-scoring-panel tpl:absolute tpl:top-14 tpl:right-0 tpl:bottom-0 tpl:flex tpl:w-[360px] tpl:flex-col tpl:border-l tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg-elevated)]\"\n >\n <!-- Header -->\n <div\n class=\"tpl:flex tpl:items-center tpl:justify-between tpl:border-b tpl:border-[var(--tpl-border)] tpl:px-4 tpl:py-3\"\n >\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-primary)]\"\n >\n <ShieldCheck :size=\"13\" :stroke-width=\"2\" />\n <span>{{ cloudT.scoring.title }}</span>\n </div>\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <button\n v-if=\"scoring.scoringResult.value && !scoring.isScoring.value\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :title=\"cloudT.scoring.rescore\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"14\" :stroke-width=\"2\" />\n </button>\n <button\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n @click=\"emit('close')\"\n >\n <X :size=\"14\" :stroke-width=\"2\" />\n </button>\n </div>\n </div>\n\n <!-- Content -->\n <div class=\"tpl:flex-1 tpl:overflow-y-auto tpl:p-4\">\n <!-- Loading state -->\n <div\n v-if=\"scoring.isScoring.value\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <p class=\"tpl:text-sm tpl:text-[var(--tpl-text-muted)]\">\n {{ cloudT.scoring.scoring }}\n </p>\n <LoadingTrack class=\"tpl:w-3/4\" />\n </div>\n\n <!-- Error state -->\n <div\n v-else-if=\"scoring.error.value && !scoring.scoringResult.value\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <CircleAlert\n :size=\"32\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-danger)]\"\n />\n <p\n class=\"tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.error }}\n </p>\n <button\n class=\"tpl:mt-2 tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-md tpl:border tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:transition-all tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-text-muted)]\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"12\" :stroke-width=\"2\" />\n {{ cloudT.scoring.rescore }}\n </button>\n </div>\n\n <!-- Results -->\n <div\n v-else-if=\"scoring.scoringResult.value\"\n class=\"tpl:flex tpl:flex-col tpl:gap-4\"\n >\n <!-- Overall score -->\n <div\n class=\"tpl:flex tpl:flex-col tpl:items-center tpl:gap-2 tpl:rounded-[var(--tpl-radius)] tpl:p-5\"\n :style=\"{\n backgroundColor: scoreBgColor(scoring.scoringResult.value.score),\n }\"\n >\n <span\n class=\"tpl:text-4xl tpl:font-bold tpl:tabular-nums\"\n :style=\"{\n color: scoreColor(scoring.scoringResult.value.score),\n }\"\n >\n {{ scoring.scoringResult.value.score }}\n </span>\n <span\n class=\"tpl:text-xs tpl:font-medium tpl:uppercase tpl:tracking-wider tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.overallScore }}\n </span>\n <span\n v-if=\"totalFindings() > 0\"\n class=\"tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ totalFindings() }}\n {{ cloudT.scoring.findings }}\n </span>\n </div>\n\n <!-- Fix error -->\n <div\n v-if=\"scoring.fixError.value\"\n class=\"tpl:flex tpl:items-start tpl:gap-2 tpl:rounded-lg tpl:px-3 tpl:py-2 tpl:text-xs tpl:bg-[var(--tpl-danger-light)] tpl:text-[var(--tpl-danger)]\"\n >\n <CircleAlert\n :size=\"14\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n />\n <span>{{ cloudT.scoring.fixError }}</span>\n </div>\n\n <!-- Category cards -->\n <div\n v-for=\"category in categoryOrder\"\n :key=\"category\"\n class=\"tpl:overflow-hidden tpl:rounded-[var(--tpl-radius)] tpl:border tpl:border-[var(--tpl-border)]\"\n >\n <!-- Category header -->\n <button\n class=\"tpl:flex tpl:w-full tpl:cursor-pointer tpl:items-center tpl:gap-2.5 tpl:px-3 tpl:py-2.5 tpl:text-left tpl:transition-colors tpl:bg-[var(--tpl-bg)]\"\n @click=\"toggleCategory(category)\"\n >\n <component\n :is=\"categoryIcons[category]\"\n :size=\"14\"\n :stroke-width=\"2\"\n :style=\"{\n color: scoreColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n }\"\n />\n <span\n class=\"tpl:flex-1 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)]\"\n >\n {{ cloudT.scoring.categories[category] }}\n </span>\n <span\n class=\"tpl:rounded-full tpl:px-2 tpl:py-0.5 tpl:text-xs tpl:font-semibold tpl:tabular-nums\"\n :style=\"{\n color: scoreColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n backgroundColor: scoreBgColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n }\"\n >\n {{ scoring.scoringResult.value.categories[category].score }}\n </span>\n <span\n v-if=\"\n scoring.scoringResult.value.categories[category].findings\n .length > 0\n \"\n class=\"tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{\n scoring.scoringResult.value.categories[category].findings\n .length\n }}\n </span>\n <ChevronDown\n :size=\"12\"\n :stroke-width=\"2\"\n class=\"tpl:transition-transform tpl:duration-200 tpl:text-[var(--tpl-text-dim)]\"\n :class=\"\n expandedCategories[category]\n ? 'tpl:rotate-0'\n : 'tpl:-rotate-90'\n \"\n />\n </button>\n\n <!-- Findings list -->\n <div\n v-if=\"expandedCategories[category]\"\n class=\"tpl:border-t tpl:border-[var(--tpl-border)]\"\n >\n <div\n v-if=\"\n scoring.scoringResult.value.categories[category].findings\n .length === 0\n \"\n class=\"tpl:px-3 tpl:py-3 tpl:text-center tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.scoring.noFindings }}\n </div>\n <div\n v-for=\"finding in scoring.scoringResult.value.categories[\n category\n ].findings\"\n :key=\"finding.id\"\n class=\"tpl:border-t tpl:px-3 tpl:py-2.5 tpl:first:border-t-0 tpl:border-[var(--tpl-border-light)]\"\n >\n <div class=\"tpl:flex tpl:items-start tpl:gap-2\">\n <!-- Severity icon -->\n <component\n :is=\"\n finding.severity === 'high'\n ? CircleAlert\n : finding.severity === 'medium'\n ? TriangleAlert\n : Info\n \"\n :size=\"13\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n :style=\"{\n color: severityColor(finding.severity),\n }\"\n />\n <div class=\"tpl:flex-1 tpl:min-w-0\">\n <!-- Severity badge + message -->\n <div class=\"tpl:flex tpl:items-start tpl:gap-1.5\">\n <span\n class=\"tpl:mt-0.5 tpl:shrink-0 tpl:rounded tpl:px-1 tpl:py-px tpl:text-[10px] tpl:font-medium tpl:leading-tight\"\n :style=\"{\n color: severityColor(finding.severity),\n backgroundColor: severityBgColor(finding.severity),\n }\"\n >\n {{ cloudT.scoring.severity[finding.severity] }}\n </span>\n <span\n class=\"tpl:text-xs tpl:leading-snug tpl:text-[var(--tpl-text)]\"\n >\n {{ finding.message }}\n </span>\n </div>\n <!-- Suggestion -->\n <p\n v-if=\"finding.suggestion\"\n class=\"tpl:mt-1 tpl:text-[11px] tpl:leading-snug tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ finding.suggestion }}\n </p>\n <!-- Fix button -->\n <div\n v-if=\"finding.blockId\"\n class=\"tpl:mt-2 tpl:flex tpl:justify-center\"\n >\n <button\n class=\"tpl-scoring-fix-btn tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded tpl:border tpl:px-3 tpl:py-1.5 tpl:text-[11px] tpl:font-medium tpl:transition-all tpl:disabled:opacity-50 tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-primary)]\"\n style=\"background-color: transparent\"\n :disabled=\"scoring.fixingFindingId.value !== null\"\n @click=\"handleFix(finding)\"\n >\n <LoaderCircle\n v-if=\"scoring.fixingFindingId.value === finding.id\"\n class=\"tpl-spinner\"\n :size=\"11\"\n :stroke-width=\"2\"\n />\n <Sparkles v-else :size=\"11\" :stroke-width=\"2\" />\n {{\n scoring.fixingFindingId.value === finding.id\n ? cloudT.scoring.fixing\n : cloudT.scoring.fix\n }}\n </button>\n <p\n v-if=\"scoring.fixError.value\"\n class=\"tpl:mt-1.5 tpl:text-[11px] tpl:text-[var(--tpl-danger)]\"\n >\n {{ scoring.fixError.value }}\n </p>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Empty state (no result, no loading, no error) -->\n <div\n v-else\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <ShieldCheck\n :size=\"32\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <p\n class=\"tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.emptyState }}\n </p>\n </div>\n\n <!-- AI disclaimer -->\n <p\n class=\"tpl:m-0 tpl:px-4 tpl:pb-2 tpl:pt-2 tpl:text-center tpl:text-[11px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.aiMenu.disclaimer }}\n </p>\n </div>\n </div>\n </Transition>\n</template>\n\n<style scoped>\n.tpl-scoring-slide-enter-active {\n transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-scoring-slide-leave-active {\n transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-scoring-fix-btn:not(:disabled):hover {\n border-color: var(--tpl-primary) !important;\n background-color: var(--tpl-primary-light) !important;\n}\n</style>\n","<script setup lang=\"ts\">\nimport LoadingTrack from \"../../components/LoadingTrack.vue\";\nimport {\n EDITOR_KEY,\n SCORING_KEY,\n MERGE_TAGS_KEY,\n NO_MERGE_TAGS,\n requireInject,\n} from \"../../keys\";\nimport {\n scoreColor,\n scoreBgColor,\n severityColor,\n severityBgColor,\n} from \"../utils/scoringStyles\";\nimport { useCloudI18nStrict } from \"../../composables/useCloudI18n\";\nimport type { ScoringCategory, ScoringFinding } from \"@templatical/types\";\nimport {\n CircleAlert,\n TriangleAlert,\n ChevronDown,\n Eye,\n Info,\n LoaderCircle,\n RefreshCw,\n ShieldCheck,\n ShieldX,\n Sparkles,\n X,\n Zap,\n} from \"@lucide/vue\";\nimport { inject, ref, watch } from \"vue\";\n\nconst props = defineProps<{\n visible: boolean;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n}>();\n\nconst { t: cloudT } = useCloudI18nStrict();\nconst editor = requireInject(EDITOR_KEY, \"TemplateScoringPanel\");\nconst scoring = requireInject(SCORING_KEY, \"TemplateScoringPanel\");\nconst mergeTags = inject(MERGE_TAGS_KEY, NO_MERGE_TAGS);\n\nconst expandedCategories = ref<Record<string, boolean>>({\n spam: true,\n readability: true,\n accessibility: true,\n bestPractices: true,\n});\n\nfunction toggleCategory(category: string): void {\n expandedCategories.value[category] = !expandedCategories.value[category];\n}\n\nconst categoryOrder: ScoringCategory[] = [\n \"spam\",\n \"readability\",\n \"accessibility\",\n \"bestPractices\",\n];\n\nconst categoryIcons: Record<ScoringCategory, typeof ShieldCheck> = {\n spam: ShieldX,\n readability: Eye,\n accessibility: Sparkles,\n bestPractices: Zap,\n};\n\nfunction triggerScore(): void {\n scoring.score(editor.content.value, mergeTags.value);\n}\n\nwatch(\n () => props.visible,\n (isVisible) => {\n if (isVisible && !scoring.scoringResult.value && !scoring.isScoring.value) {\n triggerScore();\n }\n },\n);\n\nasync function handleFix(finding: ScoringFinding): Promise<void> {\n if (!finding.blockId) {\n return;\n }\n\n // Get the block content from the editor\n const block = editor.content.value.blocks.find(\n (b) => b.id === finding.blockId,\n );\n if (!block) {\n return;\n }\n\n // Extract HTML content from the block (text blocks have content property)\n const blockContent = (block as unknown as Record<string, unknown>).content as\n string | undefined;\n if (!blockContent) {\n return;\n }\n\n const fixedContent = await scoring.fixFinding(\n blockContent,\n finding,\n mergeTags.value,\n );\n\n if (fixedContent) {\n editor.updateBlock(finding.blockId, { content: fixedContent });\n scoring.removeFinding(finding.category, finding.id);\n }\n}\n\nfunction totalFindings(): number {\n if (!scoring.scoringResult.value) {\n return 0;\n }\n return categoryOrder.reduce((sum, cat) => {\n return (\n sum + (scoring.scoringResult.value?.categories[cat]?.findings.length ?? 0)\n );\n }, 0);\n}\n</script>\n\n<template>\n <Transition\n enter-active-class=\"tpl-scoring-slide-enter-active\"\n enter-from-class=\"tpl:translate-x-full\"\n enter-to-class=\"tpl:translate-x-0\"\n leave-active-class=\"tpl-scoring-slide-leave-active\"\n leave-from-class=\"tpl:translate-x-0\"\n leave-to-class=\"tpl:translate-x-full\"\n >\n <div\n v-if=\"visible\"\n class=\"tpl-scoring-panel tpl:absolute tpl:top-14 tpl:right-0 tpl:bottom-0 tpl:flex tpl:w-[360px] tpl:flex-col tpl:border-l tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg-elevated)]\"\n >\n <!-- Header -->\n <div\n class=\"tpl:flex tpl:items-center tpl:justify-between tpl:border-b tpl:border-[var(--tpl-border)] tpl:px-4 tpl:py-3\"\n >\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-primary)]\"\n >\n <ShieldCheck :size=\"13\" :stroke-width=\"2\" />\n <span>{{ cloudT.scoring.title }}</span>\n </div>\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <button\n v-if=\"scoring.scoringResult.value && !scoring.isScoring.value\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :title=\"cloudT.scoring.rescore\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"14\" :stroke-width=\"2\" />\n </button>\n <button\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n @click=\"emit('close')\"\n >\n <X :size=\"14\" :stroke-width=\"2\" />\n </button>\n </div>\n </div>\n\n <!-- Content -->\n <div class=\"tpl:flex-1 tpl:overflow-y-auto tpl:p-4\">\n <!-- Loading state -->\n <div\n v-if=\"scoring.isScoring.value\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <p class=\"tpl:text-sm tpl:text-[var(--tpl-text-muted)]\">\n {{ cloudT.scoring.scoring }}\n </p>\n <LoadingTrack class=\"tpl:w-3/4\" />\n </div>\n\n <!-- Error state -->\n <div\n v-else-if=\"scoring.error.value && !scoring.scoringResult.value\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <CircleAlert\n :size=\"32\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-danger)]\"\n />\n <p\n class=\"tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.error }}\n </p>\n <button\n class=\"tpl:mt-2 tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-md tpl:border tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:transition-all tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-text-muted)]\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"12\" :stroke-width=\"2\" />\n {{ cloudT.scoring.rescore }}\n </button>\n </div>\n\n <!-- Results -->\n <div\n v-else-if=\"scoring.scoringResult.value\"\n class=\"tpl:flex tpl:flex-col tpl:gap-4\"\n >\n <!-- Overall score -->\n <div\n class=\"tpl:flex tpl:flex-col tpl:items-center tpl:gap-2 tpl:rounded-[var(--tpl-radius)] tpl:p-5\"\n :style=\"{\n backgroundColor: scoreBgColor(scoring.scoringResult.value.score),\n }\"\n >\n <span\n class=\"tpl:text-4xl tpl:font-bold tpl:tabular-nums\"\n :style=\"{\n color: scoreColor(scoring.scoringResult.value.score),\n }\"\n >\n {{ scoring.scoringResult.value.score }}\n </span>\n <span\n class=\"tpl:text-xs tpl:font-medium tpl:uppercase tpl:tracking-wider tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.overallScore }}\n </span>\n <span\n v-if=\"totalFindings() > 0\"\n class=\"tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ totalFindings() }}\n {{ cloudT.scoring.findings }}\n </span>\n </div>\n\n <!-- Fix error -->\n <div\n v-if=\"scoring.fixError.value\"\n class=\"tpl:flex tpl:items-start tpl:gap-2 tpl:rounded-lg tpl:px-3 tpl:py-2 tpl:text-xs tpl:bg-[var(--tpl-danger-light)] tpl:text-[var(--tpl-danger)]\"\n >\n <CircleAlert\n :size=\"14\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n />\n <span>{{ cloudT.scoring.fixError }}</span>\n </div>\n\n <!-- Category cards -->\n <div\n v-for=\"category in categoryOrder\"\n :key=\"category\"\n class=\"tpl:overflow-hidden tpl:rounded-[var(--tpl-radius)] tpl:border tpl:border-[var(--tpl-border)]\"\n >\n <!-- Category header -->\n <button\n class=\"tpl:flex tpl:w-full tpl:cursor-pointer tpl:items-center tpl:gap-2.5 tpl:px-3 tpl:py-2.5 tpl:text-left tpl:transition-colors tpl:bg-[var(--tpl-bg)]\"\n @click=\"toggleCategory(category)\"\n >\n <component\n :is=\"categoryIcons[category]\"\n :size=\"14\"\n :stroke-width=\"2\"\n :style=\"{\n color: scoreColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n }\"\n />\n <span\n class=\"tpl:flex-1 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)]\"\n >\n {{ cloudT.scoring.categories[category] }}\n </span>\n <span\n class=\"tpl:rounded-full tpl:px-2 tpl:py-0.5 tpl:text-xs tpl:font-semibold tpl:tabular-nums\"\n :style=\"{\n color: scoreColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n backgroundColor: scoreBgColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n }\"\n >\n {{ scoring.scoringResult.value.categories[category].score }}\n </span>\n <span\n v-if=\"\n scoring.scoringResult.value.categories[category].findings\n .length > 0\n \"\n class=\"tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{\n scoring.scoringResult.value.categories[category].findings\n .length\n }}\n </span>\n <ChevronDown\n :size=\"12\"\n :stroke-width=\"2\"\n class=\"tpl:transition-transform tpl:duration-200 tpl:text-[var(--tpl-text-dim)]\"\n :class=\"\n expandedCategories[category]\n ? 'tpl:rotate-0'\n : 'tpl:-rotate-90'\n \"\n />\n </button>\n\n <!-- Findings list -->\n <div\n v-if=\"expandedCategories[category]\"\n class=\"tpl:border-t tpl:border-[var(--tpl-border)]\"\n >\n <div\n v-if=\"\n scoring.scoringResult.value.categories[category].findings\n .length === 0\n \"\n class=\"tpl:px-3 tpl:py-3 tpl:text-center tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.scoring.noFindings }}\n </div>\n <div\n v-for=\"finding in scoring.scoringResult.value.categories[\n category\n ].findings\"\n :key=\"finding.id\"\n class=\"tpl:border-t tpl:px-3 tpl:py-2.5 tpl:first:border-t-0 tpl:border-[var(--tpl-border-light)]\"\n >\n <div class=\"tpl:flex tpl:items-start tpl:gap-2\">\n <!-- Severity icon -->\n <component\n :is=\"\n finding.severity === 'high'\n ? CircleAlert\n : finding.severity === 'medium'\n ? TriangleAlert\n : Info\n \"\n :size=\"13\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n :style=\"{\n color: severityColor(finding.severity),\n }\"\n />\n <div class=\"tpl:flex-1 tpl:min-w-0\">\n <!-- Severity badge + message -->\n <div class=\"tpl:flex tpl:items-start tpl:gap-1.5\">\n <span\n class=\"tpl:mt-0.5 tpl:shrink-0 tpl:rounded tpl:px-1 tpl:py-px tpl:text-[10px] tpl:font-medium tpl:leading-tight\"\n :style=\"{\n color: severityColor(finding.severity),\n backgroundColor: severityBgColor(finding.severity),\n }\"\n >\n {{ cloudT.scoring.severity[finding.severity] }}\n </span>\n <span\n class=\"tpl:text-xs tpl:leading-snug tpl:text-[var(--tpl-text)]\"\n >\n {{ finding.message }}\n </span>\n </div>\n <!-- Suggestion -->\n <p\n v-if=\"finding.suggestion\"\n class=\"tpl:mt-1 tpl:text-[11px] tpl:leading-snug tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ finding.suggestion }}\n </p>\n <!-- Fix button -->\n <div\n v-if=\"finding.blockId\"\n class=\"tpl:mt-2 tpl:flex tpl:justify-center\"\n >\n <button\n class=\"tpl-scoring-fix-btn tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded tpl:border tpl:px-3 tpl:py-1.5 tpl:text-[11px] tpl:font-medium tpl:transition-all tpl:disabled:opacity-50 tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-primary)]\"\n style=\"background-color: transparent\"\n :disabled=\"scoring.fixingFindingId.value !== null\"\n @click=\"handleFix(finding)\"\n >\n <LoaderCircle\n v-if=\"scoring.fixingFindingId.value === finding.id\"\n class=\"tpl-spinner\"\n :size=\"11\"\n :stroke-width=\"2\"\n />\n <Sparkles v-else :size=\"11\" :stroke-width=\"2\" />\n {{\n scoring.fixingFindingId.value === finding.id\n ? cloudT.scoring.fixing\n : cloudT.scoring.fix\n }}\n </button>\n <p\n v-if=\"scoring.fixError.value\"\n class=\"tpl:mt-1.5 tpl:text-[11px] tpl:text-[var(--tpl-danger)]\"\n >\n {{ scoring.fixError.value }}\n </p>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Empty state (no result, no loading, no error) -->\n <div\n v-else\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <ShieldCheck\n :size=\"32\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <p\n class=\"tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.emptyState }}\n </p>\n </div>\n\n <!-- AI disclaimer -->\n <p\n class=\"tpl:m-0 tpl:px-4 tpl:pb-2 tpl:pt-2 tpl:text-center tpl:text-[11px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.aiMenu.disclaimer }}\n </p>\n </div>\n </div>\n </Transition>\n</template>\n\n<style scoped>\n.tpl-scoring-slide-enter-active {\n transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-scoring-slide-leave-active {\n transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-scoring-fix-btn:not(:disabled):hover {\n border-color: var(--tpl-primary) !important;\n background-color: var(--tpl-primary-light) !important;\n}\n</style>\n"],"mappings":";;;;;;;AAEA,SAAgB,EAAW,GAAuB;CAGhD,OAFI,KAAS,KAAW,uBACpB,KAAS,KAAW,uBACjB;AACT;AAEA,SAAgB,EAAa,GAAuB;CAGlD,OAFI,KAAS,KAAW,6BACpB,KAAS,KAAW,6BACjB;AACT;AAEA,SAAgB,EAAc,GAAmC;CAG/D,OAFI,MAAa,SAAe,sBAC5B,MAAa,WAAiB,uBAC3B;AACT;AAEA,SAAgB,EAAgB,GAAmC;CAGjE,OAFI,MAAa,SAAe,4BAC5B,MAAa,WAAiB,6BAC3B;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECSA,IAAM,IAAQ,GAIR,KAAO,GAIP,EAAE,GAAG,MAAW,EAAmB,GACnC,IAAS,EAAc,IAAY,sBAAsB,GACzD,IAAU,EAAc,IAAa,sBAAsB,GAC3D,IAAY,EAAO,IAAgB,EAAa,GAEhD,IAAqB,GAA6B;GACtD,MAAM;GACN,aAAa;GACb,eAAe;GACf,eAAe;EACjB,CAAC;EAED,SAAS,GAAe,GAAwB;GAC9C,EAAmB,MAAM,KAAY,CAAC,EAAmB,MAAM;EACjE;EAEA,IAAM,IAAmC;GACvC;GACA;GACA;GACA;EACF,GAEM,KAA6D;GACjE,MAAM;GACN,aAAa;GACb,eAAe;GACf,eAAe;EACjB;EAEA,SAAS,IAAqB;GAC5B,EAAQ,MAAM,EAAO,QAAQ,OAAO,EAAU,KAAK;EACrD;EAEA,QACQ,EAAM,UACX,MAAc;GACb,AAAI,KAAa,CAAC,EAAQ,cAAc,SAAS,CAAC,EAAQ,UAAU,SAClE,EAAa;EAEjB,CACF;EAEA,eAAe,GAAU,GAAwC;GAC/D,IAAI,CAAC,EAAQ,SACX;GAIF,IAAM,IAAQ,EAAO,QAAQ,MAAM,OAAO,MACvC,MAAM,EAAE,OAAO,EAAQ,OAC1B;GACA,IAAI,CAAC,GACH;GAIF,IAAM,IAAgB,EAA6C;GAEnE,IAAI,CAAC,GACH;GAGF,IAAM,IAAe,MAAM,EAAQ,WACjC,GACA,GACA,EAAU,KACZ;GAEA,AAAI,MACF,EAAO,YAAY,EAAQ,SAAS,EAAE,SAAS,EAAa,CAAC,GAC7D,EAAQ,cAAc,EAAQ,UAAU,EAAQ,EAAE;EAEtD;EAEA,SAAS,IAAwB;GAI/B,OAHK,EAAQ,cAAc,QAGpB,EAAc,QAAQ,GAAK,MAE9B,KAAO,EAAQ,cAAc,OAAO,WAAW,EAAI,EAAE,SAAS,UAAU,IAEzE,CAAC,IANK;EAOX;oBAIE,EAAA,GAAA,EAyTa,GAAA;GAxTX,sBAAmB;GACnB,oBAAiB;GACjB,kBAAe;GACf,sBAAmB;GACnB,oBAAiB;GACjB,kBAAe;;GAEf,SAAA,QAgTM,CA/SE,EAAA,WADR,EAAA,GAAA,EAgTM,OAhTN,GAgTM,CA3SJ,EAyBM,OAzBN,GAyBM,CAtBJ,EAKM,OALN,GAKM,CAFJ,EAA4C,EAAA,CAAA,GAAA;IAA9B,MAAM;IAAK,gBAAc;GACvC,CAAA,GAAA,EAAuC,QAAA,MAAA,EAA9B,EAAA,CAAA,CAAM,CAAC,QAAQ,KAAK,GAAA,CAAA,CAAA,CAAA,GAE/B,EAeM,OAfN,GAeM,CAbI,EAAA,CAAA,CAAO,CAAC,cAAc,SAAK,CAAK,EAAA,CAAA,CAAO,CAAC,UAAU,SAD1D,EAAA,GAAA,EAOS,UAAA;;IALP,OAAM;IACL,OAAO,EAAA,CAAA,CAAM,CAAC,QAAQ;IACtB,SAAK,AAAA,EAAA,QAAA,MAAE,EAAY;GAEpB,GAAA,CAAA,EAA0C,EAAA,CAAA,GAAA;IAA9B,MAAM;IAAK,gBAAc;GAEvC,CAAA,CAAA,GAAA,GAAA,CAAA,KAAA,EAAA,IAAA,EAAA,GAAA,EAKS,UAAA;IAJP,OAAM;IACL,SAAK,AAAA,EAAA,QAAA,MAAE,GAAI,OAAA;GAEZ,GAAA,CAAA,EAAkC,EAAA,EAAA,GAAA;IAA9B,MAAM;IAAK,gBAAc;GAMnC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,EA8QM,OA9QN,GA8QM,CA3QI,EAAA,CAAA,CAAO,CAAC,UAAU,SAD1B,EAAA,GAAA,EAQM,OARN,GAQM,CAJJ,EAEI,KAFJ,GAEI,EADC,EAAA,CAAA,CAAM,CAAC,QAAQ,OAAO,GAAA,CAAA,GAE3B,EAAkC,GAAA,EAApB,OAAM,YAAW,CAAA,CAAA,CAAA,KAKpB,EAAA,CAAA,CAAO,CAAC,MAAM,SAAK,CAAK,EAAA,CAAA,CAAO,CAAC,cAAc,SAD3D,EAAA,GAAA,EAqBM,OArBN,GAqBM;IAjBJ,EAIE,EAAA,CAAA,GAAA;KAHC,MAAM;KACN,gBAAc;KACf,OAAM;;IAER,EAII,KAJJ,GAII,EADC,EAAA,CAAA,CAAM,CAAC,QAAQ,KAAK,GAAA,CAAA;IAEzB,EAMS,UAAA;KALP,OAAM;KACL,SAAK,AAAA,EAAA,QAAA,MAAE,EAAY;IAEpB,GAAA,CAAA,EAA0C,EAAA,CAAA,GAAA;KAA9B,MAAM;KAAK,gBAAc;IAAK,CAAA,GAAA,EAAA,MAC1C,EAAG,EAAA,CAAA,CAAM,CAAC,QAAQ,OAAO,GAAA,CAAA,CAAA,CAAA;GAMhB,CAAA,KAAA,EAAA,CAAA,CAAO,CAAC,cAAc,SADnC,EAAA,GAAA,EAgNM,OAhNN,GAgNM;IA3MJ,EA0BM,OAAA;KAzBJ,OAAM;KACL,OAAK,EAAA,EAAmC,iBAAA,EAAA,CAAA,CAAY,CAAC,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,KAAK,EAAA,CAAA;;KAIvF,EAOO,QAAA;MANL,OAAM;MACL,OAAK,EAAA,EAA2B,OAAA,EAAA,CAAA,CAAU,CAAC,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,KAAK,EAAA,CAAA;KAI1E,GAAA,EAAA,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,KAAK,GAAA,CAAA;KAEtC,EAIO,QAJP,IAIO,EADF,EAAA,CAAA,CAAM,CAAC,QAAQ,YAAY,GAAA,CAAA;KAGxB,EAAa,IAAA,KADrB,EAAA,GAAA,EAMO,QANP,IAMO,EAFF,EAAa,CAAA,IAAK,MACrB,EAAG,EAAA,CAAA,CAAM,CAAC,QAAQ,QAAQ,GAAA,CAAA,KAAA,EAAA,IAAA,EAAA;;IAMtB,EAAA,CAAA,CAAO,CAAC,SAAS,SADzB,EAAA,GAAA,EAUM,OAVN,IAUM,CANJ,EAIE,EAAA,CAAA,GAAA;KAHC,MAAM;KACN,gBAAc;KACf,OAAM;IAER,CAAA,GAAA,EAA0C,QAAA,MAAA,EAAjC,EAAA,CAAA,CAAM,CAAC,QAAQ,QAAQ,GAAA,CAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA;KAIlC,EAAA,GAAA,EAgKM,GAAA,MAAA,EA/Je,IAAZ,MADT,EAgKM,OAAA;KA9JH,KAAK;KACN,OAAM;IAGN,GAAA,CAAA,EAsDS,UAAA;KArDP,OAAM;KACL,UAAK,MAAE,GAAe,CAAQ;;MAE/B,EAAA,GAAA,EASE,EARK,GAAc,EAAQ,GAAA;MAC1B,MAAM;MACN,gBAAc;MACd,OAAK,EAAA,EAA6B,OAAA,EAAA,CAAA,CAAU,CAAsB,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,WAAW,EAAQ,CAAE,KAAA,EAAA,CAAA;;KAMtH,EAIO,QAJP,IAIO,EADF,EAAA,CAAA,CAAM,CAAC,QAAQ,WAAW,EAAQ,GAAA,CAAA;KAEvC,EAYO,QAAA;MAXL,OAAM;MACL,OAAK,EAAA;OAA6B,OAAA,EAAA,CAAA,CAAU,CAAsB,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,WAAW,EAAQ,CAAE,KAAA;OAA+D,iBAAA,EAAA,CAAA,CAAY,CAAsB,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,WAAW,EAAQ,CAAE,KAAA;;KASnQ,GAAA,EAAA,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,WAAW,EAAQ,CAAE,KAAK,GAAA,CAAA;KAGhC,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,WAAW,EAAQ,CAAE,SAA8B,SAAM,KADhH,EAAA,GAAA,EAWO,QAXP,IAWO,EAHH,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,WAAW,EAAQ,CAAE,SAA8B,MAAM,GAAA,CAAA,KAAA,EAAA,IAAA,EAAA;KAIzF,EASE,EAAA,EAAA,GAAA;MARC,MAAM;MACN,gBAAc;MACf,OAAK,GAAA,CAAC,4EACqB,EAAA,MAAmB,KAAA,iBAAA,gBAAA,CAAA;;IAU1C,GAAA,GAAA,CAAA,GAAA,EAAA,MAAmB,MAD3B,EAAA,GAAA,EAgGM,OAhGN,IAgGM,CA3FuB,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,WAAW,EAAQ,CAAE,SAA8B,WAAM,KADhH,EAAA,GAAA,EAQM,OARN,IAQM,EADD,EAAA,CAAA,CAAM,CAAC,QAAQ,UAAU,GAAA,CAAA,KAAA,EAAA,IAAA,EAAA,IAE9B,EAAA,EAAA,GAAA,EAkFM,GAAA,MAAA,EAjFc,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,WAA8B,EAA2B,CAAA,WAAhG,OADT,EAAA,GAAA,EAkFM,OAAA;KA9EH,KAAK,EAAQ;KACd,OAAM;IAEN,GAAA,CAAA,EA0EM,OA1EN,IA0EM,EAxEJ,EAAA,GAAA,EAcE,EAbkF,EAAtD,EAAQ,aAAQ,SAAsC,IAAsC,EAAQ,aAAQ,WAA0C,KAA0C,CAAA,CAAA,GAAA;KAO3N,MAAM;KACN,gBAAc;KACf,OAAM;KACL,OAAK,EAAA,EAAiC,OAAA,EAAA,CAAA,CAAa,CAAC,EAAQ,QAAQ,EAAA,CAAA;IAIvE,GAAA,MAAA,GAAA,CAAA,OAAA,CAAA,IAAA,EAwDM,OAxDN,IAwDM;KAtDJ,EAeM,OAfN,IAeM,CAdJ,EAQO,QAAA;MAPL,OAAM;MACL,OAAK,EAAA;OAAqC,OAAA,EAAA,CAAA,CAAa,CAAC,EAAQ,QAAQ;OAA8C,iBAAA,EAAA,CAAA,CAAe,CAAC,EAAQ,QAAQ;;KAKpJ,GAAA,EAAA,EAAA,CAAA,CAAM,CAAC,QAAQ,SAAS,EAAQ,SAAQ,GAAA,CAAA,GAE7C,EAIO,QAJP,IAIO,EADF,EAAQ,OAAO,GAAA,CAAA,CAAA,CAAA;KAKd,EAAQ,cADhB,EAAA,GAAA,EAKI,KALJ,IAKI,EADC,EAAQ,UAAU,GAAA,CAAA,KAAA,EAAA,IAAA,EAAA;KAIf,EAAQ,WADhB,EAAA,GAAA,EA6BM,OA7BN,IA6BM,CAzBJ,EAkBS,UAAA;MAjBP,OAAM;MACN,OAAA,EAAA,oBAAA,cAAA;MACC,UAAU,EAAA,CAAA,CAAO,CAAC,gBAAgB,UAAK;MACvC,UAAK,MAAE,GAAU,CAAO;KAGjB,GAAA,CAAA,EAAA,CAAA,CAAO,CAAC,gBAAgB,UAAU,EAAQ,MADlD,EAAA,GAAA,EAKE,EAAA,CAAA,GAAA;;MAHA,OAAM;MACL,MAAM;MACN,gBAAc;KAEjB,CAAA,MAAA,EAAA,GAAA,EAAgD,EAAA,CAAA,GAAA;;MAA9B,MAAM;MAAK,gBAAc;KAAK,CAAA,IAAA,EAAA,MAChD,EACE,EAAA,CAAA,CAAO,CAAC,gBAAgB,UAAU,EAAQ,KAAiC,EAAA,CAAA,CAAM,CAAC,QAAQ,SAAqC,EAAA,CAAA,CAAM,CAAC,QAAQ,GAAG,GAAA,CAAA,CAAA,GAAA,GAAA,EAAA,GAM7I,EAAA,CAAA,CAAO,CAAC,SAAS,SADzB,EAAA,GAAA,EAKI,KALJ,IAKI,EADC,EAAA,CAAA,CAAO,CAAC,SAAS,KAAK,GAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA;;GAWzC,CAAA,MAAA,EAAA,GAAA,EAcM,OAdN,IAcM,CAVJ,EAIE,EAAA,CAAA,GAAA;IAHC,MAAM;IACN,gBAAc;IACf,OAAM;GAER,CAAA,GAAA,EAII,KAJJ,IAII,EADC,EAAA,CAAA,CAAM,CAAC,QAAQ,UAAU,GAAA,CAAA,CAAA,CAAA,IAKhC,EAII,KAJJ,IAII,EADC,EAAA,CAAA,CAAM,CAAC,OAAO,UAAU,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"TemplateScoringPanel--JxR6CsQ.js","names":[],"sources":["../../../src/cloud/utils/scoringStyles.ts","../../../src/cloud/components/TemplateScoringPanel.vue","../../../src/cloud/components/TemplateScoringPanel.vue"],"sourcesContent":["export type ScoringSeverity = \"high\" | \"medium\" | \"low\" | string;\n\nexport function scoreColor(score: number): string {\n if (score >= 80) return \"var(--tpl-success)\";\n if (score >= 60) return \"var(--tpl-warning)\";\n return \"var(--tpl-danger)\";\n}\n\nexport function scoreBgColor(score: number): string {\n if (score >= 80) return \"var(--tpl-success-light)\";\n if (score >= 60) return \"var(--tpl-warning-light)\";\n return \"var(--tpl-danger-light)\";\n}\n\nexport function severityColor(severity: ScoringSeverity): string {\n if (severity === \"high\") return \"var(--tpl-danger)\";\n if (severity === \"medium\") return \"var(--tpl-warning)\";\n return \"var(--tpl-text-muted)\";\n}\n\nexport function severityBgColor(severity: ScoringSeverity): string {\n if (severity === \"high\") return \"var(--tpl-danger-light)\";\n if (severity === \"medium\") return \"var(--tpl-warning-light)\";\n return \"var(--tpl-bg-hover)\";\n}\n","<script setup lang=\"ts\">\nimport LoadingTrack from \"../../components/LoadingTrack.vue\";\nimport {\n EDITOR_KEY,\n SCORING_KEY,\n MERGE_TAGS_KEY,\n NO_MERGE_TAGS,\n requireInject,\n} from \"../../keys\";\nimport {\n scoreColor,\n scoreBgColor,\n severityColor,\n severityBgColor,\n} from \"../utils/scoringStyles\";\nimport { useCloudI18nStrict } from \"../../composables/useCloudI18n\";\nimport type { ScoringCategory, ScoringFinding } from \"@templatical/types\";\nimport {\n CircleAlert,\n TriangleAlert,\n ChevronDown,\n Eye,\n Info,\n LoaderCircle,\n RefreshCw,\n ShieldCheck,\n ShieldX,\n Sparkles,\n X,\n Zap,\n} from \"@lucide/vue\";\nimport { inject, ref, watch } from \"vue\";\n\nconst props = defineProps<{\n visible: boolean;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n}>();\n\nconst { t: cloudT } = useCloudI18nStrict();\nconst editor = requireInject(EDITOR_KEY, \"TemplateScoringPanel\");\nconst scoring = requireInject(SCORING_KEY, \"TemplateScoringPanel\");\nconst mergeTags = inject(MERGE_TAGS_KEY, NO_MERGE_TAGS);\n\nconst expandedCategories = ref<Record<string, boolean>>({\n spam: true,\n readability: true,\n accessibility: true,\n bestPractices: true,\n});\n\nfunction toggleCategory(category: string): void {\n expandedCategories.value[category] = !expandedCategories.value[category];\n}\n\nconst categoryOrder: ScoringCategory[] = [\n \"spam\",\n \"readability\",\n \"accessibility\",\n \"bestPractices\",\n];\n\nconst categoryIcons: Record<ScoringCategory, typeof ShieldCheck> = {\n spam: ShieldX,\n readability: Eye,\n accessibility: Sparkles,\n bestPractices: Zap,\n};\n\nfunction triggerScore(): void {\n scoring.score(editor.content.value, mergeTags.value);\n}\n\nwatch(\n () => props.visible,\n (isVisible) => {\n if (isVisible && !scoring.scoringResult.value && !scoring.isScoring.value) {\n triggerScore();\n }\n },\n);\n\nasync function handleFix(finding: ScoringFinding): Promise<void> {\n if (!finding.blockId) {\n return;\n }\n\n // Get the block content from the editor\n const block = editor.content.value.blocks.find(\n (b) => b.id === finding.blockId,\n );\n if (!block) {\n return;\n }\n\n // Extract HTML content from the block (text blocks have content property)\n const blockContent = (block as unknown as Record<string, unknown>).content as\n string | undefined;\n if (!blockContent) {\n return;\n }\n\n const fixedContent = await scoring.fixFinding(\n blockContent,\n finding,\n mergeTags.value,\n );\n\n if (fixedContent) {\n editor.updateBlock(finding.blockId, { content: fixedContent });\n scoring.removeFinding(finding.category, finding.id);\n }\n}\n\nfunction totalFindings(): number {\n if (!scoring.scoringResult.value) {\n return 0;\n }\n return categoryOrder.reduce((sum, cat) => {\n return (\n sum + (scoring.scoringResult.value?.categories[cat]?.findings.length ?? 0)\n );\n }, 0);\n}\n</script>\n\n<template>\n <Transition\n enter-active-class=\"tpl-scoring-slide-enter-active\"\n enter-from-class=\"tpl:translate-x-full\"\n enter-to-class=\"tpl:translate-x-0\"\n leave-active-class=\"tpl-scoring-slide-leave-active\"\n leave-from-class=\"tpl:translate-x-0\"\n leave-to-class=\"tpl:translate-x-full\"\n >\n <div\n v-if=\"visible\"\n class=\"tpl-scoring-panel tpl:absolute tpl:top-14 tpl:right-0 tpl:bottom-0 tpl:flex tpl:w-[360px] tpl:flex-col tpl:border-l tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg-elevated)]\"\n >\n <!-- Header -->\n <div\n class=\"tpl:flex tpl:items-center tpl:justify-between tpl:border-b tpl:border-[var(--tpl-border)] tpl:px-4 tpl:py-3\"\n >\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-primary)]\"\n >\n <ShieldCheck :size=\"13\" :stroke-width=\"2\" />\n <span>{{ cloudT.scoring.title }}</span>\n </div>\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <button\n v-if=\"scoring.scoringResult.value && !scoring.isScoring.value\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :title=\"cloudT.scoring.rescore\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"14\" :stroke-width=\"2\" />\n </button>\n <button\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n @click=\"emit('close')\"\n >\n <X :size=\"14\" :stroke-width=\"2\" />\n </button>\n </div>\n </div>\n\n <!-- Content -->\n <div class=\"tpl:flex-1 tpl:overflow-y-auto tpl:p-4\">\n <!-- Loading state -->\n <div\n v-if=\"scoring.isScoring.value\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <p class=\"tpl:text-sm tpl:text-[var(--tpl-text-muted)]\">\n {{ cloudT.scoring.scoring }}\n </p>\n <LoadingTrack class=\"tpl:w-3/4\" />\n </div>\n\n <!-- Error state -->\n <div\n v-else-if=\"scoring.error.value && !scoring.scoringResult.value\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <CircleAlert\n :size=\"32\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-danger)]\"\n />\n <p\n class=\"tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.error }}\n </p>\n <button\n class=\"tpl:mt-2 tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-md tpl:border tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:transition-all tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-text-muted)]\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"12\" :stroke-width=\"2\" />\n {{ cloudT.scoring.rescore }}\n </button>\n </div>\n\n <!-- Results -->\n <div\n v-else-if=\"scoring.scoringResult.value\"\n class=\"tpl:flex tpl:flex-col tpl:gap-4\"\n >\n <!-- Overall score -->\n <div\n class=\"tpl:flex tpl:flex-col tpl:items-center tpl:gap-2 tpl:rounded-[var(--tpl-radius)] tpl:p-5\"\n :style=\"{\n backgroundColor: scoreBgColor(scoring.scoringResult.value.score),\n }\"\n >\n <span\n class=\"tpl:text-4xl tpl:font-bold tpl:tabular-nums\"\n :style=\"{\n color: scoreColor(scoring.scoringResult.value.score),\n }\"\n >\n {{ scoring.scoringResult.value.score }}\n </span>\n <span\n class=\"tpl:text-xs tpl:font-medium tpl:uppercase tpl:tracking-wider tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.overallScore }}\n </span>\n <span\n v-if=\"totalFindings() > 0\"\n class=\"tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ totalFindings() }}\n {{ cloudT.scoring.findings }}\n </span>\n </div>\n\n <!-- Fix error -->\n <div\n v-if=\"scoring.fixError.value\"\n class=\"tpl:flex tpl:items-start tpl:gap-2 tpl:rounded-lg tpl:px-3 tpl:py-2 tpl:text-xs tpl:bg-[var(--tpl-danger-light)] tpl:text-[var(--tpl-danger)]\"\n >\n <CircleAlert\n :size=\"14\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n />\n <span>{{ cloudT.scoring.fixError }}</span>\n </div>\n\n <!-- Category cards -->\n <div\n v-for=\"category in categoryOrder\"\n :key=\"category\"\n class=\"tpl:overflow-hidden tpl:rounded-[var(--tpl-radius)] tpl:border tpl:border-[var(--tpl-border)]\"\n >\n <!-- Category header -->\n <button\n class=\"tpl:flex tpl:w-full tpl:cursor-pointer tpl:items-center tpl:gap-2.5 tpl:px-3 tpl:py-2.5 tpl:text-left tpl:transition-colors tpl:bg-[var(--tpl-bg)]\"\n @click=\"toggleCategory(category)\"\n >\n <component\n :is=\"categoryIcons[category]\"\n :size=\"14\"\n :stroke-width=\"2\"\n :style=\"{\n color: scoreColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n }\"\n />\n <span\n class=\"tpl:flex-1 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)]\"\n >\n {{ cloudT.scoring.categories[category] }}\n </span>\n <span\n class=\"tpl:rounded-full tpl:px-2 tpl:py-0.5 tpl:text-xs tpl:font-semibold tpl:tabular-nums\"\n :style=\"{\n color: scoreColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n backgroundColor: scoreBgColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n }\"\n >\n {{ scoring.scoringResult.value.categories[category].score }}\n </span>\n <span\n v-if=\"\n scoring.scoringResult.value.categories[category].findings\n .length > 0\n \"\n class=\"tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{\n scoring.scoringResult.value.categories[category].findings\n .length\n }}\n </span>\n <ChevronDown\n :size=\"12\"\n :stroke-width=\"2\"\n class=\"tpl:transition-transform tpl:duration-200 tpl:text-[var(--tpl-text-dim)]\"\n :class=\"\n expandedCategories[category]\n ? 'tpl:rotate-0'\n : 'tpl:-rotate-90'\n \"\n />\n </button>\n\n <!-- Findings list -->\n <div\n v-if=\"expandedCategories[category]\"\n class=\"tpl:border-t tpl:border-[var(--tpl-border)]\"\n >\n <div\n v-if=\"\n scoring.scoringResult.value.categories[category].findings\n .length === 0\n \"\n class=\"tpl:px-3 tpl:py-3 tpl:text-center tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.scoring.noFindings }}\n </div>\n <div\n v-for=\"finding in scoring.scoringResult.value.categories[\n category\n ].findings\"\n :key=\"finding.id\"\n class=\"tpl:border-t tpl:px-3 tpl:py-2.5 tpl:first:border-t-0 tpl:border-[var(--tpl-border-light)]\"\n >\n <div class=\"tpl:flex tpl:items-start tpl:gap-2\">\n <!-- Severity icon -->\n <component\n :is=\"\n finding.severity === 'high'\n ? CircleAlert\n : finding.severity === 'medium'\n ? TriangleAlert\n : Info\n \"\n :size=\"13\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n :style=\"{\n color: severityColor(finding.severity),\n }\"\n />\n <div class=\"tpl:flex-1 tpl:min-w-0\">\n <!-- Severity badge + message -->\n <div class=\"tpl:flex tpl:items-start tpl:gap-1.5\">\n <span\n class=\"tpl:mt-0.5 tpl:shrink-0 tpl:rounded tpl:px-1 tpl:py-px tpl:text-[10px] tpl:font-medium tpl:leading-tight\"\n :style=\"{\n color: severityColor(finding.severity),\n backgroundColor: severityBgColor(finding.severity),\n }\"\n >\n {{ cloudT.scoring.severity[finding.severity] }}\n </span>\n <span\n class=\"tpl:text-xs tpl:leading-snug tpl:text-[var(--tpl-text)]\"\n >\n {{ finding.message }}\n </span>\n </div>\n <!-- Suggestion -->\n <p\n v-if=\"finding.suggestion\"\n class=\"tpl:mt-1 tpl:text-[11px] tpl:leading-snug tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ finding.suggestion }}\n </p>\n <!-- Fix button -->\n <div\n v-if=\"finding.blockId\"\n class=\"tpl:mt-2 tpl:flex tpl:justify-center\"\n >\n <button\n class=\"tpl-scoring-fix-btn tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded tpl:border tpl:px-3 tpl:py-1.5 tpl:text-[11px] tpl:font-medium tpl:transition-all tpl:disabled:opacity-50 tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-primary)]\"\n style=\"background-color: transparent\"\n :disabled=\"scoring.fixingFindingId.value !== null\"\n @click=\"handleFix(finding)\"\n >\n <LoaderCircle\n v-if=\"scoring.fixingFindingId.value === finding.id\"\n class=\"tpl-spinner\"\n :size=\"11\"\n :stroke-width=\"2\"\n />\n <Sparkles v-else :size=\"11\" :stroke-width=\"2\" />\n {{\n scoring.fixingFindingId.value === finding.id\n ? cloudT.scoring.fixing\n : cloudT.scoring.fix\n }}\n </button>\n <p\n v-if=\"scoring.fixError.value\"\n class=\"tpl:mt-1.5 tpl:text-[11px] tpl:text-[var(--tpl-danger)]\"\n >\n {{ scoring.fixError.value }}\n </p>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Empty state (no result, no loading, no error) -->\n <div\n v-else\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <ShieldCheck\n :size=\"32\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <p\n class=\"tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.emptyState }}\n </p>\n </div>\n\n <!-- AI disclaimer -->\n <p\n class=\"tpl:m-0 tpl:px-4 tpl:pb-2 tpl:pt-2 tpl:text-center tpl:text-[11px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.aiMenu.disclaimer }}\n </p>\n </div>\n </div>\n </Transition>\n</template>\n\n<style scoped>\n.tpl-scoring-slide-enter-active {\n transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-scoring-slide-leave-active {\n transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-scoring-fix-btn:not(:disabled):hover {\n border-color: var(--tpl-primary) !important;\n background-color: var(--tpl-primary-light) !important;\n}\n</style>\n","<script setup lang=\"ts\">\nimport LoadingTrack from \"../../components/LoadingTrack.vue\";\nimport {\n EDITOR_KEY,\n SCORING_KEY,\n MERGE_TAGS_KEY,\n NO_MERGE_TAGS,\n requireInject,\n} from \"../../keys\";\nimport {\n scoreColor,\n scoreBgColor,\n severityColor,\n severityBgColor,\n} from \"../utils/scoringStyles\";\nimport { useCloudI18nStrict } from \"../../composables/useCloudI18n\";\nimport type { ScoringCategory, ScoringFinding } from \"@templatical/types\";\nimport {\n CircleAlert,\n TriangleAlert,\n ChevronDown,\n Eye,\n Info,\n LoaderCircle,\n RefreshCw,\n ShieldCheck,\n ShieldX,\n Sparkles,\n X,\n Zap,\n} from \"@lucide/vue\";\nimport { inject, ref, watch } from \"vue\";\n\nconst props = defineProps<{\n visible: boolean;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n}>();\n\nconst { t: cloudT } = useCloudI18nStrict();\nconst editor = requireInject(EDITOR_KEY, \"TemplateScoringPanel\");\nconst scoring = requireInject(SCORING_KEY, \"TemplateScoringPanel\");\nconst mergeTags = inject(MERGE_TAGS_KEY, NO_MERGE_TAGS);\n\nconst expandedCategories = ref<Record<string, boolean>>({\n spam: true,\n readability: true,\n accessibility: true,\n bestPractices: true,\n});\n\nfunction toggleCategory(category: string): void {\n expandedCategories.value[category] = !expandedCategories.value[category];\n}\n\nconst categoryOrder: ScoringCategory[] = [\n \"spam\",\n \"readability\",\n \"accessibility\",\n \"bestPractices\",\n];\n\nconst categoryIcons: Record<ScoringCategory, typeof ShieldCheck> = {\n spam: ShieldX,\n readability: Eye,\n accessibility: Sparkles,\n bestPractices: Zap,\n};\n\nfunction triggerScore(): void {\n scoring.score(editor.content.value, mergeTags.value);\n}\n\nwatch(\n () => props.visible,\n (isVisible) => {\n if (isVisible && !scoring.scoringResult.value && !scoring.isScoring.value) {\n triggerScore();\n }\n },\n);\n\nasync function handleFix(finding: ScoringFinding): Promise<void> {\n if (!finding.blockId) {\n return;\n }\n\n // Get the block content from the editor\n const block = editor.content.value.blocks.find(\n (b) => b.id === finding.blockId,\n );\n if (!block) {\n return;\n }\n\n // Extract HTML content from the block (text blocks have content property)\n const blockContent = (block as unknown as Record<string, unknown>).content as\n string | undefined;\n if (!blockContent) {\n return;\n }\n\n const fixedContent = await scoring.fixFinding(\n blockContent,\n finding,\n mergeTags.value,\n );\n\n if (fixedContent) {\n editor.updateBlock(finding.blockId, { content: fixedContent });\n scoring.removeFinding(finding.category, finding.id);\n }\n}\n\nfunction totalFindings(): number {\n if (!scoring.scoringResult.value) {\n return 0;\n }\n return categoryOrder.reduce((sum, cat) => {\n return (\n sum + (scoring.scoringResult.value?.categories[cat]?.findings.length ?? 0)\n );\n }, 0);\n}\n</script>\n\n<template>\n <Transition\n enter-active-class=\"tpl-scoring-slide-enter-active\"\n enter-from-class=\"tpl:translate-x-full\"\n enter-to-class=\"tpl:translate-x-0\"\n leave-active-class=\"tpl-scoring-slide-leave-active\"\n leave-from-class=\"tpl:translate-x-0\"\n leave-to-class=\"tpl:translate-x-full\"\n >\n <div\n v-if=\"visible\"\n class=\"tpl-scoring-panel tpl:absolute tpl:top-14 tpl:right-0 tpl:bottom-0 tpl:flex tpl:w-[360px] tpl:flex-col tpl:border-l tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg-elevated)]\"\n >\n <!-- Header -->\n <div\n class=\"tpl:flex tpl:items-center tpl:justify-between tpl:border-b tpl:border-[var(--tpl-border)] tpl:px-4 tpl:py-3\"\n >\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-primary)]\"\n >\n <ShieldCheck :size=\"13\" :stroke-width=\"2\" />\n <span>{{ cloudT.scoring.title }}</span>\n </div>\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <button\n v-if=\"scoring.scoringResult.value && !scoring.isScoring.value\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :title=\"cloudT.scoring.rescore\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"14\" :stroke-width=\"2\" />\n </button>\n <button\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n @click=\"emit('close')\"\n >\n <X :size=\"14\" :stroke-width=\"2\" />\n </button>\n </div>\n </div>\n\n <!-- Content -->\n <div class=\"tpl:flex-1 tpl:overflow-y-auto tpl:p-4\">\n <!-- Loading state -->\n <div\n v-if=\"scoring.isScoring.value\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <p class=\"tpl:text-sm tpl:text-[var(--tpl-text-muted)]\">\n {{ cloudT.scoring.scoring }}\n </p>\n <LoadingTrack class=\"tpl:w-3/4\" />\n </div>\n\n <!-- Error state -->\n <div\n v-else-if=\"scoring.error.value && !scoring.scoringResult.value\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <CircleAlert\n :size=\"32\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-danger)]\"\n />\n <p\n class=\"tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.error }}\n </p>\n <button\n class=\"tpl:mt-2 tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-md tpl:border tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:transition-all tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-text-muted)]\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"12\" :stroke-width=\"2\" />\n {{ cloudT.scoring.rescore }}\n </button>\n </div>\n\n <!-- Results -->\n <div\n v-else-if=\"scoring.scoringResult.value\"\n class=\"tpl:flex tpl:flex-col tpl:gap-4\"\n >\n <!-- Overall score -->\n <div\n class=\"tpl:flex tpl:flex-col tpl:items-center tpl:gap-2 tpl:rounded-[var(--tpl-radius)] tpl:p-5\"\n :style=\"{\n backgroundColor: scoreBgColor(scoring.scoringResult.value.score),\n }\"\n >\n <span\n class=\"tpl:text-4xl tpl:font-bold tpl:tabular-nums\"\n :style=\"{\n color: scoreColor(scoring.scoringResult.value.score),\n }\"\n >\n {{ scoring.scoringResult.value.score }}\n </span>\n <span\n class=\"tpl:text-xs tpl:font-medium tpl:uppercase tpl:tracking-wider tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.overallScore }}\n </span>\n <span\n v-if=\"totalFindings() > 0\"\n class=\"tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ totalFindings() }}\n {{ cloudT.scoring.findings }}\n </span>\n </div>\n\n <!-- Fix error -->\n <div\n v-if=\"scoring.fixError.value\"\n class=\"tpl:flex tpl:items-start tpl:gap-2 tpl:rounded-lg tpl:px-3 tpl:py-2 tpl:text-xs tpl:bg-[var(--tpl-danger-light)] tpl:text-[var(--tpl-danger)]\"\n >\n <CircleAlert\n :size=\"14\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n />\n <span>{{ cloudT.scoring.fixError }}</span>\n </div>\n\n <!-- Category cards -->\n <div\n v-for=\"category in categoryOrder\"\n :key=\"category\"\n class=\"tpl:overflow-hidden tpl:rounded-[var(--tpl-radius)] tpl:border tpl:border-[var(--tpl-border)]\"\n >\n <!-- Category header -->\n <button\n class=\"tpl:flex tpl:w-full tpl:cursor-pointer tpl:items-center tpl:gap-2.5 tpl:px-3 tpl:py-2.5 tpl:text-left tpl:transition-colors tpl:bg-[var(--tpl-bg)]\"\n @click=\"toggleCategory(category)\"\n >\n <component\n :is=\"categoryIcons[category]\"\n :size=\"14\"\n :stroke-width=\"2\"\n :style=\"{\n color: scoreColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n }\"\n />\n <span\n class=\"tpl:flex-1 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)]\"\n >\n {{ cloudT.scoring.categories[category] }}\n </span>\n <span\n class=\"tpl:rounded-full tpl:px-2 tpl:py-0.5 tpl:text-xs tpl:font-semibold tpl:tabular-nums\"\n :style=\"{\n color: scoreColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n backgroundColor: scoreBgColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n }\"\n >\n {{ scoring.scoringResult.value.categories[category].score }}\n </span>\n <span\n v-if=\"\n scoring.scoringResult.value.categories[category].findings\n .length > 0\n \"\n class=\"tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{\n scoring.scoringResult.value.categories[category].findings\n .length\n }}\n </span>\n <ChevronDown\n :size=\"12\"\n :stroke-width=\"2\"\n class=\"tpl:transition-transform tpl:duration-200 tpl:text-[var(--tpl-text-dim)]\"\n :class=\"\n expandedCategories[category]\n ? 'tpl:rotate-0'\n : 'tpl:-rotate-90'\n \"\n />\n </button>\n\n <!-- Findings list -->\n <div\n v-if=\"expandedCategories[category]\"\n class=\"tpl:border-t tpl:border-[var(--tpl-border)]\"\n >\n <div\n v-if=\"\n scoring.scoringResult.value.categories[category].findings\n .length === 0\n \"\n class=\"tpl:px-3 tpl:py-3 tpl:text-center tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.scoring.noFindings }}\n </div>\n <div\n v-for=\"finding in scoring.scoringResult.value.categories[\n category\n ].findings\"\n :key=\"finding.id\"\n class=\"tpl:border-t tpl:px-3 tpl:py-2.5 tpl:first:border-t-0 tpl:border-[var(--tpl-border-light)]\"\n >\n <div class=\"tpl:flex tpl:items-start tpl:gap-2\">\n <!-- Severity icon -->\n <component\n :is=\"\n finding.severity === 'high'\n ? CircleAlert\n : finding.severity === 'medium'\n ? TriangleAlert\n : Info\n \"\n :size=\"13\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n :style=\"{\n color: severityColor(finding.severity),\n }\"\n />\n <div class=\"tpl:flex-1 tpl:min-w-0\">\n <!-- Severity badge + message -->\n <div class=\"tpl:flex tpl:items-start tpl:gap-1.5\">\n <span\n class=\"tpl:mt-0.5 tpl:shrink-0 tpl:rounded tpl:px-1 tpl:py-px tpl:text-[10px] tpl:font-medium tpl:leading-tight\"\n :style=\"{\n color: severityColor(finding.severity),\n backgroundColor: severityBgColor(finding.severity),\n }\"\n >\n {{ cloudT.scoring.severity[finding.severity] }}\n </span>\n <span\n class=\"tpl:text-xs tpl:leading-snug tpl:text-[var(--tpl-text)]\"\n >\n {{ finding.message }}\n </span>\n </div>\n <!-- Suggestion -->\n <p\n v-if=\"finding.suggestion\"\n class=\"tpl:mt-1 tpl:text-[11px] tpl:leading-snug tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ finding.suggestion }}\n </p>\n <!-- Fix button -->\n <div\n v-if=\"finding.blockId\"\n class=\"tpl:mt-2 tpl:flex tpl:justify-center\"\n >\n <button\n class=\"tpl-scoring-fix-btn tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded tpl:border tpl:px-3 tpl:py-1.5 tpl:text-[11px] tpl:font-medium tpl:transition-all tpl:disabled:opacity-50 tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-primary)]\"\n style=\"background-color: transparent\"\n :disabled=\"scoring.fixingFindingId.value !== null\"\n @click=\"handleFix(finding)\"\n >\n <LoaderCircle\n v-if=\"scoring.fixingFindingId.value === finding.id\"\n class=\"tpl-spinner\"\n :size=\"11\"\n :stroke-width=\"2\"\n />\n <Sparkles v-else :size=\"11\" :stroke-width=\"2\" />\n {{\n scoring.fixingFindingId.value === finding.id\n ? cloudT.scoring.fixing\n : cloudT.scoring.fix\n }}\n </button>\n <p\n v-if=\"scoring.fixError.value\"\n class=\"tpl:mt-1.5 tpl:text-[11px] tpl:text-[var(--tpl-danger)]\"\n >\n {{ scoring.fixError.value }}\n </p>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Empty state (no result, no loading, no error) -->\n <div\n v-else\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <ShieldCheck\n :size=\"32\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <p\n class=\"tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.emptyState }}\n </p>\n </div>\n\n <!-- AI disclaimer -->\n <p\n class=\"tpl:m-0 tpl:px-4 tpl:pb-2 tpl:pt-2 tpl:text-center tpl:text-[11px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.aiMenu.disclaimer }}\n </p>\n </div>\n </div>\n </Transition>\n</template>\n\n<style scoped>\n.tpl-scoring-slide-enter-active {\n transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-scoring-slide-leave-active {\n transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-scoring-fix-btn:not(:disabled):hover {\n border-color: var(--tpl-primary) !important;\n background-color: var(--tpl-primary-light) !important;\n}\n</style>\n"],"mappings":";;;;;;;AAEA,SAAgB,EAAW,GAAuB;CAGhD,OAFI,KAAS,KAAW,uBACpB,KAAS,KAAW,uBACjB;AACT;AAEA,SAAgB,EAAa,GAAuB;CAGlD,OAFI,KAAS,KAAW,6BACpB,KAAS,KAAW,6BACjB;AACT;AAEA,SAAgB,EAAc,GAAmC;CAG/D,OAFI,MAAa,SAAe,sBAC5B,MAAa,WAAiB,uBAC3B;AACT;AAEA,SAAgB,EAAgB,GAAmC;CAGjE,OAFI,MAAa,SAAe,4BAC5B,MAAa,WAAiB,6BAC3B;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECSA,IAAM,IAAQ,GAIR,KAAO,GAIP,EAAE,GAAG,MAAW,EAAmB,GACnC,IAAS,EAAc,IAAY,sBAAsB,GACzD,IAAU,EAAc,IAAa,sBAAsB,GAC3D,IAAY,EAAO,IAAgB,EAAa,GAEhD,IAAqB,GAA6B;GACtD,MAAM;GACN,aAAa;GACb,eAAe;GACf,eAAe;EACjB,CAAC;EAED,SAAS,GAAe,GAAwB;GAC9C,EAAmB,MAAM,KAAY,CAAC,EAAmB,MAAM;EACjE;EAEA,IAAM,IAAmC;GACvC;GACA;GACA;GACA;EACF,GAEM,KAA6D;GACjE,MAAM;GACN,aAAa;GACb,eAAe;GACf,eAAe;EACjB;EAEA,SAAS,IAAqB;GAC5B,EAAQ,MAAM,EAAO,QAAQ,OAAO,EAAU,KAAK;EACrD;EAEA,QACQ,EAAM,UACX,MAAc;GACb,AAAI,KAAa,CAAC,EAAQ,cAAc,SAAS,CAAC,EAAQ,UAAU,SAClE,EAAa;EAEjB,CACF;EAEA,eAAe,GAAU,GAAwC;GAC/D,IAAI,CAAC,EAAQ,SACX;GAIF,IAAM,IAAQ,EAAO,QAAQ,MAAM,OAAO,MACvC,MAAM,EAAE,OAAO,EAAQ,OAC1B;GACA,IAAI,CAAC,GACH;GAIF,IAAM,IAAgB,EAA6C;GAEnE,IAAI,CAAC,GACH;GAGF,IAAM,IAAe,MAAM,EAAQ,WACjC,GACA,GACA,EAAU,KACZ;GAEA,AAAI,MACF,EAAO,YAAY,EAAQ,SAAS,EAAE,SAAS,EAAa,CAAC,GAC7D,EAAQ,cAAc,EAAQ,UAAU,EAAQ,EAAE;EAEtD;EAEA,SAAS,IAAwB;GAI/B,OAHK,EAAQ,cAAc,QAGpB,EAAc,QAAQ,GAAK,MAE9B,KAAO,EAAQ,cAAc,OAAO,WAAW,EAAI,EAAE,SAAS,UAAU,IAEzE,CAAC,IANK;EAOX;oBAIE,EAAA,GAAA,EAyTa,GAAA;GAxTX,sBAAmB;GACnB,oBAAiB;GACjB,kBAAe;GACf,sBAAmB;GACnB,oBAAiB;GACjB,kBAAe;;GAEf,SAAA,QAgTM,CA/SE,EAAA,WADR,EAAA,GAAA,EAgTM,OAhTN,GAgTM,CA3SJ,EAyBM,OAzBN,GAyBM,CAtBJ,EAKM,OALN,GAKM,CAFJ,EAA4C,EAAA,CAAA,GAAA;IAA9B,MAAM;IAAK,gBAAc;GACvC,CAAA,GAAA,EAAuC,QAAA,MAAA,EAA9B,EAAA,CAAA,CAAM,CAAC,QAAQ,KAAK,GAAA,CAAA,CAAA,CAAA,GAE/B,EAeM,OAfN,GAeM,CAbI,EAAA,CAAA,CAAO,CAAC,cAAc,SAAK,CAAK,EAAA,CAAA,CAAO,CAAC,UAAU,SAD1D,EAAA,GAAA,EAOS,UAAA;;IALP,OAAM;IACL,OAAO,EAAA,CAAA,CAAM,CAAC,QAAQ;IACtB,SAAK,AAAA,EAAA,QAAA,MAAE,EAAY;GAEpB,GAAA,CAAA,EAA0C,EAAA,CAAA,GAAA;IAA9B,MAAM;IAAK,gBAAc;GAEvC,CAAA,CAAA,GAAA,GAAA,CAAA,KAAA,EAAA,IAAA,EAAA,GAAA,EAKS,UAAA;IAJP,OAAM;IACL,SAAK,AAAA,EAAA,QAAA,MAAE,GAAI,OAAA;GAEZ,GAAA,CAAA,EAAkC,EAAA,EAAA,GAAA;IAA9B,MAAM;IAAK,gBAAc;GAMnC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,EA8QM,OA9QN,GA8QM,CA3QI,EAAA,CAAA,CAAO,CAAC,UAAU,SAD1B,EAAA,GAAA,EAQM,OARN,GAQM,CAJJ,EAEI,KAFJ,GAEI,EADC,EAAA,CAAA,CAAM,CAAC,QAAQ,OAAO,GAAA,CAAA,GAE3B,EAAkC,GAAA,EAApB,OAAM,YAAW,CAAA,CAAA,CAAA,KAKpB,EAAA,CAAA,CAAO,CAAC,MAAM,SAAK,CAAK,EAAA,CAAA,CAAO,CAAC,cAAc,SAD3D,EAAA,GAAA,EAqBM,OArBN,GAqBM;IAjBJ,EAIE,EAAA,CAAA,GAAA;KAHC,MAAM;KACN,gBAAc;KACf,OAAM;;IAER,EAII,KAJJ,GAII,EADC,EAAA,CAAA,CAAM,CAAC,QAAQ,KAAK,GAAA,CAAA;IAEzB,EAMS,UAAA;KALP,OAAM;KACL,SAAK,AAAA,EAAA,QAAA,MAAE,EAAY;IAEpB,GAAA,CAAA,EAA0C,EAAA,CAAA,GAAA;KAA9B,MAAM;KAAK,gBAAc;IAAK,CAAA,GAAA,EAAA,MAC1C,EAAG,EAAA,CAAA,CAAM,CAAC,QAAQ,OAAO,GAAA,CAAA,CAAA,CAAA;GAMhB,CAAA,KAAA,EAAA,CAAA,CAAO,CAAC,cAAc,SADnC,EAAA,GAAA,EAgNM,OAhNN,GAgNM;IA3MJ,EA0BM,OAAA;KAzBJ,OAAM;KACL,OAAK,EAAA,EAAmC,iBAAA,EAAA,CAAA,CAAY,CAAC,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,KAAK,EAAA,CAAA;;KAIvF,EAOO,QAAA;MANL,OAAM;MACL,OAAK,EAAA,EAA2B,OAAA,EAAA,CAAA,CAAU,CAAC,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,KAAK,EAAA,CAAA;KAI1E,GAAA,EAAA,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,KAAK,GAAA,CAAA;KAEtC,EAIO,QAJP,IAIO,EADF,EAAA,CAAA,CAAM,CAAC,QAAQ,YAAY,GAAA,CAAA;KAGxB,EAAa,IAAA,KADrB,EAAA,GAAA,EAMO,QANP,IAMO,EAFF,EAAa,CAAA,IAAK,MACrB,EAAG,EAAA,CAAA,CAAM,CAAC,QAAQ,QAAQ,GAAA,CAAA,KAAA,EAAA,IAAA,EAAA;;IAMtB,EAAA,CAAA,CAAO,CAAC,SAAS,SADzB,EAAA,GAAA,EAUM,OAVN,IAUM,CANJ,EAIE,EAAA,CAAA,GAAA;KAHC,MAAM;KACN,gBAAc;KACf,OAAM;IAER,CAAA,GAAA,EAA0C,QAAA,MAAA,EAAjC,EAAA,CAAA,CAAM,CAAC,QAAQ,QAAQ,GAAA,CAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA;KAIlC,EAAA,GAAA,EAgKM,GAAA,MAAA,EA/Je,IAAZ,MADT,EAgKM,OAAA;KA9JH,KAAK;KACN,OAAM;IAGN,GAAA,CAAA,EAsDS,UAAA;KArDP,OAAM;KACL,UAAK,MAAE,GAAe,CAAQ;;MAE/B,EAAA,GAAA,EASE,EARK,GAAc,EAAQ,GAAA;MAC1B,MAAM;MACN,gBAAc;MACd,OAAK,EAAA,EAA6B,OAAA,EAAA,CAAA,CAAU,CAAsB,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,WAAW,EAAQ,CAAE,KAAA,EAAA,CAAA;;KAMtH,EAIO,QAJP,IAIO,EADF,EAAA,CAAA,CAAM,CAAC,QAAQ,WAAW,EAAQ,GAAA,CAAA;KAEvC,EAYO,QAAA;MAXL,OAAM;MACL,OAAK,EAAA;OAA6B,OAAA,EAAA,CAAA,CAAU,CAAsB,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,WAAW,EAAQ,CAAE,KAAA;OAA+D,iBAAA,EAAA,CAAA,CAAY,CAAsB,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,WAAW,EAAQ,CAAE,KAAA;;KASnQ,GAAA,EAAA,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,WAAW,EAAQ,CAAE,KAAK,GAAA,CAAA;KAGhC,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,WAAW,EAAQ,CAAE,SAA8B,SAAM,KADhH,EAAA,GAAA,EAWO,QAXP,IAWO,EAHH,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,WAAW,EAAQ,CAAE,SAA8B,MAAM,GAAA,CAAA,KAAA,EAAA,IAAA,EAAA;KAIzF,EASE,EAAA,EAAA,GAAA;MARC,MAAM;MACN,gBAAc;MACf,OAAK,GAAA,CAAC,4EACqB,EAAA,MAAmB,KAAA,iBAAA,gBAAA,CAAA;;IAU1C,GAAA,GAAA,CAAA,GAAA,EAAA,MAAmB,MAD3B,EAAA,GAAA,EAgGM,OAhGN,IAgGM,CA3FuB,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,WAAW,EAAQ,CAAE,SAA8B,WAAM,KADhH,EAAA,GAAA,EAQM,OARN,IAQM,EADD,EAAA,CAAA,CAAM,CAAC,QAAQ,UAAU,GAAA,CAAA,KAAA,EAAA,IAAA,EAAA,IAE9B,EAAA,EAAA,GAAA,EAkFM,GAAA,MAAA,EAjFc,EAAA,CAAA,CAAO,CAAC,cAAc,MAAM,WAA8B,EAA2B,CAAA,WAAhG,OADT,EAAA,GAAA,EAkFM,OAAA;KA9EH,KAAK,EAAQ;KACd,OAAM;IAEN,GAAA,CAAA,EA0EM,OA1EN,IA0EM,EAxEJ,EAAA,GAAA,EAcE,EAbkF,EAAtD,EAAQ,aAAQ,SAAsC,IAAsC,EAAQ,aAAQ,WAA0C,KAA0C,CAAA,CAAA,GAAA;KAO3N,MAAM;KACN,gBAAc;KACf,OAAM;KACL,OAAK,EAAA,EAAiC,OAAA,EAAA,CAAA,CAAa,CAAC,EAAQ,QAAQ,EAAA,CAAA;IAIvE,GAAA,MAAA,GAAA,CAAA,OAAA,CAAA,IAAA,EAwDM,OAxDN,IAwDM;KAtDJ,EAeM,OAfN,IAeM,CAdJ,EAQO,QAAA;MAPL,OAAM;MACL,OAAK,EAAA;OAAqC,OAAA,EAAA,CAAA,CAAa,CAAC,EAAQ,QAAQ;OAA8C,iBAAA,EAAA,CAAA,CAAe,CAAC,EAAQ,QAAQ;;KAKpJ,GAAA,EAAA,EAAA,CAAA,CAAM,CAAC,QAAQ,SAAS,EAAQ,SAAQ,GAAA,CAAA,GAE7C,EAIO,QAJP,IAIO,EADF,EAAQ,OAAO,GAAA,CAAA,CAAA,CAAA;KAKd,EAAQ,cADhB,EAAA,GAAA,EAKI,KALJ,IAKI,EADC,EAAQ,UAAU,GAAA,CAAA,KAAA,EAAA,IAAA,EAAA;KAIf,EAAQ,WADhB,EAAA,GAAA,EA6BM,OA7BN,IA6BM,CAzBJ,EAkBS,UAAA;MAjBP,OAAM;MACN,OAAA,EAAA,oBAAA,cAAA;MACC,UAAU,EAAA,CAAA,CAAO,CAAC,gBAAgB,UAAK;MACvC,UAAK,MAAE,GAAU,CAAO;KAGjB,GAAA,CAAA,EAAA,CAAA,CAAO,CAAC,gBAAgB,UAAU,EAAQ,MADlD,EAAA,GAAA,EAKE,EAAA,CAAA,GAAA;;MAHA,OAAM;MACL,MAAM;MACN,gBAAc;KAEjB,CAAA,MAAA,EAAA,GAAA,EAAgD,EAAA,CAAA,GAAA;;MAA9B,MAAM;MAAK,gBAAc;KAAK,CAAA,IAAA,EAAA,MAChD,EACE,EAAA,CAAA,CAAO,CAAC,gBAAgB,UAAU,EAAQ,KAAiC,EAAA,CAAA,CAAM,CAAC,QAAQ,SAAqC,EAAA,CAAA,CAAM,CAAC,QAAQ,GAAG,GAAA,CAAA,CAAA,GAAA,GAAA,EAAA,GAM7I,EAAA,CAAA,CAAO,CAAC,SAAS,SADzB,EAAA,GAAA,EAKI,KALJ,IAKI,EADC,EAAA,CAAA,CAAO,CAAC,SAAS,KAAK,GAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA;;GAWzC,CAAA,MAAA,EAAA,GAAA,EAcM,OAdN,IAcM,CAVJ,EAIE,EAAA,CAAA,GAAA;IAHC,MAAM;IACN,gBAAc;IACf,OAAM;GAER,CAAA,GAAA,EAII,KAJJ,IAII,EADC,EAAA,CAAA,CAAM,CAAC,QAAQ,UAAU,GAAA,CAAA,CAAA,CAAA,IAKhC,EAII,KAJJ,IAII,EADC,EAAA,CAAA,CAAM,CAAC,OAAO,UAAU,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,CAAA"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { E as e, F as t, N as n, S as r, at as i, b as a, ct as o, f as s, g as c, h as l, lt as u, p as d, u as f, ut as p } from "./draggable-IB4x6w2O.js";
|
|
2
|
+
import { R as ee } from "./src-Dwgq7hf4.js";
|
|
3
|
+
import { G as te, Z as ne, v as re } from "./keys-dJbD1QPs.js";
|
|
4
|
+
import { t as ie } from "./useI18n-DTZ9sIcv.js";
|
|
5
|
+
import { n as ae, t as m } from "./templateSettingsFields-YCFVBVYh.js";
|
|
6
|
+
import { At as h, _t as g, dt as oe, w as _, wt as v } from "./icons-BKkJ-5xF.js";
|
|
7
|
+
import { g as y, h as se, l as ce, m as le, p as b, t as x } from "./styleConstants-C_YAPdQS.js";
|
|
8
|
+
import { c as S } from "./LogicTagInsertButton-DpyPozop.js";
|
|
9
|
+
import { n as C, t as w } from "./ToggleSwitch-CDy8OfcB.js";
|
|
10
|
+
//#region src/components/TemplateSettings.vue?vue&type=script&setup=true&lang.ts
|
|
11
|
+
var T = {
|
|
12
|
+
"data-testid": "template-settings",
|
|
13
|
+
class: "tpl:flex tpl:w-full tpl:flex-1 tpl:flex-col tpl:bg-[var(--tpl-bg-elevated)]"
|
|
14
|
+
}, E = { class: "tpl:flex tpl:flex-1 tpl:flex-col tpl:gap-3 tpl:overflow-y-auto tpl:p-4" }, D = { class: "tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]" }, O = {
|
|
15
|
+
key: 0,
|
|
16
|
+
"data-testid": "template-settings-width-preset"
|
|
17
|
+
}, k = { class: "tpl:grid tpl:grid-cols-4 tpl:gap-1 tpl:rounded-[var(--tpl-radius-sm)] tpl:p-1 tpl:bg-[var(--tpl-bg-hover)]" }, A = ["onClick"], j = {
|
|
18
|
+
key: 1,
|
|
19
|
+
"data-testid": "template-settings-width-custom"
|
|
20
|
+
}, M = { class: "tpl:flex tpl:items-stretch" }, N = ["value"], P = { class: "tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]" }, F = {
|
|
21
|
+
key: 0,
|
|
22
|
+
"data-testid": "template-settings-background"
|
|
23
|
+
}, I = {
|
|
24
|
+
key: 1,
|
|
25
|
+
"data-testid": "template-settings-text-color"
|
|
26
|
+
}, L = {
|
|
27
|
+
key: 2,
|
|
28
|
+
"data-testid": "template-settings-link-color"
|
|
29
|
+
}, R = {
|
|
30
|
+
key: 3,
|
|
31
|
+
"data-testid": "template-settings-link-underline"
|
|
32
|
+
}, z = {
|
|
33
|
+
key: 4,
|
|
34
|
+
"data-testid": "template-settings-font-family"
|
|
35
|
+
}, B = ["value"], V = ["value"], H = { class: "tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]" }, ue = {
|
|
36
|
+
key: 0,
|
|
37
|
+
"data-testid": "template-settings-locale"
|
|
38
|
+
}, U = ["value"], de = { class: "tpl:mt-1 tpl:text-xs tpl:leading-relaxed tpl:text-[var(--tpl-text-dim)]" }, fe = {
|
|
39
|
+
key: 1,
|
|
40
|
+
"data-testid": "template-settings-direction"
|
|
41
|
+
}, pe = { class: "tpl:mt-1 tpl:text-xs tpl:leading-relaxed tpl:text-[var(--tpl-text-dim)]" }, me = { class: "tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]" }, he = {
|
|
42
|
+
key: 0,
|
|
43
|
+
"data-testid": "template-settings-preheader"
|
|
44
|
+
}, ge = { class: "tpl:mt-1 tpl:flex tpl:items-start tpl:justify-between tpl:gap-2" }, _e = { class: "tpl:text-xs tpl:leading-relaxed tpl:text-[var(--tpl-text-dim)]" }, ve = { class: "tpl:shrink-0 tpl:text-xs tpl:tabular-nums tpl:text-[var(--tpl-text-dim)]" }, ye = {
|
|
45
|
+
key: 4,
|
|
46
|
+
class: "tpl:rounded-[var(--tpl-radius)] tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:p-3",
|
|
47
|
+
"data-testid": "template-settings-card-tips"
|
|
48
|
+
}, be = { class: "tpl:mb-2.5 tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text-muted)]" }, xe = { class: "tpl:m-0 tpl:pl-[18px] tpl:text-xs tpl:leading-relaxed tpl:text-[var(--tpl-text-dim)]" }, Se = { class: "tpl:mb-1 tpl:last:mb-0" }, Ce = { class: "tpl:mb-1 tpl:last:mb-0" }, we = { class: "tpl:mb-1 tpl:last:mb-0" }, Te = 150, W = /* @__PURE__ */ r({
|
|
49
|
+
__name: "TemplateSettings",
|
|
50
|
+
props: { settings: {} },
|
|
51
|
+
emits: ["update"],
|
|
52
|
+
setup(r, { emit: W }) {
|
|
53
|
+
let G = r, K = W, { t: q } = ie(), J = ne(re, "TemplateSettings"), Y = s(() => J.fonts.value), Ee = s(() => Y.value.some((e) => e.value === G.settings.fontFamily) ? G.settings.fontFamily : J.defaultFont.value), De = [
|
|
54
|
+
{
|
|
55
|
+
value: 480,
|
|
56
|
+
label: "480px"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
value: 600,
|
|
60
|
+
label: "600px"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
value: 700,
|
|
64
|
+
label: "700px"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
value: 800,
|
|
68
|
+
label: "800px"
|
|
69
|
+
}
|
|
70
|
+
], X = e(te, new Set(m));
|
|
71
|
+
function Z(e) {
|
|
72
|
+
return X.has(e);
|
|
73
|
+
}
|
|
74
|
+
function Q(e) {
|
|
75
|
+
return m.some((t) => ae[t] === e && Z(t));
|
|
76
|
+
}
|
|
77
|
+
let Oe = X.size > 0, ke = s(() => ee(G.settings) === "rtl"), $ = `${ce} tpl:flex tpl:flex-col tpl:gap-3.5`;
|
|
78
|
+
return (e, s) => (n(), c("aside", T, [d("div", E, [
|
|
79
|
+
Q("layout") ? (n(), c("div", {
|
|
80
|
+
key: 0,
|
|
81
|
+
class: o($),
|
|
82
|
+
"data-testid": "template-settings-card-layout"
|
|
83
|
+
}, [
|
|
84
|
+
d("div", D, [a(i(_), {
|
|
85
|
+
class: "tpl:text-[var(--tpl-text-muted)]",
|
|
86
|
+
size: 14,
|
|
87
|
+
"stroke-width": 2
|
|
88
|
+
}), d("span", null, p(i(q).templateSettings.layout), 1)]),
|
|
89
|
+
Z("width") ? (n(), c("div", O, [d("label", { class: o(i(y)) }, p(i(q).templateSettings.widthPreset), 3), d("div", k, [(n(), c(f, null, t(De, (e) => d("button", {
|
|
90
|
+
key: e.value,
|
|
91
|
+
class: "tpl:cursor-pointer tpl:rounded-[var(--tpl-radius-sm)] tpl:border-none tpl:px-2 tpl:py-1.5 tpl:text-sm tpl:font-medium tpl:transition-all tpl:duration-[120ms] tpl:ease-[cubic-bezier(0.16,1,0.3,1)]",
|
|
92
|
+
style: u({
|
|
93
|
+
backgroundColor: r.settings.width === e.value ? "var(--tpl-bg)" : "transparent",
|
|
94
|
+
color: r.settings.width === e.value ? "var(--tpl-primary)" : "var(--tpl-text-muted)",
|
|
95
|
+
boxShadow: r.settings.width === e.value ? "var(--tpl-shadow)" : "none"
|
|
96
|
+
}),
|
|
97
|
+
onClick: (t) => K("update", { width: e.value })
|
|
98
|
+
}, p(e.label), 13, A)), 64))])])) : l("", !0),
|
|
99
|
+
Z("width") ? (n(), c("div", j, [d("label", { class: o(i(y)) }, p(i(q).templateSettings.customWidth), 3), d("div", M, [d("input", {
|
|
100
|
+
type: "number",
|
|
101
|
+
class: o(i(le)),
|
|
102
|
+
value: r.settings.width,
|
|
103
|
+
min: "300",
|
|
104
|
+
max: "900",
|
|
105
|
+
onInput: s[0] ||= (e) => K("update", { width: Number(e.target.value) })
|
|
106
|
+
}, null, 42, N), d("span", { class: o(i(se)) }, "px", 2)])])) : l("", !0)
|
|
107
|
+
])) : l("", !0),
|
|
108
|
+
Q("appearance") ? (n(), c("div", {
|
|
109
|
+
key: 1,
|
|
110
|
+
class: o($),
|
|
111
|
+
"data-testid": "template-settings-card-appearance"
|
|
112
|
+
}, [
|
|
113
|
+
d("div", P, [a(i(h), {
|
|
114
|
+
class: "tpl:text-[var(--tpl-text-muted)]",
|
|
115
|
+
size: 14,
|
|
116
|
+
"stroke-width": 2
|
|
117
|
+
}), d("span", null, p(i(q).templateSettings.appearance), 1)]),
|
|
118
|
+
Z("backgroundColor") ? (n(), c("div", F, [d("label", { class: o(i(y)) }, p(i(q).templateSettings.backgroundColor), 3), a(S, {
|
|
119
|
+
"model-value": r.settings.backgroundColor,
|
|
120
|
+
placeholder: i(x),
|
|
121
|
+
"onUpdate:modelValue": s[1] ||= (e) => K("update", { backgroundColor: e })
|
|
122
|
+
}, null, 8, ["model-value", "placeholder"])])) : l("", !0),
|
|
123
|
+
Z("textColor") ? (n(), c("div", I, [d("label", { class: o(i(y)) }, p(i(q).templateSettings.textColor), 3), a(S, {
|
|
124
|
+
"model-value": r.settings.textColor ?? "",
|
|
125
|
+
"seed-color": "#1a1a1a",
|
|
126
|
+
"onUpdate:modelValue": s[2] ||= (e) => K("update", { textColor: e })
|
|
127
|
+
}, null, 8, ["model-value"])])) : l("", !0),
|
|
128
|
+
Z("linkColor") ? (n(), c("div", L, [d("label", { class: o(i(y)) }, p(i(q).templateSettings.linkColor), 3), a(S, {
|
|
129
|
+
"model-value": r.settings.linkColor ?? "",
|
|
130
|
+
"seed-color": "#0066cc",
|
|
131
|
+
"onUpdate:modelValue": s[3] ||= (e) => K("update", { linkColor: e || void 0 })
|
|
132
|
+
}, null, 8, ["model-value"])])) : l("", !0),
|
|
133
|
+
Z("linkUnderline") ? (n(), c("div", R, [a(w, {
|
|
134
|
+
class: "tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-text-muted)]",
|
|
135
|
+
"model-value": r.settings.linkUnderline,
|
|
136
|
+
label: i(q).templateSettings.linkUnderline,
|
|
137
|
+
"onUpdate:modelValue": s[4] ||= (e) => K("update", { linkUnderline: e })
|
|
138
|
+
}, null, 8, ["model-value", "label"])])) : l("", !0),
|
|
139
|
+
Z("fontFamily") ? (n(), c("div", z, [d("label", { class: o(i(y)) }, p(i(q).templateSettings.fontFamily), 3), d("select", {
|
|
140
|
+
class: o(i(b)),
|
|
141
|
+
value: Ee.value,
|
|
142
|
+
onChange: s[5] ||= (e) => K("update", { fontFamily: e.target.value })
|
|
143
|
+
}, [(n(!0), c(f, null, t(Y.value, (e) => (n(), c("option", {
|
|
144
|
+
key: e.value,
|
|
145
|
+
value: e.value
|
|
146
|
+
}, p(e.label), 9, V))), 128))], 42, B)])) : l("", !0)
|
|
147
|
+
])) : l("", !0),
|
|
148
|
+
Q("language") ? (n(), c("div", {
|
|
149
|
+
key: 2,
|
|
150
|
+
class: o($),
|
|
151
|
+
"data-testid": "template-settings-card-language"
|
|
152
|
+
}, [
|
|
153
|
+
d("div", H, [a(i(g), {
|
|
154
|
+
class: "tpl:text-[var(--tpl-text-muted)]",
|
|
155
|
+
size: 14,
|
|
156
|
+
"stroke-width": 2
|
|
157
|
+
}), d("span", null, p(i(q).templateSettings.language), 1)]),
|
|
158
|
+
Z("locale") ? (n(), c("div", ue, [
|
|
159
|
+
d("label", { class: o(i(y)) }, p(i(q).templateSettings.contentLocale), 3),
|
|
160
|
+
d("input", {
|
|
161
|
+
type: "text",
|
|
162
|
+
class: o(i(b)),
|
|
163
|
+
value: r.settings.locale ?? "",
|
|
164
|
+
placeholder: "en",
|
|
165
|
+
spellcheck: "false",
|
|
166
|
+
autocapitalize: "off",
|
|
167
|
+
autocomplete: "off",
|
|
168
|
+
onInput: s[6] ||= (e) => K("update", { locale: e.target.value.trim() || void 0 })
|
|
169
|
+
}, null, 42, U),
|
|
170
|
+
d("p", de, p(i(q).templateSettings.contentLocaleHint), 1)
|
|
171
|
+
])) : l("", !0),
|
|
172
|
+
Z("direction") ? (n(), c("div", fe, [a(w, {
|
|
173
|
+
class: "tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-text-muted)]",
|
|
174
|
+
"model-value": ke.value,
|
|
175
|
+
label: i(q).templateSettings.contentDirection,
|
|
176
|
+
"onUpdate:modelValue": s[7] ||= (e) => K("update", { direction: e ? "rtl" : "ltr" })
|
|
177
|
+
}, null, 8, ["model-value", "label"]), d("p", pe, p(i(q).templateSettings.contentDirectionHint), 1)])) : l("", !0)
|
|
178
|
+
])) : l("", !0),
|
|
179
|
+
Q("preheader") ? (n(), c("div", {
|
|
180
|
+
key: 3,
|
|
181
|
+
class: o($),
|
|
182
|
+
"data-testid": "template-settings-card-preheader"
|
|
183
|
+
}, [d("div", me, [a(i(v), {
|
|
184
|
+
class: "tpl:text-[var(--tpl-text-muted)]",
|
|
185
|
+
size: 14,
|
|
186
|
+
"stroke-width": 2
|
|
187
|
+
}), d("span", null, p(i(q).templateSettings.preheaderText), 1)]), Z("preheaderText") ? (n(), c("div", he, [a(C, {
|
|
188
|
+
"model-value": r.settings.preheaderText ?? "",
|
|
189
|
+
placeholder: i(q).templateSettings.preheaderTextPlaceholder,
|
|
190
|
+
rows: 2,
|
|
191
|
+
"onUpdate:modelValue": s[8] ||= (e) => K("update", { preheaderText: e.replace(/[\r\n]/g, " ") || void 0 })
|
|
192
|
+
}, null, 8, ["model-value", "placeholder"]), d("div", ge, [d("span", _e, p(i(q).templateSettings.preheaderTextHint), 1), d("span", ve, p((r.settings.preheaderText ?? "").length) + "/" + p(Te), 1)])])) : l("", !0)])) : l("", !0),
|
|
193
|
+
Oe ? (n(), c("div", ye, [d("div", be, [a(i(oe), {
|
|
194
|
+
size: 14,
|
|
195
|
+
"stroke-width": 2
|
|
196
|
+
}), d("span", null, p(i(q).templateSettings.tips), 1)]), d("ul", xe, [
|
|
197
|
+
d("li", Se, p(i(q).templateSettings.tip1), 1),
|
|
198
|
+
d("li", Ce, p(i(q).templateSettings.tip2), 1),
|
|
199
|
+
d("li", we, p(i(q).templateSettings.tip3), 1)
|
|
200
|
+
])])) : l("", !0)
|
|
201
|
+
])]));
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
//#endregion
|
|
205
|
+
export { W as default };
|
|
206
|
+
|
|
207
|
+
//# sourceMappingURL=TemplateSettings-DjXiiiNr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TemplateSettings-DjXiiiNr.js","names":[],"sources":["../../../src/components/TemplateSettings.vue","../../../src/components/TemplateSettings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport ColorPicker from \"./ColorPicker.vue\";\nimport MergeTagTextarea from \"./MergeTagTextarea.vue\";\nimport ToggleSwitch from \"./ToggleSwitch.vue\";\nimport { useI18n } from \"../composables/useI18n\";\nimport {\n resolveContentDirection,\n type TemplateSettings,\n} from \"@templatical/types\";\nimport {\n cardClass,\n inputClass,\n inputGroupInputClass,\n inputSuffixClass,\n labelClass,\n DEFAULT_BG_COLOR,\n} from \"../constants/styleConstants\";\nimport { Circle, Eye, Globe, Info, Square } from \"@lucide/vue\";\nimport { computed, inject } from \"vue\";\nimport {\n FONTS_MANAGER_KEY,\n TEMPLATE_SETTINGS_FIELDS_KEY,\n requireInject,\n} from \"../keys\";\nimport {\n ALL_TEMPLATE_SETTINGS_FIELDS,\n TEMPLATE_SETTINGS_FIELD_CARDS,\n type TemplateSettingsCard,\n type TemplateSettingsField,\n} from \"../utils/templateSettingsFields\";\n\nconst props = defineProps<{\n settings: TemplateSettings;\n}>();\n\nconst emit = defineEmits<{\n (e: \"update\", settings: Partial<TemplateSettings>): void;\n}>();\n\nconst PREHEADER_MAX_LENGTH = 150;\n\nconst { t } = useI18n();\n\nconst fontsManager = requireInject(FONTS_MANAGER_KEY, \"TemplateSettings\");\nconst fontFamilies = computed(() => fontsManager.fonts.value);\n\n// If current font is not in available list (e.g., custom font when disabled), use default\nconst displayedFontFamily = computed(() => {\n const isAvailable = fontFamilies.value.some(\n (font) => font.value === props.settings.fontFamily,\n );\n return isAvailable\n ? props.settings.fontFamily\n : fontsManager.defaultFont.value;\n});\n\nconst widthPresets = [\n { value: 480, label: \"480px\" },\n { value: 600, label: \"600px\" },\n { value: 700, label: \"700px\" },\n { value: 800, label: \"800px\" },\n];\n\n// Default to every field: the key is absent whenever a consumer configured no\n// `templateSettings`, and that config only ever narrows.\nconst allowedFields = inject(\n TEMPLATE_SETTINGS_FIELDS_KEY,\n new Set(ALL_TEMPLATE_SETTINGS_FIELDS),\n);\n\nfunction shows(field: TemplateSettingsField): boolean {\n return allowedFields.has(field);\n}\n\n// A card earns its heading only if it still has something to hold. Derived from\n// the field→card map rather than hand-listed per card, so a new setting joins\n// its card's gate the moment it joins the map.\nfunction showsCard(card: TemplateSettingsCard): boolean {\n return ALL_TEMPLATE_SETTINGS_FIELDS.some(\n (field) => TEMPLATE_SETTINGS_FIELD_CARDS[field] === card && shows(field),\n );\n}\n\n// Tips is advice about the settings, so it rides on there being at least one:\n// a Settings tab holding nothing but advice reads as a bug. Plain const, like\n// the two helpers above — the allowlist is init-time config, not reactive\n// state, and a `computed` here would imply it can change.\nconst showsAnyField = allowedFields.size > 0;\n\nconst isRtl = computed(() => resolveContentDirection(props.settings) === \"rtl\");\n\n// Cards lay their contents out with a flex gap rather than a bottom margin on\n// every child but the last. A margin leaves dead space under whichever field\n// became last once an excluded one is dropped, and which field that is depends\n// on the consumer's allowlist — so there is no \"last\" to special-case.\nconst cardStackClass = `${cardClass} tpl:flex tpl:flex-col tpl:gap-3.5`;\n</script>\n\n<template>\n <aside\n data-testid=\"template-settings\"\n class=\"tpl:flex tpl:w-full tpl:flex-1 tpl:flex-col tpl:bg-[var(--tpl-bg-elevated)]\"\n >\n <div\n class=\"tpl:flex tpl:flex-1 tpl:flex-col tpl:gap-3 tpl:overflow-y-auto tpl:p-4\"\n >\n <!-- Layout card -->\n <div\n v-if=\"showsCard('layout')\"\n :class=\"cardStackClass\"\n data-testid=\"template-settings-card-layout\"\n >\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n >\n <Square\n class=\"tpl:text-[var(--tpl-text-muted)]\"\n :size=\"14\"\n :stroke-width=\"2\"\n />\n <span>{{ t.templateSettings.layout }}</span>\n </div>\n\n <div v-if=\"shows('width')\" data-testid=\"template-settings-width-preset\">\n <label :class=\"labelClass\">{{\n t.templateSettings.widthPreset\n }}</label>\n <div\n class=\"tpl:grid tpl:grid-cols-4 tpl:gap-1 tpl:rounded-[var(--tpl-radius-sm)] tpl:p-1 tpl:bg-[var(--tpl-bg-hover)]\"\n >\n <button\n v-for=\"preset in widthPresets\"\n :key=\"preset.value\"\n class=\"tpl:cursor-pointer tpl:rounded-[var(--tpl-radius-sm)] tpl:border-none tpl:px-2 tpl:py-1.5 tpl:text-sm tpl:font-medium tpl:transition-all tpl:duration-[120ms] tpl:ease-[cubic-bezier(0.16,1,0.3,1)]\"\n :style=\"{\n backgroundColor:\n settings.width === preset.value\n ? 'var(--tpl-bg)'\n : 'transparent',\n color:\n settings.width === preset.value\n ? 'var(--tpl-primary)'\n : 'var(--tpl-text-muted)',\n boxShadow:\n settings.width === preset.value\n ? 'var(--tpl-shadow)'\n : 'none',\n }\"\n @click=\"emit('update', { width: preset.value })\"\n >\n {{ preset.label }}\n </button>\n </div>\n </div>\n\n <div v-if=\"shows('width')\" data-testid=\"template-settings-width-custom\">\n <label :class=\"labelClass\">{{\n t.templateSettings.customWidth\n }}</label>\n <div class=\"tpl:flex tpl:items-stretch\">\n <input\n type=\"number\"\n :class=\"inputGroupInputClass\"\n :value=\"settings.width\"\n min=\"300\"\n max=\"900\"\n @input=\"\n emit('update', {\n width: Number(($event.target as HTMLInputElement).value),\n })\n \"\n />\n <span :class=\"inputSuffixClass\">px</span>\n </div>\n </div>\n </div>\n\n <!-- Appearance card -->\n <div\n v-if=\"showsCard('appearance')\"\n :class=\"cardStackClass\"\n data-testid=\"template-settings-card-appearance\"\n >\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n >\n <Circle\n class=\"tpl:text-[var(--tpl-text-muted)]\"\n :size=\"14\"\n :stroke-width=\"2\"\n />\n <span>{{ t.templateSettings.appearance }}</span>\n </div>\n\n <div\n v-if=\"shows('backgroundColor')\"\n data-testid=\"template-settings-background\"\n >\n <label :class=\"labelClass\">{{\n t.templateSettings.backgroundColor\n }}</label>\n <ColorPicker\n :model-value=\"settings.backgroundColor\"\n :placeholder=\"DEFAULT_BG_COLOR\"\n @update:model-value=\"emit('update', { backgroundColor: $event })\"\n />\n </div>\n\n <div\n v-if=\"shows('textColor')\"\n data-testid=\"template-settings-text-color\"\n >\n <label :class=\"labelClass\">{{ t.templateSettings.textColor }}</label>\n <ColorPicker\n :model-value=\"settings.textColor ?? ''\"\n seed-color=\"#1a1a1a\"\n @update:model-value=\"emit('update', { textColor: $event })\"\n />\n </div>\n\n <div\n v-if=\"shows('linkColor')\"\n data-testid=\"template-settings-link-color\"\n >\n <label :class=\"labelClass\">{{ t.templateSettings.linkColor }}</label>\n <ColorPicker\n :model-value=\"settings.linkColor ?? ''\"\n seed-color=\"#0066cc\"\n @update:model-value=\"\n emit('update', { linkColor: $event || undefined })\n \"\n />\n </div>\n\n <div\n v-if=\"shows('linkUnderline')\"\n data-testid=\"template-settings-link-underline\"\n >\n <ToggleSwitch\n class=\"tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-text-muted)]\"\n :model-value=\"settings.linkUnderline\"\n :label=\"t.templateSettings.linkUnderline\"\n @update:model-value=\"emit('update', { linkUnderline: $event })\"\n />\n </div>\n\n <div\n v-if=\"shows('fontFamily')\"\n data-testid=\"template-settings-font-family\"\n >\n <label :class=\"labelClass\">{{ t.templateSettings.fontFamily }}</label>\n <select\n :class=\"inputClass\"\n :value=\"displayedFontFamily\"\n @change=\"\n emit('update', {\n fontFamily: ($event.target as HTMLSelectElement).value,\n })\n \"\n >\n <option\n v-for=\"font in fontFamilies\"\n :key=\"font.value\"\n :value=\"font.value\"\n >\n {{ font.label }}\n </option>\n </select>\n </div>\n </div>\n\n <!-- Language card -->\n <div\n v-if=\"showsCard('language')\"\n :class=\"cardStackClass\"\n data-testid=\"template-settings-card-language\"\n >\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n >\n <Globe\n class=\"tpl:text-[var(--tpl-text-muted)]\"\n :size=\"14\"\n :stroke-width=\"2\"\n />\n <span>{{ t.templateSettings.language }}</span>\n </div>\n\n <div v-if=\"shows('locale')\" data-testid=\"template-settings-locale\">\n <label :class=\"labelClass\">{{\n t.templateSettings.contentLocale\n }}</label>\n <input\n type=\"text\"\n :class=\"inputClass\"\n :value=\"settings.locale ?? ''\"\n placeholder=\"en\"\n spellcheck=\"false\"\n autocapitalize=\"off\"\n autocomplete=\"off\"\n @input=\"\n emit('update', {\n locale:\n ($event.target as HTMLInputElement).value.trim() || undefined,\n })\n \"\n />\n <p\n class=\"tpl:mt-1 tpl:text-xs tpl:leading-relaxed tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ t.templateSettings.contentLocaleHint }}\n </p>\n </div>\n\n <div\n v-if=\"shows('direction')\"\n data-testid=\"template-settings-direction\"\n >\n <ToggleSwitch\n class=\"tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-text-muted)]\"\n :model-value=\"isRtl\"\n :label=\"t.templateSettings.contentDirection\"\n @update:model-value=\"\n emit('update', { direction: $event ? 'rtl' : 'ltr' })\n \"\n />\n <p\n class=\"tpl:mt-1 tpl:text-xs tpl:leading-relaxed tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ t.templateSettings.contentDirectionHint }}\n </p>\n </div>\n </div>\n\n <!-- Preheader card -->\n <div\n v-if=\"showsCard('preheader')\"\n :class=\"cardStackClass\"\n data-testid=\"template-settings-card-preheader\"\n >\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n >\n <Eye\n class=\"tpl:text-[var(--tpl-text-muted)]\"\n :size=\"14\"\n :stroke-width=\"2\"\n />\n <span>{{ t.templateSettings.preheaderText }}</span>\n </div>\n\n <div\n v-if=\"shows('preheaderText')\"\n data-testid=\"template-settings-preheader\"\n >\n <MergeTagTextarea\n :model-value=\"settings.preheaderText ?? ''\"\n :placeholder=\"t.templateSettings.preheaderTextPlaceholder\"\n :rows=\"2\"\n @update:model-value=\"\n emit('update', {\n preheaderText: $event.replace(/[\\r\\n]/g, ' ') || undefined,\n })\n \"\n />\n <div\n class=\"tpl:mt-1 tpl:flex tpl:items-start tpl:justify-between tpl:gap-2\"\n >\n <span\n class=\"tpl:text-xs tpl:leading-relaxed tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ t.templateSettings.preheaderTextHint }}\n </span>\n <span\n class=\"tpl:shrink-0 tpl:text-xs tpl:tabular-nums tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ (settings.preheaderText ?? \"\").length }}/{{\n PREHEADER_MAX_LENGTH\n }}\n </span>\n </div>\n </div>\n </div>\n\n <!-- Tips card -->\n <div\n v-if=\"showsAnyField\"\n class=\"tpl:rounded-[var(--tpl-radius)] tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:p-3\"\n data-testid=\"template-settings-card-tips\"\n >\n <div\n class=\"tpl:mb-2.5 tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text-muted)]\"\n >\n <Info :size=\"14\" :stroke-width=\"2\" />\n <span>{{ t.templateSettings.tips }}</span>\n </div>\n <ul\n class=\"tpl:m-0 tpl:pl-[18px] tpl:text-xs tpl:leading-relaxed tpl:text-[var(--tpl-text-dim)]\"\n >\n <li class=\"tpl:mb-1 tpl:last:mb-0\">\n {{ t.templateSettings.tip1 }}\n </li>\n <li class=\"tpl:mb-1 tpl:last:mb-0\">\n {{ t.templateSettings.tip2 }}\n </li>\n <li class=\"tpl:mb-1 tpl:last:mb-0\">\n {{ t.templateSettings.tip3 }}\n </li>\n </ul>\n </div>\n </div>\n </aside>\n</template>\n","<script setup lang=\"ts\">\nimport ColorPicker from \"./ColorPicker.vue\";\nimport MergeTagTextarea from \"./MergeTagTextarea.vue\";\nimport ToggleSwitch from \"./ToggleSwitch.vue\";\nimport { useI18n } from \"../composables/useI18n\";\nimport {\n resolveContentDirection,\n type TemplateSettings,\n} from \"@templatical/types\";\nimport {\n cardClass,\n inputClass,\n inputGroupInputClass,\n inputSuffixClass,\n labelClass,\n DEFAULT_BG_COLOR,\n} from \"../constants/styleConstants\";\nimport { Circle, Eye, Globe, Info, Square } from \"@lucide/vue\";\nimport { computed, inject } from \"vue\";\nimport {\n FONTS_MANAGER_KEY,\n TEMPLATE_SETTINGS_FIELDS_KEY,\n requireInject,\n} from \"../keys\";\nimport {\n ALL_TEMPLATE_SETTINGS_FIELDS,\n TEMPLATE_SETTINGS_FIELD_CARDS,\n type TemplateSettingsCard,\n type TemplateSettingsField,\n} from \"../utils/templateSettingsFields\";\n\nconst props = defineProps<{\n settings: TemplateSettings;\n}>();\n\nconst emit = defineEmits<{\n (e: \"update\", settings: Partial<TemplateSettings>): void;\n}>();\n\nconst PREHEADER_MAX_LENGTH = 150;\n\nconst { t } = useI18n();\n\nconst fontsManager = requireInject(FONTS_MANAGER_KEY, \"TemplateSettings\");\nconst fontFamilies = computed(() => fontsManager.fonts.value);\n\n// If current font is not in available list (e.g., custom font when disabled), use default\nconst displayedFontFamily = computed(() => {\n const isAvailable = fontFamilies.value.some(\n (font) => font.value === props.settings.fontFamily,\n );\n return isAvailable\n ? props.settings.fontFamily\n : fontsManager.defaultFont.value;\n});\n\nconst widthPresets = [\n { value: 480, label: \"480px\" },\n { value: 600, label: \"600px\" },\n { value: 700, label: \"700px\" },\n { value: 800, label: \"800px\" },\n];\n\n// Default to every field: the key is absent whenever a consumer configured no\n// `templateSettings`, and that config only ever narrows.\nconst allowedFields = inject(\n TEMPLATE_SETTINGS_FIELDS_KEY,\n new Set(ALL_TEMPLATE_SETTINGS_FIELDS),\n);\n\nfunction shows(field: TemplateSettingsField): boolean {\n return allowedFields.has(field);\n}\n\n// A card earns its heading only if it still has something to hold. Derived from\n// the field→card map rather than hand-listed per card, so a new setting joins\n// its card's gate the moment it joins the map.\nfunction showsCard(card: TemplateSettingsCard): boolean {\n return ALL_TEMPLATE_SETTINGS_FIELDS.some(\n (field) => TEMPLATE_SETTINGS_FIELD_CARDS[field] === card && shows(field),\n );\n}\n\n// Tips is advice about the settings, so it rides on there being at least one:\n// a Settings tab holding nothing but advice reads as a bug. Plain const, like\n// the two helpers above — the allowlist is init-time config, not reactive\n// state, and a `computed` here would imply it can change.\nconst showsAnyField = allowedFields.size > 0;\n\nconst isRtl = computed(() => resolveContentDirection(props.settings) === \"rtl\");\n\n// Cards lay their contents out with a flex gap rather than a bottom margin on\n// every child but the last. A margin leaves dead space under whichever field\n// became last once an excluded one is dropped, and which field that is depends\n// on the consumer's allowlist — so there is no \"last\" to special-case.\nconst cardStackClass = `${cardClass} tpl:flex tpl:flex-col tpl:gap-3.5`;\n</script>\n\n<template>\n <aside\n data-testid=\"template-settings\"\n class=\"tpl:flex tpl:w-full tpl:flex-1 tpl:flex-col tpl:bg-[var(--tpl-bg-elevated)]\"\n >\n <div\n class=\"tpl:flex tpl:flex-1 tpl:flex-col tpl:gap-3 tpl:overflow-y-auto tpl:p-4\"\n >\n <!-- Layout card -->\n <div\n v-if=\"showsCard('layout')\"\n :class=\"cardStackClass\"\n data-testid=\"template-settings-card-layout\"\n >\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n >\n <Square\n class=\"tpl:text-[var(--tpl-text-muted)]\"\n :size=\"14\"\n :stroke-width=\"2\"\n />\n <span>{{ t.templateSettings.layout }}</span>\n </div>\n\n <div v-if=\"shows('width')\" data-testid=\"template-settings-width-preset\">\n <label :class=\"labelClass\">{{\n t.templateSettings.widthPreset\n }}</label>\n <div\n class=\"tpl:grid tpl:grid-cols-4 tpl:gap-1 tpl:rounded-[var(--tpl-radius-sm)] tpl:p-1 tpl:bg-[var(--tpl-bg-hover)]\"\n >\n <button\n v-for=\"preset in widthPresets\"\n :key=\"preset.value\"\n class=\"tpl:cursor-pointer tpl:rounded-[var(--tpl-radius-sm)] tpl:border-none tpl:px-2 tpl:py-1.5 tpl:text-sm tpl:font-medium tpl:transition-all tpl:duration-[120ms] tpl:ease-[cubic-bezier(0.16,1,0.3,1)]\"\n :style=\"{\n backgroundColor:\n settings.width === preset.value\n ? 'var(--tpl-bg)'\n : 'transparent',\n color:\n settings.width === preset.value\n ? 'var(--tpl-primary)'\n : 'var(--tpl-text-muted)',\n boxShadow:\n settings.width === preset.value\n ? 'var(--tpl-shadow)'\n : 'none',\n }\"\n @click=\"emit('update', { width: preset.value })\"\n >\n {{ preset.label }}\n </button>\n </div>\n </div>\n\n <div v-if=\"shows('width')\" data-testid=\"template-settings-width-custom\">\n <label :class=\"labelClass\">{{\n t.templateSettings.customWidth\n }}</label>\n <div class=\"tpl:flex tpl:items-stretch\">\n <input\n type=\"number\"\n :class=\"inputGroupInputClass\"\n :value=\"settings.width\"\n min=\"300\"\n max=\"900\"\n @input=\"\n emit('update', {\n width: Number(($event.target as HTMLInputElement).value),\n })\n \"\n />\n <span :class=\"inputSuffixClass\">px</span>\n </div>\n </div>\n </div>\n\n <!-- Appearance card -->\n <div\n v-if=\"showsCard('appearance')\"\n :class=\"cardStackClass\"\n data-testid=\"template-settings-card-appearance\"\n >\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n >\n <Circle\n class=\"tpl:text-[var(--tpl-text-muted)]\"\n :size=\"14\"\n :stroke-width=\"2\"\n />\n <span>{{ t.templateSettings.appearance }}</span>\n </div>\n\n <div\n v-if=\"shows('backgroundColor')\"\n data-testid=\"template-settings-background\"\n >\n <label :class=\"labelClass\">{{\n t.templateSettings.backgroundColor\n }}</label>\n <ColorPicker\n :model-value=\"settings.backgroundColor\"\n :placeholder=\"DEFAULT_BG_COLOR\"\n @update:model-value=\"emit('update', { backgroundColor: $event })\"\n />\n </div>\n\n <div\n v-if=\"shows('textColor')\"\n data-testid=\"template-settings-text-color\"\n >\n <label :class=\"labelClass\">{{ t.templateSettings.textColor }}</label>\n <ColorPicker\n :model-value=\"settings.textColor ?? ''\"\n seed-color=\"#1a1a1a\"\n @update:model-value=\"emit('update', { textColor: $event })\"\n />\n </div>\n\n <div\n v-if=\"shows('linkColor')\"\n data-testid=\"template-settings-link-color\"\n >\n <label :class=\"labelClass\">{{ t.templateSettings.linkColor }}</label>\n <ColorPicker\n :model-value=\"settings.linkColor ?? ''\"\n seed-color=\"#0066cc\"\n @update:model-value=\"\n emit('update', { linkColor: $event || undefined })\n \"\n />\n </div>\n\n <div\n v-if=\"shows('linkUnderline')\"\n data-testid=\"template-settings-link-underline\"\n >\n <ToggleSwitch\n class=\"tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-text-muted)]\"\n :model-value=\"settings.linkUnderline\"\n :label=\"t.templateSettings.linkUnderline\"\n @update:model-value=\"emit('update', { linkUnderline: $event })\"\n />\n </div>\n\n <div\n v-if=\"shows('fontFamily')\"\n data-testid=\"template-settings-font-family\"\n >\n <label :class=\"labelClass\">{{ t.templateSettings.fontFamily }}</label>\n <select\n :class=\"inputClass\"\n :value=\"displayedFontFamily\"\n @change=\"\n emit('update', {\n fontFamily: ($event.target as HTMLSelectElement).value,\n })\n \"\n >\n <option\n v-for=\"font in fontFamilies\"\n :key=\"font.value\"\n :value=\"font.value\"\n >\n {{ font.label }}\n </option>\n </select>\n </div>\n </div>\n\n <!-- Language card -->\n <div\n v-if=\"showsCard('language')\"\n :class=\"cardStackClass\"\n data-testid=\"template-settings-card-language\"\n >\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n >\n <Globe\n class=\"tpl:text-[var(--tpl-text-muted)]\"\n :size=\"14\"\n :stroke-width=\"2\"\n />\n <span>{{ t.templateSettings.language }}</span>\n </div>\n\n <div v-if=\"shows('locale')\" data-testid=\"template-settings-locale\">\n <label :class=\"labelClass\">{{\n t.templateSettings.contentLocale\n }}</label>\n <input\n type=\"text\"\n :class=\"inputClass\"\n :value=\"settings.locale ?? ''\"\n placeholder=\"en\"\n spellcheck=\"false\"\n autocapitalize=\"off\"\n autocomplete=\"off\"\n @input=\"\n emit('update', {\n locale:\n ($event.target as HTMLInputElement).value.trim() || undefined,\n })\n \"\n />\n <p\n class=\"tpl:mt-1 tpl:text-xs tpl:leading-relaxed tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ t.templateSettings.contentLocaleHint }}\n </p>\n </div>\n\n <div\n v-if=\"shows('direction')\"\n data-testid=\"template-settings-direction\"\n >\n <ToggleSwitch\n class=\"tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-text-muted)]\"\n :model-value=\"isRtl\"\n :label=\"t.templateSettings.contentDirection\"\n @update:model-value=\"\n emit('update', { direction: $event ? 'rtl' : 'ltr' })\n \"\n />\n <p\n class=\"tpl:mt-1 tpl:text-xs tpl:leading-relaxed tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ t.templateSettings.contentDirectionHint }}\n </p>\n </div>\n </div>\n\n <!-- Preheader card -->\n <div\n v-if=\"showsCard('preheader')\"\n :class=\"cardStackClass\"\n data-testid=\"template-settings-card-preheader\"\n >\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-2 tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]\"\n >\n <Eye\n class=\"tpl:text-[var(--tpl-text-muted)]\"\n :size=\"14\"\n :stroke-width=\"2\"\n />\n <span>{{ t.templateSettings.preheaderText }}</span>\n </div>\n\n <div\n v-if=\"shows('preheaderText')\"\n data-testid=\"template-settings-preheader\"\n >\n <MergeTagTextarea\n :model-value=\"settings.preheaderText ?? ''\"\n :placeholder=\"t.templateSettings.preheaderTextPlaceholder\"\n :rows=\"2\"\n @update:model-value=\"\n emit('update', {\n preheaderText: $event.replace(/[\\r\\n]/g, ' ') || undefined,\n })\n \"\n />\n <div\n class=\"tpl:mt-1 tpl:flex tpl:items-start tpl:justify-between tpl:gap-2\"\n >\n <span\n class=\"tpl:text-xs tpl:leading-relaxed tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ t.templateSettings.preheaderTextHint }}\n </span>\n <span\n class=\"tpl:shrink-0 tpl:text-xs tpl:tabular-nums tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ (settings.preheaderText ?? \"\").length }}/{{\n PREHEADER_MAX_LENGTH\n }}\n </span>\n </div>\n </div>\n </div>\n\n <!-- Tips card -->\n <div\n v-if=\"showsAnyField\"\n class=\"tpl:rounded-[var(--tpl-radius)] tpl:border tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:p-3\"\n data-testid=\"template-settings-card-tips\"\n >\n <div\n class=\"tpl:mb-2.5 tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text-muted)]\"\n >\n <Info :size=\"14\" :stroke-width=\"2\" />\n <span>{{ t.templateSettings.tips }}</span>\n </div>\n <ul\n class=\"tpl:m-0 tpl:pl-[18px] tpl:text-xs tpl:leading-relaxed tpl:text-[var(--tpl-text-dim)]\"\n >\n <li class=\"tpl:mb-1 tpl:last:mb-0\">\n {{ t.templateSettings.tip1 }}\n </li>\n <li class=\"tpl:mb-1 tpl:last:mb-0\">\n {{ t.templateSettings.tip2 }}\n </li>\n <li class=\"tpl:mb-1 tpl:last:mb-0\">\n {{ t.templateSettings.tip3 }}\n </li>\n </ul>\n </div>\n </div>\n </aside>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { B as e, E as t, F as n, H as r, N as i, Q as a, S as o, U as s, a as ee, at as c, b as l, ct as u, f as d, g as f, h as p, m, o as te, p as h, u as g, ut as _, y as v } from "./draggable-
|
|
1
|
+
import { B as e, E as t, F as n, H as r, N as i, Q as a, S as o, U as s, a as ee, at as c, b as l, ct as u, f as d, g as f, h as p, m, o as te, p as h, u as g, ut as _, y as v } from "./draggable-IB4x6w2O.js";
|
|
2
2
|
import { u as ne } from "./src-Dwgq7hf4.js";
|
|
3
|
-
import {
|
|
4
|
-
import { D as ie, P as y, V as ae, g as oe, j as se } from "./keys-
|
|
5
|
-
import { t as ce } from "./useI18n-
|
|
6
|
-
import { Lt as le, it as ue } from "./icons-
|
|
3
|
+
import { N as re } from "./useEditorCore-BHmIp1hW.js";
|
|
4
|
+
import { D as ie, P as y, V as ae, g as oe, j as se } from "./keys-dJbD1QPs.js";
|
|
5
|
+
import { t as ce } from "./useI18n-DTZ9sIcv.js";
|
|
6
|
+
import { Lt as le, it as ue } from "./icons-BKkJ-5xF.js";
|
|
7
7
|
import { v as de } from "./styleConstants-C_YAPdQS.js";
|
|
8
|
-
import { n as fe, t as pe } from "./MergeTagModeToggle-
|
|
9
|
-
import { t as me } from "./TplModal-
|
|
10
|
-
import { t as he } from "./BlockPreviewCanvas-
|
|
8
|
+
import { n as fe, t as pe } from "./MergeTagModeToggle-n3nvSNeQ.js";
|
|
9
|
+
import { t as me } from "./TplModal-DuwS2ifK.js";
|
|
10
|
+
import { t as he } from "./BlockPreviewCanvas-lQrAdgG3.js";
|
|
11
11
|
//#region src/utils/validateEmailShape.ts
|
|
12
12
|
var b = /[,;<>()[\]\\"'`|/?#@!$%^&*+=~{}]/;
|
|
13
13
|
function x(e) {
|
|
@@ -203,4 +203,4 @@ var S = ["aria-busy"], C = {
|
|
|
203
203
|
//#endregion
|
|
204
204
|
export { z as default };
|
|
205
205
|
|
|
206
|
-
//# sourceMappingURL=TestEmailModal-
|
|
206
|
+
//# sourceMappingURL=TestEmailModal-BAuDxJtD.js.map
|