@templatical/editor 0.22.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/dist/{AiChatSidebar-K_AehWc-.js → AiChatSidebar-Nq-jrGaf.js} +2 -2
  2. package/dist/{AiFeatureMenu-CcqjRMFW.js → AiFeatureMenu-tg_zMKMK.js} +3 -3
  3. package/dist/{BlockIssueBadge-Dmj9rVra.js → BlockIssueBadge-Bd94kIiw.js} +2 -2
  4. package/dist/BlockPreviewCanvas-B34aMhHe.js +117 -0
  5. package/dist/{CloudEditor-BVH7D1Ka.js → CloudEditor-DjN_9Yso.js} +285 -284
  6. package/dist/{CollaboratorBar-C_1SF7Xf.js → CollaboratorBar-Bhazzcg-.js} +2 -2
  7. package/dist/{ColorPicker-s9GHXjZs.js → ColorPicker-DXGrcJxJ.js} +5 -5
  8. package/dist/{CommentsSidebar-DvNEdugN.js → CommentsSidebar-ku1kt10u.js} +3 -3
  9. package/dist/{CountdownBlock-J_Q9JRQM.js → CountdownBlock-CN9Lc23W.js} +1 -1
  10. package/dist/{CountdownToolbar-DPRcv3Fu.js → CountdownToolbar-VEsIyKV6.js} +3 -3
  11. package/dist/{DesignReferenceSidebar-DNmK3dxp.js → DesignReferenceSidebar-C4pTMzQE.js} +3 -3
  12. package/dist/{IssuesPanel-CEnEGFtd.js → IssuesPanel-CEfzOpS_.js} +2 -2
  13. package/dist/MergeTagModeToggle-C3V2xGAg.js +180 -0
  14. package/dist/{MergeTagSuggestion-D9eCryMC.js → MergeTagSuggestion-Dn8ww9nV.js} +2 -2
  15. package/dist/{NumberWithSuffix-CCPN_oCh.js → NumberWithSuffix-BGocZkj9.js} +1 -1
  16. package/dist/{ParagraphEditor-MKJYyWN9.js → ParagraphEditor-D-fz0kUb.js} +19 -19
  17. package/dist/{RichTextEditorContent-FbnWsh46.js → RichTextEditorContent-DydrqFts.js} +5 -5
  18. package/dist/{SaveBlockDialog-B_5KBaXW.js → SaveBlockDialog-BDDFbAWF.js} +100 -99
  19. package/dist/{SavedBlocksBrowserModal-DoJBoYPk.js → SavedBlocksBrowserModal-Djik_fJh.js} +6 -6
  20. package/dist/{SavedBlocksPanels-3Af5dMaf.js → SavedBlocksPanels-CxemyPxL.js} +1 -1
  21. package/dist/{SavedBlocksPickBar-C1FTJP-I.js → SavedBlocksPickBar-Dlhipmob.js} +2 -2
  22. package/dist/{SnapshotHistory-DWlQ3Eh0.js → SnapshotHistory-DPbM4ons.js} +4 -4
  23. package/dist/{TemplateScoringPanel-ifGGGWs5.js → TemplateScoringPanel-BFYgweDX.js} +2 -2
  24. package/dist/TestEmailModal-IZfwgya-.js +174 -0
  25. package/dist/TestEmailPanel-QEEx_PkN.js +33 -0
  26. package/dist/{TitleEditor-DzsPxKv4.js → TitleEditor-BB4YlIBF.js} +10 -10
  27. package/dist/{TplModal-CykwWFhF.js → TplModal-DPH4vV8M.js} +3 -3
  28. package/dist/{blockTypeIcons-CpKkI47V.js → blockTypeIcons-Wzd7W_2x.js} +1 -1
  29. package/dist/bundle-stats.json +7 -7
  30. package/dist/{ca-BBgad6y5.js → ca-CO4nq6TX.js} +22 -1
  31. package/dist/cdn/chunks/{AiChatSidebar-A1CuWGY0.js → AiChatSidebar-CN-0DIuA.js} +11 -11
  32. package/dist/cdn/chunks/{AiChatSidebar-A1CuWGY0.js.map → AiChatSidebar-CN-0DIuA.js.map} +1 -1
  33. package/dist/cdn/chunks/{AiFeatureMenu-hWgWQg11.js → AiFeatureMenu-B5pV6Iux.js} +8 -8
  34. package/dist/cdn/chunks/{AiFeatureMenu-hWgWQg11.js.map → AiFeatureMenu-B5pV6Iux.js.map} +1 -1
  35. package/dist/cdn/chunks/{BlockIssueBadge-Da4yR-mh.js → BlockIssueBadge-aanOjeyi.js} +4 -4
  36. package/dist/cdn/chunks/{BlockIssueBadge-Da4yR-mh.js.map → BlockIssueBadge-aanOjeyi.js.map} +1 -1
  37. package/dist/cdn/chunks/BlockPreviewCanvas-Dc4F4HzY.js +119 -0
  38. package/dist/cdn/chunks/BlockPreviewCanvas-Dc4F4HzY.js.map +1 -0
  39. package/dist/cdn/chunks/{CloudEditor-FCS53UcZ.js → CloudEditor-CeKaWWO5.js} +264 -263
  40. package/dist/cdn/chunks/CloudEditor-CeKaWWO5.js.map +1 -0
  41. package/dist/cdn/chunks/{CollaboratorBar-mkJVAkSh.js → CollaboratorBar-CEdKr0A2.js} +4 -4
  42. package/dist/cdn/chunks/{CollaboratorBar-mkJVAkSh.js.map → CollaboratorBar-CEdKr0A2.js.map} +1 -1
  43. package/dist/cdn/chunks/{ColorPicker-DZSzZ5ZP.js → ColorPicker-BckwEfcN.js} +7 -7
  44. package/dist/cdn/chunks/{ColorPicker-DZSzZ5ZP.js.map → ColorPicker-BckwEfcN.js.map} +1 -1
  45. package/dist/cdn/chunks/{CommentsSidebar-DHdRiGPX.js → CommentsSidebar-6PfpJKh-.js} +18 -18
  46. package/dist/cdn/chunks/{CommentsSidebar-DHdRiGPX.js.map → CommentsSidebar-6PfpJKh-.js.map} +1 -1
  47. package/dist/cdn/chunks/{CountdownBlock-Bffpoppw.js → CountdownBlock-CoBmvQKv.js} +2 -2
  48. package/dist/cdn/chunks/{CountdownBlock-Bffpoppw.js.map → CountdownBlock-CoBmvQKv.js.map} +1 -1
  49. package/dist/cdn/chunks/{CountdownToolbar-DAnmIZjq.js → CountdownToolbar-CdV8RTQu.js} +4 -4
  50. package/dist/cdn/chunks/{CountdownToolbar-DAnmIZjq.js.map → CountdownToolbar-CdV8RTQu.js.map} +1 -1
  51. package/dist/cdn/chunks/{DesignReferenceSidebar-Dre99DTH.js → DesignReferenceSidebar-BjlaP69l.js} +90 -90
  52. package/dist/cdn/chunks/{DesignReferenceSidebar-Dre99DTH.js.map → DesignReferenceSidebar-BjlaP69l.js.map} +1 -1
  53. package/dist/cdn/chunks/{IssuesPanel-D80JedOj.js → IssuesPanel-CkkEnhxZ.js} +9 -9
  54. package/dist/cdn/chunks/{IssuesPanel-D80JedOj.js.map → IssuesPanel-CkkEnhxZ.js.map} +1 -1
  55. package/dist/cdn/chunks/MergeTagModeToggle-DmtR300G.js +127 -0
  56. package/dist/cdn/chunks/MergeTagModeToggle-DmtR300G.js.map +1 -0
  57. package/dist/cdn/chunks/{MergeTagSuggestion-BM349_QH.js → MergeTagSuggestion-Cvlkw_PM.js} +2 -2
  58. package/dist/cdn/chunks/{MergeTagSuggestion-BM349_QH.js.map → MergeTagSuggestion-Cvlkw_PM.js.map} +1 -1
  59. package/dist/cdn/chunks/{NumberWithSuffix-CjlVNIEe.js → NumberWithSuffix-BOcMN26z.js} +2 -2
  60. package/dist/cdn/chunks/{NumberWithSuffix-CjlVNIEe.js.map → NumberWithSuffix-BOcMN26z.js.map} +1 -1
  61. package/dist/cdn/chunks/{ParagraphEditor-J-1RLyi7.js → ParagraphEditor-CX1yks4N.js} +35 -35
  62. package/dist/cdn/chunks/{ParagraphEditor-J-1RLyi7.js.map → ParagraphEditor-CX1yks4N.js.map} +1 -1
  63. package/dist/cdn/chunks/{RichTextEditorContent-BbdgJqWM.js → RichTextEditorContent-z9s7qxs3.js} +7 -7
  64. package/dist/cdn/chunks/{RichTextEditorContent-BbdgJqWM.js.map → RichTextEditorContent-z9s7qxs3.js.map} +1 -1
  65. package/dist/cdn/chunks/{SaveBlockDialog-CSeD3gn9.js → SaveBlockDialog-D2CtW4lC.js} +100 -99
  66. package/dist/cdn/chunks/SaveBlockDialog-D2CtW4lC.js.map +1 -0
  67. package/dist/cdn/chunks/{SavedBlocksBrowserModal-B2x5WRPN.js → SavedBlocksBrowserModal-DdUKJzzF.js} +8 -8
  68. package/dist/cdn/chunks/SavedBlocksBrowserModal-DdUKJzzF.js.map +1 -0
  69. package/dist/cdn/chunks/{SavedBlocksPanels-BzMTZxf2.js → SavedBlocksPanels-1kVbqdpc.js} +2 -2
  70. package/dist/cdn/chunks/{SavedBlocksPanels-BzMTZxf2.js.map → SavedBlocksPanels-1kVbqdpc.js.map} +1 -1
  71. package/dist/cdn/chunks/{SavedBlocksPickBar-CduR1Cpb.js → SavedBlocksPickBar--noDJIyN.js} +6 -6
  72. package/dist/cdn/chunks/{SavedBlocksPickBar-CduR1Cpb.js.map → SavedBlocksPickBar--noDJIyN.js.map} +1 -1
  73. package/dist/cdn/chunks/{SnapshotHistory-DO-gzr3i.js → SnapshotHistory-DFuNJRc9.js} +8 -8
  74. package/dist/cdn/chunks/{SnapshotHistory-DO-gzr3i.js.map → SnapshotHistory-DFuNJRc9.js.map} +1 -1
  75. package/dist/cdn/chunks/{TemplateScoringPanel-CTk8WwxU.js → TemplateScoringPanel-DG1dAjQk.js} +52 -52
  76. package/dist/cdn/chunks/{TemplateScoringPanel-CTk8WwxU.js.map → TemplateScoringPanel-DG1dAjQk.js.map} +1 -1
  77. package/dist/cdn/chunks/TestEmailModal-CiPfOn2v.js +174 -0
  78. package/dist/cdn/chunks/TestEmailModal-CiPfOn2v.js.map +1 -0
  79. package/dist/cdn/chunks/TestEmailPanel-saOfnpjz.js +35 -0
  80. package/dist/cdn/chunks/TestEmailPanel-saOfnpjz.js.map +1 -0
  81. package/dist/cdn/chunks/{TitleEditor-J1vgU_J6.js → TitleEditor-08KM_VzZ.js} +18 -18
  82. package/dist/cdn/chunks/{TitleEditor-J1vgU_J6.js.map → TitleEditor-08KM_VzZ.js.map} +1 -1
  83. package/dist/cdn/chunks/{TplModal-BN53d9Se.js → TplModal-Cu4tBBnF.js} +4 -4
  84. package/dist/cdn/chunks/{TplModal-BN53d9Se.js.map → TplModal-Cu4tBBnF.js.map} +1 -1
  85. package/dist/cdn/chunks/blockTypeIcons-DvohkXqi.js +21 -0
  86. package/dist/cdn/chunks/{blockTypeIcons-etMMQoVv.js.map → blockTypeIcons-DvohkXqi.js.map} +1 -1
  87. package/dist/cdn/chunks/{ca-BBgad6y5.js → ca-CO4nq6TX.js} +23 -2
  88. package/dist/cdn/chunks/{ca-BBgad6y5.js.map → ca-CO4nq6TX.js.map} +1 -1
  89. package/dist/cdn/chunks/{cloud-BJlbXGTJ.js → cloud-C2I0P9qj.js} +46 -42
  90. package/dist/cdn/chunks/cloud-C2I0P9qj.js.map +1 -0
  91. package/dist/{de-D7WbpFBR.js → cdn/chunks/de-CUeaFJph.js} +24 -1
  92. package/dist/cdn/chunks/{de-D7WbpFBR.js.map → de-CUeaFJph.js.map} +1 -1
  93. package/dist/{de-Bw6fB5JU.js → cdn/chunks/de-uVoSP1xF.js} +2 -9
  94. package/dist/cdn/chunks/de-uVoSP1xF.js.map +1 -0
  95. package/dist/cdn/chunks/emailFrameWidth-BmFCN2dp.js +8 -0
  96. package/dist/cdn/chunks/emailFrameWidth-BmFCN2dp.js.map +1 -0
  97. package/dist/{en-DAdHJz7h.js → cdn/chunks/en-CjhsJxb-.js} +2 -9
  98. package/dist/cdn/chunks/en-CjhsJxb-.js.map +1 -0
  99. package/dist/{en-BrZ0uGK2.js → cdn/chunks/en-zCYIPAL5.js} +24 -1
  100. package/dist/cdn/chunks/{en-BrZ0uGK2.js.map → en-zCYIPAL5.js.map} +1 -1
  101. package/dist/{es-tLSLysPs.js → cdn/chunks/es-BSiH7YkP.js} +24 -1
  102. package/dist/cdn/chunks/{es-tLSLysPs.js.map → es-BSiH7YkP.js.map} +1 -1
  103. package/dist/cdn/chunks/{extensions-C49c51P1.js → extensions-DBWF_lxx.js} +16 -16
  104. package/dist/cdn/chunks/{extensions-C49c51P1.js.map → extensions-DBWF_lxx.js.map} +1 -1
  105. package/dist/{fr-BMWOPztQ.js → cdn/chunks/fr-DTVJ3det.js} +24 -1
  106. package/dist/cdn/chunks/fr-DTVJ3det.js.map +1 -0
  107. package/dist/cdn/chunks/{icons-CYWw8Xfp.js → icons-Cqxvwgz7.js} +35 -14
  108. package/dist/cdn/chunks/icons-Cqxvwgz7.js.map +1 -0
  109. package/dist/cdn/chunks/keys-B5uoP9P7.js +12 -0
  110. package/dist/cdn/chunks/keys-B5uoP9P7.js.map +1 -0
  111. package/dist/{nl-Dhctu7JL.js → cdn/chunks/nl-BqSquFS3.js} +24 -1
  112. package/dist/cdn/chunks/nl-BqSquFS3.js.map +1 -0
  113. package/dist/cdn/chunks/{pt-BR-BWFokdTU.js → pt-BR-CMljK37h.js} +23 -2
  114. package/dist/cdn/chunks/{pt-BR-BWFokdTU.js.map → pt-BR-CMljK37h.js.map} +1 -1
  115. package/dist/{pt-BR-w2sGzHNX.js → cdn/chunks/pt-BR-CTzHTqJD.js} +2 -9
  116. package/dist/cdn/chunks/pt-BR-CTzHTqJD.js.map +1 -0
  117. package/dist/cdn/chunks/{src-BKI1x1k7.js → src-BCJna-6p.js} +183 -165
  118. package/dist/cdn/chunks/{src-BKI1x1k7.js.map → src-BCJna-6p.js.map} +1 -1
  119. package/dist/cdn/chunks/{src-MA8DWI8O.js → src-C45kfA2t.js} +17 -17
  120. package/dist/cdn/chunks/{src-MA8DWI8O.js.map → src-C45kfA2t.js.map} +1 -1
  121. package/dist/cdn/chunks/{src-ByWL5K1f.js → src-XQmI_Xs1.js} +48 -48
  122. package/dist/cdn/chunks/{src-ByWL5K1f.js.map → src-XQmI_Xs1.js.map} +1 -1
  123. package/dist/cdn/chunks/{src-CM0gCvAS.js → src-YVsPFLNJ.js} +251 -251
  124. package/dist/cdn/chunks/{src-CM0gCvAS.js.map → src-YVsPFLNJ.js.map} +1 -1
  125. package/dist/cdn/chunks/{styles-BkXzQ4-n.js → styles-BohMfIBd.js} +785 -746
  126. package/dist/cdn/chunks/styles-BohMfIBd.js.map +1 -0
  127. package/dist/cdn/chunks/{tiptap-DUTbZTeR.js → tiptap-DRKu__AX.js} +5 -5
  128. package/dist/cdn/chunks/{tiptap-DUTbZTeR.js.map → tiptap-DRKu__AX.js.map} +1 -1
  129. package/dist/cdn/chunks/{useCloudI18n-BjNENqkM.js → useCloudI18n-Bem8DUjH.js} +2 -2
  130. package/dist/cdn/chunks/{useCloudI18n-BjNENqkM.js.map → useCloudI18n-Bem8DUjH.js.map} +1 -1
  131. package/dist/cdn/chunks/{useEditorCore-CzMhD6Gd.js → useEditorCore-B_vwuKdI.js} +434 -414
  132. package/dist/cdn/chunks/useEditorCore-B_vwuKdI.js.map +1 -0
  133. package/dist/cdn/chunks/{useI18n-8Wd7G-cq.js → useI18n-graz19nI.js} +2 -2
  134. package/dist/cdn/chunks/{useI18n-8Wd7G-cq.js.map → useI18n-graz19nI.js.map} +1 -1
  135. package/dist/cdn/chunks/{useMergeTag-C7G31KV-.js → useMergeTag-rTzAFMlr.js} +4 -4
  136. package/dist/cdn/chunks/{useMergeTag-C7G31KV-.js.map → useMergeTag-rTzAFMlr.js.map} +1 -1
  137. package/dist/cdn/chunks/{usePopoverPosition-Bx0QewTv.js → usePopoverPosition-BaFxLP3w.js} +2 -2
  138. package/dist/cdn/chunks/{usePopoverPosition-Bx0QewTv.js.map → usePopoverPosition-BaFxLP3w.js.map} +1 -1
  139. package/dist/cdn/editor.css +1 -1
  140. package/dist/cdn/editor.js +172 -150
  141. package/dist/cdn/editor.js.map +1 -1
  142. package/dist/{cloud-Du7mnkz2.js → cloud-DsUct4Zq.js} +42 -40
  143. package/dist/{cdn/chunks/de-D7WbpFBR.js → de-CUeaFJph.js} +22 -3
  144. package/dist/{cdn/chunks/de-Bw6fB5JU.js → de-uVoSP1xF.js} +0 -11
  145. package/dist/{dist-CL_CfQ3Q.js → dist-9uhI32Q4.js} +2 -2
  146. package/dist/{dist-3DHaYEiT.js → dist-BAkGuPYm.js} +2 -2
  147. package/dist/dist-BIYm-U9x.js +5 -0
  148. package/dist/{dist-3HenmYIg.js → dist-ByJVlKWy.js} +1 -1
  149. package/dist/{dist-DKWoZJAV.js → dist-C5tigvDF.js} +2 -2
  150. package/dist/{dist-bivrM-nS.js → dist-CQiAZlTt.js} +2 -2
  151. package/dist/{dist-Ih7ejWzn.js → dist-C_kAE1sC.js} +2 -2
  152. package/dist/{dist-CclnU_v0.js → dist-CkCVlKj_.js} +2 -2
  153. package/dist/{dist-B_etKYyh.js → dist-DFO896yT.js} +5 -5
  154. package/dist/{dist-BJbqgyPn.js → dist-DPHqs0Yh.js} +105 -87
  155. package/dist/{dist-DOtLGnLr.js → dist-DWu9QWFl.js} +2 -2
  156. package/dist/{dist-BCnJcAQc.js → dist-IGetXrbO.js} +2 -2
  157. package/dist/dist-JXOq1hib.js +5 -0
  158. package/dist/emailFrameWidth-BmFCN2dp.js +6 -0
  159. package/dist/{cdn/chunks/en-DAdHJz7h.js → en-CjhsJxb-.js} +0 -11
  160. package/dist/{cdn/chunks/en-BrZ0uGK2.js → en-zCYIPAL5.js} +22 -3
  161. package/dist/{cdn/chunks/es-tLSLysPs.js → es-BSiH7YkP.js} +22 -3
  162. package/dist/{extensions-3870a_3R.js → extensions-C0DXnYdA.js} +13 -13
  163. package/dist/{cdn/chunks/fr-BMWOPztQ.js → fr-DTVJ3det.js} +22 -3
  164. package/dist/index.d.ts +74 -0
  165. package/dist/keys-BVlG5Ozc.js +10 -0
  166. package/dist/{cdn/chunks/nl-Dhctu7JL.js → nl-BqSquFS3.js} +22 -3
  167. package/dist/{pt-BR-BWFokdTU.js → pt-BR-CMljK37h.js} +22 -1
  168. package/dist/{cdn/chunks/pt-BR-w2sGzHNX.js → pt-BR-CTzHTqJD.js} +0 -11
  169. package/dist/style.css +1 -1
  170. package/dist/{styles-AxBd7CgB.js → styles-BTTD0Je4.js} +941 -935
  171. package/dist/templatical-editor.js +112 -89
  172. package/dist/{useCloudI18n-BmiygEM4.js → useCloudI18n-DGr3b2SX.js} +1 -1
  173. package/dist/{useEditorCore-CuMMIfiS.js → useEditorCore-DOrGex_t.js} +917 -897
  174. package/dist/{useI18n-D2L9Mkik.js → useI18n-BhAejA-x.js} +1 -1
  175. package/dist/{useMergeTag-BTdDq5DC.js → useMergeTag-Ce95YIOO.js} +3 -3
  176. package/dist/{usePopoverPosition-BO2LNy5n.js → usePopoverPosition-vjKJaqJf.js} +1 -1
  177. package/package.json +20 -20
  178. package/dist/SavedBlockPreviewCanvas-DXkGDYph.js +0 -109
  179. package/dist/TestEmailModal-DComAFpR.js +0 -95
  180. package/dist/cdn/chunks/CloudEditor-FCS53UcZ.js.map +0 -1
  181. package/dist/cdn/chunks/SaveBlockDialog-CSeD3gn9.js.map +0 -1
  182. package/dist/cdn/chunks/SavedBlockPreviewCanvas-DgLOKtR_.js +0 -111
  183. package/dist/cdn/chunks/SavedBlockPreviewCanvas-DgLOKtR_.js.map +0 -1
  184. package/dist/cdn/chunks/SavedBlocksBrowserModal-B2x5WRPN.js.map +0 -1
  185. package/dist/cdn/chunks/TestEmailModal-DT37w7i_.js +0 -96
  186. package/dist/cdn/chunks/TestEmailModal-DT37w7i_.js.map +0 -1
  187. package/dist/cdn/chunks/blockTypeIcons-etMMQoVv.js +0 -21
  188. package/dist/cdn/chunks/cloud-BJlbXGTJ.js.map +0 -1
  189. package/dist/cdn/chunks/de-Bw6fB5JU.js.map +0 -1
  190. package/dist/cdn/chunks/en-DAdHJz7h.js.map +0 -1
  191. package/dist/cdn/chunks/fr-BMWOPztQ.js.map +0 -1
  192. package/dist/cdn/chunks/icons-CYWw8Xfp.js.map +0 -1
  193. package/dist/cdn/chunks/keys-D7kUmfpE.js +0 -12
  194. package/dist/cdn/chunks/keys-D7kUmfpE.js.map +0 -1
  195. package/dist/cdn/chunks/nl-Dhctu7JL.js.map +0 -1
  196. package/dist/cdn/chunks/pt-BR-w2sGzHNX.js.map +0 -1
  197. package/dist/cdn/chunks/styles-BkXzQ4-n.js.map +0 -1
  198. package/dist/cdn/chunks/useEditorCore-CzMhD6Gd.js.map +0 -1
  199. package/dist/dist-CcQLJeWV.js +0 -5
  200. package/dist/dist-DerdmERj.js +0 -5
  201. package/dist/keys-CHPcp-Nz.js +0 -10
