collabmd 0.1.46 → 0.1.48

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 (317) hide show
  1. package/README.md +9 -5
  2. package/dist/client/assets/{CodeMirrorEditor-UCMRAMCV-CYM5nxUi.js → CodeMirrorEditor-UCMRAMCV-BPH4FJkv.js} +1 -1
  3. package/dist/client/assets/JetBrainsMono-Regular-BQaDgvhP.woff2 +0 -0
  4. package/dist/client/assets/{abnfDiagram-N423BO3Z-CUMTFJhI.js → abnfDiagram-VCTEODGH-BNDLzJ7L.js} +1 -1
  5. package/dist/client/assets/architecture-7GRP2DOG-BMOPAkUC.js +1 -0
  6. package/dist/client/assets/{architectureDiagram-T3A2C74G-w25m71oV.js → architectureDiagram-5GKGNRK7-I39sYjHI.js} +1 -1
  7. package/dist/client/assets/babel-CY5KOv-I.js +16 -0
  8. package/dist/client/assets/base-BYODPHdS.js +1 -0
  9. package/dist/client/assets/blockDiagram-NRAW4CY4-C6DtJy5Y.js +129 -0
  10. package/dist/client/assets/browser-BKLM0ThC-IxjwuOIz-BBqQnUEb.js +1 -0
  11. package/dist/client/assets/c4Diagram-UCG6FXSJ-CtWtxS9_.js +38 -0
  12. package/dist/client/assets/channel-CaoKA_We.js +1 -0
  13. package/dist/client/assets/{chunk-U6XO7XAA-BFxjP5U3.js → chunk-2ZTRR5NV-C2qZJila.js} +1 -1
  14. package/dist/client/assets/{chunk-YOTPTUD7-D0vRKqYp.js → chunk-3Z5EZCMW-DMniOlPd.js} +1 -1
  15. package/dist/client/assets/{chunk-BIQX33UG-DZEsGuSn.js → chunk-5V3GS4D5-i-ZDOEnP.js} +1 -1
  16. package/dist/client/assets/{chunk-MOZMSUNE-XVucA-n6.js → chunk-6AZGARVD-BB6FqMl-.js} +1 -1
  17. package/dist/client/assets/{chunk-5JV3BV7I-Cy5pj3QY.js → chunk-6EIED4P4-DdUJkP0f.js} +1 -1
  18. package/dist/client/assets/{chunk-R7FJI6CG-Cnn3gE-Y.js → chunk-6K3QC6MW-CqVsVn-y.js} +1 -1
  19. package/dist/client/assets/{chunk-OSBZ3O6U-CrKZOUOr.js → chunk-6TQVIW2G-DKlLbNIP.js} +1 -1
  20. package/dist/client/assets/{chunk-JG7HCLWE-BYfiSaVt.js → chunk-747NJXEK-BFkZPlab.js} +1 -1
  21. package/dist/client/assets/{chunk-NSK5VX7P-TLH37VXI.js → chunk-75Z2AOVW-CdFSaPjz.js} +1 -1
  22. package/dist/client/assets/chunk-CKBBP62Z-DG26UiBv.js +2 -0
  23. package/dist/client/assets/{chunk-3NCLNEKW-Y2Jf_LI-.js → chunk-CLGD4ZFX-DQLgbQrv.js} +1 -1
  24. package/dist/client/assets/chunk-DSNCTWBM-8xkug7fQ.js +2 -0
  25. package/dist/client/assets/chunk-DU6HZSFF-COXDzJK1.js +127 -0
  26. package/dist/client/assets/{chunk-2GRJ4B5K-DhnlUv3F.js → chunk-F27PBJKO-CNHIFhjo.js} +1 -1
  27. package/dist/client/assets/{chunk-YGJVY4SA-CjSe7Bx7.js → chunk-FLYJHZSQ-Be7lKF17.js} +1 -1
  28. package/dist/client/assets/{chunk-KEIR6QF5-BICK3FdT.js → chunk-FOHPRMQF-DHwB1DNv.js} +2 -2
  29. package/dist/client/assets/{chunk-5RXB4S5H-BWrwFqMI.js → chunk-G27WJ6UU-D9-eg537.js} +2 -2
  30. package/dist/client/assets/chunk-GMAD6QVW-CbcBqPM5.js +72 -0
  31. package/dist/client/assets/{chunk-QBLGF6JB-CxAyS2mW.js → chunk-I5DQTOEV-Hm2LfiYI.js} +1 -1
  32. package/dist/client/assets/{chunk-5FCAYU7R-Dh5nylU8.js → chunk-ICYGCRZG-749o-pGJ.js} +1 -1
  33. package/dist/client/assets/{chunk-CQNSW5MT-B8S09OIh.js → chunk-IH6LHLGP-CC6I9F3i.js} +1 -1
  34. package/dist/client/assets/chunk-JQ64N6SF-DSFNH4bh.js +1 -0
  35. package/dist/client/assets/{chunk-CYSBUYHQ-C1Rf4art.js → chunk-KI3K4JFJ-Rma-0k_M.js} +1 -1
  36. package/dist/client/assets/{chunk-GF5L2VYU-DkJpO7ff.js → chunk-LCL6LL3I-DmDkVukh.js} +1 -1
  37. package/dist/client/assets/chunk-LNGE3PJU-DWpGwHrW.js +34 -0
  38. package/dist/client/assets/chunk-OBVCFTLP-BJR7u1jh.js +1 -0
  39. package/dist/client/assets/{chunk-5TONJI2A-DQOY3q1H.js → chunk-OUJLGHUK-D0j2JRSg.js} +1 -1
  40. package/dist/client/assets/chunk-P2QGCYS3-BRpqY32H.js +1 -0
  41. package/dist/client/assets/{chunk-KBJHAD2P-CB_3zWUf.js → chunk-POPQ4Y6H-Cb4SlVZF.js} +1 -1
  42. package/dist/client/assets/{chunk-4I5QYGJK-CCB2YcIH.js → chunk-PWAF6VOD-Cz8IwBB5.js} +1 -1
  43. package/dist/client/assets/chunk-R7TYR2AO-CTd0Yj98.js +10 -0
  44. package/dist/client/assets/chunk-RHFEMEQ7-CWY8cf4H.js +168 -0
  45. package/dist/client/assets/chunk-RM4UPSZO-CWRwxNWJ.js +41 -0
  46. package/dist/client/assets/{chunk-6Q2QTUOP-CPlWzBtc.js → chunk-SVP7TREG-CyHOmcac.js} +1 -1
  47. package/dist/client/assets/chunk-TEH6E4GO-DVayPj-q.js +62 -0
  48. package/dist/client/assets/{chunk-EMLP6XTP-RLD4nXpI.js → chunk-UY3FDG6J-CnmaAkG5.js} +1 -1
  49. package/dist/client/assets/{chunk-5HE753X5-Bw-yg4kO.js → chunk-XHIXRSVI-BFQ6B8BE.js} +1 -1
  50. package/dist/client/assets/classDiagram-DTDB5LWJ-7fEmn0zV.js +1 -0
  51. package/dist/client/assets/classDiagram-v2-JRS7N3AN-7fEmn0zV.js +1 -0
  52. package/dist/client/assets/comment-ui-shared-DuoyznXW.js +7 -0
  53. package/dist/client/assets/cynefin-OW5HDTMX-7tP7QfM3.js +1 -0
  54. package/dist/client/assets/{cynefinDiagram-MW4NZA55-CJxXfJek.js → cynefinDiagram-5FMLGOSQ-CdTPi2yO.js} +1 -1
  55. package/dist/client/assets/dagre-3AP2YEHR-5gtJtd0O.js +4 -0
  56. package/dist/client/assets/dagre-PrKaheQc.js +1 -0
  57. package/dist/client/assets/{diagram-7IWD3JNH-B2d2Bm15.js → diagram-S7CK7UJ4-BudWz9WU.js} +4 -4
  58. package/dist/client/assets/{diagram-UB23O5K3-DJcKCwv9.js → diagram-UQ7AKVKN-3v4rbH-s.js} +1 -1
  59. package/dist/client/assets/{diagram-B4RE2ZJO-NP4UAwjR.js → diagram-VSXAHHWV-CQRVEZR7.js} +1 -1
  60. package/dist/client/assets/{diagram-Q27KOJAE-DylDuwor.js → diagram-VX7I27RA-C_-rj0sw.js} +1 -1
  61. package/dist/client/assets/{diagram-LBJQPF4R-D1FJQV8t.js → diagram-Z3DM3KII-B4yxavgj.js} +1 -1
  62. package/dist/client/assets/direct-engine-DdrQKpgq-CtKfQzCt.js +5 -0
  63. package/dist/client/assets/dist-73RPdcyU.js +1 -0
  64. package/dist/client/assets/{dist-Bm6pf9Bl.js → dist-BJ1bJs33.js} +1 -1
  65. package/dist/client/assets/{dist-BalScOwZ.js → dist-BK9QvQrc.js} +1 -1
  66. package/dist/client/assets/{dist-DLMiIsNC.js → dist-BPHLJ09L.js} +1 -1
  67. package/dist/client/assets/{dist-Bf8f4HmM.js → dist-B_yQaEv_.js} +1 -1
  68. package/dist/client/assets/{dist-CC5IrQMG.js → dist-BeajGMhO.js} +1 -1
  69. package/dist/client/assets/{dist-PDZ3bSqm.js → dist-Bw3VIE_v.js} +1 -1
  70. package/dist/client/assets/{dist-xElaxbia.js → dist-ByrG2qBA.js} +1 -1
  71. package/dist/client/assets/{dist-ule2n6ak.js → dist-C5NgpdG5.js} +1 -1
  72. package/dist/client/assets/dist-CH-sQu3r.js +1 -0
  73. package/dist/client/assets/dist-CKS_-are.js +1 -0
  74. package/dist/client/assets/{dist-D-Z6FLem.js → dist-CdmKGRGr.js} +1 -1
  75. package/dist/client/assets/dist-ChRoo3IB.js +9 -0
  76. package/dist/client/assets/{dist-dtAdgL39.js → dist-CietwTVS.js} +1 -1
  77. package/dist/client/assets/{dist-jv4WdPnK.js → dist-D37Hyu3h.js} +1 -1
  78. package/dist/client/assets/dist-D3fehAZ2.js +2 -0
  79. package/dist/client/assets/{dist-BEwK4csK.js → dist-D5wCC32z.js} +1 -1
  80. package/dist/client/assets/{dist-shrl6K_0.js → dist-DDUn5zTz.js} +1 -1
  81. package/dist/client/assets/{dist-CZgOmxK6.js → dist-DGEbEfw4.js} +1 -1
  82. package/dist/client/assets/{dist-B5HTH2BO.js → dist-DVy5woUy.js} +1 -1
  83. package/dist/client/assets/{dist-DZKu9Cs8.js → dist-DZAAWTG-.js} +1 -1
  84. package/dist/client/assets/{dist-TjMh8n1u.js → dist-Dir5dDKZ.js} +1 -1
  85. package/dist/client/assets/dist-Dl_tpDSr.js +1 -0
  86. package/dist/client/assets/{dist-FWJsgGYI.js → dist-DuH3ZrHo.js} +1 -1
  87. package/dist/client/assets/{dist-BjHJDtyU.js → dist-DutPuFmC.js} +1 -1
  88. package/dist/client/assets/{dist-Cqhv5LAk.js → dist-LQ4kDCKz.js} +1 -1
  89. package/dist/client/assets/{dist-CCP_AKPG.js → dist-RKBTaQMb.js} +1 -1
  90. package/dist/client/assets/{dist-BoVBdSjk.js → dist-Tw-Fxpeb.js} +1 -1
  91. package/dist/client/assets/dist-eBx8q6Sy.js +1 -0
  92. package/dist/client/assets/{dist-rGBmqxC7.js → dist-mj2Ht75J.js} +1 -1
  93. package/dist/client/assets/{dist-BDt3rz7l.js → dist-netZOQtD.js} +1 -1
  94. package/dist/client/assets/document-formatter-Dxl_a8XO.js +2 -0
  95. package/dist/client/assets/{drawio-editor-FzY1cVw8.js → drawio-editor-BVaNNtYp.js} +2 -2
  96. package/dist/client/assets/{drawioEditor-BjiKJqlc.js → drawioEditor-BkIBlXx0.js} +2 -2
  97. package/dist/client/assets/{ebnfDiagram-BXEA7PRR-nw0wmA6y.js → ebnfDiagram-PWID7BFC-OXa8VEp1.js} +1 -1
  98. package/dist/client/assets/editor-session-DMyVdHLj.js +54 -0
  99. package/dist/client/assets/embedded-editor-base-B3l6Xy65.css +1 -0
  100. package/dist/client/assets/embedpdf-BmE13ZZ0.js +1 -0
  101. package/dist/client/assets/embedpdf-DA4bA119-BPqZxwjc.js +2363 -0
  102. package/dist/client/assets/{en-7NFCYGKX-BrgYZAEe.js → en-SJ2YIMFF-CJBL3nkq.js} +1 -1
  103. package/dist/client/assets/erDiagram-SSCWMZ5O-C-iy6VkX.js +99 -0
  104. package/dist/client/assets/estree-CuT_pB8K.js +44 -0
  105. package/dist/client/assets/eventmodeling-NTZA5JFV-BR2FzK4R.js +1 -0
  106. package/dist/client/assets/excalidraw-editor-BbSbI80a.css +1 -0
  107. package/dist/client/assets/excalidraw-editor-BjYaNEMY.js +9 -0
  108. package/dist/client/assets/excalidrawEditor-ChqF_d82.js +2 -0
  109. package/dist/client/assets/export-page-Dyu0XCbu.js +57 -0
  110. package/dist/client/assets/exportDocument-CJBx4Xjx.css +1 -0
  111. package/dist/client/assets/exportDocument-Dgvfa2Sd.js +2 -0
  112. package/dist/client/assets/{file-icon-svg-CQAjlWjK.js → file-icon-svg-Y_kpF957.js} +1 -1
  113. package/dist/client/assets/file-kind-BwMIcZbi.js +1 -0
  114. package/dist/client/assets/file-search-DDLyyLDU.js +1 -0
  115. package/dist/client/assets/flowDiagram-A5DVABFB-CiW1eN8C.js +1 -0
  116. package/dist/client/assets/{ganttDiagram-PKOTCBZU-BnM97BCT.js → ganttDiagram-EL5Y4UJY-DtKHAbez.js} +1 -1
  117. package/dist/client/assets/gitGraph-4MIJSDKK-DYlXv_yJ.js +1 -0
  118. package/dist/client/assets/{gitGraphDiagram-DS77QQ5N-BQpQhjuN.js → gitGraphDiagram-WWUBYQGX-oue8fQ5o.js} +1 -1
  119. package/dist/client/assets/github-dark.min-BV82VuKq.css +1 -0
  120. package/dist/client/assets/github.min-v3dd8CNH.css +1 -0
  121. package/dist/client/assets/html-Cdnr2qzU.js +25 -0
  122. package/dist/client/assets/image-ZVKINSPA-0zXSnE7M.js +1 -0
  123. package/dist/client/assets/index-CSNIMyOP.css +1 -0
  124. package/dist/client/assets/index-DG3N2Ps-.js +2 -0
  125. package/dist/client/assets/info-A6RAGUB7-BlU-8_xu.js +1 -0
  126. package/dist/client/assets/{infoDiagram-6WML65LV-DYB8HCDQ.js → infoDiagram-RXCK75RN-BMzo6KIn.js} +1 -1
  127. package/dist/client/assets/{ishikawaDiagram-WSZJBQD7-Coz_P3t6.js → ishikawaDiagram-5VMMS53U-BIM3h287.js} +1 -1
  128. package/dist/client/assets/{journeyDiagram-NVQOT4AX-B6edChce.js → journeyDiagram-EYS64GPL-mF6Lh8O-.js} +1 -1
  129. package/dist/client/assets/{kanban-definition-27J2QSJJ-BFd9-cLc.js → kanban-definition-3QL26DDD-DLN2NyoR.js} +2 -2
  130. package/dist/client/assets/{line-B_S_S8kV.js → line-BfTWJmgf.js} +1 -1
  131. package/dist/client/assets/main-D0wCxpVn.js +903 -0
  132. package/dist/client/assets/markdown-CByV-4CU.js +70 -0
  133. package/dist/client/assets/{mermaid-parser.core-CUVdebAV.js → mermaid-parser.core-Bl0efOMt.js} +2 -2
  134. package/dist/client/assets/mermaid.core-BJRLUQZE.js +11 -0
  135. package/dist/client/assets/{mindmap-definition-FAOFIHXS-C9PQ38Al.js → mindmap-definition-FBJOCRG2-CRyHaHTk.js} +1 -1
  136. package/dist/client/assets/packet-AYTQ26CC-BSJEH9Lb.js +1 -0
  137. package/dist/client/assets/pdfium-RAgkpwfK.wasm +0 -0
  138. package/dist/client/assets/{pegDiagram-VL7TDLO6-BMZUrSaU.js → pegDiagram-XKGWAZYB-B31fKPR2.js} +1 -1
  139. package/dist/client/assets/pie-WAS4IAKB-qxv01Y8W.js +1 -0
  140. package/dist/client/assets/{pieDiagram-7S7Q4E2Y-h8kbCL9o.js → pieDiagram-E7YTZNPT-B5OZPb88.js} +1 -1
  141. package/dist/client/assets/preview-render-compiler-CrJIooVD.js +35 -0
  142. package/dist/client/assets/preview-render-compiler-O0JxBVNF.js +1 -0
  143. package/dist/client/assets/{preview-render-profile-CE-5rVTC.js → preview-render-profile-B4RWYWHt.js} +1 -1
  144. package/dist/client/assets/preview-render-worker-_QTxqKvP.js +60 -0
  145. package/dist/client/assets/prod-BiYPMR1i.js +177 -0
  146. package/dist/client/assets/prod-VxdGZ5Ly.js +1 -0
  147. package/dist/client/assets/{quadrantDiagram-CIZ2JOQS-CkElyfMi.js → quadrantDiagram-AXDQQJYC-Drrw14YH.js} +1 -1
  148. package/dist/client/assets/quick-switcher-controller-CaEjEtq_.js +1 -0
  149. package/dist/client/assets/radar-RG4KPBEZ-B6h6pWOs.js +1 -0
  150. package/dist/client/assets/railroad-74A4TZTK-CGtTWdGc.js +1 -0
  151. package/dist/client/assets/railroad-abnf-HS5TGJTU-Cq7y22IA.js +1 -0
  152. package/dist/client/assets/railroad-ebnf-LZEXJU2U-V0aQVv9m.js +1 -0
  153. package/dist/client/assets/railroad-peg-WCYAUIDC-BQiIsX_p.js +1 -0
  154. package/dist/client/assets/{railroadDiagram-AXF67PYL-c75gnikD.js → railroadDiagram-O6MQD6OU-BPifP0MB.js} +1 -1
  155. package/dist/client/assets/{requirementDiagram-LRYGKXZP-mNxKLuHS.js → requirementDiagram-EFPCY7ZU-CRZG6mRB.js} +2 -2
  156. package/dist/client/assets/{sankeyDiagram-W5VNT64P-0OhplksI.js → sankeyDiagram-P5KCCOFB-DvarEJpo.js} +1 -1
  157. package/dist/client/assets/{sequenceDiagram-SI44F4Z6-BJ_yAocC.js → sequenceDiagram-WJ2MYXX4-B4oWlb-w.js} +1 -1
  158. package/dist/client/assets/standalone-6z5x8CWe.js +29 -0
  159. package/dist/client/assets/{stateDiagram-OKZ733FA-Cc83O86s.js → stateDiagram-HBIQ2CUA-qbHIIqRZ.js} +1 -1
  160. package/dist/client/assets/stateDiagram-v2-4QOOHH4V-B--gjrit.js +1 -0
  161. package/dist/client/assets/swimlanes-XN3QIQJK-xB6CtUGj.js +1 -0
  162. package/dist/client/assets/swimlanesDiagram-VK2B7HYN-DO8XNXEg.js +8 -0
  163. package/dist/client/assets/{timeline-definition-Z64GVDOM-BWDAGTHz.js → timeline-definition-24CTP7MA-Lj_yTNlY.js} +1 -1
  164. package/dist/client/assets/treeView-Q6P3EWNA-BTTYcvrF.js +1 -0
  165. package/dist/client/assets/treemap-WGGIJYW6-Cg7tyfH8.js +1 -0
  166. package/dist/client/assets/{vault-api-client-_LpV1aIn.js → vault-api-client-BkwdFjx0.js} +2 -2
  167. package/dist/client/assets/vault-utils-DvoSftJT.js +22 -0
  168. package/dist/client/assets/{vennDiagram-T6HMQDX7-LOSsnlMB.js → vennDiagram-4TSXK5OY-BekRp5Y0.js} +1 -1
  169. package/dist/client/assets/wardley-WFR3VGLG-C6N1rULY.js +1 -0
  170. package/dist/client/assets/{wardleyDiagram-T6FBY63Y-BxII3foY.js → wardleyDiagram-VM6X3IG4-kdnV_Hdm.js} +1 -1
  171. package/dist/client/assets/worker-engine-m0rlHn8R-S8mpn_O0.js +17369 -0
  172. package/dist/client/assets/{xychartDiagram-ELKLHX3M-B-pTEjju.js → xychartDiagram-S5SC5T6Z-DufGwNSB.js} +3 -3
  173. package/dist/client/assets/yaml-9ltHPDNO.js +154 -0
  174. package/dist/client/drawio-editor.html +1 -1
  175. package/dist/client/excalidraw-editor.html +1 -1
  176. package/dist/client/export-document.html +3 -3
  177. package/dist/client/index.html +56 -24
  178. package/package.json +22 -18
  179. package/src/client/app/index.html +53 -21
  180. package/src/client/application/app-shell/comments-feature.js +2 -3
  181. package/src/client/application/app-shell/export-feature.js +17 -1
  182. package/src/client/application/app-shell/git-feature.js +30 -11
  183. package/src/client/application/app-shell/presence-feature.js +2 -2
  184. package/src/client/application/app-shell/ui-feature-identity.js +13 -0
  185. package/src/client/application/app-shell/ui-feature-shell.js +228 -9
  186. package/src/client/application/app-shell-elements.js +5 -0
  187. package/src/client/application/pdf-preview-controller.js +53 -970
  188. package/src/client/application/preview-render-compiler.js +3 -0
  189. package/src/client/application/quick-switcher-loader.js +1 -1
  190. package/src/client/application/workspace-coordinator.js +21 -4
  191. package/src/client/application/workspace-preview-controller.js +120 -5
  192. package/src/client/application/workspace-route-controller.js +4 -1
  193. package/src/client/assets/vendor/highlight/github-dark.min.css +2 -10
  194. package/src/client/assets/vendor/highlight/github.min.css +2 -10
  195. package/src/client/assets/vendor/jetbrains-mono/JetBrainsMono-Regular.woff2 +0 -0
  196. package/src/client/assets/vendor/jetbrains-mono/OFL.txt +93 -0
  197. package/src/client/bootstrap/collabmd-app-shell.js +31 -8
  198. package/src/client/domain/document-formatter.js +193 -0
  199. package/src/client/domain/file-search.js +73 -0
  200. package/src/client/domain/git-labels.js +5 -0
  201. package/src/client/domain/vault-paths.js +6 -4
  202. package/src/client/domain/wiki-link-completions.js +20 -20
  203. package/src/client/drawio-editor.js +8 -3
  204. package/src/client/excalidraw-editor.js +163 -6
  205. package/src/client/export/export-host.js +57 -36
  206. package/src/client/export/export-page.js +20 -6
  207. package/src/client/export/export-pipeline.js +322 -22
  208. package/src/client/infrastructure/editor-session.js +4 -0
  209. package/src/client/infrastructure/editor-view-adapter.js +60 -14
  210. package/src/client/presentation/bases-preview-controller.js +35 -11
  211. package/src/client/presentation/comment-ui/comment-ui-render.js +4 -0
  212. package/src/client/presentation/comment-ui-controller.js +2 -0
  213. package/src/client/presentation/excalidraw-embed-controller.js +7 -0
  214. package/src/client/presentation/file-action-controller.js +15 -2
  215. package/src/client/presentation/file-explorer-controller.js +3 -5
  216. package/src/client/presentation/file-explorer-view.js +43 -45
  217. package/src/client/presentation/file-history-view-controller.js +6 -1
  218. package/src/client/presentation/file-tree-state.js +5 -14
  219. package/src/client/presentation/git-diff-view-controller.js +36 -11
  220. package/src/client/presentation/git-panel-controller.js +12 -8
  221. package/src/client/presentation/quick-switcher-controller.js +92 -153
  222. package/src/client/styles/components/scrollbars.css +10 -0
  223. package/src/client/styles/export-document.css +44 -29
  224. package/src/client/styles/features/collaboration-presence.css +13 -1
  225. package/src/client/styles/features/preview-markdown.css +79 -0
  226. package/src/client/styles/features/quick-switcher.css +8 -0
  227. package/src/client/styles/foundation/themes.css +1 -0
  228. package/src/client/styles/foundation/tokens.css +8 -0
  229. package/src/client/styles/layout/shell.css +73 -339
  230. package/src/client/styles/layout/sidebar.css +42 -4
  231. package/src/client/styles/layout/view-modes.css +2 -0
  232. package/src/client/styles/overrides/codemirror.css +31 -19
  233. package/src/client/styles/overrides/highlightjs.css +20 -4
  234. package/src/client/styles/surfaces/excalidraw-editor.css +42 -0
  235. package/src/domain/file-kind.js +12 -1
  236. package/src/server/domain/ripgrep-search-service.js +110 -37
  237. package/src/server/infrastructure/git/git-service.js +23 -11
  238. package/src/server/infrastructure/http/create-git-api-command-handler.js +3 -1
  239. package/src/server/infrastructure/http/create-structurizr-api-handler.js +4 -2
  240. package/src/server/infrastructure/persistence/path-utils.js +10 -4
  241. package/src/server/infrastructure/persistence/vault-file-store.js +2 -0
  242. package/src/server/infrastructure/structurizr/structurizr-workspace-service.js +33 -7
  243. package/dist/client/assets/architecture-TIHT7OUA-CsHfPErM.js +0 -1
  244. package/dist/client/assets/base-CxPEiHuy.js +0 -1
  245. package/dist/client/assets/blockDiagram-VBNYF7ZC-CipJt9Jl.js +0 -132
  246. package/dist/client/assets/c4Diagram-5PPSVZJV-B5ktVx6g.js +0 -10
  247. package/dist/client/assets/channel-4Jkmq93I.js +0 -1
  248. package/dist/client/assets/chunk-7BUUIJ7U-Bb538aSH.js +0 -1
  249. package/dist/client/assets/chunk-7Z6QIM7H-BP9Pdsm9.js +0 -10
  250. package/dist/client/assets/chunk-ERSWUTIN-hHdvnhaY.js +0 -41
  251. package/dist/client/assets/chunk-I66GZJ75-CVFiiffQ.js +0 -127
  252. package/dist/client/assets/chunk-J7OUQ5F2-4CEb7pvH.js +0 -2
  253. package/dist/client/assets/chunk-JQJVKLGR-cx8X_24v.js +0 -156
  254. package/dist/client/assets/chunk-QR6OTTB3-CDAA_5Ib.js +0 -62
  255. package/dist/client/assets/chunk-RYQCIY6F-D-a0zH8K.js +0 -1
  256. package/dist/client/assets/chunk-UBXNYLIW-Bhk-PbFK.js +0 -1
  257. package/dist/client/assets/chunk-W5SLKNZC-BdNSCxZ9.js +0 -1
  258. package/dist/client/assets/chunk-WRU74C26-h6_XkD3_.js +0 -70
  259. package/dist/client/assets/chunk-ZIRB5QZD-O39ZBUk3.js +0 -32
  260. package/dist/client/assets/classDiagram-JCYQIIEL-L7lsyW_w.js +0 -1
  261. package/dist/client/assets/classDiagram-v2-OCEON4UE-L7lsyW_w.js +0 -1
  262. package/dist/client/assets/comment-ui-shared-BC4pt4w8.js +0 -7
  263. package/dist/client/assets/cynefin-VYW2F7L2-Ds2Fw2Y0.js +0 -1
  264. package/dist/client/assets/dagre-Buvkdvvj.js +0 -1
  265. package/dist/client/assets/dagre-VZM6K2ZE-L1xArOGs.js +0 -4
  266. package/dist/client/assets/dist-B5Jf1SLZ.js +0 -2
  267. package/dist/client/assets/dist-BKW4PALF.js +0 -1
  268. package/dist/client/assets/dist-BWcHHOx-.js +0 -1
  269. package/dist/client/assets/dist-DaYdhcVs.js +0 -1
  270. package/dist/client/assets/dist-Kh2COra_.js +0 -1
  271. package/dist/client/assets/dist-tOaegDYS2.js +0 -1
  272. package/dist/client/assets/editor-session-Cm9ekeNo.js +0 -54
  273. package/dist/client/assets/embedded-editor-base-CwTkk911.css +0 -1
  274. package/dist/client/assets/erDiagram-JOGREHBK-cYUpEKpf.js +0 -85
  275. package/dist/client/assets/es-DXGV3RHd.js +0 -22
  276. package/dist/client/assets/eventmodeling-45OFAUF4-CLEiVx5s.js +0 -1
  277. package/dist/client/assets/excalidraw-editor-B46zsTFI.js +0 -9
  278. package/dist/client/assets/excalidraw-editor-Bt7gMSoh.css +0 -1
  279. package/dist/client/assets/excalidrawEditor-CT2pHq7e.js +0 -2
  280. package/dist/client/assets/export-page-A7NHawJY.js +0 -39
  281. package/dist/client/assets/exportDocument-B2L8fe34.css +0 -1
  282. package/dist/client/assets/exportDocument-BaqcOAAW.js +0 -2
  283. package/dist/client/assets/file-kind-BbqgGzpc.js +0 -1
  284. package/dist/client/assets/flowDiagram-UKHOOZJN-D0ypP0Ez.js +0 -1
  285. package/dist/client/assets/gitGraph-TEB2WS4Q-CZFBqwW-.js +0 -1
  286. package/dist/client/assets/github-dark.min-Z5exjX_n.css +0 -1
  287. package/dist/client/assets/github.min-D2BCvnWf.css +0 -1
  288. package/dist/client/assets/image-QXRYHUNP-SWEV8H0J.js +0 -1
  289. package/dist/client/assets/index-ClbjMBVt.js +0 -2
  290. package/dist/client/assets/index-Pum8ET-5.css +0 -1
  291. package/dist/client/assets/info-DKCQHKI2--1InqQeT.js +0 -1
  292. package/dist/client/assets/main-B3uPyqic.js +0 -893
  293. package/dist/client/assets/map-BaFkSB1l.js +0 -1
  294. package/dist/client/assets/mermaid.core-DN-lF51U.js +0 -11
  295. package/dist/client/assets/packet-7NZHBO7P-BGMXB0XL.js +0 -1
  296. package/dist/client/assets/pdf-BL9Pr2D5.js +0 -54
  297. package/dist/client/assets/pdf.worker-CLesOks4.mjs +0 -64857
  298. package/dist/client/assets/pdf_viewer-FVkkThnz.js +0 -551
  299. package/dist/client/assets/pie-RZYD4A2V-DgYg3tCt.js +0 -1
  300. package/dist/client/assets/preview-render-compiler-BD-XhkS2.js +0 -35
  301. package/dist/client/assets/preview-render-compiler-BKedaMxx.js +0 -1
  302. package/dist/client/assets/preview-render-worker-CiPqc9n6.js +0 -60
  303. package/dist/client/assets/prod-Dy20X7eT.js +0 -1
  304. package/dist/client/assets/prod-hnwh7wRM.js +0 -177
  305. package/dist/client/assets/quick-switcher-controller-fqOYR7qR.js +0 -12
  306. package/dist/client/assets/radar-I7S5WNFK-Ag-zp_Rq.js +0 -1
  307. package/dist/client/assets/railroad-3IZDKUUU-aibJDIDV.js +0 -1
  308. package/dist/client/assets/railroad-abnf-AHOZXSZD-BBMEuvIl.js +0 -1
  309. package/dist/client/assets/railroad-ebnf-EBAXGLYW-Be1nseej.js +0 -1
  310. package/dist/client/assets/railroad-peg-LSFZ7HO6-DIvD-Eyb.js +0 -1
  311. package/dist/client/assets/stateDiagram-v2-UEYNNEHI-B1-BufUk.js +0 -1
  312. package/dist/client/assets/swimlanes-SLNWSIFB-oVTWEJIj.js +0 -2
  313. package/dist/client/assets/swimlanesDiagram-ULZ7WXOC-C5OTVwEu.js +0 -8
  314. package/dist/client/assets/treeView-QDETBFTQ-uHZ-3Fz8.js +0 -1
  315. package/dist/client/assets/treemap-6X3UGDF4-BnUKyy3l.js +0 -1
  316. package/dist/client/assets/vault-utils-wdQ0RNR9.js +0 -1
  317. package/dist/client/assets/wardley-OPB4EBWU-Da7TLC2F.js +0 -1
