@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
|
@@ -2,32 +2,32 @@ import { t as e } from "./rolldown-runtime-Dy4uBu1J.js";
|
|
|
2
2
|
import { A as t, At as n, B as r, F as i, M as a, N as o, R as s, S as c, V as l, Y as u, Z as d, _ as f, at as p, c as m, d as h, g, h as _, jt as v, kt as y, l as b, r as x, s as S, u as C, v as w } from "./vue.runtime.esm-bundler-CyqhBwpY.js";
|
|
3
3
|
import { a as T, o as E } from "./runtime-dom.esm-bundler-BGbPz4-g.js";
|
|
4
4
|
import { J as D, P as O, V as k, at as A, c as j, it as ee, m as M, n as N, o as P, t as te } from "./dist-iLUVPysa.js";
|
|
5
|
-
import { c as ne, f as re, i as F, l as I, r as ie, u as ae, x as oe } from "./socialIcons-
|
|
5
|
+
import { c as ne, f as re, i as F, l as I, r as ie, u as ae, x as oe } from "./socialIcons-QYtdurnO.js";
|
|
6
6
|
import { _ as se } from "./dist-8VFzbeu9.js";
|
|
7
7
|
import { $ as L, C as ce, G as le, L as ue, P as de, c as fe, d as pe, h as me, n as he, p as ge, v as _e } from "./keys-CDqfZIRt.js";
|
|
8
8
|
import { t as R } from "./useI18n-B_CdcBwG.js";
|
|
9
9
|
import { o as ve } from "./usePopoverPosition-BYmd-lhR.js";
|
|
10
|
-
import { t as ye } from "./createLucideIcon-
|
|
11
|
-
import { c as z } from "./LogicTagInsertButton-
|
|
12
|
-
import { t as be } from "./chevron-down-
|
|
13
|
-
import { t as xe } from "./circle-alert-
|
|
14
|
-
import { n as B, t as Se } from "./blockTypeIcons-
|
|
15
|
-
import { t as Ce } from "./copy-
|
|
16
|
-
import { t as we } from "./info-
|
|
17
|
-
import { t as Te } from "./link-
|
|
18
|
-
import { t as Ee } from "./loader-circle-
|
|
19
|
-
import { n as De, t as Oe } from "./smartphone-
|
|
20
|
-
import { t as V } from "./plus-
|
|
21
|
-
import { t as ke } from "./refresh-cw-
|
|
22
|
-
import { n as H, r as Ae, t as je } from "./text-align-start-
|
|
23
|
-
import { t as Me } from "./trash-
|
|
24
|
-
import { t as Ne } from "./upload-
|
|
25
|
-
import { t as Pe } from "./x-
|
|
10
|
+
import { t as ye } from "./createLucideIcon-MrFrvtkF.js";
|
|
11
|
+
import { c as z } from "./LogicTagInsertButton-D2Fjo444.js";
|
|
12
|
+
import { t as be } from "./chevron-down-Cv11TeKQ.js";
|
|
13
|
+
import { t as xe } from "./circle-alert-B_NqWETg.js";
|
|
14
|
+
import { n as B, t as Se } from "./blockTypeIcons-CEk_GHmU.js";
|
|
15
|
+
import { t as Ce } from "./copy-Dv2VltLv.js";
|
|
16
|
+
import { t as we } from "./info-q7gVjMBC.js";
|
|
17
|
+
import { t as Te } from "./link-B1-UqOP6.js";
|
|
18
|
+
import { t as Ee } from "./loader-circle-CJ8klGfl.js";
|
|
19
|
+
import { n as De, t as Oe } from "./smartphone-CkVOj7Qn.js";
|
|
20
|
+
import { t as V } from "./plus-C0eGj8vT.js";
|
|
21
|
+
import { t as ke } from "./refresh-cw-BQTOIZKD.js";
|
|
22
|
+
import { n as H, r as Ae, t as je } from "./text-align-start-CkFs2Zig.js";
|
|
23
|
+
import { t as Me } from "./trash-C2LPw5pa.js";
|
|
24
|
+
import { t as Ne } from "./upload-C_DYZD_p.js";
|
|
25
|
+
import { t as Pe } from "./x-JhKma5YO.js";
|
|
26
26
|
import { t as Fe } from "./_plugin-vue_export-helper-B3ysoDQm.js";
|
|
27
27
|
import { t as Ie } from "./useAliveFlag-BkKyhkwZ.js";
|
|
28
28
|
import { _ as Le, b as Re, c as ze, g as U, h as W, m as G, p as K, r as Be, v as Ve } from "./styleConstants-C_YAPdQS.js";
|
|
29
|
-
import { n as He, t as q } from "./ToggleSwitch-
|
|
30
|
-
import { t as J } from "./MergeTagInput-
|
|
29
|
+
import { n as He, t as q } from "./ToggleSwitch-Z-rqEcig.js";
|
|
30
|
+
import { t as J } from "./MergeTagInput-fEOOY7OU.js";
|
|
31
31
|
var Ue = ye({
|
|
32
32
|
name: "lock-open",
|
|
33
33
|
size: 24,
|
|
@@ -1785,12 +1785,12 @@ var er = {
|
|
|
1785
1785
|
{
|
|
1786
1786
|
value: "center",
|
|
1787
1787
|
label: s.title.alignCenter,
|
|
1788
|
-
icon:
|
|
1788
|
+
icon: H
|
|
1789
1789
|
},
|
|
1790
1790
|
{
|
|
1791
1791
|
value: "right",
|
|
1792
1792
|
label: s.title.alignRight,
|
|
1793
|
-
icon:
|
|
1793
|
+
icon: Ae
|
|
1794
1794
|
}
|
|
1795
1795
|
]);
|
|
1796
1796
|
function u(e, t) {
|
|
@@ -2226,12 +2226,12 @@ var si = { class: "tpl:mb-3.5" }, ci = ["value"], li = ["value"], ui = {
|
|
|
2226
2226
|
{
|
|
2227
2227
|
value: "center",
|
|
2228
2228
|
label: p(o).title.alignCenter,
|
|
2229
|
-
icon: p(
|
|
2229
|
+
icon: p(H)
|
|
2230
2230
|
},
|
|
2231
2231
|
{
|
|
2232
2232
|
value: "right",
|
|
2233
2233
|
label: p(o).title.alignRight,
|
|
2234
|
-
icon: p(
|
|
2234
|
+
icon: p(Ae)
|
|
2235
2235
|
}
|
|
2236
2236
|
],
|
|
2237
2237
|
"model-value": e.block.align,
|
|
@@ -2412,12 +2412,12 @@ var si = { class: "tpl:mb-3.5" }, ci = ["value"], li = ["value"], ui = {
|
|
|
2412
2412
|
{
|
|
2413
2413
|
value: "center",
|
|
2414
2414
|
label: p(o).title.alignCenter,
|
|
2415
|
-
icon: p(
|
|
2415
|
+
icon: p(H)
|
|
2416
2416
|
},
|
|
2417
2417
|
{
|
|
2418
2418
|
value: "right",
|
|
2419
2419
|
label: p(o).title.alignRight,
|
|
2420
|
-
icon: p(
|
|
2420
|
+
icon: p(Ae)
|
|
2421
2421
|
}
|
|
2422
2422
|
],
|
|
2423
2423
|
"model-value": e.block.textAlign,
|
|
@@ -2470,12 +2470,12 @@ var si = { class: "tpl:mb-3.5" }, ci = ["value"], li = ["value"], ui = {
|
|
|
2470
2470
|
{
|
|
2471
2471
|
value: "center",
|
|
2472
2472
|
label: p(i).title.alignCenter,
|
|
2473
|
-
icon: p(
|
|
2473
|
+
icon: p(H)
|
|
2474
2474
|
},
|
|
2475
2475
|
{
|
|
2476
2476
|
value: "right",
|
|
2477
2477
|
label: p(i).title.alignRight,
|
|
2478
|
-
icon: p(
|
|
2478
|
+
icon: p(Ae)
|
|
2479
2479
|
}
|
|
2480
2480
|
],
|
|
2481
2481
|
"model-value": e.block.textAlign,
|
|
@@ -2629,7 +2629,7 @@ var si = { class: "tpl:mb-3.5" }, ci = ["value"], li = ["value"], ui = {
|
|
|
2629
2629
|
"duplicate"
|
|
2630
2630
|
],
|
|
2631
2631
|
setup(e, { emit: n }) {
|
|
2632
|
-
let r = f(() => import("./CountdownToolbar-
|
|
2632
|
+
let r = f(() => import("./CountdownToolbar-B-pAigUh.js")), a = e, o = n, { t: s } = R(), l = L(_e, "Toolbar"), u = c(ge, []), d = S(() => a.block.type), _ = S(() => k(a.block)), y = S(() => {
|
|
2633
2633
|
if (_.value) return u.find((e) => e.type === a.block.customType);
|
|
2634
2634
|
}), x = S(() => _.value ? y.value?.name ?? a.block.customType : re(d.value, s)), w = l.fonts;
|
|
2635
2635
|
function T(e) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { A as e, At as t, B as n, N as r, S as i, Z as a, at as o, c as s, d as c, g as l, i as u, l as d, s as f, u as p, v as m } from "./vue.runtime.esm-bundler-CyqhBwpY.js";
|
|
2
2
|
import { c as h, t as g } from "./runtime-dom.esm-bundler-BGbPz4-g.js";
|
|
3
|
-
import { x as _ } from "./useEditorCore-
|
|
3
|
+
import { x as _ } from "./useEditorCore-Cmv5ll-D.js";
|
|
4
4
|
import { J as v, Z as y } from "./keys-CDqfZIRt.js";
|
|
5
5
|
import { n as b } from "./usePopoverPosition-BYmd-lhR.js";
|
|
6
6
|
//#region src/components/TplModal.vue?vue&type=script&setup=true&lang.ts
|
|
@@ -3,11 +3,11 @@ import { c as g, t as _ } from "./runtime-dom.esm-bundler-BGbPz4-g.js";
|
|
|
3
3
|
import { t as v } from "./dist-BDuPwOyn.js";
|
|
4
4
|
import { X as y } from "./keys-CDqfZIRt.js";
|
|
5
5
|
import { t as b } from "./useI18n-B_CdcBwG.js";
|
|
6
|
-
import { t as x } from "./createLucideIcon-
|
|
7
|
-
import { t as S } from "./chevron-down-
|
|
8
|
-
import { t as C } from "./chevron-right-
|
|
9
|
-
import { t as w } from "./clock-
|
|
10
|
-
import { t as ee } from "./loader-circle-
|
|
6
|
+
import { t as x } from "./createLucideIcon-MrFrvtkF.js";
|
|
7
|
+
import { t as S } from "./chevron-down-Cv11TeKQ.js";
|
|
8
|
+
import { t as C } from "./chevron-right-R8dOpzBZ.js";
|
|
9
|
+
import { t as w } from "./clock-CDGKPx_X.js";
|
|
10
|
+
import { t as ee } from "./loader-circle-CJ8klGfl.js";
|
|
11
11
|
import { t as T } from "./formatAbsoluteDateTime-DMmop3C-.js";
|
|
12
12
|
import { t as E } from "./formatRelativeTime-CtUU-QZ8.js";
|
|
13
13
|
var D = x({
|
|
@@ -5,7 +5,7 @@ var c = /* @__PURE__ */ s({
|
|
|
5
5
|
__name: "VersionHistoryPanels",
|
|
6
6
|
props: { feature: {} },
|
|
7
7
|
setup(s) {
|
|
8
|
-
let c = s, l = t(() => import("./VersionPreviewBanner-
|
|
8
|
+
let c = s, l = t(() => import("./VersionPreviewBanner-D5RZtvUf.js")), u = t(() => import("./RestoreVersionDialog-DYaoFk5G.js"));
|
|
9
9
|
async function d() {
|
|
10
10
|
try {
|
|
11
11
|
await c.feature.requestRestore();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { A as e, at as t, c as n, d as r, g as i, jt as a, kt as o, u as s, v as c } from "./vue.runtime.esm-bundler-CyqhBwpY.js";
|
|
2
2
|
import { t as l } from "./useI18n-B_CdcBwG.js";
|
|
3
|
-
import { t as u } from "./clock-
|
|
3
|
+
import { t as u } from "./clock-CDGKPx_X.js";
|
|
4
4
|
import { f as d, v as f } from "./styleConstants-C_YAPdQS.js";
|
|
5
5
|
//#region src/components/VersionPreviewBanner.vue?vue&type=script&setup=true&lang.ts
|
|
6
6
|
var p = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { A as e, At as t, F as n, M as r, S as i, at as a, d as o, l as s, r as c, s as l, v as u } from "./vue.runtime.esm-bundler-CyqhBwpY.js";
|
|
2
|
-
import { A as d, D as f, k as p } from "./useEditorCore-
|
|
2
|
+
import { A as d, D as f, k as p } from "./useEditorCore-Cmv5ll-D.js";
|
|
3
3
|
import { s as m } from "./keys-CDqfZIRt.js";
|
|
4
4
|
function h(e, t = "desktop") {
|
|
5
5
|
return t === "mobile" ? 375 : e?.width ?? 600;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as e, c as t, l as n, o as r, s as i } from "./socialIcons-
|
|
2
|
-
import { t as a } from "./createLucideIcon-
|
|
1
|
+
import { a as e, c as t, l as n, o as r, s as i } from "./socialIcons-QYtdurnO.js";
|
|
2
|
+
import { t as a } from "./createLucideIcon-MrFrvtkF.js";
|
|
3
3
|
var o = a({
|
|
4
4
|
name: "columns-3",
|
|
5
5
|
size: 24,
|
package/dist/bundle-stats.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.43.
|
|
3
|
-
"initialGzipBytes":
|
|
4
|
-
"initialRawBytes":
|
|
2
|
+
"version": "0.43.3",
|
|
3
|
+
"initialGzipBytes": 176672,
|
|
4
|
+
"initialRawBytes": 588339,
|
|
5
5
|
"initialFileCount": 48,
|
|
6
|
-
"lazyGzipBytes":
|
|
7
|
-
"lazyRawBytes":
|
|
6
|
+
"lazyGzipBytes": 430742,
|
|
7
|
+
"lazyRawBytes": 1519982,
|
|
8
8
|
"lazyFileCount": 84,
|
|
9
|
-
"generatedAt": "2026-10-
|
|
9
|
+
"generatedAt": "2026-10-06T13:07:55.774Z"
|
|
10
10
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
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 ee, at as s, b as c, ct as te, g as l, h as u, k as ne, m as d, n as re, o as ie, p as f, u as p, ut as m, y as h } from "./draggable-IB4x6w2O.js";
|
|
2
2
|
import { _ as g, g as ae } from "./dist-BRZhN8qJ.js";
|
|
3
3
|
import { $ as _, F as oe, O as se, g as ce, i as le, u as ue } from "./keys-DCWeHkSF.js";
|
|
4
|
-
import { D as v, N as de, Nt as fe, V as pe, at as me, f as y, l as b, n as x } from "./icons-
|
|
4
|
+
import { D as v, N as de, Nt as fe, V as pe, at as me, f as y, l as b, n as x } from "./icons-BF0mJX0V.js";
|
|
5
5
|
import { t as S } from "./LoadingTrack-_7DH_5aw.js";
|
|
6
6
|
import { t as C } from "./_plugin-vue_export-helper-B3ysoDQm.js";
|
|
7
7
|
import { t as w } from "./useAliveFlag-DAlQLbM2.js";
|
|
@@ -206,4 +206,4 @@ var E = ["aria-label"], D = { class: "tpl:flex tpl:items-center tpl:justify-betw
|
|
|
206
206
|
//#endregion
|
|
207
207
|
export { B as default };
|
|
208
208
|
|
|
209
|
-
//# sourceMappingURL=AiChatSidebar-
|
|
209
|
+
//# sourceMappingURL=AiChatSidebar-oFwacME4.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiChatSidebar-DW1uRkKE.js","names":["_openBlock","_createBlock","_Transition","_withCtx","_createElementBlock","_unref","_createElementVNode","_createVNode","_toDisplayString","Trash2","_createCommentVNode","_Fragment","_renderList","LoadingTrack","_createTextVNode","_normalizeClass","_withDirectives","_vModelText","_sfc_main","watch","inject","renderList","withCtx","openBlock","ref","defineComponent","withDirectives","unref","createVNode","normalizeClass","createElementBlock","createCommentVNode","nextTick","createBlock","Transition","vModelText","createBaseVNode","Fragment","toDisplayString","createTextVNode","useTimeoutFn","useIntervalFn","requireInject","NO_MERGE_TAGS","MERGE_TAGS_KEY","EDITOR_KEY","AUTH_MANAGER_KEY","CLOUD_TRANSLATIONS_KEY","Sparkles","Send","CircleAlert","Redo2","LoaderCircle","Trash","Undo2","X","LoadingTrack_default","_plugin_vue_export_helper_default","useAliveFlag","useAiChat","_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","\"color\"","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","AiChatSidebar_default","__emit","props","__props","emit","cloudTranslations","editor","authManager","mergeTags","aliveFlag","aiChat","promptInput","messagesContainer","historyLoaded","visibleSuggestionCount","pauseReveal","resumeReveal","startRevealTimeout","count","scrollToBottom","isVisible","handleSend","prompt","stripJsonBlock","text","handleSuggestionClick","suggestion","handleKeydown","event","_cache","message","index","$event"],"sources":["../../../src/cloud/components/AiChatSidebar.vue","../../../src/cloud/components/AiChatSidebar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport LoadingTrack from \"../../components/LoadingTrack.vue\";\nimport { useAiChat } from \"@templatical/core/cloud\";\nimport {\n CLOUD_TRANSLATIONS_KEY,\n EDITOR_KEY,\n AUTH_MANAGER_KEY,\n MERGE_TAGS_KEY,\n NO_MERGE_TAGS,\n requireInject,\n} from \"../../keys\";\nimport { useAliveFlag } from \"../../composables/useAliveFlag\";\nimport type { TemplateContent } from \"@templatical/types\";\nimport {\n CircleAlert,\n LoaderCircle,\n Redo2,\n Send,\n Sparkles,\n Trash2,\n Undo2,\n X,\n} from \"@lucide/vue\";\nimport { inject, nextTick, ref, watch } from \"vue\";\nimport { useIntervalFn, useTimeoutFn } from \"@vueuse/core\";\n\nconst props = defineProps<{\n visible: boolean;\n onApply?: (content: TemplateContent) => void;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n}>();\n\nconst cloudTranslations = requireInject(\n CLOUD_TRANSLATIONS_KEY,\n \"AiChatSidebar\",\n);\nconst editor = requireInject(EDITOR_KEY, \"AiChatSidebar\");\nconst authManager = requireInject(AUTH_MANAGER_KEY, \"AiChatSidebar\");\nconst mergeTags = inject(MERGE_TAGS_KEY, NO_MERGE_TAGS);\nconst aliveFlag = useAliveFlag();\n\nconst aiChat = useAiChat({\n authManager,\n getTemplateId: () => editor.state.template?.id ?? null,\n onApply: props.onApply,\n onError: undefined,\n});\n\nconst promptInput = ref(\"\");\nconst messagesContainer = ref<HTMLElement | null>(null);\nconst historyLoaded = ref(false);\nconst visibleSuggestionCount = ref(0);\n\nconst { pause: pauseReveal, resume: resumeReveal } = useIntervalFn(\n () => {\n const count = aiChat.suggestions.value?.length ?? 0;\n if (visibleSuggestionCount.value < count) {\n visibleSuggestionCount.value++;\n } else {\n pauseReveal();\n }\n },\n 150,\n { immediate: false },\n);\n\nconst { start: startRevealTimeout } = useTimeoutFn(() => resumeReveal(), 100, {\n immediate: false,\n});\n\nwatch(\n () => aiChat.suggestions.value?.length ?? 0,\n (count) => {\n pauseReveal();\n if (count === 0) {\n visibleSuggestionCount.value = 0;\n return;\n }\n\n visibleSuggestionCount.value = 0;\n startRevealTimeout();\n },\n);\n\nfunction scrollToBottom(): void {\n nextTick(() => {\n if (messagesContainer.value) {\n messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;\n }\n });\n}\n\nwatch(\n () => aiChat.messages.value?.length ?? 0,\n () => scrollToBottom(),\n);\n\nwatch(\n () => props.visible,\n async (isVisible) => {\n if (isVisible && !historyLoaded.value) {\n historyLoaded.value = true;\n await aiChat.loadConversation();\n if (!aliveFlag.alive) return;\n\n if (\n (aiChat.messages.value?.length ?? 0) === 0 &&\n editor.content.value.blocks.length === 0\n ) {\n aiChat.loadSuggestions(editor.content.value, mergeTags.value);\n }\n }\n },\n);\n\nasync function handleSend(): Promise<void> {\n const prompt = promptInput.value.trim();\n if (!prompt || aiChat.isGenerating.value) {\n return;\n }\n\n promptInput.value = \"\";\n aiChat.error.value = null;\n aiChat.failedPrompt.value = null;\n scrollToBottom();\n\n await aiChat.sendPrompt(prompt, editor.content.value, mergeTags.value);\n if (!aliveFlag.alive) return;\n\n if (aiChat.failedPrompt.value) {\n promptInput.value = aiChat.failedPrompt.value;\n }\n\n scrollToBottom();\n}\n\nfunction stripJsonBlock(text: string): string {\n return text\n .replace(/```json[\\s\\S]*?```/g, \"\")\n .replace(/```json[\\s\\S]*/g, \"\")\n .trim();\n}\n\nfunction handleSuggestionClick(suggestion: string): void {\n pauseReveal();\n promptInput.value = suggestion;\n handleSend();\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n handleSend();\n }\n}\n</script>\n\n<template>\n <Transition\n enter-active-class=\"tpl-ai-slide-enter-active\"\n enter-from-class=\"tpl:translate-x-full\"\n enter-to-class=\"tpl:translate-x-0\"\n leave-active-class=\"tpl-ai-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=\"cloudTranslations.aiChat.title\"\n class=\"tpl-ai-sidebar 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 <Sparkles :size=\"13\" :stroke-width=\"2\" />\n <span>\n {{ cloudTranslations.aiChat.title }}\n </span>\n </div>\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <button\n v-if=\"(aiChat.messages.value?.length ?? 0) > 0\"\n type=\"button\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :aria-label=\"cloudTranslations.aiChat.clear\"\n :title=\"cloudTranslations.aiChat.clear\"\n @click=\"aiChat.clearChat()\"\n >\n <Trash2 :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=\"cloudTranslations.aiChat.close\"\n @click=\"emit('close')\"\n >\n <X :size=\"14\" :stroke-width=\"2\" />\n </button>\n </div>\n </div>\n\n <!-- Messages wrapper -->\n <div class=\"tpl:relative tpl:flex tpl:min-h-0 tpl:flex-1 tpl:flex-col\">\n <!-- Messages -->\n <div\n ref=\"messagesContainer\"\n class=\"tpl:flex-1 tpl:overflow-y-auto tpl:p-4\"\n >\n <!-- Loading history state -->\n <div\n v-if=\"aiChat.isLoadingHistory.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 <LoaderCircle\n class=\"tpl-spinner tpl:text-[var(--tpl-text-muted)]\"\n :size=\"24\"\n :stroke-width=\"2\"\n />\n <p class=\"tpl:text-sm tpl:text-[var(--tpl-text-muted)]\">\n {{ cloudTranslations.aiChat.loadingHistory }}\n </p>\n </div>\n\n <!-- Empty state -->\n <div\n v-else-if=\"(aiChat.messages.value?.length ?? 0) === 0\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <Sparkles\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 {{ cloudTranslations.aiChat.placeholder }}\n </p>\n </div>\n\n <!-- Message list -->\n <div v-else class=\"tpl:flex tpl:flex-col tpl:gap-4\">\n <div\n v-for=\"(message, index) in aiChat.messages.value\"\n :key=\"message.id\"\n class=\"tpl:flex tpl:flex-col tpl:gap-2\"\n >\n <!-- User message -->\n <div\n v-if=\"message.role === 'user'\"\n class=\"tpl:self-end tpl:rounded-[var(--tpl-radius-sm)] tpl:px-3.5 tpl:py-2.5 tpl:text-sm\"\n style=\"\n background-color: var(--tpl-primary-light);\n color: var(--tpl-text);\n max-width: 85%;\n box-shadow: var(--tpl-shadow);\n \"\n >\n {{ message.content }}\n </div>\n\n <!-- Assistant message -->\n <div v-else class=\"tpl:flex tpl:flex-col tpl:gap-2\">\n <LoadingTrack\n v-if=\"\n !stripJsonBlock(message.content) &&\n aiChat.isGenerating.value &&\n index === (aiChat.messages.value?.length ?? 0) - 1\n \"\n />\n <div\n v-else\n class=\"tpl:rounded-[var(--tpl-radius-sm)] tpl:px-3.5 tpl:py-2.5 tpl:text-sm tpl:whitespace-pre-wrap\"\n style=\"\n max-width: 85%;\n background-color: var(--tpl-bg);\n color: var(--tpl-text);\n box-shadow: var(--tpl-shadow);\n \"\n >\n {{\n stripJsonBlock(message.content) ||\n cloudTranslations.aiChat.applied\n }}\n </div>\n <button\n v-if=\"\n message.id === aiChat.lastApplyMessageId.value &&\n !aiChat.isGenerating.value\n \"\n class=\"tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:self-start tpl:rounded-md tpl:border tpl:px-2.5 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:transition-all\"\n style=\"\n border-color: var(--tpl-border);\n color: var(--tpl-text-muted);\n background-color: transparent;\n \"\n @click=\"aiChat.toggleLastRevert()\"\n >\n <template v-if=\"aiChat.isLastChangeReverted.value\">\n <Redo2 :size=\"12\" :stroke-width=\"2\" />\n {{ cloudTranslations.aiChat.reapply }}\n </template>\n <template v-else>\n <Undo2 :size=\"12\" :stroke-width=\"2\" />\n {{ cloudTranslations.aiChat.revert }}\n </template>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Error message -->\n <div\n v-if=\"aiChat.error.value\"\n class=\"tpl:mx-3 tpl:mb-2 tpl:flex tpl:items-start tpl:gap-2 tpl:rounded-lg tpl:px-3 tpl:py-2 tpl:text-xs\"\n style=\"\n background-color: var(--tpl-danger-light);\n color: var(--tpl-danger);\n \"\n >\n <CircleAlert\n :size=\"14\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n />\n <span>{{\n aiChat.error.value === \"ai_apply_failed\"\n ? cloudTranslations.aiChat.applyFailed\n : cloudTranslations.aiChat.error\n }}</span>\n </div>\n\n <!-- Suggestions (overlay) -->\n <div\n v-if=\"(aiChat.suggestions.value?.length ?? 0) > 0\"\n class=\"tpl:absolute tpl:right-0 tpl:bottom-0 tpl:left-0 tpl:z-10 tpl:px-3 tpl:pb-3\"\n style=\"\n background-color: color-mix(\n in srgb,\n var(--tpl-bg) 50%,\n transparent\n );\n backdrop-filter: blur(2px);\n \"\n >\n <div class=\"tpl:flex tpl:flex-col tpl:gap-1.5\">\n <button\n v-for=\"(suggestion, index) in aiChat.suggestions.value ?? []\"\n :key=\"index\"\n class=\"tpl-suggestion-btn tpl:cursor-pointer tpl:rounded-[var(--tpl-radius-sm)] tpl:border tpl:px-3 tpl:py-2 tpl:text-left tpl:text-xs tpl:leading-snug tpl:transition-all tpl:duration-300 tpl:ease-out\"\n :class=\"\n (aiChat.suggestions.value?.length ?? 0) - 1 - index <\n visibleSuggestionCount\n ? 'tpl:translate-y-0 tpl:opacity-100'\n : 'tpl:pointer-events-none tpl:-translate-y-2 tpl:opacity-0'\n \"\n style=\"\n border-color: var(--tpl-border);\n color: var(--tpl-primary);\n background-color: var(--tpl-bg);\n box-shadow: var(--tpl-shadow);\n \"\n @click=\"handleSuggestionClick(suggestion)\"\n >\n {{ suggestion }}\n </button>\n </div>\n </div>\n </div>\n\n <!-- Input area -->\n <div class=\"tpl:border-t tpl:p-3 tpl:border-[var(--tpl-border)]\">\n <div\n class=\"tpl-ai-input-wrapper tpl-focus-ring-host tpl:flex tpl:items-end tpl:gap-2 tpl:rounded-[var(--tpl-radius)] tpl:border tpl:px-3 tpl:py-2 tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)]\"\n >\n <textarea\n v-model=\"promptInput\"\n class=\"tpl:max-h-32 tpl:min-h-[64px] tpl:flex-1 tpl:resize-none tpl:border-none tpl:bg-transparent tpl:font-sans tpl:text-sm tpl:outline-none tpl:text-[var(--tpl-text)]\"\n :placeholder=\"cloudTranslations.aiChat.inputPlaceholder\"\n :disabled=\"aiChat.isGenerating.value\"\n rows=\"3\"\n @keydown=\"handleKeydown\"\n />\n <button\n class=\"tpl-ai-send-btn tpl:flex tpl:shrink-0 tpl:items-center tpl:justify-center tpl:rounded-md tpl:p-1.5 tpl:transition-all tpl:disabled:opacity-40 tpl:text-[var(--tpl-primary)]\"\n :disabled=\"!promptInput.trim() || aiChat.isGenerating.value\"\n @click=\"handleSend\"\n >\n <Send :size=\"16\" :stroke-width=\"2\" />\n </button>\n </div>\n\n <!-- AI disclaimer -->\n <p\n class=\"tpl:m-0 tpl:px-1 tpl:pt-2 tpl:text-center tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudTranslations.aiMenu.disclaimer }}\n </p>\n </div>\n </div>\n </Transition>\n</template>\n\n<style scoped>\n.tpl-ai-slide-enter-active {\n transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-ai-slide-leave-active {\n transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-ai-input-wrapper:focus-within {\n border-color: var(--tpl-primary);\n box-shadow: var(--tpl-ring);\n}\n\n.tpl-ai-send-btn:not(:disabled):hover {\n transform: scale(1.05);\n}\n\n.tpl-suggestion-btn: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 { useAiChat } from \"@templatical/core/cloud\";\nimport {\n CLOUD_TRANSLATIONS_KEY,\n EDITOR_KEY,\n AUTH_MANAGER_KEY,\n MERGE_TAGS_KEY,\n NO_MERGE_TAGS,\n requireInject,\n} from \"../../keys\";\nimport { useAliveFlag } from \"../../composables/useAliveFlag\";\nimport type { TemplateContent } from \"@templatical/types\";\nimport {\n CircleAlert,\n LoaderCircle,\n Redo2,\n Send,\n Sparkles,\n Trash2,\n Undo2,\n X,\n} from \"@lucide/vue\";\nimport { inject, nextTick, ref, watch } from \"vue\";\nimport { useIntervalFn, useTimeoutFn } from \"@vueuse/core\";\n\nconst props = defineProps<{\n visible: boolean;\n onApply?: (content: TemplateContent) => void;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n}>();\n\nconst cloudTranslations = requireInject(\n CLOUD_TRANSLATIONS_KEY,\n \"AiChatSidebar\",\n);\nconst editor = requireInject(EDITOR_KEY, \"AiChatSidebar\");\nconst authManager = requireInject(AUTH_MANAGER_KEY, \"AiChatSidebar\");\nconst mergeTags = inject(MERGE_TAGS_KEY, NO_MERGE_TAGS);\nconst aliveFlag = useAliveFlag();\n\nconst aiChat = useAiChat({\n authManager,\n getTemplateId: () => editor.state.template?.id ?? null,\n onApply: props.onApply,\n onError: undefined,\n});\n\nconst promptInput = ref(\"\");\nconst messagesContainer = ref<HTMLElement | null>(null);\nconst historyLoaded = ref(false);\nconst visibleSuggestionCount = ref(0);\n\nconst { pause: pauseReveal, resume: resumeReveal } = useIntervalFn(\n () => {\n const count = aiChat.suggestions.value?.length ?? 0;\n if (visibleSuggestionCount.value < count) {\n visibleSuggestionCount.value++;\n } else {\n pauseReveal();\n }\n },\n 150,\n { immediate: false },\n);\n\nconst { start: startRevealTimeout } = useTimeoutFn(() => resumeReveal(), 100, {\n immediate: false,\n});\n\nwatch(\n () => aiChat.suggestions.value?.length ?? 0,\n (count) => {\n pauseReveal();\n if (count === 0) {\n visibleSuggestionCount.value = 0;\n return;\n }\n\n visibleSuggestionCount.value = 0;\n startRevealTimeout();\n },\n);\n\nfunction scrollToBottom(): void {\n nextTick(() => {\n if (messagesContainer.value) {\n messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;\n }\n });\n}\n\nwatch(\n () => aiChat.messages.value?.length ?? 0,\n () => scrollToBottom(),\n);\n\nwatch(\n () => props.visible,\n async (isVisible) => {\n if (isVisible && !historyLoaded.value) {\n historyLoaded.value = true;\n await aiChat.loadConversation();\n if (!aliveFlag.alive) return;\n\n if (\n (aiChat.messages.value?.length ?? 0) === 0 &&\n editor.content.value.blocks.length === 0\n ) {\n aiChat.loadSuggestions(editor.content.value, mergeTags.value);\n }\n }\n },\n);\n\nasync function handleSend(): Promise<void> {\n const prompt = promptInput.value.trim();\n if (!prompt || aiChat.isGenerating.value) {\n return;\n }\n\n promptInput.value = \"\";\n aiChat.error.value = null;\n aiChat.failedPrompt.value = null;\n scrollToBottom();\n\n await aiChat.sendPrompt(prompt, editor.content.value, mergeTags.value);\n if (!aliveFlag.alive) return;\n\n if (aiChat.failedPrompt.value) {\n promptInput.value = aiChat.failedPrompt.value;\n }\n\n scrollToBottom();\n}\n\nfunction stripJsonBlock(text: string): string {\n return text\n .replace(/```json[\\s\\S]*?```/g, \"\")\n .replace(/```json[\\s\\S]*/g, \"\")\n .trim();\n}\n\nfunction handleSuggestionClick(suggestion: string): void {\n pauseReveal();\n promptInput.value = suggestion;\n handleSend();\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n handleSend();\n }\n}\n</script>\n\n<template>\n <Transition\n enter-active-class=\"tpl-ai-slide-enter-active\"\n enter-from-class=\"tpl:translate-x-full\"\n enter-to-class=\"tpl:translate-x-0\"\n leave-active-class=\"tpl-ai-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=\"cloudTranslations.aiChat.title\"\n class=\"tpl-ai-sidebar 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 <Sparkles :size=\"13\" :stroke-width=\"2\" />\n <span>\n {{ cloudTranslations.aiChat.title }}\n </span>\n </div>\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <button\n v-if=\"(aiChat.messages.value?.length ?? 0) > 0\"\n type=\"button\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :aria-label=\"cloudTranslations.aiChat.clear\"\n :title=\"cloudTranslations.aiChat.clear\"\n @click=\"aiChat.clearChat()\"\n >\n <Trash2 :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=\"cloudTranslations.aiChat.close\"\n @click=\"emit('close')\"\n >\n <X :size=\"14\" :stroke-width=\"2\" />\n </button>\n </div>\n </div>\n\n <!-- Messages wrapper -->\n <div class=\"tpl:relative tpl:flex tpl:min-h-0 tpl:flex-1 tpl:flex-col\">\n <!-- Messages -->\n <div\n ref=\"messagesContainer\"\n class=\"tpl:flex-1 tpl:overflow-y-auto tpl:p-4\"\n >\n <!-- Loading history state -->\n <div\n v-if=\"aiChat.isLoadingHistory.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 <LoaderCircle\n class=\"tpl-spinner tpl:text-[var(--tpl-text-muted)]\"\n :size=\"24\"\n :stroke-width=\"2\"\n />\n <p class=\"tpl:text-sm tpl:text-[var(--tpl-text-muted)]\">\n {{ cloudTranslations.aiChat.loadingHistory }}\n </p>\n </div>\n\n <!-- Empty state -->\n <div\n v-else-if=\"(aiChat.messages.value?.length ?? 0) === 0\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <Sparkles\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 {{ cloudTranslations.aiChat.placeholder }}\n </p>\n </div>\n\n <!-- Message list -->\n <div v-else class=\"tpl:flex tpl:flex-col tpl:gap-4\">\n <div\n v-for=\"(message, index) in aiChat.messages.value\"\n :key=\"message.id\"\n class=\"tpl:flex tpl:flex-col tpl:gap-2\"\n >\n <!-- User message -->\n <div\n v-if=\"message.role === 'user'\"\n class=\"tpl:self-end tpl:rounded-[var(--tpl-radius-sm)] tpl:px-3.5 tpl:py-2.5 tpl:text-sm\"\n style=\"\n background-color: var(--tpl-primary-light);\n color: var(--tpl-text);\n max-width: 85%;\n box-shadow: var(--tpl-shadow);\n \"\n >\n {{ message.content }}\n </div>\n\n <!-- Assistant message -->\n <div v-else class=\"tpl:flex tpl:flex-col tpl:gap-2\">\n <LoadingTrack\n v-if=\"\n !stripJsonBlock(message.content) &&\n aiChat.isGenerating.value &&\n index === (aiChat.messages.value?.length ?? 0) - 1\n \"\n />\n <div\n v-else\n class=\"tpl:rounded-[var(--tpl-radius-sm)] tpl:px-3.5 tpl:py-2.5 tpl:text-sm tpl:whitespace-pre-wrap\"\n style=\"\n max-width: 85%;\n background-color: var(--tpl-bg);\n color: var(--tpl-text);\n box-shadow: var(--tpl-shadow);\n \"\n >\n {{\n stripJsonBlock(message.content) ||\n cloudTranslations.aiChat.applied\n }}\n </div>\n <button\n v-if=\"\n message.id === aiChat.lastApplyMessageId.value &&\n !aiChat.isGenerating.value\n \"\n class=\"tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:self-start tpl:rounded-md tpl:border tpl:px-2.5 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:transition-all\"\n style=\"\n border-color: var(--tpl-border);\n color: var(--tpl-text-muted);\n background-color: transparent;\n \"\n @click=\"aiChat.toggleLastRevert()\"\n >\n <template v-if=\"aiChat.isLastChangeReverted.value\">\n <Redo2 :size=\"12\" :stroke-width=\"2\" />\n {{ cloudTranslations.aiChat.reapply }}\n </template>\n <template v-else>\n <Undo2 :size=\"12\" :stroke-width=\"2\" />\n {{ cloudTranslations.aiChat.revert }}\n </template>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Error message -->\n <div\n v-if=\"aiChat.error.value\"\n class=\"tpl:mx-3 tpl:mb-2 tpl:flex tpl:items-start tpl:gap-2 tpl:rounded-lg tpl:px-3 tpl:py-2 tpl:text-xs\"\n style=\"\n background-color: var(--tpl-danger-light);\n color: var(--tpl-danger);\n \"\n >\n <CircleAlert\n :size=\"14\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n />\n <span>{{\n aiChat.error.value === \"ai_apply_failed\"\n ? cloudTranslations.aiChat.applyFailed\n : cloudTranslations.aiChat.error\n }}</span>\n </div>\n\n <!-- Suggestions (overlay) -->\n <div\n v-if=\"(aiChat.suggestions.value?.length ?? 0) > 0\"\n class=\"tpl:absolute tpl:right-0 tpl:bottom-0 tpl:left-0 tpl:z-10 tpl:px-3 tpl:pb-3\"\n style=\"\n background-color: color-mix(\n in srgb,\n var(--tpl-bg) 50%,\n transparent\n );\n backdrop-filter: blur(2px);\n \"\n >\n <div class=\"tpl:flex tpl:flex-col tpl:gap-1.5\">\n <button\n v-for=\"(suggestion, index) in aiChat.suggestions.value ?? []\"\n :key=\"index\"\n class=\"tpl-suggestion-btn tpl:cursor-pointer tpl:rounded-[var(--tpl-radius-sm)] tpl:border tpl:px-3 tpl:py-2 tpl:text-left tpl:text-xs tpl:leading-snug tpl:transition-all tpl:duration-300 tpl:ease-out\"\n :class=\"\n (aiChat.suggestions.value?.length ?? 0) - 1 - index <\n visibleSuggestionCount\n ? 'tpl:translate-y-0 tpl:opacity-100'\n : 'tpl:pointer-events-none tpl:-translate-y-2 tpl:opacity-0'\n \"\n style=\"\n border-color: var(--tpl-border);\n color: var(--tpl-primary);\n background-color: var(--tpl-bg);\n box-shadow: var(--tpl-shadow);\n \"\n @click=\"handleSuggestionClick(suggestion)\"\n >\n {{ suggestion }}\n </button>\n </div>\n </div>\n </div>\n\n <!-- Input area -->\n <div class=\"tpl:border-t tpl:p-3 tpl:border-[var(--tpl-border)]\">\n <div\n class=\"tpl-ai-input-wrapper tpl-focus-ring-host tpl:flex tpl:items-end tpl:gap-2 tpl:rounded-[var(--tpl-radius)] tpl:border tpl:px-3 tpl:py-2 tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)]\"\n >\n <textarea\n v-model=\"promptInput\"\n class=\"tpl:max-h-32 tpl:min-h-[64px] tpl:flex-1 tpl:resize-none tpl:border-none tpl:bg-transparent tpl:font-sans tpl:text-sm tpl:outline-none tpl:text-[var(--tpl-text)]\"\n :placeholder=\"cloudTranslations.aiChat.inputPlaceholder\"\n :disabled=\"aiChat.isGenerating.value\"\n rows=\"3\"\n @keydown=\"handleKeydown\"\n />\n <button\n class=\"tpl-ai-send-btn tpl:flex tpl:shrink-0 tpl:items-center tpl:justify-center tpl:rounded-md tpl:p-1.5 tpl:transition-all tpl:disabled:opacity-40 tpl:text-[var(--tpl-primary)]\"\n :disabled=\"!promptInput.trim() || aiChat.isGenerating.value\"\n @click=\"handleSend\"\n >\n <Send :size=\"16\" :stroke-width=\"2\" />\n </button>\n </div>\n\n <!-- AI disclaimer -->\n <p\n class=\"tpl:m-0 tpl:px-1 tpl:pt-2 tpl:text-center tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudTranslations.aiMenu.disclaimer }}\n </p>\n </div>\n </div>\n </Transition>\n</template>\n\n<style scoped>\n.tpl-ai-slide-enter-active {\n transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-ai-slide-leave-active {\n transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-ai-input-wrapper:focus-within {\n border-color: var(--tpl-primary);\n box-shadow: var(--tpl-ring);\n}\n\n.tpl-ai-send-btn:not(:disabled):hover {\n transform: scale(1.05);\n}\n\n.tpl-suggestion-btn: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":"AiChatSidebar-oFwacME4.js","names":["_openBlock","_createBlock","_Transition","_withCtx","_createElementBlock","_unref","_createElementVNode","_createVNode","_toDisplayString","Trash2","_createCommentVNode","_Fragment","_renderList","LoadingTrack","_createTextVNode","_normalizeClass","_withDirectives","_vModelText","_sfc_main","watch","inject","renderList","withCtx","openBlock","ref","defineComponent","withDirectives","unref","createVNode","normalizeClass","createElementBlock","createCommentVNode","nextTick","createBlock","Transition","vModelText","createBaseVNode","Fragment","toDisplayString","createTextVNode","useTimeoutFn","useIntervalFn","requireInject","NO_MERGE_TAGS","MERGE_TAGS_KEY","EDITOR_KEY","AUTH_MANAGER_KEY","CLOUD_TRANSLATIONS_KEY","Sparkles","Send","CircleAlert","Redo2","LoaderCircle","Trash","Undo2","X","LoadingTrack_default","_plugin_vue_export_helper_default","useAliveFlag","useAiChat","_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","\"color\"","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","AiChatSidebar_default","__emit","props","__props","emit","cloudTranslations","editor","authManager","mergeTags","aliveFlag","aiChat","promptInput","messagesContainer","historyLoaded","visibleSuggestionCount","pauseReveal","resumeReveal","startRevealTimeout","count","scrollToBottom","isVisible","handleSend","prompt","stripJsonBlock","text","handleSuggestionClick","suggestion","handleKeydown","event","_cache","message","index","$event"],"sources":["../../../src/cloud/components/AiChatSidebar.vue","../../../src/cloud/components/AiChatSidebar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport LoadingTrack from \"../../components/LoadingTrack.vue\";\nimport { useAiChat } from \"@templatical/core/cloud\";\nimport {\n CLOUD_TRANSLATIONS_KEY,\n EDITOR_KEY,\n AUTH_MANAGER_KEY,\n MERGE_TAGS_KEY,\n NO_MERGE_TAGS,\n requireInject,\n} from \"../../keys\";\nimport { useAliveFlag } from \"../../composables/useAliveFlag\";\nimport type { TemplateContent } from \"@templatical/types\";\nimport {\n CircleAlert,\n LoaderCircle,\n Redo2,\n Send,\n Sparkles,\n Trash2,\n Undo2,\n X,\n} from \"@lucide/vue\";\nimport { inject, nextTick, ref, watch } from \"vue\";\nimport { useIntervalFn, useTimeoutFn } from \"@vueuse/core\";\n\nconst props = defineProps<{\n visible: boolean;\n onApply?: (content: TemplateContent) => void;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n}>();\n\nconst cloudTranslations = requireInject(\n CLOUD_TRANSLATIONS_KEY,\n \"AiChatSidebar\",\n);\nconst editor = requireInject(EDITOR_KEY, \"AiChatSidebar\");\nconst authManager = requireInject(AUTH_MANAGER_KEY, \"AiChatSidebar\");\nconst mergeTags = inject(MERGE_TAGS_KEY, NO_MERGE_TAGS);\nconst aliveFlag = useAliveFlag();\n\nconst aiChat = useAiChat({\n authManager,\n getTemplateId: () => editor.state.template?.id ?? null,\n onApply: props.onApply,\n onError: undefined,\n});\n\nconst promptInput = ref(\"\");\nconst messagesContainer = ref<HTMLElement | null>(null);\nconst historyLoaded = ref(false);\nconst visibleSuggestionCount = ref(0);\n\nconst { pause: pauseReveal, resume: resumeReveal } = useIntervalFn(\n () => {\n const count = aiChat.suggestions.value?.length ?? 0;\n if (visibleSuggestionCount.value < count) {\n visibleSuggestionCount.value++;\n } else {\n pauseReveal();\n }\n },\n 150,\n { immediate: false },\n);\n\nconst { start: startRevealTimeout } = useTimeoutFn(() => resumeReveal(), 100, {\n immediate: false,\n});\n\nwatch(\n () => aiChat.suggestions.value?.length ?? 0,\n (count) => {\n pauseReveal();\n if (count === 0) {\n visibleSuggestionCount.value = 0;\n return;\n }\n\n visibleSuggestionCount.value = 0;\n startRevealTimeout();\n },\n);\n\nfunction scrollToBottom(): void {\n nextTick(() => {\n if (messagesContainer.value) {\n messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;\n }\n });\n}\n\nwatch(\n () => aiChat.messages.value?.length ?? 0,\n () => scrollToBottom(),\n);\n\nwatch(\n () => props.visible,\n async (isVisible) => {\n if (isVisible && !historyLoaded.value) {\n historyLoaded.value = true;\n await aiChat.loadConversation();\n if (!aliveFlag.alive) return;\n\n if (\n (aiChat.messages.value?.length ?? 0) === 0 &&\n editor.content.value.blocks.length === 0\n ) {\n aiChat.loadSuggestions(editor.content.value, mergeTags.value);\n }\n }\n },\n);\n\nasync function handleSend(): Promise<void> {\n const prompt = promptInput.value.trim();\n if (!prompt || aiChat.isGenerating.value) {\n return;\n }\n\n promptInput.value = \"\";\n aiChat.error.value = null;\n aiChat.failedPrompt.value = null;\n scrollToBottom();\n\n await aiChat.sendPrompt(prompt, editor.content.value, mergeTags.value);\n if (!aliveFlag.alive) return;\n\n if (aiChat.failedPrompt.value) {\n promptInput.value = aiChat.failedPrompt.value;\n }\n\n scrollToBottom();\n}\n\nfunction stripJsonBlock(text: string): string {\n return text\n .replace(/```json[\\s\\S]*?```/g, \"\")\n .replace(/```json[\\s\\S]*/g, \"\")\n .trim();\n}\n\nfunction handleSuggestionClick(suggestion: string): void {\n pauseReveal();\n promptInput.value = suggestion;\n handleSend();\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n handleSend();\n }\n}\n</script>\n\n<template>\n <Transition\n enter-active-class=\"tpl-ai-slide-enter-active\"\n enter-from-class=\"tpl:translate-x-full\"\n enter-to-class=\"tpl:translate-x-0\"\n leave-active-class=\"tpl-ai-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=\"cloudTranslations.aiChat.title\"\n class=\"tpl-ai-sidebar 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 <Sparkles :size=\"13\" :stroke-width=\"2\" />\n <span>\n {{ cloudTranslations.aiChat.title }}\n </span>\n </div>\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <button\n v-if=\"(aiChat.messages.value?.length ?? 0) > 0\"\n type=\"button\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :aria-label=\"cloudTranslations.aiChat.clear\"\n :title=\"cloudTranslations.aiChat.clear\"\n @click=\"aiChat.clearChat()\"\n >\n <Trash2 :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=\"cloudTranslations.aiChat.close\"\n @click=\"emit('close')\"\n >\n <X :size=\"14\" :stroke-width=\"2\" />\n </button>\n </div>\n </div>\n\n <!-- Messages wrapper -->\n <div class=\"tpl:relative tpl:flex tpl:min-h-0 tpl:flex-1 tpl:flex-col\">\n <!-- Messages -->\n <div\n ref=\"messagesContainer\"\n class=\"tpl:flex-1 tpl:overflow-y-auto tpl:p-4\"\n >\n <!-- Loading history state -->\n <div\n v-if=\"aiChat.isLoadingHistory.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 <LoaderCircle\n class=\"tpl-spinner tpl:text-[var(--tpl-text-muted)]\"\n :size=\"24\"\n :stroke-width=\"2\"\n />\n <p class=\"tpl:text-sm tpl:text-[var(--tpl-text-muted)]\">\n {{ cloudTranslations.aiChat.loadingHistory }}\n </p>\n </div>\n\n <!-- Empty state -->\n <div\n v-else-if=\"(aiChat.messages.value?.length ?? 0) === 0\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <Sparkles\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 {{ cloudTranslations.aiChat.placeholder }}\n </p>\n </div>\n\n <!-- Message list -->\n <div v-else class=\"tpl:flex tpl:flex-col tpl:gap-4\">\n <div\n v-for=\"(message, index) in aiChat.messages.value\"\n :key=\"message.id\"\n class=\"tpl:flex tpl:flex-col tpl:gap-2\"\n >\n <!-- User message -->\n <div\n v-if=\"message.role === 'user'\"\n class=\"tpl:self-end tpl:rounded-[var(--tpl-radius-sm)] tpl:px-3.5 tpl:py-2.5 tpl:text-sm\"\n style=\"\n background-color: var(--tpl-primary-light);\n color: var(--tpl-text);\n max-width: 85%;\n box-shadow: var(--tpl-shadow);\n \"\n >\n {{ message.content }}\n </div>\n\n <!-- Assistant message -->\n <div v-else class=\"tpl:flex tpl:flex-col tpl:gap-2\">\n <LoadingTrack\n v-if=\"\n !stripJsonBlock(message.content) &&\n aiChat.isGenerating.value &&\n index === (aiChat.messages.value?.length ?? 0) - 1\n \"\n />\n <div\n v-else\n class=\"tpl:rounded-[var(--tpl-radius-sm)] tpl:px-3.5 tpl:py-2.5 tpl:text-sm tpl:whitespace-pre-wrap\"\n style=\"\n max-width: 85%;\n background-color: var(--tpl-bg);\n color: var(--tpl-text);\n box-shadow: var(--tpl-shadow);\n \"\n >\n {{\n stripJsonBlock(message.content) ||\n cloudTranslations.aiChat.applied\n }}\n </div>\n <button\n v-if=\"\n message.id === aiChat.lastApplyMessageId.value &&\n !aiChat.isGenerating.value\n \"\n class=\"tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:self-start tpl:rounded-md tpl:border tpl:px-2.5 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:transition-all\"\n style=\"\n border-color: var(--tpl-border);\n color: var(--tpl-text-muted);\n background-color: transparent;\n \"\n @click=\"aiChat.toggleLastRevert()\"\n >\n <template v-if=\"aiChat.isLastChangeReverted.value\">\n <Redo2 :size=\"12\" :stroke-width=\"2\" />\n {{ cloudTranslations.aiChat.reapply }}\n </template>\n <template v-else>\n <Undo2 :size=\"12\" :stroke-width=\"2\" />\n {{ cloudTranslations.aiChat.revert }}\n </template>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Error message -->\n <div\n v-if=\"aiChat.error.value\"\n class=\"tpl:mx-3 tpl:mb-2 tpl:flex tpl:items-start tpl:gap-2 tpl:rounded-lg tpl:px-3 tpl:py-2 tpl:text-xs\"\n style=\"\n background-color: var(--tpl-danger-light);\n color: var(--tpl-danger);\n \"\n >\n <CircleAlert\n :size=\"14\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n />\n <span>{{\n aiChat.error.value === \"ai_apply_failed\"\n ? cloudTranslations.aiChat.applyFailed\n : cloudTranslations.aiChat.error\n }}</span>\n </div>\n\n <!-- Suggestions (overlay) -->\n <div\n v-if=\"(aiChat.suggestions.value?.length ?? 0) > 0\"\n class=\"tpl:absolute tpl:right-0 tpl:bottom-0 tpl:left-0 tpl:z-10 tpl:px-3 tpl:pb-3\"\n style=\"\n background-color: color-mix(\n in srgb,\n var(--tpl-bg) 50%,\n transparent\n );\n backdrop-filter: blur(2px);\n \"\n >\n <div class=\"tpl:flex tpl:flex-col tpl:gap-1.5\">\n <button\n v-for=\"(suggestion, index) in aiChat.suggestions.value ?? []\"\n :key=\"index\"\n class=\"tpl-suggestion-btn tpl:cursor-pointer tpl:rounded-[var(--tpl-radius-sm)] tpl:border tpl:px-3 tpl:py-2 tpl:text-left tpl:text-xs tpl:leading-snug tpl:transition-all tpl:duration-300 tpl:ease-out\"\n :class=\"\n (aiChat.suggestions.value?.length ?? 0) - 1 - index <\n visibleSuggestionCount\n ? 'tpl:translate-y-0 tpl:opacity-100'\n : 'tpl:pointer-events-none tpl:-translate-y-2 tpl:opacity-0'\n \"\n style=\"\n border-color: var(--tpl-border);\n color: var(--tpl-primary);\n background-color: var(--tpl-bg);\n box-shadow: var(--tpl-shadow);\n \"\n @click=\"handleSuggestionClick(suggestion)\"\n >\n {{ suggestion }}\n </button>\n </div>\n </div>\n </div>\n\n <!-- Input area -->\n <div class=\"tpl:border-t tpl:p-3 tpl:border-[var(--tpl-border)]\">\n <div\n class=\"tpl-ai-input-wrapper tpl-focus-ring-host tpl:flex tpl:items-end tpl:gap-2 tpl:rounded-[var(--tpl-radius)] tpl:border tpl:px-3 tpl:py-2 tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)]\"\n >\n <textarea\n v-model=\"promptInput\"\n class=\"tpl:max-h-32 tpl:min-h-[64px] tpl:flex-1 tpl:resize-none tpl:border-none tpl:bg-transparent tpl:font-sans tpl:text-sm tpl:outline-none tpl:text-[var(--tpl-text)]\"\n :placeholder=\"cloudTranslations.aiChat.inputPlaceholder\"\n :disabled=\"aiChat.isGenerating.value\"\n rows=\"3\"\n @keydown=\"handleKeydown\"\n />\n <button\n class=\"tpl-ai-send-btn tpl:flex tpl:shrink-0 tpl:items-center tpl:justify-center tpl:rounded-md tpl:p-1.5 tpl:transition-all tpl:disabled:opacity-40 tpl:text-[var(--tpl-primary)]\"\n :disabled=\"!promptInput.trim() || aiChat.isGenerating.value\"\n @click=\"handleSend\"\n >\n <Send :size=\"16\" :stroke-width=\"2\" />\n </button>\n </div>\n\n <!-- AI disclaimer -->\n <p\n class=\"tpl:m-0 tpl:px-1 tpl:pt-2 tpl:text-center tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudTranslations.aiMenu.disclaimer }}\n </p>\n </div>\n </div>\n </Transition>\n</template>\n\n<style scoped>\n.tpl-ai-slide-enter-active {\n transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-ai-slide-leave-active {\n transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-ai-input-wrapper:focus-within {\n border-color: var(--tpl-primary);\n box-shadow: var(--tpl-ring);\n}\n\n.tpl-ai-send-btn:not(:disabled):hover {\n transform: scale(1.05);\n}\n\n.tpl-suggestion-btn: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 { useAiChat } from \"@templatical/core/cloud\";\nimport {\n CLOUD_TRANSLATIONS_KEY,\n EDITOR_KEY,\n AUTH_MANAGER_KEY,\n MERGE_TAGS_KEY,\n NO_MERGE_TAGS,\n requireInject,\n} from \"../../keys\";\nimport { useAliveFlag } from \"../../composables/useAliveFlag\";\nimport type { TemplateContent } from \"@templatical/types\";\nimport {\n CircleAlert,\n LoaderCircle,\n Redo2,\n Send,\n Sparkles,\n Trash2,\n Undo2,\n X,\n} from \"@lucide/vue\";\nimport { inject, nextTick, ref, watch } from \"vue\";\nimport { useIntervalFn, useTimeoutFn } from \"@vueuse/core\";\n\nconst props = defineProps<{\n visible: boolean;\n onApply?: (content: TemplateContent) => void;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n}>();\n\nconst cloudTranslations = requireInject(\n CLOUD_TRANSLATIONS_KEY,\n \"AiChatSidebar\",\n);\nconst editor = requireInject(EDITOR_KEY, \"AiChatSidebar\");\nconst authManager = requireInject(AUTH_MANAGER_KEY, \"AiChatSidebar\");\nconst mergeTags = inject(MERGE_TAGS_KEY, NO_MERGE_TAGS);\nconst aliveFlag = useAliveFlag();\n\nconst aiChat = useAiChat({\n authManager,\n getTemplateId: () => editor.state.template?.id ?? null,\n onApply: props.onApply,\n onError: undefined,\n});\n\nconst promptInput = ref(\"\");\nconst messagesContainer = ref<HTMLElement | null>(null);\nconst historyLoaded = ref(false);\nconst visibleSuggestionCount = ref(0);\n\nconst { pause: pauseReveal, resume: resumeReveal } = useIntervalFn(\n () => {\n const count = aiChat.suggestions.value?.length ?? 0;\n if (visibleSuggestionCount.value < count) {\n visibleSuggestionCount.value++;\n } else {\n pauseReveal();\n }\n },\n 150,\n { immediate: false },\n);\n\nconst { start: startRevealTimeout } = useTimeoutFn(() => resumeReveal(), 100, {\n immediate: false,\n});\n\nwatch(\n () => aiChat.suggestions.value?.length ?? 0,\n (count) => {\n pauseReveal();\n if (count === 0) {\n visibleSuggestionCount.value = 0;\n return;\n }\n\n visibleSuggestionCount.value = 0;\n startRevealTimeout();\n },\n);\n\nfunction scrollToBottom(): void {\n nextTick(() => {\n if (messagesContainer.value) {\n messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;\n }\n });\n}\n\nwatch(\n () => aiChat.messages.value?.length ?? 0,\n () => scrollToBottom(),\n);\n\nwatch(\n () => props.visible,\n async (isVisible) => {\n if (isVisible && !historyLoaded.value) {\n historyLoaded.value = true;\n await aiChat.loadConversation();\n if (!aliveFlag.alive) return;\n\n if (\n (aiChat.messages.value?.length ?? 0) === 0 &&\n editor.content.value.blocks.length === 0\n ) {\n aiChat.loadSuggestions(editor.content.value, mergeTags.value);\n }\n }\n },\n);\n\nasync function handleSend(): Promise<void> {\n const prompt = promptInput.value.trim();\n if (!prompt || aiChat.isGenerating.value) {\n return;\n }\n\n promptInput.value = \"\";\n aiChat.error.value = null;\n aiChat.failedPrompt.value = null;\n scrollToBottom();\n\n await aiChat.sendPrompt(prompt, editor.content.value, mergeTags.value);\n if (!aliveFlag.alive) return;\n\n if (aiChat.failedPrompt.value) {\n promptInput.value = aiChat.failedPrompt.value;\n }\n\n scrollToBottom();\n}\n\nfunction stripJsonBlock(text: string): string {\n return text\n .replace(/```json[\\s\\S]*?```/g, \"\")\n .replace(/```json[\\s\\S]*/g, \"\")\n .trim();\n}\n\nfunction handleSuggestionClick(suggestion: string): void {\n pauseReveal();\n promptInput.value = suggestion;\n handleSend();\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n handleSend();\n }\n}\n</script>\n\n<template>\n <Transition\n enter-active-class=\"tpl-ai-slide-enter-active\"\n enter-from-class=\"tpl:translate-x-full\"\n enter-to-class=\"tpl:translate-x-0\"\n leave-active-class=\"tpl-ai-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=\"cloudTranslations.aiChat.title\"\n class=\"tpl-ai-sidebar 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 <Sparkles :size=\"13\" :stroke-width=\"2\" />\n <span>\n {{ cloudTranslations.aiChat.title }}\n </span>\n </div>\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <button\n v-if=\"(aiChat.messages.value?.length ?? 0) > 0\"\n type=\"button\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:text-[var(--tpl-text-muted)]\"\n :aria-label=\"cloudTranslations.aiChat.clear\"\n :title=\"cloudTranslations.aiChat.clear\"\n @click=\"aiChat.clearChat()\"\n >\n <Trash2 :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=\"cloudTranslations.aiChat.close\"\n @click=\"emit('close')\"\n >\n <X :size=\"14\" :stroke-width=\"2\" />\n </button>\n </div>\n </div>\n\n <!-- Messages wrapper -->\n <div class=\"tpl:relative tpl:flex tpl:min-h-0 tpl:flex-1 tpl:flex-col\">\n <!-- Messages -->\n <div\n ref=\"messagesContainer\"\n class=\"tpl:flex-1 tpl:overflow-y-auto tpl:p-4\"\n >\n <!-- Loading history state -->\n <div\n v-if=\"aiChat.isLoadingHistory.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 <LoaderCircle\n class=\"tpl-spinner tpl:text-[var(--tpl-text-muted)]\"\n :size=\"24\"\n :stroke-width=\"2\"\n />\n <p class=\"tpl:text-sm tpl:text-[var(--tpl-text-muted)]\">\n {{ cloudTranslations.aiChat.loadingHistory }}\n </p>\n </div>\n\n <!-- Empty state -->\n <div\n v-else-if=\"(aiChat.messages.value?.length ?? 0) === 0\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <Sparkles\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 {{ cloudTranslations.aiChat.placeholder }}\n </p>\n </div>\n\n <!-- Message list -->\n <div v-else class=\"tpl:flex tpl:flex-col tpl:gap-4\">\n <div\n v-for=\"(message, index) in aiChat.messages.value\"\n :key=\"message.id\"\n class=\"tpl:flex tpl:flex-col tpl:gap-2\"\n >\n <!-- User message -->\n <div\n v-if=\"message.role === 'user'\"\n class=\"tpl:self-end tpl:rounded-[var(--tpl-radius-sm)] tpl:px-3.5 tpl:py-2.5 tpl:text-sm\"\n style=\"\n background-color: var(--tpl-primary-light);\n color: var(--tpl-text);\n max-width: 85%;\n box-shadow: var(--tpl-shadow);\n \"\n >\n {{ message.content }}\n </div>\n\n <!-- Assistant message -->\n <div v-else class=\"tpl:flex tpl:flex-col tpl:gap-2\">\n <LoadingTrack\n v-if=\"\n !stripJsonBlock(message.content) &&\n aiChat.isGenerating.value &&\n index === (aiChat.messages.value?.length ?? 0) - 1\n \"\n />\n <div\n v-else\n class=\"tpl:rounded-[var(--tpl-radius-sm)] tpl:px-3.5 tpl:py-2.5 tpl:text-sm tpl:whitespace-pre-wrap\"\n style=\"\n max-width: 85%;\n background-color: var(--tpl-bg);\n color: var(--tpl-text);\n box-shadow: var(--tpl-shadow);\n \"\n >\n {{\n stripJsonBlock(message.content) ||\n cloudTranslations.aiChat.applied\n }}\n </div>\n <button\n v-if=\"\n message.id === aiChat.lastApplyMessageId.value &&\n !aiChat.isGenerating.value\n \"\n class=\"tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:self-start tpl:rounded-md tpl:border tpl:px-2.5 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:transition-all\"\n style=\"\n border-color: var(--tpl-border);\n color: var(--tpl-text-muted);\n background-color: transparent;\n \"\n @click=\"aiChat.toggleLastRevert()\"\n >\n <template v-if=\"aiChat.isLastChangeReverted.value\">\n <Redo2 :size=\"12\" :stroke-width=\"2\" />\n {{ cloudTranslations.aiChat.reapply }}\n </template>\n <template v-else>\n <Undo2 :size=\"12\" :stroke-width=\"2\" />\n {{ cloudTranslations.aiChat.revert }}\n </template>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Error message -->\n <div\n v-if=\"aiChat.error.value\"\n class=\"tpl:mx-3 tpl:mb-2 tpl:flex tpl:items-start tpl:gap-2 tpl:rounded-lg tpl:px-3 tpl:py-2 tpl:text-xs\"\n style=\"\n background-color: var(--tpl-danger-light);\n color: var(--tpl-danger);\n \"\n >\n <CircleAlert\n :size=\"14\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n />\n <span>{{\n aiChat.error.value === \"ai_apply_failed\"\n ? cloudTranslations.aiChat.applyFailed\n : cloudTranslations.aiChat.error\n }}</span>\n </div>\n\n <!-- Suggestions (overlay) -->\n <div\n v-if=\"(aiChat.suggestions.value?.length ?? 0) > 0\"\n class=\"tpl:absolute tpl:right-0 tpl:bottom-0 tpl:left-0 tpl:z-10 tpl:px-3 tpl:pb-3\"\n style=\"\n background-color: color-mix(\n in srgb,\n var(--tpl-bg) 50%,\n transparent\n );\n backdrop-filter: blur(2px);\n \"\n >\n <div class=\"tpl:flex tpl:flex-col tpl:gap-1.5\">\n <button\n v-for=\"(suggestion, index) in aiChat.suggestions.value ?? []\"\n :key=\"index\"\n class=\"tpl-suggestion-btn tpl:cursor-pointer tpl:rounded-[var(--tpl-radius-sm)] tpl:border tpl:px-3 tpl:py-2 tpl:text-left tpl:text-xs tpl:leading-snug tpl:transition-all tpl:duration-300 tpl:ease-out\"\n :class=\"\n (aiChat.suggestions.value?.length ?? 0) - 1 - index <\n visibleSuggestionCount\n ? 'tpl:translate-y-0 tpl:opacity-100'\n : 'tpl:pointer-events-none tpl:-translate-y-2 tpl:opacity-0'\n \"\n style=\"\n border-color: var(--tpl-border);\n color: var(--tpl-primary);\n background-color: var(--tpl-bg);\n box-shadow: var(--tpl-shadow);\n \"\n @click=\"handleSuggestionClick(suggestion)\"\n >\n {{ suggestion }}\n </button>\n </div>\n </div>\n </div>\n\n <!-- Input area -->\n <div class=\"tpl:border-t tpl:p-3 tpl:border-[var(--tpl-border)]\">\n <div\n class=\"tpl-ai-input-wrapper tpl-focus-ring-host tpl:flex tpl:items-end tpl:gap-2 tpl:rounded-[var(--tpl-radius)] tpl:border tpl:px-3 tpl:py-2 tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)]\"\n >\n <textarea\n v-model=\"promptInput\"\n class=\"tpl:max-h-32 tpl:min-h-[64px] tpl:flex-1 tpl:resize-none tpl:border-none tpl:bg-transparent tpl:font-sans tpl:text-sm tpl:outline-none tpl:text-[var(--tpl-text)]\"\n :placeholder=\"cloudTranslations.aiChat.inputPlaceholder\"\n :disabled=\"aiChat.isGenerating.value\"\n rows=\"3\"\n @keydown=\"handleKeydown\"\n />\n <button\n class=\"tpl-ai-send-btn tpl:flex tpl:shrink-0 tpl:items-center tpl:justify-center tpl:rounded-md tpl:p-1.5 tpl:transition-all tpl:disabled:opacity-40 tpl:text-[var(--tpl-primary)]\"\n :disabled=\"!promptInput.trim() || aiChat.isGenerating.value\"\n @click=\"handleSend\"\n >\n <Send :size=\"16\" :stroke-width=\"2\" />\n </button>\n </div>\n\n <!-- AI disclaimer -->\n <p\n class=\"tpl:m-0 tpl:px-1 tpl:pt-2 tpl:text-center tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudTranslations.aiMenu.disclaimer }}\n </p>\n </div>\n </div>\n </Transition>\n</template>\n\n<style scoped>\n.tpl-ai-slide-enter-active {\n transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-ai-slide-leave-active {\n transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-ai-input-wrapper:focus-within {\n border-color: var(--tpl-primary);\n box-shadow: var(--tpl-ring);\n}\n\n.tpl-ai-send-btn:not(:disabled):hover {\n transform: scale(1.05);\n}\n\n.tpl-suggestion-btn:hover {\n border-color: var(--tpl-primary) !important;\n background-color: var(--tpl-primary-light) !important;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0BA,IAAMuF,IAAQC,GAKRC,KAAOH,GAIPI,IAAoBhD,EACxBK,IACA,eACF,GACM4C,IAASjD,EAAcG,IAAY,eAAe,GAClD+C,KAAclD,EAAcI,IAAkB,eAAe,GAC7D+C,IAAYzE,EAAOwB,IAAgBD,EAAa,GAChDmD,IAAYpC,EAAa,GAEzBqC,IAASpC,EAAU;GACvB;GACA,qBAAqBgC,EAAO,MAAM,UAAU,MAAM;GAClD,SAASJ,EAAM;GACf,SAAS,KAAA;EACX,CAAC,GAEKS,IAAcxE,EAAI,EAAE,GACpByE,IAAoBzE,EAAwB,IAAI,GAChD0E,IAAgB1E,EAAI,EAAK,GACzB2E,IAAyB3E,EAAI,CAAC,GAE9B,EAAE,OAAO4E,GAAa,QAAQC,OAAiB5D,SAC7C;GAEJ,AAAI0D,EAAuB,SADbJ,EAAO,YAAY,OAAO,UAAU,KAEhD,EAAuB,UAEvBK,EAAY;EAEhB,GACA,KACA,EAAE,WAAW,GAAM,CACrB,GAEM,EAAE,OAAOE,OAAuB9D,QAAmB6D,GAAa,GAAG,KAAK,EAC5E,WAAW,GACb,CAAC;EAED,QACQN,EAAO,YAAY,OAAO,UAAU,IACzC,MAAU;GAET,IADAK,EAAY,GACRG,MAAU,GAAG;IACf,EAAuB,QAAQ;IAC/B;GACF;GAGA,AADA,EAAuB,QAAQ,GAC/BD,GAAmB;EACrB,CACF;EAEA,SAASE,IAAuB;GAC9B,SAAe;IACb,AAAIP,EAAkB,UACpB,EAAkB,MAAM,YAAYA,EAAkB,MAAM;GAEhE,CAAC;EACH;EAOA,AALA9E,QACQ4E,EAAO,SAAS,OAAO,UAAU,SACjCS,EAAe,CACvB,GAEArF,QACQoE,EAAM,SACZ,OAAO,MAAc;GACnB,IAAIkB,KAAa,CAACP,EAAc,OAAO;IAGrC,IAFA,EAAc,QAAQ,IACtB,MAAMH,EAAO,iBAAiB,GAC1B,CAACD,EAAU,OAAO;IAEtB,CACGC,EAAO,SAAS,OAAO,UAAU,OAAO,KACzCJ,EAAO,QAAQ,MAAM,OAAO,WAAW,KAEvCI,EAAO,gBAAgBJ,EAAO,QAAQ,OAAOE,EAAU,KAAK;GAEhE;EACF,CACF;EAEA,eAAea,IAA4B;GACzC,IAAMC,IAASX,EAAY,MAAM,KAAK;GACtC,AAAKW,KAAU,GAAO,aAAa,UAInC,EAAY,QAAQ,IACpB,EAAO,MAAM,QAAQ,MACrB,EAAO,aAAa,QAAQ,MAC5BH,EAAe,GAEf,MAAMT,EAAO,WAAWY,GAAQhB,EAAO,QAAQ,OAAOE,EAAU,KAAK,GAChEC,EAAU,UAEXC,EAAO,aAAa,UACtB,EAAY,QAAQA,EAAO,aAAa,QAG1CS,EAAe;EACjB;EAEA,SAASI,EAAe,GAAsB;GAC5C,OAAOC,EACJ,QAAQ,uBAAuB,EAAE,CAAA,CACjC,QAAQ,mBAAmB,EAAE,CAAA,CAC7B,KAAK;EACV;EAEA,SAASC,GAAsB,GAA0B;GAGvD,AAFAV,EAAY,GACZ,EAAY,QAAQW,GACpBL,EAAW;EACb;EAEA,SAASM,GAAc,GAA4B;GACjD,AAAIC,EAAM,QAAQ,WAAW,CAACA,EAAM,aAClCA,EAAM,eAAe,GACrBP,EAAW;EAEf;oBAIE1G,EAAA,GAAAC,EAwPaC,IAAA;GAvPX,sBAAmB;GACnB,oBAAiB;GACjB,kBAAe;GACf,sBAAmB;GACnB,oBAAiB;GACjB,kBAAe;;GAEf,SAAAC,QA+OM,CA9OEqF,EAAA,WADRxF,EAAA,GAAAI,EA+OM,OAAA;;IA7OJ,MAAK;IACJ,cAAYC,EAAAqF,CAAA,CAAiB,CAAC,OAAO;IACtC,OAAM;;IAGNpF,EA+BM,OA/BNuD,GA+BM,CA5BJvD,EAOM,OAPNwD,GAOM,CAJJvD,EAAyCF,EAAA2C,CAAA,GAAA;KAA9B,MAAM;KAAK,gBAAc;IACpC1C,CAAAA,GAAAA,EAEO,QAAA,MAAAE,EADFH,EAAAqF,CAAA,CAAiB,CAAC,OAAO,KAAK,GAAA,CAAA,CAAA,CAAA,GAGrCpF,EAmBM,OAnBNyD,GAmBM,EAjBK1D,EAAA0F,CAAA,CAAM,CAAC,SAAS,OAAO,UAAM,KAAA,KADtC/F,EAAA,GAAAI,EASS,UAAA;;KAPP,MAAK;KACL,OAAM;KACL,cAAYC,EAAAqF,CAAA,CAAiB,CAAC,OAAO;KACrC,OAAOrF,EAAAqF,CAAA,CAAiB,CAAC,OAAO;KAChC,SAAK,AAAAwB,EAAA,QAAA,MAAE7G,EAAA0F,CAAA,CAAM,CAAC,UAAS;IAExBxF,GAAAA,CAAAA,EAAuCF,EAAAI,CAAA,GAAA;KAA9B,MAAM;KAAK,gBAAc;IAEpCH,CAAAA,CAAAA,GAAAA,GAAAA,CAAAA,KAAAA,EAAAA,IAAAA,EAAAA,GAAAA,EAOS,UAAA;KANP,MAAK;KACL,OAAM;KACL,cAAYD,EAAAqF,CAAA,CAAiB,CAAC,OAAO;KACrC,SAAK,AAAAwB,EAAA,QAAA,MAAEzB,GAAI,OAAA;IAEZlF,GAAAA,CAAAA,EAAkCF,EAAAkD,CAAA,GAAA;KAA9B,MAAM;KAAK,gBAAc;;IAMnCjD,EAuKM,OAvKN4D,GAuKM;KArKJ5D,EA0GM,OAAA;MAzGA,SAAA;MAAJ,KAAI2F;MACJ,OAAM;KAIE5F,GAAAA,CAAAA,EAAA0F,CAAA,CAAM,CAAC,iBAAiB,SADhC/F,EAAA,GAAAI,EAYM,OAZN+D,GAYM,CARJ5D,EAIEF,EAAA+C,EAAA,GAAA;MAHA,OAAM;MACL,MAAM;MACN,gBAAc;KAEjB9C,CAAAA,GAAAA,EAEI,KAFJ8D,GAEI5D,EADCH,EAAAqF,CAAA,CAAiB,CAAC,OAAO,cAAc,GAAA,CAAA,CAAA,CAAA,MAMhCrF,EAAA0F,CAAA,CAAM,CAAC,SAAS,OAAO,UAAM,OAAA,KAD3C/F,EAAA,GAAAI,EAcM,OAdNiE,GAcM,CAVJ9D,EAIEF,EAAA2C,CAAA,GAAA;MAHC,MAAM;MACN,gBAAc;MACf,OAAM;KAER1C,CAAAA,GAAAA,EAII,KAJJgE,GAII9D,EADCH,EAAAqF,CAAA,CAAiB,CAAC,OAAO,WAAW,GAAA,CAAA,CAAA,CAAA,MAK3C1F,EAAA,GAAAI,EAoEM,OApENmE,GAoEM,EAnEJvE,EAAA,EAAA,GAAAI,EAkEMO,GAAA,MAAAC,EAjEuBP,EAAA0F,CAAA,CAAM,CAAC,SAAS,QAAnC,GAAS,OADnB/F,EAAA,GAAAI,EAkEM,OAAA;MAhEH,KAAK+G,EAAQ;MACd,OAAM;KAIE,GAAA,CAAAA,EAAQ,SAAI,UADpBnH,EAAA,GAAAI,EAWM,OAXNoE,GAWMhE,EADD2G,EAAQ,OAAO,GAAA,CAAA,MAIpBnH,EAAA,GAAAI,EA6CM,OA7CNsE,GA6CM,CA3C0B,CAAAkC,EAAeO,EAAQ,OAAO,KAAyB9G,EAAA0F,CAAA,CAAM,CAAC,aAAa,SAA6BqB,OAAW/G,EAAA0F,CAAA,CAAM,CAAC,SAAS,OAAO,UAAM,KAAA,KAD9K/F,EAAA,GAAAC,EAMEY,GAAA,EAAA,KAAA,EAAA,CAAA,MACFb,EAAA,GAAAI,EAcM,OAdNuE,IAcMnE,EAHFoG,EAAeO,EAAQ,OAAO,KAAyB9G,EAAAqF,CAAA,CAAiB,CAAC,OAAO,OAAO,GAAA,CAAA,IAK9DyB,EAAQ,OAAO9G,EAAA0F,CAAA,CAAM,CAAC,mBAAmB,SAA8B,CAAA1F,EAAA0F,CAAA,CAAM,CAAC,aAAa,SADxH/F,EAAA,GAAAI,EAqBS,UAAA;;MAhBP,OAAM;MACN,OAAA;OAAA,gBAAA;OAAAqE,OAAA;OAAA,oBAAA;MAAA;MAKC,SAAK,AAAAyC,EAAA,QAAA,MAAE7G,EAAA0F,CAAA,CAAM,CAAC,iBAAgB;KAEf1F,GAAAA,CAAAA,EAAA0F,CAAA,CAAM,CAAC,qBAAqB,SAA5C/F,EAAA,GAAAI,EAGWO,GAAA,EAAA,KAAA,EAAA,GAAA,CAFTJ,EAAsCF,EAAA8C,EAAA,GAAA;MAA9B,MAAM;MAAK,gBAAc;KAAKrC,CAAAA,GAAAA,EAAA,MACtCN,EAAGH,EAAAqF,CAAA,CAAiB,CAAC,OAAO,OAAO,GAAA,CAAA,CAAA,GAAA,EAAA,MAErC1F,EAAA,GAAAI,EAGWO,GAAA,EAAA,KAAA,EAAA,GAAA,CAFTJ,EAAsCF,EAAAiD,CAAA,GAAA;MAA9B,MAAM;MAAK,gBAAc;KAAKxC,CAAAA,GAAAA,EAAA,MACtCN,EAAGH,EAAAqF,CAAA,CAAiB,CAAC,OAAO,MAAM,GAAA,CAAA,CAAA,GAAA,EAAA,EAAA,CAAA,KAAA3D,EAAA,IAAA,EAAA,CAAA,CAAA,EAAA,CAAA;KAUtC1B,EAAA0F,CAAA,CAAM,CAAC,MAAM,SADrB/F,EAAA,GAAAI,EAkBM,OAlBNwE,IAkBM,CAVJrE,EAIEF,EAAA6C,EAAA,GAAA;MAHC,MAAM;MACN,gBAAc;MACf,OAAM;KAER5C,CAAAA,GAAAA,EAIS,QAAA,MAAAE,EAHPH,EAAA0F,CAAA,CAAM,CAAC,MAAM,UAAK,oBAAuC1F,EAAAqF,CAAA,CAAiB,CAAC,OAAO,cAA4BrF,EAAAqF,CAAA,CAAiB,CAAC,OAAO,KAAK,GAAA,CAAA,CAAA,CAAA,KAAA3D,EAAA,IAAA,EAAA;MAQvI1B,EAAA0F,CAAA,CAAM,CAAC,YAAY,OAAO,UAAM,KAAA,KADzC/F,EAAA,GAAAI,EAkCM,OAlCNyE,IAkCM,CAtBJvE,EAqBM,OArBNwE,IAqBM,EApBJ9E,EAAA,EAAA,GAAAI,EAmBSO,GAAA,MAAAC,EAlBuBP,EAAA0F,CAAA,CAAM,CAAC,YAAY,SAAK,CAAA,IAA9C,GAAY,OADtB/F,EAAA,GAAAI,EAmBS,UAAA;MAjBN,KAAKgH;MACN,OAAKrG,GAAA,CAAC,sMACoBV,EAAA0F,CAAA,CAAM,CAAC,YAAY,OAAO,UAAM,KAAA,IAAaqB,IAAwBjB,EAAA,QAAA,sCAAA,0DAAA,CAAA;MAM/F,OAAA;OAAA,gBAAA;OAAA1B,OAAA;OAAA,oBAAA;OAAA,cAAA;MAAA;MAMC,UAAK,MAAEqC,GAAsBC,CAAU;KAErC,GAAAvG,EAAAuG,CAAU,GAAA,IAAAhC,EAAA;;IAOrBzE,EA2BM,OA3BN0E,IA2BM,CA1BJ1E,EAkBM,OAlBN2E,IAkBM,CAfJjE,GAAAV,EAOE,YAAA;KANS,uBAAA,AAAA4G,EAAA,QAAA,MAAA,EAAW,QAAAG;KACpB,OAAM;KACL,aAAahH,EAAAqF,CAAA,CAAiB,CAAC,OAAO;KACtC,UAAUrF,EAAA0F,CAAA,CAAM,CAAC,aAAa;KAC/B,MAAK;KACJ,WAASiB;IALD,GAAA,MAAA,IAAA9B,EAAA,GAAA,CAAA,CAAAjE,IAAA+E,EAAA,KAAW,CAAA,CAAA,GAOtB1F,EAMS,UAAA;KALP,OAAM;KACL,UAAQ,CAAG0F,EAAA,MAAY,KAAI,KAAM3F,EAAA0F,CAAA,CAAM,CAAC,aAAa;KACrD,SAAOW;IAERnG,GAAAA,CAAAA,EAAqCF,EAAA4C,EAAA,GAAA;KAA9B,MAAM;KAAK,gBAAc;IAKpC3C,CAAAA,CAAAA,GAAAA,GAAAA,EAAAA,CAAAA,CAAAA,GAAAA,EAII,KAJJ8E,IAII5E,EADCH,EAAAqF,CAAA,CAAiB,CAAC,OAAO,UAAU,GAAA,CAAA,CAAA,CAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { F as e, N as t, R as n, S as r, f as i, g as a, lt as o, m as s, p as c, u as l, ut as u } from "./draggable-IB4x6w2O.js";
|
|
2
|
-
import "./useEditorCore-
|
|
2
|
+
import "./useEditorCore-DWvAia8X.js";
|
|
3
3
|
import { $ as d, t as f } from "./keys-DCWeHkSF.js";
|
|
4
|
-
import { A as p, D as m, mt as h } from "./icons-
|
|
4
|
+
import { A as p, D as m, mt as h } from "./icons-BF0mJX0V.js";
|
|
5
5
|
import { t as g } from "./_plugin-vue_export-helper-B3ysoDQm.js";
|
|
6
6
|
import { n as _ } from "./useCloudI18n-CrjWbpbu.js";
|
|
7
7
|
//#region src/cloud/components/AiFeatureMenu.vue?vue&type=script&setup=true&lang.ts
|
|
@@ -54,4 +54,4 @@ var v = { class: "tpl-ai-feature-menu tpl:w-[280px] tpl:overflow-hidden tpl:roun
|
|
|
54
54
|
//#endregion
|
|
55
55
|
export { C as default };
|
|
56
56
|
|
|
57
|
-
//# sourceMappingURL=AiFeatureMenu-
|
|
57
|
+
//# sourceMappingURL=AiFeatureMenu-BiHFJf9i.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiFeatureMenu-
|
|
1
|
+
{"version":3,"file":"AiFeatureMenu-BiHFJf9i.js","names":["_openBlock","_createElementBlock","_Fragment","_renderList","_normalizeStyle","_createElementVNode","_createBlock","_resolveDynamicComponent","_toDisplayString","_sfc_main","renderList","openBlock","resolveDynamicComponent","defineComponent","computed","createElementBlock","normalizeStyle","createBlock","createBaseVNode","Fragment","toDisplayString","requireInject","AI_CONFIG_KEY","ShieldCheck","Sparkles","ImageUp","_plugin_vue_export_helper_default","useCloudI18nStrict","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","AiFeatureMenu_default","__emit","emit","cloudT","aiConfig","configKeyMap","allFeatures","features","f","getTitle","key","getDescription","feature","__props"],"sources":["../../../src/cloud/components/AiFeatureMenu.vue","../../../src/cloud/components/AiFeatureMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useCloudI18nStrict } from \"../../composables\";\nimport { AI_CONFIG_KEY, requireInject } from \"../../keys\";\nimport type { AiConfig } from \"@templatical/types\";\nimport { ImageUp, ShieldCheck, Sparkles } from \"@lucide/vue\";\nimport { computed } from \"vue\";\n\nexport type AiFeature = \"ai-chat\" | \"design-reference\" | \"scoring\";\n\ndefineProps<{\n activeFeature: AiFeature | null;\n}>();\n\nconst emit = defineEmits<{\n (e: \"select\", feature: AiFeature): void;\n}>();\n\nconst { t: cloudT } = useCloudI18nStrict();\n\nconst aiConfig = requireInject(AI_CONFIG_KEY, \"AiFeatureMenu\");\n\nconst configKeyMap: Record<AiFeature, keyof AiConfig> = {\n \"ai-chat\": \"chat\",\n \"design-reference\": \"designToTemplate\",\n scoring: \"scoring\",\n};\n\nconst allFeatures: { key: AiFeature; icon: typeof Sparkles }[] = [\n { key: \"ai-chat\", icon: Sparkles },\n { key: \"design-reference\", icon: ImageUp },\n { key: \"scoring\", icon: ShieldCheck },\n];\n\nconst features = computed(() =>\n allFeatures.filter((f) => aiConfig.isFeatureEnabled(configKeyMap[f.key])),\n);\n\nfunction getTitle(key: AiFeature): string {\n if (key === \"ai-chat\") return cloudT.aiMenu.aiAssistant;\n if (key === \"design-reference\") return cloudT.aiMenu.designToTemplate;\n return cloudT.aiMenu.templateScore;\n}\n\nfunction getDescription(key: AiFeature): string {\n if (key === \"ai-chat\") return cloudT.aiMenu.aiAssistantDesc;\n if (key === \"design-reference\") return cloudT.aiMenu.designToTemplateDesc;\n return cloudT.aiMenu.templateScoreDesc;\n}\n</script>\n\n<template>\n <div\n class=\"tpl-ai-feature-menu tpl:w-[280px] tpl:overflow-hidden tpl:rounded-[var(--tpl-radius)] tpl:py-1 tpl:bg-[var(--tpl-bg)] tpl:border tpl:border-[var(--tpl-border)] tpl:shadow-[var(--tpl-shadow-lg)]\"\n >\n <button\n v-for=\"feature in features\"\n :key=\"feature.key\"\n class=\"tpl-ai-feature-menu-item tpl:flex tpl:w-full tpl:cursor-pointer tpl:items-start tpl:gap-3 tpl:border-none tpl:px-3 tpl:py-2.5 tpl:text-left tpl:transition-colors\"\n :style=\"{\n backgroundColor:\n activeFeature === feature.key\n ? 'var(--tpl-primary-light)'\n : 'transparent',\n }\"\n @click=\"emit('select', feature.key)\"\n >\n <div\n class=\"tpl:mt-0.5 tpl:flex tpl:size-7 tpl:shrink-0 tpl:items-center tpl:justify-center tpl:rounded-[var(--tpl-radius-sm)]\"\n :style=\"{\n backgroundColor:\n activeFeature === feature.key\n ? 'var(--tpl-primary)'\n : 'var(--tpl-bg-active)',\n color:\n activeFeature === feature.key\n ? 'var(--tpl-bg)'\n : 'var(--tpl-text-muted)',\n }\"\n >\n <component :is=\"feature.icon\" :size=\"15\" :stroke-width=\"2\" />\n </div>\n <div class=\"tpl:flex tpl:min-w-0 tpl:flex-col tpl:gap-0.5\">\n <span class=\"tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-text)]\">\n {{ getTitle(feature.key) }}\n </span>\n <span\n class=\"tpl:text-xs tpl:leading-snug tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ getDescription(feature.key) }}\n </span>\n </div>\n </button>\n </div>\n</template>\n\n<style scoped>\n.tpl-ai-feature-menu-item:hover {\n background-color: var(--tpl-bg-hover) !important;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { useCloudI18nStrict } from \"../../composables\";\nimport { AI_CONFIG_KEY, requireInject } from \"../../keys\";\nimport type { AiConfig } from \"@templatical/types\";\nimport { ImageUp, ShieldCheck, Sparkles } from \"@lucide/vue\";\nimport { computed } from \"vue\";\n\nexport type AiFeature = \"ai-chat\" | \"design-reference\" | \"scoring\";\n\ndefineProps<{\n activeFeature: AiFeature | null;\n}>();\n\nconst emit = defineEmits<{\n (e: \"select\", feature: AiFeature): void;\n}>();\n\nconst { t: cloudT } = useCloudI18nStrict();\n\nconst aiConfig = requireInject(AI_CONFIG_KEY, \"AiFeatureMenu\");\n\nconst configKeyMap: Record<AiFeature, keyof AiConfig> = {\n \"ai-chat\": \"chat\",\n \"design-reference\": \"designToTemplate\",\n scoring: \"scoring\",\n};\n\nconst allFeatures: { key: AiFeature; icon: typeof Sparkles }[] = [\n { key: \"ai-chat\", icon: Sparkles },\n { key: \"design-reference\", icon: ImageUp },\n { key: \"scoring\", icon: ShieldCheck },\n];\n\nconst features = computed(() =>\n allFeatures.filter((f) => aiConfig.isFeatureEnabled(configKeyMap[f.key])),\n);\n\nfunction getTitle(key: AiFeature): string {\n if (key === \"ai-chat\") return cloudT.aiMenu.aiAssistant;\n if (key === \"design-reference\") return cloudT.aiMenu.designToTemplate;\n return cloudT.aiMenu.templateScore;\n}\n\nfunction getDescription(key: AiFeature): string {\n if (key === \"ai-chat\") return cloudT.aiMenu.aiAssistantDesc;\n if (key === \"design-reference\") return cloudT.aiMenu.designToTemplateDesc;\n return cloudT.aiMenu.templateScoreDesc;\n}\n</script>\n\n<template>\n <div\n class=\"tpl-ai-feature-menu tpl:w-[280px] tpl:overflow-hidden tpl:rounded-[var(--tpl-radius)] tpl:py-1 tpl:bg-[var(--tpl-bg)] tpl:border tpl:border-[var(--tpl-border)] tpl:shadow-[var(--tpl-shadow-lg)]\"\n >\n <button\n v-for=\"feature in features\"\n :key=\"feature.key\"\n class=\"tpl-ai-feature-menu-item tpl:flex tpl:w-full tpl:cursor-pointer tpl:items-start tpl:gap-3 tpl:border-none tpl:px-3 tpl:py-2.5 tpl:text-left tpl:transition-colors\"\n :style=\"{\n backgroundColor:\n activeFeature === feature.key\n ? 'var(--tpl-primary-light)'\n : 'transparent',\n }\"\n @click=\"emit('select', feature.key)\"\n >\n <div\n class=\"tpl:mt-0.5 tpl:flex tpl:size-7 tpl:shrink-0 tpl:items-center tpl:justify-center tpl:rounded-[var(--tpl-radius-sm)]\"\n :style=\"{\n backgroundColor:\n activeFeature === feature.key\n ? 'var(--tpl-primary)'\n : 'var(--tpl-bg-active)',\n color:\n activeFeature === feature.key\n ? 'var(--tpl-bg)'\n : 'var(--tpl-text-muted)',\n }\"\n >\n <component :is=\"feature.icon\" :size=\"15\" :stroke-width=\"2\" />\n </div>\n <div class=\"tpl:flex tpl:min-w-0 tpl:flex-col tpl:gap-0.5\">\n <span class=\"tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-text)]\">\n {{ getTitle(feature.key) }}\n </span>\n <span\n class=\"tpl:text-xs tpl:leading-snug tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ getDescription(feature.key) }}\n </span>\n </div>\n </button>\n </div>\n</template>\n\n<style scoped>\n.tpl-ai-feature-menu-item:hover {\n background-color: var(--tpl-bg-hover) !important;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;EAaA,IAAMmC,IAAOD,GAIP,EAAE,GAAGE,MAAWT,EAAmB,GAEnCU,IAAWhB,EAAcC,GAAe,eAAe,GAEvDgB,IAAkD;GACtD,WAAW;GACX,oBAAoB;GACpB,SAAS;EACX,GAEMC,IAA2D;GAC/D;IAAE,KAAK;IAAW,MAAMf;GAAS;GACjC;IAAE,KAAK;IAAoB,MAAMC;GAAQ;GACzC;IAAE,KAAK;IAAW,MAAMF;GAAY;EACtC,GAEMiB,IAAW1B,QACfyB,EAAY,QAAQ,MAAMF,EAAS,iBAAiBC,EAAaG,EAAE,IAAI,CAAC,CAC1E;EAEA,SAASC,EAAS,GAAwB;GAGxC,OAFIC,MAAQ,YAAkBP,EAAO,OAAO,cACxCO,MAAQ,qBAA2BP,EAAO,OAAO,mBAC9CA,EAAO,OAAO;EACvB;EAEA,SAASQ,EAAe,GAAwB;GAG9C,OAFID,MAAQ,YAAkBP,EAAO,OAAO,kBACxCO,MAAQ,qBAA2BP,EAAO,OAAO,uBAC9CA,EAAO,OAAO;EACvB;oBAIEpC,EAAA,GAAAC,EAyCM,OAzCN2B,GAyCM,EAtCJ5B,EAAA,EAAA,GAAAC,EAqCSC,GAAA,MAAAC,EApCWqC,EAAA,QAAX,OADTxC,EAAA,GAAAC,EAqCS,UAAA;GAnCN,KAAK4C,EAAQ;GACd,OAAM;GACL,OAAKzC,EAAA,EAAA,iBAAuC0C,EAAA,kBAAkBD,EAAQ,MAAA,6BAAA,cAAA,CAAA;GAMtE,UAAK,MAAEV,EAAI,UAAWU,EAAQ,GAAG;EAElCxC,GAAAA,CAAAA,EAcM,OAAA;GAbJ,OAAM;GACL,OAAKD,EAAA;IAA2C,iBAAA0C,EAAA,kBAAkBD,EAAQ,MAAA,uBAAA;IAA8G,OAAAC,EAAA,kBAAkBD,EAAQ,MAAA,kBAAA;;EAWnN7C,GAAAA,EAAAA,EAAA,GAAAM,EAA6DC,EAA7CsC,EAAQ,IAAI,GAAA;GAAG,MAAM;GAAK,gBAAc;EAE1DxC,CAAAA,EAAAA,GAAAA,CAAAA,GAAAA,EASM,OATNyB,GASM,CARJzB,EAEO,QAFP0B,GAEOvB,EADFkC,EAASG,EAAQ,GAAG,CAAA,GAAA,CAAA,GAEzBxC,EAIO,QAJP2B,GAIOxB,EADFoC,EAAeC,EAAQ,GAAG,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,GAAA,IAAAhB,CAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { E as e, N as t, S as n, at as r, ct as i, f as a, g as o, h as s, m as c } from "./draggable-IB4x6w2O.js";
|
|
2
2
|
import { K as l } from "./keys-DCWeHkSF.js";
|
|
3
3
|
import { t as u } from "./useI18n-CyO_Nmca.js";
|
|
4
|
-
import { Nt as d, d as f } from "./icons-
|
|
4
|
+
import { Nt as d, d as f } from "./icons-BF0mJX0V.js";
|
|
5
5
|
//#region src/components/canvas/BlockIssueBadge.vue?vue&type=script&setup=true&lang.ts
|
|
6
6
|
var p = ["title", "aria-label"], m = /* @__PURE__ */ n({
|
|
7
7
|
__name: "BlockIssueBadge",
|
|
@@ -32,4 +32,4 @@ var p = ["title", "aria-label"], m = /* @__PURE__ */ n({
|
|
|
32
32
|
//#endregion
|
|
33
33
|
export { m as default };
|
|
34
34
|
|
|
35
|
-
//# sourceMappingURL=BlockIssueBadge-
|
|
35
|
+
//# sourceMappingURL=BlockIssueBadge-CWlcDBFm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BlockIssueBadge-
|
|
1
|
+
{"version":3,"file":"BlockIssueBadge-CWlcDBFm.js","names":["_openBlock","_createElementBlock","_normalizeClass","_createBlock","_unref","_createCommentVNode","_sfc_main","inject","openBlock","defineComponent","unref","normalizeClass","computed","createElementBlock","createCommentVNode","createBlock","TEMPLATE_LINT_KEY","useI18n","CircleAlert","TriangleAlert","_hoisted_1","BlockIssueBadge_default","props","__props","lint","blockIssues","i","severity","tooltip","t"],"sources":["../../../src/components/canvas/BlockIssueBadge.vue","../../../src/components/canvas/BlockIssueBadge.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, inject } from \"vue\";\nimport { CircleAlert, TriangleAlert } from \"@lucide/vue\";\nimport { useI18n } from \"../../composables/useI18n\";\nimport { TEMPLATE_LINT_KEY } from \"../../keys\";\n\nconst props = defineProps<{ blockId: string }>();\nconst { t } = useI18n();\nconst lint = inject(TEMPLATE_LINT_KEY, null);\n\nconst blockIssues = computed(() =>\n (lint?.issues.value ?? []).filter((i) => i.blockId === props.blockId),\n);\n\nconst severity = computed<\"error\" | \"warning\" | null>(() => {\n if (blockIssues.value.some((i) => i.severity === \"error\")) return \"error\";\n if (blockIssues.value.some((i) => i.severity === \"warning\")) return \"warning\";\n return null;\n});\n\nconst tooltip = computed(() =>\n severity.value === \"error\" ? t.issues.badgeError : t.issues.badgeWarning,\n);\n</script>\n\n<template>\n <span\n v-if=\"severity\"\n class=\"tpl:absolute tpl:top-1 tpl:right-1 tpl:z-10 tpl:flex tpl:size-5 tpl:items-center tpl:justify-center tpl:rounded-full tpl:bg-[var(--tpl-bg)] tpl:shadow-[var(--tpl-shadow-sm)] tpl:ring-1 tpl:ring-[var(--tpl-border)]\"\n :class=\"\n severity === 'error'\n ? 'tpl:text-[var(--tpl-danger)]'\n : 'tpl:text-[var(--tpl-warning)]'\n \"\n :title=\"tooltip\"\n :aria-label=\"tooltip\"\n role=\"img\"\n >\n <CircleAlert\n v-if=\"severity === 'error'\"\n :size=\"14\"\n :stroke-width=\"2.25\"\n fill=\"currentColor\"\n stroke=\"var(--tpl-bg)\"\n />\n <TriangleAlert\n v-else\n :size=\"14\"\n :stroke-width=\"2.25\"\n fill=\"currentColor\"\n stroke=\"var(--tpl-bg)\"\n />\n </span>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, inject } from \"vue\";\nimport { CircleAlert, TriangleAlert } from \"@lucide/vue\";\nimport { useI18n } from \"../../composables/useI18n\";\nimport { TEMPLATE_LINT_KEY } from \"../../keys\";\n\nconst props = defineProps<{ blockId: string }>();\nconst { t } = useI18n();\nconst lint = inject(TEMPLATE_LINT_KEY, null);\n\nconst blockIssues = computed(() =>\n (lint?.issues.value ?? []).filter((i) => i.blockId === props.blockId),\n);\n\nconst severity = computed<\"error\" | \"warning\" | null>(() => {\n if (blockIssues.value.some((i) => i.severity === \"error\")) return \"error\";\n if (blockIssues.value.some((i) => i.severity === \"warning\")) return \"warning\";\n return null;\n});\n\nconst tooltip = computed(() =>\n severity.value === \"error\" ? t.issues.badgeError : t.issues.badgeWarning,\n);\n</script>\n\n<template>\n <span\n v-if=\"severity\"\n class=\"tpl:absolute tpl:top-1 tpl:right-1 tpl:z-10 tpl:flex tpl:size-5 tpl:items-center tpl:justify-center tpl:rounded-full tpl:bg-[var(--tpl-bg)] tpl:shadow-[var(--tpl-shadow-sm)] tpl:ring-1 tpl:ring-[var(--tpl-border)]\"\n :class=\"\n severity === 'error'\n ? 'tpl:text-[var(--tpl-danger)]'\n : 'tpl:text-[var(--tpl-warning)]'\n \"\n :title=\"tooltip\"\n :aria-label=\"tooltip\"\n role=\"img\"\n >\n <CircleAlert\n v-if=\"severity === 'error'\"\n :size=\"14\"\n :stroke-width=\"2.25\"\n fill=\"currentColor\"\n stroke=\"var(--tpl-bg)\"\n />\n <TriangleAlert\n v-else\n :size=\"14\"\n :stroke-width=\"2.25\"\n fill=\"currentColor\"\n stroke=\"var(--tpl-bg)\"\n />\n </span>\n</template>\n"],"mappings":";;;;;;;;;EAMA,IAAMsB,IAAQC,GACR,EAAE,SAAMN,EAAQ,GAChBO,IAAOjB,EAAOS,GAAmB,IAAI,GAErCS,IAAcb,SACjBY,GAAM,OAAO,SAAS,CAAC,EAAA,CAAG,QAAQ,MAAME,EAAE,YAAYJ,EAAM,OAAO,CACtE,GAEMK,IAAWf,QACXa,EAAY,MAAM,MAAM,MAAMC,EAAE,aAAa,OAAO,IAAU,UAC9DD,EAAY,MAAM,MAAM,MAAMC,EAAE,aAAa,SAAS,IAAU,YAC7D,IACR,GAEKE,IAAUhB,QACde,EAAS,UAAU,UAAUE,EAAE,OAAO,aAAaA,EAAE,OAAO,YAC9D;mBAKUF,EAAA,SADR3B,EAAA,GAAAC,EA0BO,QAAA;;GAxBL,OAAKC,EAAA,CAAC,yNACSyB,EAAA,UAAQ,UAAA,iCAAA,+BAAA,CAAA;GAKtB,OAAOC,EAAA;GACP,cAAYA,EAAA;GACb,MAAK;EAGG,GAAA,CAAAD,EAAA,UAAQ,WADhB3B,EAAA,GAAAG,EAMEC,EAAAc,CAAA,GAAA;;GAJC,MAAM;GACN,gBAAc;GACf,MAAK;GACL,QAAO;EAETlB,CAAAA,MAAAA,EAAA,GAAAG,EAMEC,EAAAe,CAAA,GAAA;;GAJC,MAAM;GACN,gBAAc;GACf,MAAK;GACL,QAAO"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { n as e } from "./rolldown-runtime-B0aSnxlc.js";
|
|
2
2
|
import { E as t, F as n, L as r, N as i, P as a, R as o, S as s, at as c, f as l, g as u, lt as d, m as f, p, u as m } from "./draggable-IB4x6w2O.js";
|
|
3
3
|
import { G as h } from "./src-BR3I3gOW.js";
|
|
4
|
-
import { C as g, E as _, S as v, a as y, d as b, f as x, i as S, l as C, m as w, n as T, p as E, r as D, s as O, u as k, w as A } from "./useEditorCore-
|
|
4
|
+
import { C as g, E as _, S as v, a as y, d as b, f as x, i as S, l as C, m as w, n as T, p as E, r as D, s as O, u as k, w as A } from "./useEditorCore-DWvAia8X.js";
|
|
5
5
|
import { M as j, Q as M, f as N, g as P, s as F } from "./keys-DCWeHkSF.js";
|
|
6
|
-
import { n as I, r as L, t as R } from "./WrapperBlock-
|
|
6
|
+
import { n as I, r as L, t as R } from "./WrapperBlock-DIZHUwFn.js";
|
|
7
7
|
//#region src/components/blocks/PreviewSectionBlock.vue?vue&type=script&setup=true&lang.ts
|
|
8
8
|
var z = { class: "tpl:w-full" }, B = { class: "tpl:flex tpl:gap-0" }, V = /* @__PURE__ */ s({
|
|
9
9
|
name: "PreviewSectionBlock",
|
|
@@ -132,4 +132,4 @@ var z = { class: "tpl:w-full" }, B = { class: "tpl:flex tpl:gap-0" }, V = /* @__
|
|
|
132
132
|
//#endregion
|
|
133
133
|
export { W as n, G as t };
|
|
134
134
|
|
|
135
|
-
//# sourceMappingURL=BlockPreviewCanvas-
|
|
135
|
+
//# sourceMappingURL=BlockPreviewCanvas-CIwIA3zq.js.map
|