@@ -1,9 +1,9 @@
1
- import { L as e, M as t, P as n, T as r, V as ee, Z as i, ct as a, g as o, h as s, it as c, m as l, n as u, ot as te, p as d, st as f, u as p, v as m, x as h, y as g, z as ne } from "./draggable-D840DIZB.js";
2
- import { B as _, F as v, T as y, h as b } from "./keys-D7kUmfpE.js";
3
- import { At as x, D as re, O as S, Pt as ie, R as C, St as ae, n as oe, rt as se, t as ce, u as le, ut as ue, w } from "./icons-CYWw8Xfp.js";
1
+ import { L as e, M as t, P as n, T as r, V as ee, Z as i, ct as a, g as o, h as s, it as c, m as l, n as te, ot as ne, p as u, st as d, u as f, v as p, x as m, y as h, z as re } from "./draggable-D840DIZB.js";
2
+ import { H as g, I as _, T as v, h as y } from "./keys-B5uoP9P7.js";
3
+ import { Ct as b, Ft as ie, O as ae, T as x, dt as oe, it as se, jt as S, k as C, n as ce, t as le, u as ue, z as w } from "./icons-Cqxvwgz7.js";
4
4
  import { t as T } from "./LoadingTrack-D-CW2tUa.js";
5
5
  import { t as E } from "./_plugin-vue_export-helper-B3ysoDQm.js";
6
- import { n as D } from "./useCloudI18n-BjNENqkM.js";
6
+ import { n as D } from "./useCloudI18n-Bem8DUjH.js";
7
7
  //#region src/cloud/utils/scoringStyles.ts