@@ -2,14 +2,11 @@ import { vim } from '@replit/codemirror-vim';
2
2
  import { autocompletion, closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
3
3
  import {
4
4
  defaultKeymap,
5
- history,
6
- historyKeymap,
7
5
  indentLess,
8
6
  indentMore,
9
7
  indentWithTab,
10
- redo,
11
- undo,
12
8
  } from '@codemirror/commands';
9
+ import { html } from '@codemirror/lang-html';
13
10
  import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
14
11
  import { yaml } from '@codemirror/lang-yaml';
15
12
  import {
@@ -44,15 +41,17 @@ import {
44
41
  lineNumbers,
45
42
  rectangularSelection,
46
43
  } from '@codemirror/view';
47
- import { yCollab } from 'y-codemirror.next';
44
+ import { yCollab, yUndoManagerKeymap } from 'y-codemirror.next';
48
45
 
49
46
  import {
50
47
  isBaseFilePath,
48
+ isHtmlFilePath,
51
49
  isMermaidFilePath,
52
50
  isPlantUmlFilePath,
53
51
  isStructurizrFilePath,
54
52
  } from '../../domain/file-kind.js';
55
53
  import { normalizeCommentQuote } from '../../domain/comment-threads.js';
54
+ import { formatDocumentText } from '../domain/document-formatter.js';
56
55
  import { createMarkdownToolbarEdit } from '../domain/markdown-formatting.js';
57
56
  import { mermaidLanguage, mermaidLanguageDescription } from '../domain/mermaid-language.js';
58
57
  import { wikiLinkCompletions } from '../domain/wiki-link-completions.js';
@@ -149,8 +148,6 @@ const EDITOR_COMMANDS = Object.freeze({
149
148
  indentLess,
150
149
  indentMore,
151
150
  openSearch: openSearchPanelPreservingViewport,
152
- redo,
153
- undo,
154
151
  });
155
152
 
156
153
  class RemoteUpdateCaretWidget extends WidgetType {
@@ -391,6 +388,10 @@ function createEditorTheme(theme) {
391
388
  }
392
389
 
393
390
  export function createLanguageExtension(filePath) {
391
+ if (isHtmlFilePath(filePath)) {
392
+ return html();
393
+ }
394
+
394
395
  if (isMermaidFilePath(filePath)) {
395
396
  return mermaidLanguage;
396
397
  }
@@ -441,6 +442,7 @@ export class EditorViewAdapter {
441
442
  this.onSelectionChanged = onSelectionChanged;
442
443
  this.onViewportChanged = onViewportChanged;
443
444
  this.editorView = null;
445
+ this.undoManager = null;
444
446
  this.themeCompartment = new Compartment();
445
447
  this.syntaxThemeCompartment = new Compartment();
446
448
  this.lineWrappingCompartment = new Compartment();
@@ -477,11 +479,11 @@ export class EditorViewAdapter {
477
479
  }
478
480
 
479
481
  getBaseExtensions(filePath, { readOnly = false } = {}) {
482
+ const wikiLinkCompletionSource = wikiLinkCompletions(this.getFileList);
480
483
  const extensions = [
481
484
  lineNumbers(),
482
485
  highlightActiveLineGutter(),
483
486
  highlightSpecialChars(),
484
- history(),
485
487
  foldGutter(),
486
488
  drawSelection(),
487
489
  EditorState.allowMultipleSelections.of(true),
@@ -489,9 +491,10 @@ export class EditorViewAdapter {
489
491
  syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
490
492
  bracketMatching({ renderMatch: renderBracketMatch }),
491
493
  closeBrackets(),
492
- autocompletion({
493
- override: [wikiLinkCompletions(this.getFileList)],
494
- }),
494
+ autocompletion(),
495
+ EditorState.languageData.of(() => [{
496
+ autocomplete: wikiLinkCompletionSource,
497
+ }]),
495
498
  rectangularSelection(),
496
499
  crosshairCursor(),
497
500
  highlightActiveLine(),
@@ -501,7 +504,6 @@ export class EditorViewAdapter {
501
504
  keymap.of([
502
505
  ...closeBracketsKeymap,
503
506
  ...defaultKeymap,
504
- ...historyKeymap,
505
507
  ...searchKeymap.map((binding) => (
506
508
  binding.run === openSearchPanel
507
509
  ? { ...binding, run: openSearchPanelPreservingViewport }
@@ -593,10 +595,12 @@ export class EditorViewAdapter {
593
595
 
594
596
  initialize({ awareness, filePath, undoManager, ytext }) {
595
597
  const preserveScrollTop = this.editorView?.scrollDOM?.scrollTop ?? 0;
598
+ this.undoManager = undoManager;
596
599
  const state = EditorState.create({
597
600
  doc: ytext.toString(),
598
601
  extensions: [
599
602
  ...this.getBaseExtensions(filePath),
603
+ keymap.of(yUndoManagerKeymap),
600
604
  yCollab(ytext, awareness, { undoManager }),
601
605
  ],
602
606
  });
@@ -609,6 +613,7 @@ export class EditorViewAdapter {
609
613
 
610
614
  initializeProvisional({ content = '', filePath }) {
611
615
  const preserveScrollTop = this.editorView?.scrollDOM?.scrollTop ?? 0;
616
+ this.undoManager = null;
612
617
  const state = EditorState.create({
613
618
  doc: String(content ?? ''),
614
619
  extensions: this.getBaseExtensions(filePath, { readOnly: true }),
@@ -629,6 +634,7 @@ export class EditorViewAdapter {
629
634
  clearTimeout(this.remoteUpdateFlashTimer);
630
635
  this.remoteUpdateFlashTimer = 0;
631
636
  }
637
+ this.undoManager = null;
632
638
  this.teardownEditorView({ clearContainer: true });
633
639
  }
634
640
 
@@ -709,18 +715,58 @@ export class EditorViewAdapter {
709
715
  this.editorView?.requestMeasure();
710
716
  }
711
717
 
718
+ async formatDocument(filePath) {
719
+ const view = this.editorView;
720
+ if (!view || view.state.readOnly) {
721
+ return 'unsupported';
722
+ }
723
+
724
+ const source = view.state.doc.toString();
725
+ const formatted = await formatDocumentText(filePath, source);
726
+ if (formatted == null) {
727
+ return 'unsupported';
728
+ }
729
+ if (this.editorView !== view || view.state.doc.toString() !== source) {
730
+ return 'changed';
731
+ }
732
+ if (formatted === source) {
733
+ return 'unchanged';
734
+ }
735
+
736
+ const selection = EditorSelection.create(view.state.selection.ranges.map(({ anchor, head }) => (
737
+ EditorSelection.range(Math.min(anchor, formatted.length), Math.min(head, formatted.length))
738
+ )));
739
+ view.dispatch({
740
+ changes: { from: 0, to: source.length, insert: formatted },
741
+ selection,
742
+ scrollIntoView: true,
743
+ userEvent: 'input.format',
744
+ });
745
+ view.focus();
746
+ return 'formatted';
747
+ }
748
+
712
749
  runEditorCommand(commandId) {
713
750
  if (!this.editorView) {
714
751
  return false;
715
752
  }
716
753
 
717
- const command = EDITOR_COMMANDS[String(commandId ?? '')];
754
+ const normalizedCommandId = String(commandId ?? '');
755
+ if ((normalizedCommandId === 'undo' || normalizedCommandId === 'redo') && this.undoManager) {
756
+ const applied = this.undoManager[normalizedCommandId]() != null;
757
+ if (applied) {
758
+ this.editorView.focus();
759
+ }
760
+ return applied;
761
+ }
762
+
763
+ const command = EDITOR_COMMANDS[normalizedCommandId];
718
764
  if (typeof command !== 'function') {
719
765
  return false;
720
766
  }
721
767
 
722
768
  const applied = command(this.editorView);
723
- if (applied && commandId !== 'openSearch') {
769
+ if (applied && normalizedCommandId !== 'openSearch') {
724
770
  this.editorView.focus();
725
771
  }
726
772
 
@@ -10,6 +10,26 @@ function createShellKey() {
10
10
  return `base-${Math.random().toString(36).slice(2, 10)}`;
11
11
  }
12
12
 
13
+ function replaceChildrenFromHtml(target, html) {
14
+ const markup = String(html ?? '');
15
+ if (typeof DOMParser === 'function' && typeof target?.replaceChildren === 'function') {
16
+ const parsed = new DOMParser().parseFromString(`<body>${markup}</body>`, 'text/html');
17
+ target.replaceChildren(...parsed.body.childNodes);
18
+ return;
19
+ }
20
+
21
+ // Node tests use lightweight DOM doubles without parsing APIs.
22
+ Reflect.set(target, 'innerHTML', markup);
23
+ }
24
+
25
+ function insertAfterFromHtml(target, html) {
26
+ if (typeof DOMParser !== 'function' || typeof target?.after !== 'function') {
27
+ return;
28
+ }
29
+ const parsed = new DOMParser().parseFromString(`<body>${String(html ?? '')}</body>`, 'text/html');
30
+ target.after(...parsed.body.childNodes);
31
+ }
32
+
13
33
  function looksLikeHexColor(value = '') {
14
34
  return /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/iu.test(String(value ?? '').trim());
15
35
  }
@@ -617,7 +637,11 @@ function parseRawFilterText(text = '') {
617
637
  }
618
638
 
619
639
  if (normalized.startsWith('{') || normalized.startsWith('[')) {
620
- return JSON.parse(normalized);
640
+ try {
641
+ return JSON.parse(normalized);
642
+ } catch (error) {
643
+ throw new Error('Invalid advanced filter JSON', { cause: error });
644
+ }
621
645
  }
622
646
 
623
647
  return normalized;
@@ -814,7 +838,7 @@ function syncFilterValueCombobox(entry, result, path, { fallbackToFullRender = t
814
838
  const suggestionList = combobox.querySelector('.bases-filter-suggestion-list');
815
839
  suggestionList?.remove?.();
816
840
  if (presentation.suggestionsEnabled) {
817
- input.insertAdjacentHTML('afterend', renderFilterSuggestionList(presentation, rule.value ?? ''));
841
+ insertAfterFromHtml(input, renderFilterSuggestionList(presentation, rule.value ?? ''));
818
842
  }
819
843
 
820
844
  return true;
@@ -1091,14 +1115,14 @@ function updateShellContent(entry, result, {
1091
1115
  } = {}) {
1092
1116
  const shell = findShellElement(entry);
1093
1117
  if (!shell?.querySelector) {
1094
- entry.placeholder.innerHTML = renderShellHtml(result, entry);
1118
+ replaceChildrenFromHtml(entry.placeholder, renderShellHtml(result, entry));
1095
1119
  markPlaceholderHydrated(entry.placeholder);
1096
1120
  return;
1097
1121
  }
1098
1122
 
1099
1123
  const tabsSlot = shell.querySelector('[data-base-tabs]');
1100
1124
  if (tabs && tabsSlot) {
1101
- tabsSlot.innerHTML = renderViewTabs(result);
1125
+ replaceChildrenFromHtml(tabsSlot, renderViewTabs(result));
1102
1126
  }
1103
1127
 
1104
1128
  const metaSlot = shell.querySelector('[data-base-meta]');
@@ -1108,24 +1132,24 @@ function updateShellContent(entry, result, {
1108
1132
 
1109
1133
  const actionSlot = shell.querySelector('[data-base-action-slot]');
1110
1134
  if (actions && actionSlot) {
1111
- actionSlot.innerHTML = renderActionButtons(result, entry);
1135
+ replaceChildrenFromHtml(actionSlot, renderActionButtons(result, entry));
1112
1136
  }
1113
1137
 
1114
1138
  const panelSlot = shell.querySelector('[data-base-panel-slot]');
1115
1139
  if (panel && panelSlot) {
1116
1140
  const panelState = capturePanelState(panelSlot);
1117
- panelSlot.innerHTML = renderPanel(result, entry);
1141
+ replaceChildrenFromHtml(panelSlot, renderPanel(result, entry));
1118
1142
  restorePanelState(panelSlot, panelState);
1119
1143
  }
1120
1144
 
1121
1145
  const summarySlot = shell.querySelector('[data-base-summary-slot]');
1122
1146
  if (summary && summarySlot) {
1123
- summarySlot.innerHTML = renderSummaryBar(result.summaries);
1147
+ replaceChildrenFromHtml(summarySlot, renderSummaryBar(result.summaries));
1124
1148
  }
1125
1149
 
1126
1150
  const content = shell.querySelector('[data-base-content]');
1127
1151
  if (body && content) {
1128
- content.innerHTML = renderViewBody(result);
1152
+ replaceChildrenFromHtml(content, renderViewBody(result));
1129
1153
  }
1130
1154
 
1131
1155
  const input = shell.querySelector('.bases-search-input');
@@ -1663,7 +1687,7 @@ export class BasesPreviewController {
1663
1687
  entry.requestVersion = requestVersion;
1664
1688
  const hasShell = Boolean(findShellElement(entry));
1665
1689
  if (!hasShell) {
1666
- entry.placeholder.innerHTML = '<div class="preview-shell">Loading base…</div>';
1690
+ replaceChildrenFromHtml(entry.placeholder, '<div class="preview-shell">Loading base…</div>');
1667
1691
  }
1668
1692
  try {
1669
1693
  const response = await this.vaultApiClient.queryBase({
@@ -1687,11 +1711,11 @@ export class BasesPreviewController {
1687
1711
  const shell = findShellElement(entry);
1688
1712
  const content = shell?.querySelector?.('[data-base-content]') ?? null;
1689
1713
  if (content) {
1690
- content.innerHTML = `<div class="preview-shell">Failed to load base: ${escapeHtml(error.message || 'Unknown error')}</div>`;
1714
+ replaceChildrenFromHtml(content, `<div class="preview-shell">Failed to load base: ${escapeHtml(error.message || 'Unknown error')}</div>`);
1691
1715
  return;
1692
1716
  }
1693
1717
  }
1694
- entry.placeholder.innerHTML = `<div class="preview-shell">Failed to load base: ${escapeHtml(error.message || 'Unknown error')}</div>`;
1718
+ replaceChildrenFromHtml(entry.placeholder, `<div class="preview-shell">Failed to load base: ${escapeHtml(error.message || 'Unknown error')}</div>`);
1695
1719
  }
1696
1720
  }
1697
1721
 
@@ -17,6 +17,7 @@ import {
17
17
  * @property {HTMLElement | null} commentsDrawerList
18
18
  * @property {HTMLElement | null} commentsDrawerEmpty
19
19
  * @property {HTMLElement | null} cardRoot
20
+ * @property {{ matches: boolean }} mobileBreakpointQuery
20
21
  * @property {HTMLElement | null} pendingCardFocusElement
21
22
  * @property {any} reactionPicker
22
23
  * @property {() => Array<any>} getThreadGroups
@@ -103,6 +104,9 @@ function renderDrawer() {
103
104
  });
104
105
  button.addEventListener('click', () => {
105
106
  this.onNavigateToLine?.(group.anchor?.startLine ?? 1);
107
+ if (this.mobileBreakpointQuery?.matches) {
108
+ this.setDrawerOpen(false);
109
+ }
106
110
  this.openThreadGroup(group, {
107
111
  anchor: group.anchor,
108
112
  origin: 'editor',
@@ -12,6 +12,7 @@ export class CommentUiController {
12
12
  commentsDrawerList,
13
13
  commentsToggleButton,
14
14
  editorContainer,
15
+ mobileBreakpointQuery = window.matchMedia('(max-width: 768px)'),
15
16
  onWillOpenDrawer,
16
17
  onCreateThread,
17
18
  onNavigateToLine,
@@ -27,6 +28,7 @@ export class CommentUiController {
27
28
  this.commentsDrawerList = commentsDrawerList;
28
29
  this.commentsToggleButton = commentsToggleButton;
29
30
  this.editorContainer = editorContainer;
31
+ this.mobileBreakpointQuery = mobileBreakpointQuery;
30
32
  this.onWillOpenDrawer = onWillOpenDrawer;
31
33
  this.onCreateThread = onCreateThread;
32
34
  this.onNavigateToLine = onNavigateToLine;
@@ -27,6 +27,7 @@ export class ExcalidrawEmbedController {
27
27
  getTheme,
28
28
  getLocalUser,
29
29
  onOpenFile = null,
30
+ onStopFollowing = null,
30
31
  onToggleQuickSwitcher = null,
31
32
  previewContainer,
32
33
  previewElement,
@@ -35,6 +36,7 @@ export class ExcalidrawEmbedController {
35
36
  this.getTheme = getTheme;
36
37
  this.getLocalUser = getLocalUser;
37
38
  this.onOpenFile = onOpenFile;
39
+ this.onStopFollowing = onStopFollowing;
38
40
  this.onToggleQuickSwitcher = onToggleQuickSwitcher;
39
41
  this.previewContainer = previewContainer;
40
42
  this.previewElement = previewElement;
@@ -1227,6 +1229,11 @@ export class ExcalidrawEmbedController {
1227
1229
  return;
1228
1230
  }
1229
1231
 
1232
+ if (msg.type === 'stop-following') {
1233
+ this.onStopFollowing?.();
1234
+ return;
1235
+ }
1236
+
1230
1237
  if (msg.type === 'error') {
1231
1238
  if (entry.isParked) {
1232
1239
  return;
@@ -61,6 +61,7 @@ export class FileActionController {
61
61
  mobileBreakpointQuery = (typeof window !== 'undefined' && typeof window.matchMedia === 'function')
62
62
  ? window.matchMedia('(max-width: 768px)')
63
63
  : { matches: false },
64
+ onDirectoryExport,
64
65
  onFileDelete,
65
66
  onFileSelect,
66
67
  onShowFileExtensionsChange,
@@ -72,6 +73,7 @@ export class FileActionController {
72
73
  view,
73
74
  refresh,
74
75
  }) {
76
+ this.onDirectoryExport = onDirectoryExport;
75
77
  this.onFileDelete = onFileDelete;
76
78
  this.onFileSelect = onFileSelect;
77
79
  this.onShowFileExtensionsChange = onShowFileExtensionsChange;
@@ -226,15 +228,26 @@ export class FileActionController {
226
228
 
227
229
  getDirectoryContextMenuItems(directoryPath) {
228
230
  return [
229
- ...this.createContextMenuItems(directoryPath),
231
+ {
232
+ label: 'New…',
233
+ onSelect: ({ anchor } = {}) => this.openCreateMenu({ anchor, parentDir: directoryPath }),
234
+ },
230
235
  {
231
236
  label: 'Rename / move',
232
237
  onSelect: () => this.handleRenameDirectory(directoryPath),
233
238
  },
234
239
  {
235
- label: 'Download',
240
+ label: 'Download source ZIP',
236
241
  onSelect: () => this.handleDownloadDirectory(directoryPath),
237
242
  },
243
+ {
244
+ label: 'Export HTML',
245
+ onSelect: () => this.onDirectoryExport?.(directoryPath, 'html'),
246
+ },
247
+ {
248
+ label: 'Print / save PDF',
249
+ onSelect: () => this.onDirectoryExport?.(directoryPath, 'pdf'),
250
+ },
238
251
  {
239
252
  label: 'Delete',
240
253
  danger: true,
@@ -8,6 +8,7 @@ export class FileExplorerController {
8
8
  mobileBreakpointQuery = window.matchMedia('(max-width: 768px)'),
9
9
  onFileSelect,
10
10
  onFileDelete,
11
+ onDirectoryExport,
11
12
  pendingWorkspaceRequestIds = null,
12
13
  onShowFileExtensionsChange,
13
14
  showFileExtensions = false,
@@ -16,6 +17,7 @@ export class FileExplorerController {
16
17
  }) {
17
18
  this.onFileSelect = onFileSelect;
18
19
  this.onFileDelete = onFileDelete;
20
+ this.onDirectoryExport = onDirectoryExport;
19
21
  this.onShowFileExtensionsChange = onShowFileExtensionsChange;
20
22
  this.toastController = toastController;
21
23
  this.vaultClient = vaultClient;
@@ -24,11 +26,6 @@ export class FileExplorerController {
24
26
  this.threadCounts = new Map();
25
27
  this.view = new FileExplorerView({
26
28
  mobileBreakpointQuery,
27
- onDirectorySelect: (pathValue) => {
28
- this.state.expandDirectoryPath(pathValue);
29
- this.state.setSearchQuery('');
30
- this.renderTree({ reset: true });
31
- },
32
29
  onDirectoryToggle: (pathValue) => {
33
30
  this.state.toggleDirectory(pathValue);
34
31
  if (!this.view.rerenderDirectoryBranch(pathValue, this.state.tree, {
@@ -61,6 +58,7 @@ export class FileExplorerController {
61
58
  });
62
59
  this.actionController = new FileActionController({
63
60
  mobileBreakpointQuery,
61
+ onDirectoryExport: this.onDirectoryExport,
64
62
  onFileDelete: this.onFileDelete,
65
63
  onFileSelect: this.onFileSelect,
66
64
  onShowFileExtensionsChange: (enabled) => {
@@ -32,7 +32,6 @@ export class FileExplorerView {
32
32
  constructor({
33
33
  mobileBreakpointQuery = window.matchMedia('(max-width: 768px)'),
34
34
  onEntryDrop,
35
- onDirectorySelect,
36
35
  onDirectoryToggle,
37
36
  onFileContextMenu,
38
37
  onFileSelect,
@@ -41,7 +40,6 @@ export class FileExplorerView {
41
40
  onValidateDrop,
42
41
  }) {
43
42
  this.onEntryDrop = onEntryDrop;
44
- this.onDirectorySelect = onDirectorySelect;
45
43
  this.onDirectoryToggle = onDirectoryToggle;
46
44
  this.onFileContextMenu = onFileContextMenu;
47
45
  this.onFileSelect = onFileSelect;
@@ -51,6 +49,7 @@ export class FileExplorerView {
51
49
  this.mobileBreakpointQuery = mobileBreakpointQuery;
52
50
  this.treeContainer = document.getElementById('fileTree');
53
51
  this.searchInput = document.getElementById('fileSearchInput');
52
+ this.searchStatus = document.getElementById('fileSearchStatus');
54
53
  this.renderedDirectoryWrappers = new Map();
55
54
  this.renderedChildContainers = new Map();
56
55
  this.renderedFileItems = new Map();
@@ -122,6 +121,18 @@ export class FileExplorerView {
122
121
  });
123
122
  }
124
123
 
124
+ updateSearchStatus(query, matchCount = null) {
125
+ if (!this.searchStatus) {
126
+ return;
127
+ }
128
+
129
+ const status = String(query ?? '').trim() && Number.isInteger(matchCount)
130
+ ? `${matchCount} match${matchCount === 1 ? '' : 'es'}`
131
+ : '';
132
+ this.searchStatus.textContent = status;
133
+ this.searchStatus.classList.toggle('hidden', !status);
134
+ }
135
+
125
136
  revealFile(filePath) {
126
137
  this.renderedFileItems.get(filePath)?.scrollIntoView({ block: 'nearest' });
127
138
  }
@@ -143,6 +154,10 @@ export class FileExplorerView {
143
154
  const threadCount = Number(this.threadCounts.get(filePath) ?? 0) || 0;
144
155
  let badge = button.querySelector('.file-tree-comment-count');
145
156
  button.classList.toggle('has-comments', threadCount > 0);
157
+ button.setAttribute(
158
+ 'aria-label',
159
+ `${filePath}${threadCount > 0 ? `, ${threadCount} open comment thread${threadCount === 1 ? '' : 's'}` : ''}`,
160
+ );
146
161
 
147
162
  if (threadCount <= 0) {
148
163
  delete button.dataset.threadCount;
@@ -157,7 +172,7 @@ export class FileExplorerView {
157
172
  button.appendChild(badge);
158
173
  }
159
174
  badge.textContent = String(threadCount);
160
- badge.setAttribute('aria-label', `${threadCount} open comment thread${threadCount === 1 ? '' : 's'}`);
175
+ badge.setAttribute('aria-hidden', 'true');
161
176
  });
162
177
  }
163
178
 
@@ -168,7 +183,7 @@ export class FileExplorerView {
168
183
 
169
184
  this.threadCounts = threadCounts instanceof Map ? threadCounts : new Map();
170
185
  this.showFileExtensions = Boolean(showFileExtensions);
171
- this.currentSearchQuery = String(searchQuery ?? '');
186
+ this.currentSearchQuery = String(searchQuery ?? '').trim();
172
187
  if (this.currentSearchQuery) {
173
188
  this.clearDragFeedback();
174
189
  }
@@ -176,8 +191,9 @@ export class FileExplorerView {
176
191
  if (this.searchInput && this.searchInput.value !== searchQuery) {
177
192
  this.searchInput.value = searchQuery;
178
193
  }
194
+ this.updateSearchStatus(searchQuery, this.currentSearchQuery ? searchMatches.length : null);
179
195
 
180
- if (searchQuery) {
196
+ if (this.currentSearchQuery) {
181
197
  this.lastRenderMode = 'search';
182
198
  this.renderSearchResults(searchMatches, activeFilePath);
183
199
  return;
@@ -246,17 +262,13 @@ export class FileExplorerView {
246
262
 
247
263
  const fragment = document.createDocumentFragment();
248
264
  for (const match of matches) {
249
- if (match.type === 'directory') {
250
- fragment.appendChild(this.createSearchDirectoryItem(match));
251
- continue;
252
- }
253
-
254
265
  fragment.appendChild(this.createFileItem({
255
266
  activeFilePath,
256
267
  depth: 0,
257
268
  filePath: match.path,
258
269
  fileType: match.type || (getVaultTreeNodeType(match.path) ?? 'file'),
259
270
  name: match.name || getVaultPathLeaf(match.path),
271
+ searchResult: true,
260
272
  }));
261
273
  }
262
274
  this.treeContainer.appendChild(fragment);
@@ -315,6 +327,8 @@ export class FileExplorerView {
315
327
 
316
328
  const button = document.createElement('button');
317
329
  button.className = 'file-tree-item file-tree-dir';
330
+ button.title = node.path;
331
+ button.setAttribute('aria-label', node.path);
318
332
  button.style.setProperty('--depth', depth);
319
333
  button.dataset.depth = depth;
320
334
 
@@ -364,35 +378,6 @@ export class FileExplorerView {
364
378
  return wrapper;
365
379
  }
366
380
 
367
- createSearchDirectoryItem(node) {
368
- const button = document.createElement('button');
369
- button.className = 'file-tree-item file-tree-dir';
370
- button.style.setProperty('--depth', 0);
371
- button.dataset.depth = 0;
372
- button.dataset.path = node.path;
373
- button.dataset.entryType = 'directory';
374
- button.innerHTML = `
375
- <svg class="file-tree-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>
376
- <span class="file-tree-name">${escapeHtml(node.name || getVaultPathLeaf(node.path))}</span>
377
- `;
378
-
379
- button.addEventListener('click', (event) => {
380
- if (this.consumeSuppressedActivation(button, event)) {
381
- return;
382
- }
383
- this.onDirectorySelect?.(node.path);
384
- });
385
- button.addEventListener('contextmenu', (event) => {
386
- event.preventDefault();
387
- this.onFileContextMenu?.(event, { directoryPath: node.path, type: 'directory' });
388
- });
389
- this.bindLongPress(button, () => {
390
- this.onFileContextMenu?.(this.createLongPressEvent(button), { directoryPath: node.path, type: 'directory' });
391
- });
392
-
393
- return button;
394
- }
395
-
396
381
  rerenderDirectoryBranch(parentPath, tree, { activeFilePath, expandedDirs }) {
397
382
  const wrapper = this.renderedDirectoryWrappers.get(parentPath);
398
383
  const parentNode = findNodeByPath(tree, parentPath);
@@ -453,10 +438,16 @@ export class FileExplorerView {
453
438
  });
454
439
  }
455
440
 
456
- createFileItem({ activeFilePath, depth, filePath, fileType = 'file', name }) {
441
+ createFileItem({ activeFilePath, depth, filePath, fileType = 'file', name, searchResult = false }) {
457
442
  const button = document.createElement('button');
458
- button.className = 'file-tree-item file-tree-file';
443
+ const parentPath = getVaultPathParent(filePath);
444
+ button.className = `file-tree-item file-tree-file${searchResult ? ' file-tree-search-result' : ''}`;
445
+ button.title = filePath;
459
446
  const threadCount = Number(this.threadCounts.get(filePath) ?? 0);
447
+ button.setAttribute(
448
+ 'aria-label',
449
+ `${filePath}${threadCount > 0 ? `, ${threadCount} open comment thread${threadCount === 1 ? '' : 's'}` : ''}`,
450
+ );
460
451
  const isDrawio = fileType === 'drawio';
461
452
  const isExcalidraw = fileType === 'excalidraw';
462
453
  const isBase = fileType === 'base';
@@ -504,11 +495,17 @@ export class FileExplorerView {
504
495
  if (threadCount > 0) {
505
496
  button.dataset.threadCount = String(threadCount);
506
497
  }
507
- const displayName = this.showFileExtensions ? String(name ?? '') : stripVaultFileExtension(name);
498
+ const displayName = this.showFileExtensions || searchResult ? String(name ?? '') : stripVaultFileExtension(name);
499
+ const nameMarkup = searchResult
500
+ ? `<span class="file-tree-search-copy">
501
+ <span class="file-tree-name">${escapeHtml(displayName)}</span>
502
+ ${parentPath ? `<span class="file-tree-search-path">${escapeHtml(parentPath)}</span>` : ''}
503
+ </span>`
504
+ : `<span class="file-tree-name">${escapeHtml(displayName)}</span>`;
508
505
  button.innerHTML = `
509
506
  ${getVaultFileIconSvg(filePath)}
510
- <span class="file-tree-name">${escapeHtml(displayName)}</span>
511
- ${threadCount > 0 ? `<span class="file-tree-comment-count" aria-label="${threadCount} open comment thread${threadCount === 1 ? '' : 's'}">${threadCount}</span>` : ''}
507
+ ${nameMarkup}
508
+ ${threadCount > 0 ? `<span class="file-tree-comment-count" aria-hidden="true">${threadCount}</span>` : ''}
512
509
  `;
513
510
  this.configureDragSource(button, { path: filePath, type: 'file' });
514
511
 
@@ -973,6 +970,7 @@ export class FileExplorerView {
973
970
  return;
974
971
  }
975
972
 
973
+ const contextAnchor = event.currentTarget instanceof Element ? event.currentTarget : event.target;
976
974
  const menu = document.createElement('div');
977
975
  menu.className = 'file-context-menu';
978
976
 
@@ -982,7 +980,7 @@ export class FileExplorerView {
982
980
  button.textContent = item.label;
983
981
  button.addEventListener('click', () => {
984
982
  this.removeContextMenu();
985
- item.onSelect?.();
983
+ item.onSelect?.({ anchor: contextAnchor });
986
984
  });
987
985
  menu.appendChild(button);
988
986
  }
@@ -526,6 +526,7 @@ export class FileHistoryViewController {
526
526
  }
527
527
 
528
528
  if (this.stats) {
529
+ // pi-lens-ignore: no-inner-html-js
529
530
  this.stats.innerHTML = `
530
531
  <span class="ui-stat-token ui-stat-token--add diff-stats-add">+${additions}</span>
531
532
  <span class="ui-stat-token ui-stat-token--del diff-stats-del">-${deletions}</span>
@@ -574,6 +575,7 @@ export class FileHistoryViewController {
574
575
  this.page?.classList.remove('hidden');
575
576
  if (this.content) {
576
577
  this.content.classList.add('diff-content--history');
578
+ // pi-lens-ignore: no-inner-html-js
577
579
  this.content.innerHTML = `<div class="git-panel-empty">${escapeHtml(message)}</div>`;
578
580
  }
579
581
  this.historyListElement = null;
@@ -714,7 +716,9 @@ export class FileHistoryViewController {
714
716
  if (selection.loading) {
715
717
  return `
716
718
  <section class="diff-file-block file-history-diff-block">
717
- ${this.renderDiffFileHeader({ path: entry.pathAtCommit || this.currentFilePath || '' })}
719
+ <div class="diff-file-header">
720
+ <span class="diff-file-path">${escapeHtml(entry.pathAtCommit || this.currentFilePath || '')}</span>
721
+ </div>
718
722
  <div class="diff-empty-state">Loading diff...</div>
719
723
  </section>
720
724
  `;
@@ -770,6 +774,7 @@ export class FileHistoryViewController {
770
774
 
771
775
  this.content.classList.add('diff-content--history');
772
776
  const selection = this.getSelectedDetailState();
777
+ // pi-lens-ignore: no-inner-html-js
773
778
  this.content.innerHTML = `
774
779
  <section class="file-history-shell">
775
780
  <aside class="file-history-sidebar" aria-label="File history entries">