@templatical/editor 0.43.2 → 0.43.3
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 +1 -1
- package/dist/{AiChatSidebar-DTtMEXNR.js → AiChatSidebar-BAAypLEP.js} +7 -7
- package/dist/{AiFeatureMenu-DFj-_S9b.js → AiFeatureMenu-CQcrDR-J.js} +4 -4
- package/dist/{BlockIssueBadge-CyLmqjLl.js → BlockIssueBadge-DYI7ic1j.js} +2 -2
- package/dist/{BlockPreviewCanvas-C6F66f3k.js → BlockPreviewCanvas-x5W-Sdhg.js} +2 -2
- package/dist/{CloudHeaderExtras-Z4K6OMn0.js → CloudHeaderExtras-DnLaX4ea.js} +2 -2
- package/dist/{CloudPanels-DOJ2Vske.js → CloudPanels-BHPG3d1o.js} +4 -4
- package/dist/{CollaboratorBar-BCkl3dKY.js → CollaboratorBar-DG6KroMt.js} +2 -2
- package/dist/{CommentsPanel-DPMi6-rb.js → CommentsPanel-Bzk6VhJg.js} +1 -1
- package/dist/{CommentsSidebar-C1mQcyh3.js → CommentsSidebar-CaRC3c1b.js} +10 -10
- package/dist/{CountdownToolbar-DKmzpk__.js → CountdownToolbar-B-pAigUh.js} +3 -3
- package/dist/{DesignReferenceSidebar-CGRzOOb8.js → DesignReferenceSidebar-DfuJyDBz.js} +5 -5
- package/dist/{IssuesPanel-CsdxjjRm.js → IssuesPanel-vWhcDIvb.js} +5 -5
- package/dist/{LogicTagInsertButton-BX4jOUQy.js → LogicTagInsertButton-D2Fjo444.js} +3 -3
- package/dist/{MediaEditModal-Bm8uOKBx.js → MediaEditModal-BuP8SJrv.js} +1 -1
- package/dist/{MediaPanels-BNWtEntu.js → MediaPanels-BkcF0r_r.js} +1 -1
- package/dist/{MergeTagInput-Mj8CFfX1.js → MergeTagInput-fEOOY7OU.js} +1 -1
- package/dist/{MergeTagModeToggle-CinojvpV.js → MergeTagModeToggle-BOeEL52u.js} +3 -3
- package/dist/{ParagraphEditor-DdOteRjD.js → ParagraphEditor-BlJGeBRY.js} +22 -22
- package/dist/{RestoreVersionDialog-B-i0wPjh.js → RestoreVersionDialog-DYaoFk5G.js} +3 -3
- package/dist/{RichTextEditorContent-CDtKOWsh.js → RichTextEditorContent-GacK8qwu.js} +4 -4
- package/dist/{SaveBlockDialog-DTcGPDMT.js → SaveBlockDialog-DR1UCtQY.js} +8 -8
- package/dist/{SavedBlocksBrowserModal-BA5yXQi0.js → SavedBlocksBrowserModal-q_-qYW9a.js} +9 -9
- package/dist/{SavedBlocksPanels-mfSALJqB.js → SavedBlocksPanels-nTH8NTAT.js} +1 -1
- package/dist/{SavedBlocksPickBar-BOjduGI4.js → SavedBlocksPickBar-C7vHmc5c.js} +2 -2
- package/dist/{TemplateScoringPanel-Byz-ajjf.js → TemplateScoringPanel-D9jeQCYl.js} +11 -11
- package/dist/{TemplateSettings-Bf5rfsU8.js → TemplateSettings-ClfHwxUa.js} +5 -5
- package/dist/{TestEmailModal-DJo2yFLh.js → TestEmailModal-DEnvrv38.js} +6 -6
- package/dist/{TestEmailPanel-CXIFWfDm.js → TestEmailPanel-Ca9t6KG7.js} +1 -1
- package/dist/{TitleEditor-BDtokkQF.js → TitleEditor-D7mNs3s5.js} +9 -9
- package/dist/{ToggleSwitch-BCYZvP1e.js → ToggleSwitch-Z-rqEcig.js} +1 -1
- package/dist/{Toolbar-XOtJ_N58.js → Toolbar-DUgyDBkz.js} +28 -28
- package/dist/{TplModal-C3mzMXof.js → TplModal-CYyFAScB.js} +1 -1
- package/dist/{VersionHistoryMenu-DRoFz15y.js → VersionHistoryMenu-D42tGKM6.js} +5 -5
- package/dist/{VersionHistoryPanels-CeF0JnXI.js → VersionHistoryPanels-o0HGvQJX.js} +1 -1
- package/dist/{VersionPreviewBanner-DQvIEKUU.js → VersionPreviewBanner-D5RZtvUf.js} +1 -1
- package/dist/{WrapperBlock-DZwp4G7P.js → WrapperBlock-B0_vSfSD.js} +1 -1
- package/dist/{blockTypeIcons-CAPoy6X7.js → blockTypeIcons-CEk_GHmU.js} +2 -2
- package/dist/bundle-stats.json +6 -6
- package/dist/{ca--zGWn9AU.js → ca-DSwai-th.js} +1 -4
- package/dist/cdn/chunks/{AiChatSidebar-DW1uRkKE.js → AiChatSidebar-oFwacME4.js} +2 -2
- package/dist/cdn/chunks/{AiChatSidebar-DW1uRkKE.js.map → AiChatSidebar-oFwacME4.js.map} +1 -1
- package/dist/cdn/chunks/{AiFeatureMenu-CHsgD78N.js → AiFeatureMenu-BiHFJf9i.js} +3 -3
- package/dist/cdn/chunks/{AiFeatureMenu-CHsgD78N.js.map → AiFeatureMenu-BiHFJf9i.js.map} +1 -1
- package/dist/cdn/chunks/{BlockIssueBadge-CIqu8JnG.js → BlockIssueBadge-CWlcDBFm.js} +2 -2
- package/dist/cdn/chunks/{BlockIssueBadge-CIqu8JnG.js.map → BlockIssueBadge-CWlcDBFm.js.map} +1 -1
- package/dist/cdn/chunks/{BlockPreviewCanvas-Dtea66SI.js → BlockPreviewCanvas-CIwIA3zq.js} +3 -3
- package/dist/cdn/chunks/{BlockPreviewCanvas-Dtea66SI.js.map → BlockPreviewCanvas-CIwIA3zq.js.map} +1 -1
- package/dist/cdn/chunks/{CloudHeaderExtras-Kjj78__m.js → CloudHeaderExtras-BgsjwWUQ.js} +3 -3
- package/dist/cdn/chunks/{CloudHeaderExtras-Kjj78__m.js.map → CloudHeaderExtras-BgsjwWUQ.js.map} +1 -1
- package/dist/cdn/chunks/{CloudPanels-DARXXD0q.js → CloudPanels-DFCwq8_J.js} +4 -4
- package/dist/cdn/chunks/{CloudPanels-DARXXD0q.js.map → CloudPanels-DFCwq8_J.js.map} +1 -1
- package/dist/cdn/chunks/{CollaboratorBar-C7O9mQJ_.js → CollaboratorBar-CiMZfMwN.js} +3 -3
- package/dist/cdn/chunks/{CollaboratorBar-C7O9mQJ_.js.map → CollaboratorBar-CiMZfMwN.js.map} +1 -1
- package/dist/cdn/chunks/{CommentsPanel-KH5_JS7_.js → CommentsPanel-CL4grbMp.js} +2 -2
- package/dist/cdn/chunks/{CommentsPanel-KH5_JS7_.js.map → CommentsPanel-CL4grbMp.js.map} +1 -1
- package/dist/cdn/chunks/{CommentsSidebar-ucrNvgAQ.js → CommentsSidebar-tWYYKv1s.js} +2 -2
- package/dist/cdn/chunks/{CommentsSidebar-ucrNvgAQ.js.map → CommentsSidebar-tWYYKv1s.js.map} +1 -1
- package/dist/cdn/chunks/{CountdownToolbar-DVInzkj9.js → CountdownToolbar-DfyqIppF.js} +4 -4
- package/dist/cdn/chunks/{CountdownToolbar-DVInzkj9.js.map → CountdownToolbar-DfyqIppF.js.map} +1 -1
- package/dist/cdn/chunks/{DesignReferenceSidebar-pleljkEJ.js → DesignReferenceSidebar-C6O12hvt.js} +2 -2
- package/dist/cdn/chunks/{DesignReferenceSidebar-pleljkEJ.js.map → DesignReferenceSidebar-C6O12hvt.js.map} +1 -1
- package/dist/cdn/chunks/{IssuesPanel-CPcQIUni.js → IssuesPanel-DYJXIwnw.js} +2 -2
- package/dist/cdn/chunks/{IssuesPanel-CPcQIUni.js.map → IssuesPanel-DYJXIwnw.js.map} +1 -1
- package/dist/cdn/chunks/{LogicTagInsertButton-DSrW9v0x.js → LogicTagInsertButton-FNMVxm_V.js} +2 -2
- package/dist/cdn/chunks/{LogicTagInsertButton-DSrW9v0x.js.map → LogicTagInsertButton-FNMVxm_V.js.map} +1 -1
- package/dist/cdn/chunks/{MediaEditModal-BHp7euCZ.js → MediaEditModal-C9yZ0AJv.js} +2 -2
- package/dist/cdn/chunks/{MediaEditModal-BHp7euCZ.js.map → MediaEditModal-C9yZ0AJv.js.map} +1 -1
- package/dist/cdn/chunks/{MediaPanels-CGIRlO48.js → MediaPanels-DiKU1r9P.js} +2 -2
- package/dist/cdn/chunks/{MediaPanels-CGIRlO48.js.map → MediaPanels-DiKU1r9P.js.map} +1 -1
- package/dist/cdn/chunks/{MergeTagInput-BSFofWuc.js → MergeTagInput-CSC64xNL.js} +2 -2
- package/dist/cdn/chunks/{MergeTagInput-BSFofWuc.js.map → MergeTagInput-CSC64xNL.js.map} +1 -1
- package/dist/cdn/chunks/{MergeTagModeToggle-D7KlTFZV.js → MergeTagModeToggle-027RMXDP.js} +2 -2
- package/dist/cdn/chunks/{MergeTagModeToggle-D7KlTFZV.js.map → MergeTagModeToggle-027RMXDP.js.map} +1 -1
- package/dist/cdn/chunks/{ParagraphEditor-CokXagL1.js → ParagraphEditor-0Z26-N5u.js} +19 -19
- package/dist/cdn/chunks/{ParagraphEditor-CokXagL1.js.map → ParagraphEditor-0Z26-N5u.js.map} +1 -1
- package/dist/cdn/chunks/{RestoreVersionDialog-C-XEncAM.js → RestoreVersionDialog-Dd1v1KLK.js} +3 -3
- package/dist/cdn/chunks/{RestoreVersionDialog-C-XEncAM.js.map → RestoreVersionDialog-Dd1v1KLK.js.map} +1 -1
- package/dist/cdn/chunks/{RichTextEditorContent-DS_2UsJX.js → RichTextEditorContent-BOZ_5I76.js} +4 -4
- package/dist/cdn/chunks/{RichTextEditorContent-DS_2UsJX.js.map → RichTextEditorContent-BOZ_5I76.js.map} +1 -1
- package/dist/cdn/chunks/{SaveBlockDialog-D8OAKF_k.js → SaveBlockDialog-B6WQwNJD.js} +6 -6
- package/dist/cdn/chunks/{SaveBlockDialog-D8OAKF_k.js.map → SaveBlockDialog-B6WQwNJD.js.map} +1 -1
- package/dist/cdn/chunks/{SavedBlocksBrowserModal-B6GN_llD.js → SavedBlocksBrowserModal-C015fVMV.js} +6 -6
- package/dist/cdn/chunks/{SavedBlocksBrowserModal-B6GN_llD.js.map → SavedBlocksBrowserModal-C015fVMV.js.map} +1 -1
- package/dist/cdn/chunks/{SavedBlocksPanels-hRCREVxS.js → SavedBlocksPanels-DZmfXW4x.js} +2 -2
- package/dist/cdn/chunks/{SavedBlocksPanels-hRCREVxS.js.map → SavedBlocksPanels-DZmfXW4x.js.map} +1 -1
- package/dist/cdn/chunks/{SavedBlocksPickBar-C5YrK0iB.js → SavedBlocksPickBar-DtCQFCCW.js} +3 -3
- package/dist/cdn/chunks/{SavedBlocksPickBar-C5YrK0iB.js.map → SavedBlocksPickBar-DtCQFCCW.js.map} +1 -1
- package/dist/cdn/chunks/{TemplateScoringPanel-DXyQjcdU.js → TemplateScoringPanel-CeCVyNV1.js} +2 -2
- package/dist/cdn/chunks/{TemplateScoringPanel-DXyQjcdU.js.map → TemplateScoringPanel-CeCVyNV1.js.map} +1 -1
- package/dist/cdn/chunks/{TemplateSettings-da14bXlk.js → TemplateSettings-CuXwthI6.js} +4 -4
- package/dist/cdn/chunks/{TemplateSettings-da14bXlk.js.map → TemplateSettings-CuXwthI6.js.map} +1 -1
- package/dist/cdn/chunks/{TestEmailModal-Dl_cAyj-.js → TestEmailModal-DV1XKWRh.js} +6 -6
- package/dist/cdn/chunks/{TestEmailModal-Dl_cAyj-.js.map → TestEmailModal-DV1XKWRh.js.map} +1 -1
- package/dist/cdn/chunks/{TestEmailPanel-CVZGOKaQ.js → TestEmailPanel-CnVW00RI.js} +2 -2
- package/dist/cdn/chunks/{TestEmailPanel-CVZGOKaQ.js.map → TestEmailPanel-CnVW00RI.js.map} +1 -1
- package/dist/cdn/chunks/{TitleEditor-DO8OdG_w.js → TitleEditor-B9sKbRd4.js} +8 -8
- package/dist/cdn/chunks/{TitleEditor-DO8OdG_w.js.map → TitleEditor-B9sKbRd4.js.map} +1 -1
- package/dist/cdn/chunks/{ToggleSwitch-D5Wi6Env.js → ToggleSwitch-eHkFBx4o.js} +2 -2
- package/dist/cdn/chunks/{ToggleSwitch-D5Wi6Env.js.map → ToggleSwitch-eHkFBx4o.js.map} +1 -1
- package/dist/cdn/chunks/{Toolbar-CXDE8xM-.js → Toolbar-DeKbYejp.js} +15 -15
- package/dist/cdn/chunks/{Toolbar-CXDE8xM-.js.map → Toolbar-DeKbYejp.js.map} +1 -1
- package/dist/cdn/chunks/{TplModal-CFi-Psf7.js → TplModal-Dqq-Ermd.js} +2 -2
- package/dist/cdn/chunks/{TplModal-CFi-Psf7.js.map → TplModal-Dqq-Ermd.js.map} +1 -1
- package/dist/cdn/chunks/{VersionHistoryMenu-1bfCr14E.js → VersionHistoryMenu-Kf4QFm7m.js} +2 -2
- package/dist/cdn/chunks/{VersionHistoryMenu-1bfCr14E.js.map → VersionHistoryMenu-Kf4QFm7m.js.map} +1 -1
- package/dist/cdn/chunks/{VersionHistoryPanels-DbgbyAdW.js → VersionHistoryPanels-Cz8rde-s.js} +2 -2
- package/dist/cdn/chunks/{VersionHistoryPanels-DbgbyAdW.js.map → VersionHistoryPanels-Cz8rde-s.js.map} +1 -1
- package/dist/cdn/chunks/{VersionPreviewBanner-BaOTRIrm.js → VersionPreviewBanner-DNYHqbj9.js} +2 -2
- package/dist/cdn/chunks/{VersionPreviewBanner-BaOTRIrm.js.map → VersionPreviewBanner-DNYHqbj9.js.map} +1 -1
- package/dist/cdn/chunks/{WrapperBlock-BYNfYvl3.js → WrapperBlock-DIZHUwFn.js} +2 -2
- package/dist/cdn/chunks/{WrapperBlock-BYNfYvl3.js.map → WrapperBlock-DIZHUwFn.js.map} +1 -1
- package/dist/cdn/chunks/{blockTypeIcons-B_IAjnTD.js → blockTypeIcons-hgzxMFWX.js} +2 -2
- package/dist/cdn/chunks/{blockTypeIcons-B_IAjnTD.js.map → blockTypeIcons-hgzxMFWX.js.map} +1 -1
- package/dist/cdn/chunks/{ca--zGWn9AU.js → ca-DSwai-th.js} +2 -5
- package/dist/cdn/chunks/ca-DSwai-th.js.map +1 -0
- package/dist/cdn/chunks/{de-BRNLKcDl.js → de-DOhKuphf.js} +2 -5
- package/dist/cdn/chunks/de-DOhKuphf.js.map +1 -0
- package/dist/cdn/chunks/dist-BRZhN8qJ.js.map +1 -1
- package/dist/cdn/chunks/dist-CXB2_kBa.js.map +1 -1
- package/dist/cdn/chunks/draggable-IB4x6w2O.js.map +1 -1
- package/dist/cdn/chunks/{editor-modal-BDOfw3l0.js → editor-modal-cKeJ4wC2.js} +4 -4
- package/dist/cdn/chunks/{editor-modal-BDOfw3l0.js.map → editor-modal-cKeJ4wC2.js.map} +1 -1
- package/dist/cdn/chunks/{en-JJjqHMjy.js → en-BE28ZcUF.js} +2 -5
- package/dist/cdn/chunks/en-BE28ZcUF.js.map +1 -0
- package/dist/cdn/chunks/en-CoNe1psX.js +2 -0
- package/dist/cdn/chunks/{es-BIh8BxV9.js → es-oQI-dfx2.js} +2 -5
- package/dist/cdn/chunks/es-oQI-dfx2.js.map +1 -0
- package/dist/cdn/chunks/{extensions-1hJBHnGv.js → extensions-rPP7qRRm.js} +3 -3
- package/dist/cdn/chunks/{extensions-1hJBHnGv.js.map → extensions-rPP7qRRm.js.map} +1 -1
- package/dist/cdn/chunks/{fr-C5VUZogP.js → fr-rzLdCMSG.js} +2 -5
- package/dist/cdn/chunks/fr-rzLdCMSG.js.map +1 -0
- package/dist/cdn/chunks/htmlparser-ClUZ6waR.js.map +1 -1
- package/dist/cdn/chunks/{icons-BrAyaJ0T.js → icons-BF0mJX0V.js} +18 -18
- package/dist/cdn/chunks/{icons-BrAyaJ0T.js.map → icons-BF0mJX0V.js.map} +1 -1
- package/dist/{ja-x5JYxaCW.js → cdn/chunks/ja-dyFc6Ghz.js} +3 -4
- package/dist/cdn/chunks/ja-dyFc6Ghz.js.map +1 -0
- package/dist/cdn/chunks/{liquid.browser-BypTT2oc.js → liquid.browser-DXPjcePu.js} +758 -719
- package/dist/cdn/chunks/liquid.browser-DXPjcePu.js.map +1 -0
- package/dist/cdn/chunks/{nl-UXxFyXV6.js → nl-BcQhRqKR.js} +2 -5
- package/dist/cdn/chunks/nl-BcQhRqKR.js.map +1 -0
- package/dist/cdn/chunks/{pt-BR-DHm3SP6W.js → pt-BR-UombhTMO.js} +2 -5
- package/dist/cdn/chunks/pt-BR-UombhTMO.js.map +1 -0
- package/dist/cdn/chunks/pusher-BbIHJKf3.js.map +1 -1
- package/dist/cdn/chunks/{src-D5ceT_Y4.js → src-V9_ODH_1.js} +3 -3
- package/dist/cdn/chunks/{src-D5ceT_Y4.js.map → src-V9_ODH_1.js.map} +1 -1
- package/dist/cdn/chunks/{tiptap-D1u8JIUW.js → tiptap-02G9FGkl.js} +3726 -3552
- package/dist/cdn/chunks/tiptap-02G9FGkl.js.map +1 -0
- package/dist/cdn/chunks/{useEditorCore-BTKqlRIg.js → useEditorCore-DWvAia8X.js} +14 -14
- package/dist/cdn/chunks/{useEditorCore-BTKqlRIg.js.map → useEditorCore-DWvAia8X.js.map} +1 -1
- package/dist/cdn/editor.css +1 -1
- package/dist/cdn/editor.js +337 -359
- package/dist/cdn/editor.js.map +1 -1
- package/dist/{check-CA6fvSIp.js → check-DEjsanPt.js} +1 -1
- package/dist/{chevron-down-DYGJgpqJ.js → chevron-down-Cv11TeKQ.js} +1 -1
- package/dist/{chevron-right-Dm5_X4j6.js → chevron-right-R8dOpzBZ.js} +1 -1
- package/dist/{chevron-up-Ds9ormyq.js → chevron-up-DsDEytX1.js} +1 -1
- package/dist/{circle-alert-BYXE0olE.js → circle-alert-B_NqWETg.js} +1 -1
- package/dist/{clock-Ch1-h0sb.js → clock-CDGKPx_X.js} +1 -1
- package/dist/{copy-DLNyaPza.js → copy-Dv2VltLv.js} +1 -1
- package/dist/{createLucideIcon-BrPnbRQT.js → createLucideIcon-MrFrvtkF.js} +5 -5
- package/dist/{de-BRNLKcDl.js → de-DOhKuphf.js} +1 -4
- package/dist/{dist-CxmLZQso.js → dist-8By0p8ah.js} +5 -5
- package/dist/{dist-W_ERo6c_.js → dist-BYg1EL5g.js} +5 -5
- package/dist/{dist-C2Ge44fD.js → dist-BgSLW3Hn.js} +1704 -1303
- package/dist/{dist-B0dkvy7z.js → dist-CWc7nIkA.js} +5 -5
- package/dist/{dist-CIxmOOSG.js → dist-Ceew_u40.js} +448 -699
- package/dist/{dist-BwoEME8p.js → dist-CmwBvyW0.js} +172 -171
- package/dist/{dist-CJ7RZARo.js → dist-Czzst9ng.js} +302 -279
- package/dist/dist-D2m55Lvs.js +5 -0
- package/dist/{dist-p-LkiWIQ.js → dist-D4HP93ZF.js} +13 -13
- package/dist/{dist-BPWuzECC.js → dist-DdSWMtEP.js} +6 -6
- package/dist/{dist-DRmafAUz.js → dist-DmQckB4p.js} +29 -29
- package/dist/dist-Dw2_11LA.js +5 -0
- package/dist/{editor-modal-Cl5GFWTQ.js → editor-modal-DmgxKgII.js} +16 -16
- package/dist/{en-JJjqHMjy.js → en-BE28ZcUF.js} +1 -4
- package/dist/en-DXYNty6E.js +2 -0
- package/dist/{es-BIh8BxV9.js → es-oQI-dfx2.js} +1 -4
- package/dist/{extensions-AKHJ0lax.js → extensions-CkwL1oWn.js} +61 -61
- package/dist/{eye-_7xKFxQh.js → eye-BVxcDaZZ.js} +1 -1
- package/dist/{fr-C5VUZogP.js → fr-rzLdCMSG.js} +1 -4
- package/dist/{image-up-Ck-xPOGS.js → image-up-CnC4n-8q.js} +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/{info-CBBNLK_i.js → info-q7gVjMBC.js} +1 -1
- package/dist/{cdn/chunks/ja-x5JYxaCW.js → ja-dyFc6Ghz.js} +1 -6
- package/dist/{link-BA_V9Nns.js → link-B1-UqOP6.js} +1 -1
- package/dist/{liquid.browser-wPG0n4Cs.js → liquid.browser-Cs4gOjeX.js} +757 -718
- package/dist/{list-BTujzSSo.js → list-BvlNrd6M.js} +1 -1
- package/dist/{loader-circle-B5OQFRUF.js → loader-circle-CJ8klGfl.js} +1 -1
- package/dist/{message-circle-DWXr27lZ.js → message-circle-Bgepipq_.js} +1 -1
- package/dist/{nl-UXxFyXV6.js → nl-BcQhRqKR.js} +1 -4
- package/dist/{package-DXW9QTU3.js → package-BYIdon2Q.js} +1 -1
- package/dist/{pencil-QmONZtjF.js → pencil-Bhs9MNTT.js} +1 -1
- package/dist/{plus-XxHKE_GT.js → plus-C0eGj8vT.js} +1 -1
- package/dist/{pt-BR-DHm3SP6W.js → pt-BR-UombhTMO.js} +1 -4
- package/dist/{refresh-cw-DhXU8dCo.js → refresh-cw-BQTOIZKD.js} +1 -1
- package/dist/{search-CpFaMrnL.js → search-CeT7yRBa.js} +1 -1
- package/dist/{send-CFK3e6tQ.js → send-D7ck2xEq.js} +1 -1
- package/dist/{shield-check-ndwpOTik.js → shield-check-CF_VbIbH.js} +1 -1
- package/dist/{smartphone-DndMh9W6.js → smartphone-CkVOj7Qn.js} +1 -1
- package/dist/{socialIcons-D43BLoTu.js → socialIcons-QYtdurnO.js} +1 -1
- package/dist/{sparkles-c1M5lwAQ.js → sparkles-Cfb-Kkgv.js} +1 -1
- package/dist/style.css +1 -1
- package/dist/templatical-editor.js +475 -497
- package/dist/{text-align-start-DOtBufPq.js → text-align-start-CkFs2Zig.js} +13 -13
- package/dist/{trash-DmaPdiUk.js → trash-C2LPw5pa.js} +1 -1
- package/dist/{triangle-alert-DqvxsSNL.js → triangle-alert-gaUz4rum.js} +1 -1
- package/dist/{upload-CO_hogFv.js → upload-C_DYZD_p.js} +1 -1
- package/dist/{useEditorCore-0K8joh4X.js → useEditorCore-Cmv5ll-D.js} +20 -20
- package/dist/{useScrollToBlock-BU5A9eS9.js → useScrollToBlock-BsPYYJ8h.js} +1 -1
- package/dist/{x-BCop_VsL.js → x-JhKma5YO.js} +1 -1
- package/package.json +25 -25
- package/dist/cdn/chunks/ca--zGWn9AU.js.map +0 -1
- package/dist/cdn/chunks/de-BRNLKcDl.js.map +0 -1
- package/dist/cdn/chunks/en-DxpXHoxJ.js +0 -2
- package/dist/cdn/chunks/en-JJjqHMjy.js.map +0 -1
- package/dist/cdn/chunks/es-BIh8BxV9.js.map +0 -1
- package/dist/cdn/chunks/fr-C5VUZogP.js.map +0 -1
- package/dist/cdn/chunks/ja-x5JYxaCW.js.map +0 -1
- package/dist/cdn/chunks/liquid.browser-BypTT2oc.js.map +0 -1
- package/dist/cdn/chunks/nl-UXxFyXV6.js.map +0 -1
- package/dist/cdn/chunks/pt-BR-DHm3SP6W.js.map +0 -1
- package/dist/cdn/chunks/tiptap-D1u8JIUW.js.map +0 -1
- package/dist/dist-BUHovM4k.js +0 -5
- package/dist/dist-DdOAotfz.js +0 -5
- package/dist/en-CdCFaV2V.js +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TemplateScoringPanel-DXyQjcdU.js","names":["_openBlock","_createBlock","_Transition","_withCtx","_createElementBlock","_unref","_createElementVNode","_createVNode","_toDisplayString","_createCommentVNode","LoadingTrack","_createTextVNode","_normalizeStyle","_Fragment","_renderList","_resolveDynamicComponent","_normalizeClass","_sfc_main","watch","inject","renderList","withCtx","openBlock","ref","resolveDynamicComponent","defineComponent","unref","createVNode","normalizeClass","createElementBlock","createCommentVNode","normalizeStyle","createBlock","Transition","createBaseVNode","Fragment","toDisplayString","createTextVNode","requireInject","NO_MERGE_TAGS","MERGE_TAGS_KEY","SCORING_KEY","EDITOR_KEY","ShieldCheck","RefreshCw","Sparkles","ChevronDown","CircleAlert","Eye","LoaderCircle","TriangleAlert","Info","ShieldX","X","Zap","LoadingTrack_default","_plugin_vue_export_helper_default","useCloudI18nStrict","scoreColor","score","scoreBgColor","severityColor","severity","severityBgColor","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_hoisted_25","_hoisted_26","_hoisted_27","_hoisted_28","_hoisted_29","_hoisted_30","_hoisted_31","TemplateScoringPanel_default","__emit","props","__props","emit","cloudT","editor","scoring","mergeTags","expandedCategories","toggleCategory","category","categoryOrder","categoryIcons","triggerScore","isVisible","handleFix","finding","block","b","blockContent","fixedContent","totalFindings","sum","cat","_cache"],"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 role=\"complementary\"\n :aria-label=\"cloudT.scoring.title\"\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 type=\"button\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :aria-label=\"cloudT.scoring.rescore\"\n :title=\"cloudT.scoring.rescore\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"14\" :stroke-width=\"2\" />\n </button>\n <button\n type=\"button\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :aria-label=\"cloudT.scoring.close\"\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-[10px] 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-xs 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-xs 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-[10px] 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 role=\"complementary\"\n :aria-label=\"cloudT.scoring.title\"\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 type=\"button\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :aria-label=\"cloudT.scoring.rescore\"\n :title=\"cloudT.scoring.rescore\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"14\" :stroke-width=\"2\" />\n </button>\n <button\n type=\"button\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :aria-label=\"cloudT.scoring.close\"\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-[10px] 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-xs 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-xs 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-[10px] 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":"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"}
|
|
1
|
+
{"version":3,"file":"TemplateScoringPanel-CeCVyNV1.js","names":["_openBlock","_createBlock","_Transition","_withCtx","_createElementBlock","_unref","_createElementVNode","_createVNode","_toDisplayString","_createCommentVNode","LoadingTrack","_createTextVNode","_normalizeStyle","_Fragment","_renderList","_resolveDynamicComponent","_normalizeClass","_sfc_main","watch","inject","renderList","withCtx","openBlock","ref","resolveDynamicComponent","defineComponent","unref","createVNode","normalizeClass","createElementBlock","createCommentVNode","normalizeStyle","createBlock","Transition","createBaseVNode","Fragment","toDisplayString","createTextVNode","requireInject","NO_MERGE_TAGS","MERGE_TAGS_KEY","SCORING_KEY","EDITOR_KEY","ShieldCheck","RefreshCw","Sparkles","ChevronDown","CircleAlert","Eye","LoaderCircle","TriangleAlert","Info","ShieldX","X","Zap","LoadingTrack_default","_plugin_vue_export_helper_default","useCloudI18nStrict","scoreColor","score","scoreBgColor","severityColor","severity","severityBgColor","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_hoisted_25","_hoisted_26","_hoisted_27","_hoisted_28","_hoisted_29","_hoisted_30","_hoisted_31","TemplateScoringPanel_default","__emit","props","__props","emit","cloudT","editor","scoring","mergeTags","expandedCategories","toggleCategory","category","categoryOrder","categoryIcons","triggerScore","isVisible","handleFix","finding","block","b","blockContent","fixedContent","totalFindings","sum","cat","_cache"],"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 role=\"complementary\"\n :aria-label=\"cloudT.scoring.title\"\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 type=\"button\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :aria-label=\"cloudT.scoring.rescore\"\n :title=\"cloudT.scoring.rescore\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"14\" :stroke-width=\"2\" />\n </button>\n <button\n type=\"button\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :aria-label=\"cloudT.scoring.close\"\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-[10px] 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-xs 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-xs 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-[10px] 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 role=\"complementary\"\n :aria-label=\"cloudT.scoring.title\"\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 type=\"button\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :aria-label=\"cloudT.scoring.rescore\"\n :title=\"cloudT.scoring.rescore\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"14\" :stroke-width=\"2\" />\n </button>\n <button\n type=\"button\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :aria-label=\"cloudT.scoring.close\"\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-[10px] 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-xs 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-xs 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-[10px] 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":"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"}
|
|
@@ -3,10 +3,10 @@ import { G as ee } from "./src-BR3I3gOW.js";
|
|
|
3
3
|
import { $ as te, q as ne, v as re } from "./keys-DCWeHkSF.js";
|
|
4
4
|
import { t as ie } from "./useI18n-CyO_Nmca.js";
|
|
5
5
|
import { n as ae, t as m } from "./templateSettingsFields-YCFVBVYh.js";
|
|
6
|
-
import { T as h, Tt as g, ft as oe, jt as _, vt as v } from "./icons-
|
|
6
|
+
import { T as h, Tt as g, ft as oe, jt as _, vt as v } from "./icons-BF0mJX0V.js";
|
|
7
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-
|
|
9
|
-
import { n as C, t as w } from "./ToggleSwitch-
|
|
8
|
+
import { c as S } from "./LogicTagInsertButton-FNMVxm_V.js";
|
|
9
|
+
import { n as C, t as w } from "./ToggleSwitch-eHkFBx4o.js";
|
|
10
10
|
//#region src/components/TemplateSettings.vue?vue&type=script&setup=true&lang.ts
|
|
11
11
|
var T = {
|
|
12
12
|
"data-testid": "template-settings",
|
|
@@ -204,4 +204,4 @@ var T = {
|
|
|
204
204
|
//#endregion
|
|
205
205
|
export { W as default };
|
|
206
206
|
|
|
207
|
-
//# sourceMappingURL=TemplateSettings-
|
|
207
|
+
//# sourceMappingURL=TemplateSettings-CuXwthI6.js.map
|
package/dist/cdn/chunks/{TemplateSettings-da14bXlk.js.map → TemplateSettings-CuXwthI6.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TemplateSettings-da14bXlk.js","names":["_openBlock","_createElementBlock","_createElementVNode","_normalizeClass","_createVNode","_unref","_toDisplayString","_Fragment","_renderList","_normalizeStyle","_createCommentVNode","ColorPicker","ToggleSwitch","MergeTagTextarea","_sfc_main","inject","renderList","openBlock","defineComponent","unref","createVNode","normalizeClass","computed","createElementBlock","createCommentVNode","normalizeStyle","createBaseVNode","Fragment","toDisplayString","resolveContentDirection","requireInject","TEMPLATE_SETTINGS_FIELDS_KEY","FONTS_MANAGER_KEY","useI18n","TEMPLATE_SETTINGS_FIELD_CARDS","ALL_TEMPLATE_SETTINGS_FIELDS","Square","Eye","Info","Circle","Globe","labelClass","inputSuffixClass","cardClass","inputGroupInputClass","inputClass","DEFAULT_BG_COLOR","ColorPicker_default","MergeTagTextarea_default","ToggleSwitch_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_hoisted_25","_hoisted_26","_hoisted_27","_hoisted_28","_hoisted_29","_hoisted_30","_hoisted_31","_hoisted_32","_hoisted_33","_hoisted_34","PREHEADER_MAX_LENGTH","TemplateSettings_default","__emit","props","__props","emit","fontsManager","fontFamilies","displayedFontFamily","font","widthPresets","allowedFields","shows","field","showsCard","card","showsAnyField","isRtl","cardStackClass","t","preset","_cache","$event"],"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
|
+
{"version":3,"file":"TemplateSettings-CuXwthI6.js","names":["_openBlock","_createElementBlock","_createElementVNode","_normalizeClass","_createVNode","_unref","_toDisplayString","_Fragment","_renderList","_normalizeStyle","_createCommentVNode","ColorPicker","ToggleSwitch","MergeTagTextarea","_sfc_main","inject","renderList","openBlock","defineComponent","unref","createVNode","normalizeClass","computed","createElementBlock","createCommentVNode","normalizeStyle","createBaseVNode","Fragment","toDisplayString","resolveContentDirection","requireInject","TEMPLATE_SETTINGS_FIELDS_KEY","FONTS_MANAGER_KEY","useI18n","TEMPLATE_SETTINGS_FIELD_CARDS","ALL_TEMPLATE_SETTINGS_FIELDS","Square","Eye","Info","Circle","Globe","labelClass","inputSuffixClass","cardClass","inputGroupInputClass","inputClass","DEFAULT_BG_COLOR","ColorPicker_default","MergeTagTextarea_default","ToggleSwitch_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_hoisted_25","_hoisted_26","_hoisted_27","_hoisted_28","_hoisted_29","_hoisted_30","_hoisted_31","_hoisted_32","_hoisted_33","_hoisted_34","PREHEADER_MAX_LENGTH","TemplateSettings_default","__emit","props","__props","emit","fontsManager","fontFamilies","displayedFontFamily","font","widthPresets","allowedFields","shows","field","showsCard","card","showsAnyField","isRtl","cardStackClass","t","preset","_cache","$event"],"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
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 { b as ne, u as re } from "./src-BR3I3gOW.js";
|
|
3
|
-
import { P as ie } from "./useEditorCore-
|
|
3
|
+
import { P as ie } from "./useEditorCore-DWvAia8X.js";
|
|
4
4
|
import { C as ae, F as oe, H as y, M as se, O as ce, g as le } from "./keys-DCWeHkSF.js";
|
|
5
5
|
import { t as ue } from "./useI18n-CyO_Nmca.js";
|
|
6
|
-
import { Rt as de, at as fe } from "./icons-
|
|
6
|
+
import { Rt as de, at as fe } from "./icons-BF0mJX0V.js";
|
|
7
7
|
import { v as pe } from "./styleConstants-C_YAPdQS.js";
|
|
8
|
-
import { n as me, t as he } from "./MergeTagModeToggle-
|
|
9
|
-
import { t as ge } from "./TplModal-
|
|
10
|
-
import { t as _e } from "./BlockPreviewCanvas-
|
|
8
|
+
import { n as me, t as he } from "./MergeTagModeToggle-027RMXDP.js";
|
|
9
|
+
import { t as ge } from "./TplModal-Dqq-Ermd.js";
|
|
10
|
+
import { t as _e } from "./BlockPreviewCanvas-CIwIA3zq.js";
|
|
11
11
|
//#region src/utils/validateEmailShape.ts
|
|
12
12
|
var b = /[,;<>()[\]\\"'`|/?#@!$%^&*+=~{}]/;
|
|
13
13
|
function x(e) {
|
|
@@ -208,4 +208,4 @@ var S = ["aria-busy"], C = {
|
|
|
208
208
|
//#endregion
|
|
209
209
|
export { R as default };
|
|
210
210
|
|
|
211
|
-
//# sourceMappingURL=TestEmailModal-
|
|
211
|
+
//# sourceMappingURL=TestEmailModal-DV1XKWRh.js.map
|