8
8
  function O(e) {
9
9
  return e >= 80 ? "var(--tpl-success)" : e >= 60 ? "var(--tpl-warning)" : "var(--tpl-danger)";
@@ -58,12 +58,12 @@ var M = {
58
58
  }, Ee = {
59
59
  key: 3,
60
60
  class: "tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center"
61
- }, De = { class: "tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]" }, Oe = { class: "tpl:m-0 tpl:px-4 tpl:pb-2 tpl:pt-2 tpl:text-center tpl:text-[11px] tpl:text-[var(--tpl-text-dim)]" }, W = /*#__PURE__*/ E(/* @__PURE__ */ h({
61
+ }, De = { class: "tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]" }, Oe = { class: "tpl:m-0 tpl:px-4 tpl:pb-2 tpl:pt-2 tpl:text-center tpl:text-[11px] tpl:text-[var(--tpl-text-dim)]" }, W = /*#__PURE__*/ E(/* @__PURE__ */ m({
62
62
  __name: "TemplateScoringPanel",
63
63
  props: { visible: { type: Boolean } },
64
64
  emits: ["close"],
65
- setup(h, { emit: E }) {
66
- let W = h, G = E, { t: K } = D(), q = _(b, "TemplateScoringPanel"), J = _(v, "TemplateScoringPanel"), Y = r(y, []), X = i({
65
+ setup(m, { emit: E }) {
66
+ let W = m, G = E, { t: K } = D(), q = g(y, "TemplateScoringPanel"), J = g(_, "TemplateScoringPanel"), Y = r(v, []), X = i({
67
67
  spam: !0,
68
68
  readability: !0,
69
69
  accessibility: !0,
@@ -78,15 +78,15 @@ var M = {
78
78
  "accessibility",
79
79
  "bestPractices"
80
80
  ], Ae = {
81
- spam: re,
82
- readability: ae,
83
- accessibility: w,
84
- bestPractices: ce
81
+ spam: ae,
82
+ readability: b,
83
+ accessibility: x,
84
+ bestPractices: le
85
85
  };
86
86
  function Q() {
87
87
  J.score(q.content.value, Y);
88
88
  }
89
- ne(() => W.visible, (e) => {
89
+ re(() => W.visible, (e) => {
90
90
  e && !J.scoringResult.value && !J.isScoring.value && Q();
91
91
  });
92
92
  async function je(e) {
@@ -101,7 +101,7 @@ var M = {
101
101
  function $() {
102
102
  return J.scoringResult.value ? Z.reduce((e, t) => e + (J.scoringResult.value?.categories[t]?.findings.length ?? 0), 0) : 0;
103
103
  }
104
- return (r, i) => (t(), l(u, {
104
+ return (r, i) => (t(), l(te, {
105
105
  "enter-active-class": "tpl-scoring-slide-enter-active",
106
106
  "enter-from-class": "tpl:translate-x-full",
107
107
  "enter-to-class": "tpl:translate-x-0",
@@ -109,98 +109,98 @@ var M = {
109
109
  "leave-from-class": "tpl:translate-x-0",
110
110
  "leave-to-class": "tpl:translate-x-full"
111
111
  }, {
112
- default: ee(() => [h.visible ? (t(), o("div", M, [d("div", N, [d("div", P, [g(c(S), {
112
+ default: ee(() => [m.visible ? (t(), o("div", M, [u("div", N, [u("div", P, [h(c(C), {
113
113
  size: 13,
114
114
  "stroke-width": 2
115
- }), d("span", null, a(c(K).scoring.title), 1)]), d("div", F, [c(J).scoringResult.value && !c(J).isScoring.value ? (t(), o("button", {
115
+ }), u("span", null, a(c(K).scoring.title), 1)]), u("div", F, [c(J).scoringResult.value && !c(J).isScoring.value ? (t(), o("button", {
116
116
  key: 0,
117
117
  class: "tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:duration-150 tpl:text-[var(--tpl-text-muted)]",
118
118
  title: c(K).scoring.rescore,
119
119
  onClick: i[0] ||= (e) => Q()
120
- }, [g(c(C), {
120
+ }, [h(c(w), {
121
121
  size: 14,
122
122
  "stroke-width": 2
123
- })], 8, I)) : s("", !0), d("button", {
123
+ })], 8, I)) : s("", !0), u("button", {
124
124
  class: "tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:duration-150 tpl:text-[var(--tpl-text-muted)]",
125
125
  onClick: i[1] ||= (e) => G("close")
126
- }, [g(c(oe), {
126
+ }, [h(c(ce), {
127
127
  size: 14,
128
128
  "stroke-width": 2
129
- })])])]), d("div", L, [c(J).isScoring.value ? (t(), o("div", R, [d("p", z, a(c(K).scoring.scoring), 1), g(T, { class: "tpl:w-3/4" })])) : c(J).error.value && !c(J).scoringResult.value ? (t(), o("div", B, [
130
- g(c(x), {
129
+ })])])]), u("div", L, [c(J).isScoring.value ? (t(), o("div", R, [u("p", z, a(c(K).scoring.scoring), 1), h(T, { class: "tpl:w-3/4" })])) : c(J).error.value && !c(J).scoringResult.value ? (t(), o("div", B, [
130
+ h(c(S), {
131
131
  size: 32,
132
132
  "stroke-width": 1.5,
133
133
  class: "tpl:text-[var(--tpl-danger)]"
134
134
  }),
135
- d("p", V, a(c(K).scoring.error), 1),
136
- d("button", {
135
+ u("p", V, a(c(K).scoring.error), 1),
136
+ u("button", {
137
137
  class: "tpl:mt-2 tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-md tpl:border tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:transition-all tpl:duration-150 tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-text-muted)]",
138
138
  onClick: i[2] ||= (e) => Q()
139
- }, [g(c(C), {
139
+ }, [h(c(w), {
140
140
  size: 12,
141
141
  "stroke-width": 2
142
- }), m(" " + a(c(K).scoring.rescore), 1)])
142
+ }), p(" " + a(c(K).scoring.rescore), 1)])
143
143
  ])) : c(J).scoringResult.value ? (t(), o("div", H, [
144
- d("div", {
144
+ u("div", {
145
145
  class: "tpl:flex tpl:flex-col tpl:items-center tpl:gap-2 tpl:rounded-[var(--tpl-radius)] tpl:p-5",
146
- style: f({ backgroundColor: c(k)(c(J).scoringResult.value.score) })
146
+ style: d({ backgroundColor: c(k)(c(J).scoringResult.value.score) })
147
147
  }, [
148
- d("span", {
148
+ u("span", {
149
149
  class: "tpl:text-4xl tpl:font-bold tpl:tabular-nums",
150
- style: f({ color: c(O)(c(J).scoringResult.value.score) })
150
+ style: d({ color: c(O)(c(J).scoringResult.value.score) })
151
151
  }, a(c(J).scoringResult.value.score), 5),
152
- d("span", U, a(c(K).scoring.overallScore), 1),
152
+ u("span", U, a(c(K).scoring.overallScore), 1),
153
153
  $() > 0 ? (t(), o("span", de, a($()) + " " + a(c(K).scoring.findings), 1)) : s("", !0)
154
154
  ], 4),
155
- c(J).fixError.value ? (t(), o("div", fe, [g(c(x), {
155
+ c(J).fixError.value ? (t(), o("div", fe, [h(c(S), {
156
156
  size: 14,
157
157
  "stroke-width": 2,
158
158
  class: "tpl:mt-0.5 tpl:shrink-0"
159
- }), d("span", null, a(c(K).scoring.fixError), 1)])) : s("", !0),
160
- (t(), o(p, null, n(Z, (r) => d("div", {
159
+ }), u("span", null, a(c(K).scoring.fixError), 1)])) : s("", !0),
160
+ (t(), o(f, null, n(Z, (r) => u("div", {
161
161
  key: r,
162
162
  class: "tpl:overflow-hidden tpl:rounded-[var(--tpl-radius)] tpl:border tpl:border-[var(--tpl-border)]"
163
- }, [d("button", {
163
+ }, [u("button", {
164
164
  class: "tpl:flex tpl:w-full tpl:cursor-pointer tpl:items-center tpl:gap-2.5 tpl:px-3 tpl:py-2.5 tpl:text-left tpl:transition-colors tpl:duration-100 tpl:bg-[var(--tpl-bg)]",
165
165
  onClick: (e) => ke(r)
166
166
  }, [
167
167
  (t(), l(e(Ae[r]), {
168
168
  size: 14,
169
169
  "stroke-width": 2,
170
- style: f({ color: c(O)(c(J).scoringResult.value.categories[r].score) })
170
+ style: d({ color: c(O)(c(J).scoringResult.value.categories[r].score) })
171
171
  }, null, 8, ["style"])),
172
- d("span", me, a(c(K).scoring.categories[r]), 1),
173
- d("span", {
172
+ u("span", me, a(c(K).scoring.categories[r]), 1),
173
+ u("span", {
174
174
  class: "tpl:rounded-full tpl:px-2 tpl:py-0.5 tpl:text-xs tpl:font-semibold tpl:tabular-nums",
175
- style: f({
175
+ style: d({
176
176
  color: c(O)(c(J).scoringResult.value.categories[r].score),
177
177
  backgroundColor: c(k)(c(J).scoringResult.value.categories[r].score)
178
178
  })
179
179
  }, a(c(J).scoringResult.value.categories[r].score), 5),
180
180
  c(J).scoringResult.value.categories[r].findings.length > 0 ? (t(), o("span", he, a(c(J).scoringResult.value.categories[r].findings.length), 1)) : s("", !0),
181
- g(c(ie), {
181
+ h(c(ie), {
182
182
  size: 12,
183
183
  "stroke-width": 2,
184
- class: te(["tpl:transition-transform tpl:duration-200 tpl:text-[var(--tpl-text-dim)]", X.value[r] ? "tpl:rotate-0" : "tpl:-rotate-90"])
184
+ class: ne(["tpl:transition-transform tpl:duration-200 tpl:text-[var(--tpl-text-dim)]", X.value[r] ? "tpl:rotate-0" : "tpl:-rotate-90"])
185
185
  }, null, 8, ["class"])
186
- ], 8, pe), X.value[r] ? (t(), o("div", ge, [c(J).scoringResult.value.categories[r].findings.length === 0 ? (t(), o("div", _e, a(c(K).scoring.noFindings), 1)) : s("", !0), (t(!0), o(p, null, n(c(J).scoringResult.value.categories[r].findings, (n) => (t(), o("div", {
186
+ ], 8, pe), X.value[r] ? (t(), o("div", ge, [c(J).scoringResult.value.categories[r].findings.length === 0 ? (t(), o("div", _e, a(c(K).scoring.noFindings), 1)) : s("", !0), (t(!0), o(f, null, n(c(J).scoringResult.value.categories[r].findings, (n) => (t(), o("div", {
187
187
  key: n.id,
188
188
  class: "tpl:border-t tpl:px-3 tpl:py-2.5 first:tpl:border-t-0 tpl:border-[var(--tpl-border-light)]"
189
- }, [d("div", ve, [(t(), l(e(c(n.severity === "high" ? x : n.severity === "medium" ? le : ue)), {
189
+ }, [u("div", ve, [(t(), l(e(c(n.severity === "high" ? S : n.severity === "medium" ? ue : oe)), {
190
190
  size: 13,
191
191
  "stroke-width": 2,
192
192
  class: "tpl:mt-0.5 tpl:shrink-0",
193
- style: f({ color: c(A)(n.severity) })
194
- }, null, 8, ["style"])), d("div", ye, [
195
- d("div", be, [d("span", {
193
+ style: d({ color: c(A)(n.severity) })
194
+ }, null, 8, ["style"])), u("div", ye, [
195
+ u("div", be, [u("span", {
196
196
  class: "tpl:mt-0.5 tpl:shrink-0 tpl:rounded tpl:px-1 tpl:py-px tpl:text-[10px] tpl:font-medium tpl:leading-tight",
197
- style: f({
197
+ style: d({
198
198
  color: c(A)(n.severity),
199
199
  backgroundColor: c(j)(n.severity)
200
200
  })
201
- }, a(c(K).scoring.severity[n.severity]), 5), d("span", xe, a(n.message), 1)]),
201
+ }, a(c(K).scoring.severity[n.severity]), 5), u("span", xe, a(n.message), 1)]),
202
202
  n.suggestion ? (t(), o("p", Se, a(n.suggestion), 1)) : s("", !0),
203
- n.blockId ? (t(), o("div", Ce, [d("button", {
203
+ n.blockId ? (t(), o("div", Ce, [u("button", {
204
204
  class: "tpl-scoring-fix-btn tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded tpl:border tpl:px-3 tpl:py-1.5 tpl:text-[11px] tpl:font-medium tpl:transition-all tpl:duration-150 tpl:disabled:opacity-50 tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-primary)]",
205
205
  style: { "background-color": "transparent" },
206
206
  disabled: c(J).fixingFindingId.value !== null,
@@ -210,17 +210,17 @@ var M = {
210
210
  class: "tpl-spinner",
211
211
  size: 11,
212
212
  "stroke-width": 2
213
- })) : (t(), l(c(w), {
213
+ })) : (t(), l(c(x), {
214
214
  key: 1,
215
215
  size: 11,
216
216
  "stroke-width": 2
217
- })), m(" " + a(c(J).fixingFindingId.value === n.id ? c(K).scoring.fixing : c(K).scoring.fix), 1)], 8, we), c(J).fixError.value ? (t(), o("p", Te, a(c(J).fixError.value), 1)) : s("", !0)])) : s("", !0)
217
+ })), p(" " + a(c(J).fixingFindingId.value === n.id ? c(K).scoring.fixing : c(K).scoring.fix), 1)], 8, we), c(J).fixError.value ? (t(), o("p", Te, a(c(J).fixError.value), 1)) : s("", !0)])) : s("", !0)
218
218
  ])])]))), 128))])) : s("", !0)])), 64))
219
- ])) : (t(), o("div", Ee, [g(c(S), {
219
+ ])) : (t(), o("div", Ee, [h(c(C), {
220
220
  size: 32,
221
221
  "stroke-width": 1.5,
222
222
  class: "tpl:text-[var(--tpl-text-dim)]"
223
- }), d("p", De, a(c(K).scoring.emptyState), 1)])), d("p", Oe, a(c(K).aiMenu.disclaimer), 1)])])) : s("", !0)]),
223
+ }), u("p", De, a(c(K).scoring.emptyState), 1)])), u("p", Oe, a(c(K).aiMenu.disclaimer), 1)])])) : s("", !0)]),
224
224
  _: 1
225
225
  }));
226
226
  }
@@ -228,4 +228,4 @@ var M = {
228
228
  //#endregion
229
229
  export { W as default };
230
230
 
231
- //# sourceMappingURL=TemplateScoringPanel-CTk8WwxU.js.map
231
+ //# sourceMappingURL=TemplateScoringPanel-DG1dAjQk.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TemplateScoringPanel-CTk8WwxU.js","names":[],"sources":["../../../src/cloud/utils/scoringStyles.ts","../../../src/cloud/components/TemplateScoringPanel.vue","../../../src/cloud/components/TemplateScoringPanel.vue"],"sourcesContent":["export type ScoringSeverity = \"high\" | \"medium\" | \"low\" | string;\n\nexport function scoreColor(score: number): string {\n if (score >= 80) return \"var(--tpl-success)\";\n if (score >= 60) return \"var(--tpl-warning)\";\n return \"var(--tpl-danger)\";\n}\n\nexport function scoreBgColor(score: number): string {\n if (score >= 80) return \"var(--tpl-success-light)\";\n if (score >= 60) return \"var(--tpl-warning-light)\";\n return \"var(--tpl-danger-light)\";\n}\n\nexport function severityColor(severity: ScoringSeverity): string {\n if (severity === \"high\") return \"var(--tpl-danger)\";\n if (severity === \"medium\") return \"var(--tpl-warning)\";\n return \"var(--tpl-text-muted)\";\n}\n\nexport function severityBgColor(severity: ScoringSeverity): string {\n if (severity === \"high\") return \"var(--tpl-danger-light)\";\n if (severity === \"medium\") return \"var(--tpl-warning-light)\";\n return \"var(--tpl-bg-hover)\";\n}\n","<script setup lang=\"ts\">\nimport LoadingTrack from \"../../components/LoadingTrack.vue\";\nimport {\n EDITOR_KEY,\n SCORING_KEY,\n MERGE_TAGS_KEY,\n requireInject,\n} from \"../../keys\";\nimport {\n scoreColor,\n scoreBgColor,\n severityColor,\n severityBgColor,\n} from \"../utils/scoringStyles\";\nimport { useCloudI18nStrict } from \"../../composables/useCloudI18n\";\nimport type { ScoringCategory, ScoringFinding } from \"@templatical/types\";\nimport {\n CircleAlert,\n TriangleAlert,\n ChevronDown,\n Eye,\n Info,\n LoaderCircle,\n RefreshCw,\n ShieldCheck,\n ShieldX,\n Sparkles,\n X,\n Zap,\n} from \"@lucide/vue\";\nimport { inject, ref, watch } from \"vue\";\n\nconst props = defineProps<{\n visible: boolean;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n}>();\n\nconst { t: cloudT } = useCloudI18nStrict();\nconst editor = requireInject(EDITOR_KEY, \"TemplateScoringPanel\");\nconst scoring = requireInject(SCORING_KEY, \"TemplateScoringPanel\");\nconst mergeTags = inject(MERGE_TAGS_KEY, []);\n\nconst expandedCategories = ref<Record<string, boolean>>({\n spam: true,\n readability: true,\n accessibility: true,\n bestPractices: true,\n});\n\nfunction toggleCategory(category: string): void {\n expandedCategories.value[category] = !expandedCategories.value[category];\n}\n\nconst categoryOrder: ScoringCategory[] = [\n \"spam\",\n \"readability\",\n \"accessibility\",\n \"bestPractices\",\n];\n\nconst categoryIcons: Record<ScoringCategory, typeof ShieldCheck> = {\n spam: ShieldX,\n readability: Eye,\n accessibility: Sparkles,\n bestPractices: Zap,\n};\n\nfunction triggerScore(): void {\n scoring.score(editor.content.value, mergeTags);\n}\n\nwatch(\n () => props.visible,\n (isVisible) => {\n if (isVisible && !scoring.scoringResult.value && !scoring.isScoring.value) {\n triggerScore();\n }\n },\n);\n\nasync function handleFix(finding: ScoringFinding): Promise<void> {\n if (!finding.blockId) {\n return;\n }\n\n // Get the block content from the editor\n const block = editor.content.value.blocks.find(\n (b) => b.id === finding.blockId,\n );\n if (!block) {\n return;\n }\n\n // Extract HTML content from the block (text blocks have content property)\n const blockContent = (block as unknown as Record<string, unknown>).content as\n string | undefined;\n if (!blockContent) {\n return;\n }\n\n const fixedContent = await scoring.fixFinding(\n blockContent,\n finding,\n mergeTags,\n );\n\n if (fixedContent) {\n editor.updateBlock(finding.blockId, { content: fixedContent });\n scoring.removeFinding(finding.category, finding.id);\n }\n}\n\nfunction totalFindings(): number {\n if (!scoring.scoringResult.value) {\n return 0;\n }\n return categoryOrder.reduce((sum, cat) => {\n return (\n sum + (scoring.scoringResult.value?.categories[cat]?.findings.length ?? 0)\n );\n }, 0);\n}\n</script>\n\n<template>\n <Transition\n enter-active-class=\"tpl-scoring-slide-enter-active\"\n enter-from-class=\"tpl:translate-x-full\"\n enter-to-class=\"tpl:translate-x-0\"\n leave-active-class=\"tpl-scoring-slide-leave-active\"\n leave-from-class=\"tpl:translate-x-0\"\n leave-to-class=\"tpl:translate-x-full\"\n >\n <div\n v-if=\"visible\"\n class=\"tpl-scoring-panel tpl:absolute tpl:top-14 tpl:right-0 tpl:bottom-0 tpl:z-panel tpl:flex tpl:w-[360px] tpl:flex-col tpl:border-l tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg-elevated)]\"\n >\n <!-- Header -->\n <div\n class=\"tpl:flex tpl:items-center tpl:justify-between tpl:border-b tpl:border-[var(--tpl-border)] tpl:px-4 tpl:py-3\"\n >\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-primary)]\"\n >\n <ShieldCheck :size=\"13\" :stroke-width=\"2\" />\n <span>{{ cloudT.scoring.title }}</span>\n </div>\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <button\n v-if=\"scoring.scoringResult.value && !scoring.isScoring.value\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:duration-150 tpl:text-[var(--tpl-text-muted)]\"\n :title=\"cloudT.scoring.rescore\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"14\" :stroke-width=\"2\" />\n </button>\n <button\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:duration-150 tpl:text-[var(--tpl-text-muted)]\"\n @click=\"emit('close')\"\n >\n <X :size=\"14\" :stroke-width=\"2\" />\n </button>\n </div>\n </div>\n\n <!-- Content -->\n <div class=\"tpl:flex-1 tpl:overflow-y-auto tpl:p-4\">\n <!-- Loading state -->\n <div\n v-if=\"scoring.isScoring.value\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <p class=\"tpl:text-sm tpl:text-[var(--tpl-text-muted)]\">\n {{ cloudT.scoring.scoring }}\n </p>\n <LoadingTrack class=\"tpl:w-3/4\" />\n </div>\n\n <!-- Error state -->\n <div\n v-else-if=\"scoring.error.value && !scoring.scoringResult.value\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <CircleAlert\n :size=\"32\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-danger)]\"\n />\n <p\n class=\"tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.error }}\n </p>\n <button\n class=\"tpl:mt-2 tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-md tpl:border tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:transition-all tpl:duration-150 tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-text-muted)]\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"12\" :stroke-width=\"2\" />\n {{ cloudT.scoring.rescore }}\n </button>\n </div>\n\n <!-- Results -->\n <div\n v-else-if=\"scoring.scoringResult.value\"\n class=\"tpl:flex tpl:flex-col tpl:gap-4\"\n >\n <!-- Overall score -->\n <div\n class=\"tpl:flex tpl:flex-col tpl:items-center tpl:gap-2 tpl:rounded-[var(--tpl-radius)] tpl:p-5\"\n :style=\"{\n backgroundColor: scoreBgColor(scoring.scoringResult.value.score),\n }\"\n >\n <span\n class=\"tpl:text-4xl tpl:font-bold tpl:tabular-nums\"\n :style=\"{\n color: scoreColor(scoring.scoringResult.value.score),\n }\"\n >\n {{ scoring.scoringResult.value.score }}\n </span>\n <span\n class=\"tpl:text-xs tpl:font-medium tpl:uppercase tpl:tracking-wider tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.overallScore }}\n </span>\n <span\n v-if=\"totalFindings() > 0\"\n class=\"tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ totalFindings() }}\n {{ cloudT.scoring.findings }}\n </span>\n </div>\n\n <!-- Fix error -->\n <div\n v-if=\"scoring.fixError.value\"\n class=\"tpl:flex tpl:items-start tpl:gap-2 tpl:rounded-lg tpl:px-3 tpl:py-2 tpl:text-xs tpl:bg-[var(--tpl-danger-light)] tpl:text-[var(--tpl-danger)]\"\n >\n <CircleAlert\n :size=\"14\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n />\n <span>{{ cloudT.scoring.fixError }}</span>\n </div>\n\n <!-- Category cards -->\n <div\n v-for=\"category in categoryOrder\"\n :key=\"category\"\n class=\"tpl:overflow-hidden tpl:rounded-[var(--tpl-radius)] tpl:border tpl:border-[var(--tpl-border)]\"\n >\n <!-- Category header -->\n <button\n class=\"tpl:flex tpl:w-full tpl:cursor-pointer tpl:items-center tpl:gap-2.5 tpl:px-3 tpl:py-2.5 tpl:text-left tpl:transition-colors tpl:duration-100 tpl:bg-[var(--tpl-bg)]\"\n @click=\"toggleCategory(category)\"\n >\n <component\n :is=\"categoryIcons[category]\"\n :size=\"14\"\n :stroke-width=\"2\"\n :style=\"{\n color: scoreColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n }\"\n />\n <span\n class=\"tpl:flex-1 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)]\"\n >\n {{ cloudT.scoring.categories[category] }}\n </span>\n <span\n class=\"tpl:rounded-full tpl:px-2 tpl:py-0.5 tpl:text-xs tpl:font-semibold tpl:tabular-nums\"\n :style=\"{\n color: scoreColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n backgroundColor: scoreBgColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n }\"\n >\n {{ scoring.scoringResult.value.categories[category].score }}\n </span>\n <span\n v-if=\"\n scoring.scoringResult.value.categories[category].findings\n .length > 0\n \"\n class=\"tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{\n scoring.scoringResult.value.categories[category].findings\n .length\n }}\n </span>\n <ChevronDown\n :size=\"12\"\n :stroke-width=\"2\"\n class=\"tpl:transition-transform tpl:duration-200 tpl:text-[var(--tpl-text-dim)]\"\n :class=\"\n expandedCategories[category]\n ? 'tpl:rotate-0'\n : 'tpl:-rotate-90'\n \"\n />\n </button>\n\n <!-- Findings list -->\n <div\n v-if=\"expandedCategories[category]\"\n class=\"tpl:border-t tpl:border-[var(--tpl-border)]\"\n >\n <div\n v-if=\"\n scoring.scoringResult.value.categories[category].findings\n .length === 0\n \"\n class=\"tpl:px-3 tpl:py-3 tpl:text-center tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.scoring.noFindings }}\n </div>\n <div\n v-for=\"finding in scoring.scoringResult.value.categories[\n category\n ].findings\"\n :key=\"finding.id\"\n class=\"tpl:border-t tpl:px-3 tpl:py-2.5 first:tpl:border-t-0 tpl:border-[var(--tpl-border-light)]\"\n >\n <div class=\"tpl:flex tpl:items-start tpl:gap-2\">\n <!-- Severity icon -->\n <component\n :is=\"\n finding.severity === 'high'\n ? CircleAlert\n : finding.severity === 'medium'\n ? TriangleAlert\n : Info\n \"\n :size=\"13\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n :style=\"{\n color: severityColor(finding.severity),\n }\"\n />\n <div class=\"tpl:flex-1 tpl:min-w-0\">\n <!-- Severity badge + message -->\n <div class=\"tpl:flex tpl:items-start tpl:gap-1.5\">\n <span\n class=\"tpl:mt-0.5 tpl:shrink-0 tpl:rounded tpl:px-1 tpl:py-px tpl:text-[10px] tpl:font-medium tpl:leading-tight\"\n :style=\"{\n color: severityColor(finding.severity),\n backgroundColor: severityBgColor(finding.severity),\n }\"\n >\n {{ cloudT.scoring.severity[finding.severity] }}\n </span>\n <span\n class=\"tpl:text-xs tpl:leading-snug tpl:text-[var(--tpl-text)]\"\n >\n {{ finding.message }}\n </span>\n </div>\n <!-- Suggestion -->\n <p\n v-if=\"finding.suggestion\"\n class=\"tpl:mt-1 tpl:text-[11px] tpl:leading-snug tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ finding.suggestion }}\n </p>\n <!-- Fix button -->\n <div\n v-if=\"finding.blockId\"\n class=\"tpl:mt-2 tpl:flex tpl:justify-center\"\n >\n <button\n class=\"tpl-scoring-fix-btn tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded tpl:border tpl:px-3 tpl:py-1.5 tpl:text-[11px] tpl:font-medium tpl:transition-all tpl:duration-150 tpl:disabled:opacity-50 tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-primary)]\"\n style=\"background-color: transparent\"\n :disabled=\"scoring.fixingFindingId.value !== null\"\n @click=\"handleFix(finding)\"\n >\n <LoaderCircle\n v-if=\"scoring.fixingFindingId.value === finding.id\"\n class=\"tpl-spinner\"\n :size=\"11\"\n :stroke-width=\"2\"\n />\n <Sparkles v-else :size=\"11\" :stroke-width=\"2\" />\n {{\n scoring.fixingFindingId.value === finding.id\n ? cloudT.scoring.fixing\n : cloudT.scoring.fix\n }}\n </button>\n <p\n v-if=\"scoring.fixError.value\"\n class=\"tpl:mt-1.5 tpl:text-[11px] tpl:text-[var(--tpl-danger)]\"\n >\n {{ scoring.fixError.value }}\n </p>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Empty state (no result, no loading, no error) -->\n <div\n v-else\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <ShieldCheck\n :size=\"32\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <p\n class=\"tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.emptyState }}\n </p>\n </div>\n\n <!-- AI disclaimer -->\n <p\n class=\"tpl:m-0 tpl:px-4 tpl:pb-2 tpl:pt-2 tpl:text-center tpl:text-[11px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.aiMenu.disclaimer }}\n </p>\n </div>\n </div>\n </Transition>\n</template>\n\n<style scoped>\n.tpl-scoring-slide-enter-active {\n transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-scoring-slide-leave-active {\n transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-scoring-fix-btn:not(:disabled):hover {\n border-color: var(--tpl-primary) !important;\n background-color: var(--tpl-primary-light) !important;\n}\n</style>\n","<script setup lang=\"ts\">\nimport LoadingTrack from \"../../components/LoadingTrack.vue\";\nimport {\n EDITOR_KEY,\n SCORING_KEY,\n MERGE_TAGS_KEY,\n requireInject,\n} from \"../../keys\";\nimport {\n scoreColor,\n scoreBgColor,\n severityColor,\n severityBgColor,\n} from \"../utils/scoringStyles\";\nimport { useCloudI18nStrict } from \"../../composables/useCloudI18n\";\nimport type { ScoringCategory, ScoringFinding } from \"@templatical/types\";\nimport {\n CircleAlert,\n TriangleAlert,\n ChevronDown,\n Eye,\n Info,\n LoaderCircle,\n RefreshCw,\n ShieldCheck,\n ShieldX,\n Sparkles,\n X,\n Zap,\n} from \"@lucide/vue\";\nimport { inject, ref, watch } from \"vue\";\n\nconst props = defineProps<{\n visible: boolean;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n}>();\n\nconst { t: cloudT } = useCloudI18nStrict();\nconst editor = requireInject(EDITOR_KEY, \"TemplateScoringPanel\");\nconst scoring = requireInject(SCORING_KEY, \"TemplateScoringPanel\");\nconst mergeTags = inject(MERGE_TAGS_KEY, []);\n\nconst expandedCategories = ref<Record<string, boolean>>({\n spam: true,\n readability: true,\n accessibility: true,\n bestPractices: true,\n});\n\nfunction toggleCategory(category: string): void {\n expandedCategories.value[category] = !expandedCategories.value[category];\n}\n\nconst categoryOrder: ScoringCategory[] = [\n \"spam\",\n \"readability\",\n \"accessibility\",\n \"bestPractices\",\n];\n\nconst categoryIcons: Record<ScoringCategory, typeof ShieldCheck> = {\n spam: ShieldX,\n readability: Eye,\n accessibility: Sparkles,\n bestPractices: Zap,\n};\n\nfunction triggerScore(): void {\n scoring.score(editor.content.value, mergeTags);\n}\n\nwatch(\n () => props.visible,\n (isVisible) => {\n if (isVisible && !scoring.scoringResult.value && !scoring.isScoring.value) {\n triggerScore();\n }\n },\n);\n\nasync function handleFix(finding: ScoringFinding): Promise<void> {\n if (!finding.blockId) {\n return;\n }\n\n // Get the block content from the editor\n const block = editor.content.value.blocks.find(\n (b) => b.id === finding.blockId,\n );\n if (!block) {\n return;\n }\n\n // Extract HTML content from the block (text blocks have content property)\n const blockContent = (block as unknown as Record<string, unknown>).content as\n string | undefined;\n if (!blockContent) {\n return;\n }\n\n const fixedContent = await scoring.fixFinding(\n blockContent,\n finding,\n mergeTags,\n );\n\n if (fixedContent) {\n editor.updateBlock(finding.blockId, { content: fixedContent });\n scoring.removeFinding(finding.category, finding.id);\n }\n}\n\nfunction totalFindings(): number {\n if (!scoring.scoringResult.value) {\n return 0;\n }\n return categoryOrder.reduce((sum, cat) => {\n return (\n sum + (scoring.scoringResult.value?.categories[cat]?.findings.length ?? 0)\n );\n }, 0);\n}\n</script>\n\n<template>\n <Transition\n enter-active-class=\"tpl-scoring-slide-enter-active\"\n enter-from-class=\"tpl:translate-x-full\"\n enter-to-class=\"tpl:translate-x-0\"\n leave-active-class=\"tpl-scoring-slide-leave-active\"\n leave-from-class=\"tpl:translate-x-0\"\n leave-to-class=\"tpl:translate-x-full\"\n >\n <div\n v-if=\"visible\"\n class=\"tpl-scoring-panel tpl:absolute tpl:top-14 tpl:right-0 tpl:bottom-0 tpl:z-panel tpl:flex tpl:w-[360px] tpl:flex-col tpl:border-l tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg-elevated)]\"\n >\n <!-- Header -->\n <div\n class=\"tpl:flex tpl:items-center tpl:justify-between tpl:border-b tpl:border-[var(--tpl-border)] tpl:px-4 tpl:py-3\"\n >\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-primary)]\"\n >\n <ShieldCheck :size=\"13\" :stroke-width=\"2\" />\n <span>{{ cloudT.scoring.title }}</span>\n </div>\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <button\n v-if=\"scoring.scoringResult.value && !scoring.isScoring.value\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:duration-150 tpl:text-[var(--tpl-text-muted)]\"\n :title=\"cloudT.scoring.rescore\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"14\" :stroke-width=\"2\" />\n </button>\n <button\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:duration-150 tpl:text-[var(--tpl-text-muted)]\"\n @click=\"emit('close')\"\n >\n <X :size=\"14\" :stroke-width=\"2\" />\n </button>\n </div>\n </div>\n\n <!-- Content -->\n <div class=\"tpl:flex-1 tpl:overflow-y-auto tpl:p-4\">\n <!-- Loading state -->\n <div\n v-if=\"scoring.isScoring.value\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <p class=\"tpl:text-sm tpl:text-[var(--tpl-text-muted)]\">\n {{ cloudT.scoring.scoring }}\n </p>\n <LoadingTrack class=\"tpl:w-3/4\" />\n </div>\n\n <!-- Error state -->\n <div\n v-else-if=\"scoring.error.value && !scoring.scoringResult.value\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <CircleAlert\n :size=\"32\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-danger)]\"\n />\n <p\n class=\"tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.error }}\n </p>\n <button\n class=\"tpl:mt-2 tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-md tpl:border tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:transition-all tpl:duration-150 tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-text-muted)]\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"12\" :stroke-width=\"2\" />\n {{ cloudT.scoring.rescore }}\n </button>\n </div>\n\n <!-- Results -->\n <div\n v-else-if=\"scoring.scoringResult.value\"\n class=\"tpl:flex tpl:flex-col tpl:gap-4\"\n >\n <!-- Overall score -->\n <div\n class=\"tpl:flex tpl:flex-col tpl:items-center tpl:gap-2 tpl:rounded-[var(--tpl-radius)] tpl:p-5\"\n :style=\"{\n backgroundColor: scoreBgColor(scoring.scoringResult.value.score),\n }\"\n >\n <span\n class=\"tpl:text-4xl tpl:font-bold tpl:tabular-nums\"\n :style=\"{\n color: scoreColor(scoring.scoringResult.value.score),\n }\"\n >\n {{ scoring.scoringResult.value.score }}\n </span>\n <span\n class=\"tpl:text-xs tpl:font-medium tpl:uppercase tpl:tracking-wider tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.overallScore }}\n </span>\n <span\n v-if=\"totalFindings() > 0\"\n class=\"tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ totalFindings() }}\n {{ cloudT.scoring.findings }}\n </span>\n </div>\n\n <!-- Fix error -->\n <div\n v-if=\"scoring.fixError.value\"\n class=\"tpl:flex tpl:items-start tpl:gap-2 tpl:rounded-lg tpl:px-3 tpl:py-2 tpl:text-xs tpl:bg-[var(--tpl-danger-light)] tpl:text-[var(--tpl-danger)]\"\n >\n <CircleAlert\n :size=\"14\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n />\n <span>{{ cloudT.scoring.fixError }}</span>\n </div>\n\n <!-- Category cards -->\n <div\n v-for=\"category in categoryOrder\"\n :key=\"category\"\n class=\"tpl:overflow-hidden tpl:rounded-[var(--tpl-radius)] tpl:border tpl:border-[var(--tpl-border)]\"\n >\n <!-- Category header -->\n <button\n class=\"tpl:flex tpl:w-full tpl:cursor-pointer tpl:items-center tpl:gap-2.5 tpl:px-3 tpl:py-2.5 tpl:text-left tpl:transition-colors tpl:duration-100 tpl:bg-[var(--tpl-bg)]\"\n @click=\"toggleCategory(category)\"\n >\n <component\n :is=\"categoryIcons[category]\"\n :size=\"14\"\n :stroke-width=\"2\"\n :style=\"{\n color: scoreColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n }\"\n />\n <span\n class=\"tpl:flex-1 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)]\"\n >\n {{ cloudT.scoring.categories[category] }}\n </span>\n <span\n class=\"tpl:rounded-full tpl:px-2 tpl:py-0.5 tpl:text-xs tpl:font-semibold tpl:tabular-nums\"\n :style=\"{\n color: scoreColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n backgroundColor: scoreBgColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n }\"\n >\n {{ scoring.scoringResult.value.categories[category].score }}\n </span>\n <span\n v-if=\"\n scoring.scoringResult.value.categories[category].findings\n .length > 0\n \"\n class=\"tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{\n scoring.scoringResult.value.categories[category].findings\n .length\n }}\n </span>\n <ChevronDown\n :size=\"12\"\n :stroke-width=\"2\"\n class=\"tpl:transition-transform tpl:duration-200 tpl:text-[var(--tpl-text-dim)]\"\n :class=\"\n expandedCategories[category]\n ? 'tpl:rotate-0'\n : 'tpl:-rotate-90'\n \"\n />\n </button>\n\n <!-- Findings list -->\n <div\n v-if=\"expandedCategories[category]\"\n class=\"tpl:border-t tpl:border-[var(--tpl-border)]\"\n >\n <div\n v-if=\"\n scoring.scoringResult.value.categories[category].findings\n .length === 0\n \"\n class=\"tpl:px-3 tpl:py-3 tpl:text-center tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.scoring.noFindings }}\n </div>\n <div\n v-for=\"finding in scoring.scoringResult.value.categories[\n category\n ].findings\"\n :key=\"finding.id\"\n class=\"tpl:border-t tpl:px-3 tpl:py-2.5 first:tpl:border-t-0 tpl:border-[var(--tpl-border-light)]\"\n >\n <div class=\"tpl:flex tpl:items-start tpl:gap-2\">\n <!-- Severity icon -->\n <component\n :is=\"\n finding.severity === 'high'\n ? CircleAlert\n : finding.severity === 'medium'\n ? TriangleAlert\n : Info\n \"\n :size=\"13\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n :style=\"{\n color: severityColor(finding.severity),\n }\"\n />\n <div class=\"tpl:flex-1 tpl:min-w-0\">\n <!-- Severity badge + message -->\n <div class=\"tpl:flex tpl:items-start tpl:gap-1.5\">\n <span\n class=\"tpl:mt-0.5 tpl:shrink-0 tpl:rounded tpl:px-1 tpl:py-px tpl:text-[10px] tpl:font-medium tpl:leading-tight\"\n :style=\"{\n color: severityColor(finding.severity),\n backgroundColor: severityBgColor(finding.severity),\n }\"\n >\n {{ cloudT.scoring.severity[finding.severity] }}\n </span>\n <span\n class=\"tpl:text-xs tpl:leading-snug tpl:text-[var(--tpl-text)]\"\n >\n {{ finding.message }}\n </span>\n </div>\n <!-- Suggestion -->\n <p\n v-if=\"finding.suggestion\"\n class=\"tpl:mt-1 tpl:text-[11px] tpl:leading-snug tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ finding.suggestion }}\n </p>\n <!-- Fix button -->\n <div\n v-if=\"finding.blockId\"\n class=\"tpl:mt-2 tpl:flex tpl:justify-center\"\n >\n <button\n class=\"tpl-scoring-fix-btn tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded tpl:border tpl:px-3 tpl:py-1.5 tpl:text-[11px] tpl:font-medium tpl:transition-all tpl:duration-150 tpl:disabled:opacity-50 tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-primary)]\"\n style=\"background-color: transparent\"\n :disabled=\"scoring.fixingFindingId.value !== null\"\n @click=\"handleFix(finding)\"\n >\n <LoaderCircle\n v-if=\"scoring.fixingFindingId.value === finding.id\"\n class=\"tpl-spinner\"\n :size=\"11\"\n :stroke-width=\"2\"\n />\n <Sparkles v-else :size=\"11\" :stroke-width=\"2\" />\n {{\n scoring.fixingFindingId.value === finding.id\n ? cloudT.scoring.fixing\n : cloudT.scoring.fix\n }}\n </button>\n <p\n v-if=\"scoring.fixError.value\"\n class=\"tpl:mt-1.5 tpl:text-[11px] tpl:text-[var(--tpl-danger)]\"\n >\n {{ scoring.fixError.value }}\n </p>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Empty state (no result, no loading, no error) -->\n <div\n v-else\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <ShieldCheck\n :size=\"32\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <p\n class=\"tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.emptyState }}\n </p>\n </div>\n\n <!-- AI disclaimer -->\n <p\n class=\"tpl:m-0 tpl:px-4 tpl:pb-2 tpl:pt-2 tpl:text-center tpl:text-[11px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.aiMenu.disclaimer }}\n </p>\n </div>\n </div>\n </Transition>\n</template>\n\n<style scoped>\n.tpl-scoring-slide-enter-active {\n transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-scoring-slide-leave-active {\n transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-scoring-fix-btn:not(:disabled):hover {\n border-color: var(--tpl-primary) !important;\n background-color: var(--tpl-primary-light) !important;\n}\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"TemplateScoringPanel-DG1dAjQk.js","names":[],"sources":["../../../src/cloud/utils/scoringStyles.ts","../../../src/cloud/components/TemplateScoringPanel.vue","../../../src/cloud/components/TemplateScoringPanel.vue"],"sourcesContent":["export type ScoringSeverity = \"high\" | \"medium\" | \"low\" | string;\n\nexport function scoreColor(score: number): string {\n if (score >= 80) return \"var(--tpl-success)\";\n if (score >= 60) return \"var(--tpl-warning)\";\n return \"var(--tpl-danger)\";\n}\n\nexport function scoreBgColor(score: number): string {\n if (score >= 80) return \"var(--tpl-success-light)\";\n if (score >= 60) return \"var(--tpl-warning-light)\";\n return \"var(--tpl-danger-light)\";\n}\n\nexport function severityColor(severity: ScoringSeverity): string {\n if (severity === \"high\") return \"var(--tpl-danger)\";\n if (severity === \"medium\") return \"var(--tpl-warning)\";\n return \"var(--tpl-text-muted)\";\n}\n\nexport function severityBgColor(severity: ScoringSeverity): string {\n if (severity === \"high\") return \"var(--tpl-danger-light)\";\n if (severity === \"medium\") return \"var(--tpl-warning-light)\";\n return \"var(--tpl-bg-hover)\";\n}\n","<script setup lang=\"ts\">\nimport LoadingTrack from \"../../components/LoadingTrack.vue\";\nimport {\n EDITOR_KEY,\n SCORING_KEY,\n MERGE_TAGS_KEY,\n requireInject,\n} from \"../../keys\";\nimport {\n scoreColor,\n scoreBgColor,\n severityColor,\n severityBgColor,\n} from \"../utils/scoringStyles\";\nimport { useCloudI18nStrict } from \"../../composables/useCloudI18n\";\nimport type { ScoringCategory, ScoringFinding } from \"@templatical/types\";\nimport {\n CircleAlert,\n TriangleAlert,\n ChevronDown,\n Eye,\n Info,\n LoaderCircle,\n RefreshCw,\n ShieldCheck,\n ShieldX,\n Sparkles,\n X,\n Zap,\n} from \"@lucide/vue\";\nimport { inject, ref, watch } from \"vue\";\n\nconst props = defineProps<{\n visible: boolean;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n}>();\n\nconst { t: cloudT } = useCloudI18nStrict();\nconst editor = requireInject(EDITOR_KEY, \"TemplateScoringPanel\");\nconst scoring = requireInject(SCORING_KEY, \"TemplateScoringPanel\");\nconst mergeTags = inject(MERGE_TAGS_KEY, []);\n\nconst expandedCategories = ref<Record<string, boolean>>({\n spam: true,\n readability: true,\n accessibility: true,\n bestPractices: true,\n});\n\nfunction toggleCategory(category: string): void {\n expandedCategories.value[category] = !expandedCategories.value[category];\n}\n\nconst categoryOrder: ScoringCategory[] = [\n \"spam\",\n \"readability\",\n \"accessibility\",\n \"bestPractices\",\n];\n\nconst categoryIcons: Record<ScoringCategory, typeof ShieldCheck> = {\n spam: ShieldX,\n readability: Eye,\n accessibility: Sparkles,\n bestPractices: Zap,\n};\n\nfunction triggerScore(): void {\n scoring.score(editor.content.value, mergeTags);\n}\n\nwatch(\n () => props.visible,\n (isVisible) => {\n if (isVisible && !scoring.scoringResult.value && !scoring.isScoring.value) {\n triggerScore();\n }\n },\n);\n\nasync function handleFix(finding: ScoringFinding): Promise<void> {\n if (!finding.blockId) {\n return;\n }\n\n // Get the block content from the editor\n const block = editor.content.value.blocks.find(\n (b) => b.id === finding.blockId,\n );\n if (!block) {\n return;\n }\n\n // Extract HTML content from the block (text blocks have content property)\n const blockContent = (block as unknown as Record<string, unknown>).content as\n string | undefined;\n if (!blockContent) {\n return;\n }\n\n const fixedContent = await scoring.fixFinding(\n blockContent,\n finding,\n mergeTags,\n );\n\n if (fixedContent) {\n editor.updateBlock(finding.blockId, { content: fixedContent });\n scoring.removeFinding(finding.category, finding.id);\n }\n}\n\nfunction totalFindings(): number {\n if (!scoring.scoringResult.value) {\n return 0;\n }\n return categoryOrder.reduce((sum, cat) => {\n return (\n sum + (scoring.scoringResult.value?.categories[cat]?.findings.length ?? 0)\n );\n }, 0);\n}\n</script>\n\n<template>\n <Transition\n enter-active-class=\"tpl-scoring-slide-enter-active\"\n enter-from-class=\"tpl:translate-x-full\"\n enter-to-class=\"tpl:translate-x-0\"\n leave-active-class=\"tpl-scoring-slide-leave-active\"\n leave-from-class=\"tpl:translate-x-0\"\n leave-to-class=\"tpl:translate-x-full\"\n >\n <div\n v-if=\"visible\"\n class=\"tpl-scoring-panel tpl:absolute tpl:top-14 tpl:right-0 tpl:bottom-0 tpl:z-panel tpl:flex tpl:w-[360px] tpl:flex-col tpl:border-l tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg-elevated)]\"\n >\n <!-- Header -->\n <div\n class=\"tpl:flex tpl:items-center tpl:justify-between tpl:border-b tpl:border-[var(--tpl-border)] tpl:px-4 tpl:py-3\"\n >\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-primary)]\"\n >\n <ShieldCheck :size=\"13\" :stroke-width=\"2\" />\n <span>{{ cloudT.scoring.title }}</span>\n </div>\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <button\n v-if=\"scoring.scoringResult.value && !scoring.isScoring.value\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:duration-150 tpl:text-[var(--tpl-text-muted)]\"\n :title=\"cloudT.scoring.rescore\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"14\" :stroke-width=\"2\" />\n </button>\n <button\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:duration-150 tpl:text-[var(--tpl-text-muted)]\"\n @click=\"emit('close')\"\n >\n <X :size=\"14\" :stroke-width=\"2\" />\n </button>\n </div>\n </div>\n\n <!-- Content -->\n <div class=\"tpl:flex-1 tpl:overflow-y-auto tpl:p-4\">\n <!-- Loading state -->\n <div\n v-if=\"scoring.isScoring.value\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <p class=\"tpl:text-sm tpl:text-[var(--tpl-text-muted)]\">\n {{ cloudT.scoring.scoring }}\n </p>\n <LoadingTrack class=\"tpl:w-3/4\" />\n </div>\n\n <!-- Error state -->\n <div\n v-else-if=\"scoring.error.value && !scoring.scoringResult.value\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <CircleAlert\n :size=\"32\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-danger)]\"\n />\n <p\n class=\"tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.error }}\n </p>\n <button\n class=\"tpl:mt-2 tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-md tpl:border tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:transition-all tpl:duration-150 tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-text-muted)]\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"12\" :stroke-width=\"2\" />\n {{ cloudT.scoring.rescore }}\n </button>\n </div>\n\n <!-- Results -->\n <div\n v-else-if=\"scoring.scoringResult.value\"\n class=\"tpl:flex tpl:flex-col tpl:gap-4\"\n >\n <!-- Overall score -->\n <div\n class=\"tpl:flex tpl:flex-col tpl:items-center tpl:gap-2 tpl:rounded-[var(--tpl-radius)] tpl:p-5\"\n :style=\"{\n backgroundColor: scoreBgColor(scoring.scoringResult.value.score),\n }\"\n >\n <span\n class=\"tpl:text-4xl tpl:font-bold tpl:tabular-nums\"\n :style=\"{\n color: scoreColor(scoring.scoringResult.value.score),\n }\"\n >\n {{ scoring.scoringResult.value.score }}\n </span>\n <span\n class=\"tpl:text-xs tpl:font-medium tpl:uppercase tpl:tracking-wider tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.overallScore }}\n </span>\n <span\n v-if=\"totalFindings() > 0\"\n class=\"tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ totalFindings() }}\n {{ cloudT.scoring.findings }}\n </span>\n </div>\n\n <!-- Fix error -->\n <div\n v-if=\"scoring.fixError.value\"\n class=\"tpl:flex tpl:items-start tpl:gap-2 tpl:rounded-lg tpl:px-3 tpl:py-2 tpl:text-xs tpl:bg-[var(--tpl-danger-light)] tpl:text-[var(--tpl-danger)]\"\n >\n <CircleAlert\n :size=\"14\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n />\n <span>{{ cloudT.scoring.fixError }}</span>\n </div>\n\n <!-- Category cards -->\n <div\n v-for=\"category in categoryOrder\"\n :key=\"category\"\n class=\"tpl:overflow-hidden tpl:rounded-[var(--tpl-radius)] tpl:border tpl:border-[var(--tpl-border)]\"\n >\n <!-- Category header -->\n <button\n class=\"tpl:flex tpl:w-full tpl:cursor-pointer tpl:items-center tpl:gap-2.5 tpl:px-3 tpl:py-2.5 tpl:text-left tpl:transition-colors tpl:duration-100 tpl:bg-[var(--tpl-bg)]\"\n @click=\"toggleCategory(category)\"\n >\n <component\n :is=\"categoryIcons[category]\"\n :size=\"14\"\n :stroke-width=\"2\"\n :style=\"{\n color: scoreColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n }\"\n />\n <span\n class=\"tpl:flex-1 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)]\"\n >\n {{ cloudT.scoring.categories[category] }}\n </span>\n <span\n class=\"tpl:rounded-full tpl:px-2 tpl:py-0.5 tpl:text-xs tpl:font-semibold tpl:tabular-nums\"\n :style=\"{\n color: scoreColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n backgroundColor: scoreBgColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n }\"\n >\n {{ scoring.scoringResult.value.categories[category].score }}\n </span>\n <span\n v-if=\"\n scoring.scoringResult.value.categories[category].findings\n .length > 0\n \"\n class=\"tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{\n scoring.scoringResult.value.categories[category].findings\n .length\n }}\n </span>\n <ChevronDown\n :size=\"12\"\n :stroke-width=\"2\"\n class=\"tpl:transition-transform tpl:duration-200 tpl:text-[var(--tpl-text-dim)]\"\n :class=\"\n expandedCategories[category]\n ? 'tpl:rotate-0'\n : 'tpl:-rotate-90'\n \"\n />\n </button>\n\n <!-- Findings list -->\n <div\n v-if=\"expandedCategories[category]\"\n class=\"tpl:border-t tpl:border-[var(--tpl-border)]\"\n >\n <div\n v-if=\"\n scoring.scoringResult.value.categories[category].findings\n .length === 0\n \"\n class=\"tpl:px-3 tpl:py-3 tpl:text-center tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.scoring.noFindings }}\n </div>\n <div\n v-for=\"finding in scoring.scoringResult.value.categories[\n category\n ].findings\"\n :key=\"finding.id\"\n class=\"tpl:border-t tpl:px-3 tpl:py-2.5 first:tpl:border-t-0 tpl:border-[var(--tpl-border-light)]\"\n >\n <div class=\"tpl:flex tpl:items-start tpl:gap-2\">\n <!-- Severity icon -->\n <component\n :is=\"\n finding.severity === 'high'\n ? CircleAlert\n : finding.severity === 'medium'\n ? TriangleAlert\n : Info\n \"\n :size=\"13\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n :style=\"{\n color: severityColor(finding.severity),\n }\"\n />\n <div class=\"tpl:flex-1 tpl:min-w-0\">\n <!-- Severity badge + message -->\n <div class=\"tpl:flex tpl:items-start tpl:gap-1.5\">\n <span\n class=\"tpl:mt-0.5 tpl:shrink-0 tpl:rounded tpl:px-1 tpl:py-px tpl:text-[10px] tpl:font-medium tpl:leading-tight\"\n :style=\"{\n color: severityColor(finding.severity),\n backgroundColor: severityBgColor(finding.severity),\n }\"\n >\n {{ cloudT.scoring.severity[finding.severity] }}\n </span>\n <span\n class=\"tpl:text-xs tpl:leading-snug tpl:text-[var(--tpl-text)]\"\n >\n {{ finding.message }}\n </span>\n </div>\n <!-- Suggestion -->\n <p\n v-if=\"finding.suggestion\"\n class=\"tpl:mt-1 tpl:text-[11px] tpl:leading-snug tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ finding.suggestion }}\n </p>\n <!-- Fix button -->\n <div\n v-if=\"finding.blockId\"\n class=\"tpl:mt-2 tpl:flex tpl:justify-center\"\n >\n <button\n class=\"tpl-scoring-fix-btn tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded tpl:border tpl:px-3 tpl:py-1.5 tpl:text-[11px] tpl:font-medium tpl:transition-all tpl:duration-150 tpl:disabled:opacity-50 tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-primary)]\"\n style=\"background-color: transparent\"\n :disabled=\"scoring.fixingFindingId.value !== null\"\n @click=\"handleFix(finding)\"\n >\n <LoaderCircle\n v-if=\"scoring.fixingFindingId.value === finding.id\"\n class=\"tpl-spinner\"\n :size=\"11\"\n :stroke-width=\"2\"\n />\n <Sparkles v-else :size=\"11\" :stroke-width=\"2\" />\n {{\n scoring.fixingFindingId.value === finding.id\n ? cloudT.scoring.fixing\n : cloudT.scoring.fix\n }}\n </button>\n <p\n v-if=\"scoring.fixError.value\"\n class=\"tpl:mt-1.5 tpl:text-[11px] tpl:text-[var(--tpl-danger)]\"\n >\n {{ scoring.fixError.value }}\n </p>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Empty state (no result, no loading, no error) -->\n <div\n v-else\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <ShieldCheck\n :size=\"32\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <p\n class=\"tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.emptyState }}\n </p>\n </div>\n\n <!-- AI disclaimer -->\n <p\n class=\"tpl:m-0 tpl:px-4 tpl:pb-2 tpl:pt-2 tpl:text-center tpl:text-[11px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.aiMenu.disclaimer }}\n </p>\n </div>\n </div>\n </Transition>\n</template>\n\n<style scoped>\n.tpl-scoring-slide-enter-active {\n transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-scoring-slide-leave-active {\n transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-scoring-fix-btn:not(:disabled):hover {\n border-color: var(--tpl-primary) !important;\n background-color: var(--tpl-primary-light) !important;\n}\n</style>\n","<script setup lang=\"ts\">\nimport LoadingTrack from \"../../components/LoadingTrack.vue\";\nimport {\n EDITOR_KEY,\n SCORING_KEY,\n MERGE_TAGS_KEY,\n requireInject,\n} from \"../../keys\";\nimport {\n scoreColor,\n scoreBgColor,\n severityColor,\n severityBgColor,\n} from \"../utils/scoringStyles\";\nimport { useCloudI18nStrict } from \"../../composables/useCloudI18n\";\nimport type { ScoringCategory, ScoringFinding } from \"@templatical/types\";\nimport {\n CircleAlert,\n TriangleAlert,\n ChevronDown,\n Eye,\n Info,\n LoaderCircle,\n RefreshCw,\n ShieldCheck,\n ShieldX,\n Sparkles,\n X,\n Zap,\n} from \"@lucide/vue\";\nimport { inject, ref, watch } from \"vue\";\n\nconst props = defineProps<{\n visible: boolean;\n}>();\n\nconst emit = defineEmits<{\n (e: \"close\"): void;\n}>();\n\nconst { t: cloudT } = useCloudI18nStrict();\nconst editor = requireInject(EDITOR_KEY, \"TemplateScoringPanel\");\nconst scoring = requireInject(SCORING_KEY, \"TemplateScoringPanel\");\nconst mergeTags = inject(MERGE_TAGS_KEY, []);\n\nconst expandedCategories = ref<Record<string, boolean>>({\n spam: true,\n readability: true,\n accessibility: true,\n bestPractices: true,\n});\n\nfunction toggleCategory(category: string): void {\n expandedCategories.value[category] = !expandedCategories.value[category];\n}\n\nconst categoryOrder: ScoringCategory[] = [\n \"spam\",\n \"readability\",\n \"accessibility\",\n \"bestPractices\",\n];\n\nconst categoryIcons: Record<ScoringCategory, typeof ShieldCheck> = {\n spam: ShieldX,\n readability: Eye,\n accessibility: Sparkles,\n bestPractices: Zap,\n};\n\nfunction triggerScore(): void {\n scoring.score(editor.content.value, mergeTags);\n}\n\nwatch(\n () => props.visible,\n (isVisible) => {\n if (isVisible && !scoring.scoringResult.value && !scoring.isScoring.value) {\n triggerScore();\n }\n },\n);\n\nasync function handleFix(finding: ScoringFinding): Promise<void> {\n if (!finding.blockId) {\n return;\n }\n\n // Get the block content from the editor\n const block = editor.content.value.blocks.find(\n (b) => b.id === finding.blockId,\n );\n if (!block) {\n return;\n }\n\n // Extract HTML content from the block (text blocks have content property)\n const blockContent = (block as unknown as Record<string, unknown>).content as\n string | undefined;\n if (!blockContent) {\n return;\n }\n\n const fixedContent = await scoring.fixFinding(\n blockContent,\n finding,\n mergeTags,\n );\n\n if (fixedContent) {\n editor.updateBlock(finding.blockId, { content: fixedContent });\n scoring.removeFinding(finding.category, finding.id);\n }\n}\n\nfunction totalFindings(): number {\n if (!scoring.scoringResult.value) {\n return 0;\n }\n return categoryOrder.reduce((sum, cat) => {\n return (\n sum + (scoring.scoringResult.value?.categories[cat]?.findings.length ?? 0)\n );\n }, 0);\n}\n</script>\n\n<template>\n <Transition\n enter-active-class=\"tpl-scoring-slide-enter-active\"\n enter-from-class=\"tpl:translate-x-full\"\n enter-to-class=\"tpl:translate-x-0\"\n leave-active-class=\"tpl-scoring-slide-leave-active\"\n leave-from-class=\"tpl:translate-x-0\"\n leave-to-class=\"tpl:translate-x-full\"\n >\n <div\n v-if=\"visible\"\n class=\"tpl-scoring-panel tpl:absolute tpl:top-14 tpl:right-0 tpl:bottom-0 tpl:z-panel tpl:flex tpl:w-[360px] tpl:flex-col tpl:border-l tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg-elevated)]\"\n >\n <!-- Header -->\n <div\n class=\"tpl:flex tpl:items-center tpl:justify-between tpl:border-b tpl:border-[var(--tpl-border)] tpl:px-4 tpl:py-3\"\n >\n <div\n class=\"tpl:flex tpl:items-center tpl:gap-1.5 tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-primary)]\"\n >\n <ShieldCheck :size=\"13\" :stroke-width=\"2\" />\n <span>{{ cloudT.scoring.title }}</span>\n </div>\n <div class=\"tpl:flex tpl:items-center tpl:gap-1\">\n <button\n v-if=\"scoring.scoringResult.value && !scoring.isScoring.value\"\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:duration-150 tpl:text-[var(--tpl-text-muted)]\"\n :title=\"cloudT.scoring.rescore\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"14\" :stroke-width=\"2\" />\n </button>\n <button\n class=\"tpl:rounded-md tpl:p-0.5 tpl:transition-colors tpl:duration-150 tpl:text-[var(--tpl-text-muted)]\"\n @click=\"emit('close')\"\n >\n <X :size=\"14\" :stroke-width=\"2\" />\n </button>\n </div>\n </div>\n\n <!-- Content -->\n <div class=\"tpl:flex-1 tpl:overflow-y-auto tpl:p-4\">\n <!-- Loading state -->\n <div\n v-if=\"scoring.isScoring.value\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <p class=\"tpl:text-sm tpl:text-[var(--tpl-text-muted)]\">\n {{ cloudT.scoring.scoring }}\n </p>\n <LoadingTrack class=\"tpl:w-3/4\" />\n </div>\n\n <!-- Error state -->\n <div\n v-else-if=\"scoring.error.value && !scoring.scoringResult.value\"\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <CircleAlert\n :size=\"32\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-danger)]\"\n />\n <p\n class=\"tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.error }}\n </p>\n <button\n class=\"tpl:mt-2 tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded-md tpl:border tpl:px-3 tpl:py-1.5 tpl:text-xs tpl:font-medium tpl:transition-all tpl:duration-150 tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-text-muted)]\"\n @click=\"triggerScore()\"\n >\n <RefreshCw :size=\"12\" :stroke-width=\"2\" />\n {{ cloudT.scoring.rescore }}\n </button>\n </div>\n\n <!-- Results -->\n <div\n v-else-if=\"scoring.scoringResult.value\"\n class=\"tpl:flex tpl:flex-col tpl:gap-4\"\n >\n <!-- Overall score -->\n <div\n class=\"tpl:flex tpl:flex-col tpl:items-center tpl:gap-2 tpl:rounded-[var(--tpl-radius)] tpl:p-5\"\n :style=\"{\n backgroundColor: scoreBgColor(scoring.scoringResult.value.score),\n }\"\n >\n <span\n class=\"tpl:text-4xl tpl:font-bold tpl:tabular-nums\"\n :style=\"{\n color: scoreColor(scoring.scoringResult.value.score),\n }\"\n >\n {{ scoring.scoringResult.value.score }}\n </span>\n <span\n class=\"tpl:text-xs tpl:font-medium tpl:uppercase tpl:tracking-wider tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.overallScore }}\n </span>\n <span\n v-if=\"totalFindings() > 0\"\n class=\"tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ totalFindings() }}\n {{ cloudT.scoring.findings }}\n </span>\n </div>\n\n <!-- Fix error -->\n <div\n v-if=\"scoring.fixError.value\"\n class=\"tpl:flex tpl:items-start tpl:gap-2 tpl:rounded-lg tpl:px-3 tpl:py-2 tpl:text-xs tpl:bg-[var(--tpl-danger-light)] tpl:text-[var(--tpl-danger)]\"\n >\n <CircleAlert\n :size=\"14\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n />\n <span>{{ cloudT.scoring.fixError }}</span>\n </div>\n\n <!-- Category cards -->\n <div\n v-for=\"category in categoryOrder\"\n :key=\"category\"\n class=\"tpl:overflow-hidden tpl:rounded-[var(--tpl-radius)] tpl:border tpl:border-[var(--tpl-border)]\"\n >\n <!-- Category header -->\n <button\n class=\"tpl:flex tpl:w-full tpl:cursor-pointer tpl:items-center tpl:gap-2.5 tpl:px-3 tpl:py-2.5 tpl:text-left tpl:transition-colors tpl:duration-100 tpl:bg-[var(--tpl-bg)]\"\n @click=\"toggleCategory(category)\"\n >\n <component\n :is=\"categoryIcons[category]\"\n :size=\"14\"\n :stroke-width=\"2\"\n :style=\"{\n color: scoreColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n }\"\n />\n <span\n class=\"tpl:flex-1 tpl:text-xs tpl:font-medium tpl:text-[var(--tpl-text)]\"\n >\n {{ cloudT.scoring.categories[category] }}\n </span>\n <span\n class=\"tpl:rounded-full tpl:px-2 tpl:py-0.5 tpl:text-xs tpl:font-semibold tpl:tabular-nums\"\n :style=\"{\n color: scoreColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n backgroundColor: scoreBgColor(\n scoring.scoringResult.value.categories[category].score,\n ),\n }\"\n >\n {{ scoring.scoringResult.value.categories[category].score }}\n </span>\n <span\n v-if=\"\n scoring.scoringResult.value.categories[category].findings\n .length > 0\n \"\n class=\"tpl:text-[10px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{\n scoring.scoringResult.value.categories[category].findings\n .length\n }}\n </span>\n <ChevronDown\n :size=\"12\"\n :stroke-width=\"2\"\n class=\"tpl:transition-transform tpl:duration-200 tpl:text-[var(--tpl-text-dim)]\"\n :class=\"\n expandedCategories[category]\n ? 'tpl:rotate-0'\n : 'tpl:-rotate-90'\n \"\n />\n </button>\n\n <!-- Findings list -->\n <div\n v-if=\"expandedCategories[category]\"\n class=\"tpl:border-t tpl:border-[var(--tpl-border)]\"\n >\n <div\n v-if=\"\n scoring.scoringResult.value.categories[category].findings\n .length === 0\n \"\n class=\"tpl:px-3 tpl:py-3 tpl:text-center tpl:text-xs tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.scoring.noFindings }}\n </div>\n <div\n v-for=\"finding in scoring.scoringResult.value.categories[\n category\n ].findings\"\n :key=\"finding.id\"\n class=\"tpl:border-t tpl:px-3 tpl:py-2.5 first:tpl:border-t-0 tpl:border-[var(--tpl-border-light)]\"\n >\n <div class=\"tpl:flex tpl:items-start tpl:gap-2\">\n <!-- Severity icon -->\n <component\n :is=\"\n finding.severity === 'high'\n ? CircleAlert\n : finding.severity === 'medium'\n ? TriangleAlert\n : Info\n \"\n :size=\"13\"\n :stroke-width=\"2\"\n class=\"tpl:mt-0.5 tpl:shrink-0\"\n :style=\"{\n color: severityColor(finding.severity),\n }\"\n />\n <div class=\"tpl:flex-1 tpl:min-w-0\">\n <!-- Severity badge + message -->\n <div class=\"tpl:flex tpl:items-start tpl:gap-1.5\">\n <span\n class=\"tpl:mt-0.5 tpl:shrink-0 tpl:rounded tpl:px-1 tpl:py-px tpl:text-[10px] tpl:font-medium tpl:leading-tight\"\n :style=\"{\n color: severityColor(finding.severity),\n backgroundColor: severityBgColor(finding.severity),\n }\"\n >\n {{ cloudT.scoring.severity[finding.severity] }}\n </span>\n <span\n class=\"tpl:text-xs tpl:leading-snug tpl:text-[var(--tpl-text)]\"\n >\n {{ finding.message }}\n </span>\n </div>\n <!-- Suggestion -->\n <p\n v-if=\"finding.suggestion\"\n class=\"tpl:mt-1 tpl:text-[11px] tpl:leading-snug tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ finding.suggestion }}\n </p>\n <!-- Fix button -->\n <div\n v-if=\"finding.blockId\"\n class=\"tpl:mt-2 tpl:flex tpl:justify-center\"\n >\n <button\n class=\"tpl-scoring-fix-btn tpl:inline-flex tpl:items-center tpl:gap-1.5 tpl:rounded tpl:border tpl:px-3 tpl:py-1.5 tpl:text-[11px] tpl:font-medium tpl:transition-all tpl:duration-150 tpl:disabled:opacity-50 tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-primary)]\"\n style=\"background-color: transparent\"\n :disabled=\"scoring.fixingFindingId.value !== null\"\n @click=\"handleFix(finding)\"\n >\n <LoaderCircle\n v-if=\"scoring.fixingFindingId.value === finding.id\"\n class=\"tpl-spinner\"\n :size=\"11\"\n :stroke-width=\"2\"\n />\n <Sparkles v-else :size=\"11\" :stroke-width=\"2\" />\n {{\n scoring.fixingFindingId.value === finding.id\n ? cloudT.scoring.fixing\n : cloudT.scoring.fix\n }}\n </button>\n <p\n v-if=\"scoring.fixError.value\"\n class=\"tpl:mt-1.5 tpl:text-[11px] tpl:text-[var(--tpl-danger)]\"\n >\n {{ scoring.fixError.value }}\n </p>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Empty state (no result, no loading, no error) -->\n <div\n v-else\n class=\"tpl:flex tpl:h-full tpl:flex-col tpl:items-center tpl:justify-center tpl:gap-3 tpl:text-center\"\n >\n <ShieldCheck\n :size=\"32\"\n :stroke-width=\"1.5\"\n class=\"tpl:text-[var(--tpl-text-dim)]\"\n />\n <p\n class=\"tpl:max-w-[240px] tpl:text-sm tpl:text-[var(--tpl-text-muted)]\"\n >\n {{ cloudT.scoring.emptyState }}\n </p>\n </div>\n\n <!-- AI disclaimer -->\n <p\n class=\"tpl:m-0 tpl:px-4 tpl:pb-2 tpl:pt-2 tpl:text-center tpl:text-[11px] tpl:text-[var(--tpl-text-dim)]\"\n >\n {{ cloudT.aiMenu.disclaimer }}\n </p>\n </div>\n </div>\n </Transition>\n</template>\n\n<style scoped>\n.tpl-scoring-slide-enter-active {\n transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-scoring-slide-leave-active {\n transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.tpl-scoring-fix-btn:not(:disabled):hover {\n border-color: var(--tpl-primary) !important;\n background-color: var(--tpl-primary-light) !important;\n}\n</style>\n"],"mappings":"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"}
@@ -0,0 +1,174 @@
1
+ import { H as e, M as t, P as n, T as r, V as i, Z as a, a as o, ct as s, f as c, g as l, h as u, it as d, m as ee, o as te, ot as ne, p as f, u as re, v as p, x as m, y as h, z as ie } from "./draggable-D840DIZB.js";
2
+ import { l as ae } from "./src-BCJna-6p.js";
3
+ import { O as oe, T as se, h as ce } from "./keys-B5uoP9P7.js";
4
+ import { t as le } from "./useI18n-graz19nI.js";
5
+ import { It as ue, it as de } from "./icons-Cqxvwgz7.js";
6
+ import { n as fe, t as pe } from "./MergeTagModeToggle-DmtR300G.js";
7
+ import { t as me } from "./TplModal-Cu4tBBnF.js";
8
+ import { t as g } from "./BlockPreviewCanvas-Dc4F4HzY.js";
9
+ //#region src/utils/validateEmailShape.ts
10
+ var _ = /[,;<>()[\]\\"'`|/?#@!$%^&*+=~{}]/;
11
+ function v(e) {
12
+ let t = e.trim();
13
+ if (t.length === 0 || /\s/.test(t)) return !1;
14
+ let n = t.split("@");
15
+ if (n.length !== 2) return !1;
16
+ let [r, i] = n;
17
+ if (r.length === 0 || _.test(i)) return !1;
18
+ let a = i.indexOf(".");
19
+ return a > 0 && a < i.length - 1;
20
+ }
21
+ //#endregion
22
+ //#region src/components/TestEmailModal.vue?vue&type=script&setup=true&lang.ts
23
+ var y = ["aria-busy"], b = {
24
+ id: "tpl-test-email-title",
25
+ class: "tpl:mb-4 tpl:shrink-0 tpl:text-sm tpl:font-semibold tpl:text-[var(--tpl-text)]"
26
+ }, x = { class: "tpl:mb-3 tpl:shrink-0" }, S = {
27
+ for: "tpl-test-email-recipient",
28
+ class: "tpl:mb-1.5 tpl:block tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-text-muted)]"
29
+ }, C = ["value"], w = ["disabled"], T = ["value"], E = ["placeholder", "disabled"], D = {
30
+ key: 3,
31
+ class: "tpl:mt-1.5 tpl:text-xs tpl:text-[var(--tpl-text-dim)]"
32
+ }, O = { class: "tpl:mb-2 tpl:shrink-0" }, k = { class: "tpl:flex tpl:flex-wrap tpl:items-center tpl:justify-between tpl:gap-2" }, A = { class: "tpl:text-sm tpl:font-medium tpl:text-[var(--tpl-text-muted)]" }, j = { class: "tpl:flex tpl:items-center tpl:gap-2" }, M = {
33
+ "data-testid": "test-email-preview-hint",
34
+ class: "tpl:mt-1 tpl:text-xs tpl:text-[var(--tpl-text-dim)]"
35
+ }, N = {
36
+ id: "tpl-test-email-preview",
37
+ "data-testid": "test-email-preview",
38
+ class: "tpl:mb-3 tpl:min-h-0 tpl:flex-1 tpl:overflow-y-auto tpl:rounded-[var(--tpl-radius-sm)] tpl:p-3 tpl:bg-[var(--tpl-canvas-bg)]"
39
+ }, P = {
40
+ key: 0,
41
+ role: "status",
42
+ "data-testid": "test-email-success",
43
+ class: "tpl:mb-3 tpl:flex tpl:shrink-0 tpl:items-center tpl:gap-1.5 tpl:text-xs tpl:text-[var(--tpl-success,var(--tpl-primary))]"
44
+ }, F = {
45
+ key: 1,
46
+ role: "alert",
47
+ "data-testid": "test-email-error",
48
+ class: "tpl:mb-3 tpl:shrink-0 tpl:text-xs tpl:text-[var(--tpl-danger)]"
49
+ }, he = { class: "tpl:flex tpl:shrink-0 tpl:justify-end tpl:gap-2" }, I = ["disabled"], L = ["disabled"], R = {
50
+ key: 0,
51
+ class: "tpl:flex tpl:items-center tpl:gap-1.5"
52
+ }, ge = { key: 1 }, z = /* @__PURE__ */ m({
53
+ __name: "TestEmailModal",
54
+ props: {
55
+ visible: { type: Boolean },
56
+ allowedRecipients: {},
57
+ defaultRecipient: {},
58
+ isSending: { type: Boolean },
59
+ justSent: { type: Boolean },
60
+ error: {}
61
+ },
62
+ emits: ["send", "close"],
63
+ setup(m, { emit: _ }) {
64
+ let z = m, B = _, { t: V } = le(), _e = r(ce, null), H = a(""), U = a("desktop"), W = r(oe, null), G = a(ae(r(se, []))), K = c({
65
+ get: () => W?.value ?? G.value,
66
+ set: (e) => {
67
+ W ? W.value = e : G.value = e;
68
+ }
69
+ }), ve = c(() => _e?.content.value.blocks ?? []), q = c(() => z.allowedRecipients !== void 0 && z.allowedRecipients.length > 0), ye = c(() => z.allowedRecipients?.length === 1);
70
+ ie(() => z.visible, (e) => {
71
+ e && (H.value = z.defaultRecipient ?? z.allowedRecipients?.[0] ?? "");
72
+ }, { immediate: !0 });
73
+ let J = c(() => q.value ? H.value.length > 0 : v(H.value)), Y = c(() => J.value && !z.isSending && !z.justSent), X = c(() => !q.value && H.value.trim().length > 0 && !J.value), Z = c(() => z.error ? z.error.kind === "provider" ? z.error.message : V.testEmail.recipientNotAllowed : null);
74
+ function Q() {
75
+ Y.value && B("send", H.value.trim());
76
+ }
77
+ function $() {
78
+ z.isSending || B("close");
79
+ }
80
+ function be(e) {
81
+ e.key === "Enter" && !e.shiftKey && (e.preventDefault(), Q()), e.key === "Escape" && $();
82
+ }
83
+ return (r, a) => (t(), ee(me, {
84
+ visible: m.visible,
85
+ onClose: $,
86
+ onKeydown: be
87
+ }, {
88
+ default: i(() => [f("div", {
89
+ role: "dialog",
90
+ "aria-modal": "true",
91
+ "aria-busy": m.isSending,
92
+ "aria-labelledby": "tpl-test-email-title",
93
+ class: "tpl-scale-in tpl:mx-4 tpl:flex tpl:max-h-[90vh] tpl:w-full tpl:max-w-2xl tpl:flex-col tpl:rounded-[var(--tpl-radius-lg)] tpl:p-5",
94
+ style: {
95
+ "background-color": "var(--tpl-bg-elevated)",
96
+ "box-shadow": "var(--tpl-shadow-xl)"
97
+ }
98
+ }, [
99
+ f("h3", b, s(d(V).testEmail.title), 1),
100
+ f("div", x, [
101
+ f("label", S, s(d(V).testEmail.recipientLabel), 1),
102
+ ye.value ? (t(), l("input", {
103
+ key: 0,
104
+ id: "tpl-test-email-recipient",
105
+ type: "text",
106
+ value: H.value,
107
+ disabled: "",
108
+ "data-testid": "test-email-recipient",
109
+ class: "tpl:h-9 tpl:w-full tpl:rounded-md tpl:border tpl:px-3 tpl:py-1 tpl:text-sm tpl:opacity-70 tpl:shadow-xs tpl:outline-none tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:text-[var(--tpl-text)]"
110
+ }, null, 8, C)) : q.value ? e((t(), l("select", {
111
+ key: 1,
112
+ id: "tpl-test-email-recipient",
113
+ "onUpdate:modelValue": a[0] ||= (e) => H.value = e,
114
+ disabled: m.isSending || m.justSent,
115
+ "data-testid": "test-email-recipient",
116
+ class: "tpl:h-9 tpl:w-full tpl:rounded-md tpl:border tpl:px-3 tpl:py-1 tpl:text-sm tpl:shadow-xs tpl:outline-none tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:text-[var(--tpl-text)]"
117
+ }, [(t(!0), l(re, null, n(m.allowedRecipients, (e) => (t(), l("option", {
118
+ key: e,
119
+ value: e
120
+ }, s(e), 9, T))), 128))], 8, w)), [[o, H.value]]) : e((t(), l("input", {
121
+ key: 2,
122
+ id: "tpl-test-email-recipient",
123
+ "onUpdate:modelValue": a[1] ||= (e) => H.value = e,
124
+ type: "email",
125
+ autocomplete: "email",
126
+ spellcheck: "false",
127
+ placeholder: d(V).testEmail.recipientPlaceholder,
128
+ disabled: m.isSending || m.justSent,
129
+ "data-testid": "test-email-recipient",
130
+ class: "tpl:h-9 tpl:w-full tpl:rounded-md tpl:border tpl:px-3 tpl:py-1 tpl:text-sm tpl:shadow-xs tpl:outline-none tpl:border-[var(--tpl-border)] tpl:bg-[var(--tpl-bg)] tpl:text-[var(--tpl-text)]"
131
+ }, null, 8, E)), [[te, H.value]]),
132
+ X.value ? (t(), l("p", D, s(d(V).testEmail.invalidAddress), 1)) : u("", !0)
133
+ ]),
134
+ f("div", O, [f("div", k, [f("span", A, s(d(V).testEmail.preview), 1), f("div", j, [h(pe, {
135
+ "sample-mode": K.value,
136
+ onChange: a[2] ||= (e) => K.value = e
137
+ }, null, 8, ["sample-mode"]), h(fe, {
138
+ viewport: U.value,
139
+ onChange: a[3] ||= (e) => U.value = e
140
+ }, null, 8, ["viewport"])])]), f("p", M, s(K.value ? d(V).testEmail.previewHintSample : d(V).testEmail.previewHint), 1)]),
141
+ f("div", N, [h(g, {
142
+ blocks: ve.value,
143
+ viewport: U.value
144
+ }, null, 8, ["blocks", "viewport"])]),
145
+ m.justSent ? (t(), l("p", P, [h(d(ue), {
146
+ size: 13,
147
+ "stroke-width": 2.5
148
+ }), p(" " + s(d(V).testEmail.success), 1)])) : Z.value ? (t(), l("p", F, s(Z.value), 1)) : u("", !0),
149
+ f("div", he, [f("button", {
150
+ type: "button",
151
+ "data-testid": "test-email-cancel",
152
+ class: ne(["tpl:cursor-pointer tpl:rounded-md tpl:border tpl:px-3 tpl:py-1.5 tpl:text-sm tpl:font-medium tpl:shadow-xs tpl:transition-all tpl:duration-150 tpl:border-[var(--tpl-border)] tpl:text-[var(--tpl-text)] tpl:bg-[var(--tpl-bg)]", { "tpl:cursor-not-allowed tpl:opacity-50": m.isSending }]),
153
+ disabled: m.isSending,
154
+ onClick: $
155
+ }, s(d(V).testEmail.cancel), 11, I), f("button", {
156
+ type: "button",
157
+ "data-testid": "test-email-send",
158
+ class: "tpl:cursor-pointer tpl:rounded-md tpl:px-3 tpl:py-1.5 tpl:text-sm tpl:font-medium tpl:shadow-xs tpl:transition-all tpl:duration-150 tpl:hover:opacity-90 tpl:disabled:cursor-not-allowed tpl:disabled:opacity-50 tpl:bg-[var(--tpl-primary)] tpl:text-[var(--tpl-bg)]",
159
+ disabled: !Y.value,
160
+ onClick: Q
161
+ }, [m.isSending ? (t(), l("span", R, [h(d(de), {
162
+ class: "tpl:animate-spin",
163
+ size: 12,
164
+ "stroke-width": 2
165
+ }), p(" " + s(d(V).testEmail.sending), 1)])) : (t(), l("span", ge, s(d(V).testEmail.send), 1))], 8, L)])
166
+ ], 8, y)]),
167
+ _: 1
168
+ }, 8, ["visible"]));
169
+ }
170
+ });
171
+ //#endregion
172
+ export { z as default };
173
+
174
+ //# sourceMappingURL=TestEmailModal-CiPfOn2v.js.map