collabmd 0.1.44 → 0.1.45

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 (170) hide show
  1. package/dist/client/assets/{chunk-AXR3VHVW-0GTk_evH.js → chunk-ERSWUTIN-ME9RVNel.js} +3 -3
  2. package/dist/client/assets/{chunk-CZQZEIFA-DT3N9fo7.js → chunk-YGJVY4SA-CjSe7Bx7.js} +2 -2
  3. package/dist/client/assets/{comment-threads-D-iKphIp.js → comment-threads-DDegmaFO.js} +1 -1
  4. package/dist/client/assets/drawio-editor-ClE8jpoG.js +9 -0
  5. package/dist/client/assets/drawioEditor-CXaTM9Ds.js +2 -0
  6. package/dist/client/assets/editor-session-GTwZS6Df.js +16 -0
  7. package/dist/client/assets/embedded-editor-base-CiNEc8vy.css +1 -0
  8. package/dist/client/assets/{en-GADW4C6J-DQ6zyCEM.js → en-7NFCYGKX-BrgYZAEe.js} +1 -1
  9. package/dist/client/assets/{excalidraw-editor-BHu6k8d4.js → excalidraw-editor-BZVM81BO.js} +2 -2
  10. package/dist/client/assets/excalidraw-editor-CyGwOhLz.css +1 -0
  11. package/dist/client/assets/excalidraw-scene-C8n9CHsK.js +176 -0
  12. package/dist/client/assets/excalidrawEditor-DxJanCze.js +2 -0
  13. package/dist/client/assets/export-page-CUfws2T-.js +39 -0
  14. package/dist/client/assets/exportDocument-BCuxqXDY.js +2 -0
  15. package/dist/client/assets/exportDocument-DV-OX74E.css +1 -0
  16. package/dist/client/assets/image-QXRYHUNP-lfTHE3bb.js +1 -0
  17. package/dist/client/assets/index-C3YnUgMD.css +1 -0
  18. package/dist/client/assets/index-D2wXraJ1.js +2 -0
  19. package/dist/client/assets/main-DtiGz7uI.js +795 -0
  20. package/dist/client/assets/modulepreload-polyfill-P2Xu9kJm.js +1 -0
  21. package/dist/client/assets/preview-diagram-utils-txBCoW8d.js +1 -0
  22. package/dist/client/assets/quick-switcher-controller-shW_6vPY.js +12 -0
  23. package/dist/client/assets/room-CQLoqtMo.js +1 -0
  24. package/dist/client/assets/runtime-config-DSGmGE9V.js +1 -0
  25. package/dist/client/assets/vault-api-client-C6bcGwy-.js +5 -0
  26. package/dist/client/assets/{yjs-provider-reset-guard-Cox4nxwu.js → yjs-provider-reset-guard-DE0vINDP.js} +1 -1
  27. package/dist/client/drawio-editor.html +3 -2
  28. package/dist/client/excalidraw-editor.html +3 -2
  29. package/dist/client/export-document.html +4 -3
  30. package/dist/client/index.html +97 -27
  31. package/package.json +10 -12
  32. package/src/client/app/drawio-editor-entry.js +0 -3
  33. package/src/client/app/drawio-editor.html +1 -0
  34. package/src/client/app/excalidraw-editor-entry.js +0 -3
  35. package/src/client/app/excalidraw-editor.html +1 -0
  36. package/src/client/app/export-document-entry.js +0 -3
  37. package/src/client/app/export-document.html +1 -0
  38. package/src/client/app/index.html +94 -24
  39. package/src/client/app/main-entry.js +0 -5
  40. package/src/client/application/app-shell/chat-feature.js +180 -124
  41. package/src/client/application/app-shell/comments-feature.js +1 -1
  42. package/src/client/application/app-shell/git-feature.js +4 -9
  43. package/src/client/application/app-shell/presence-feature.js +16 -10
  44. package/src/client/application/app-shell/ui-feature-shell.js +33 -15
  45. package/src/client/application/app-shell/ui-feature-sidebar.js +74 -1
  46. package/src/client/application/app-shell/ui-feature-tab-activity.js +2 -2
  47. package/src/client/application/app-shell/workspace-feature.js +22 -83
  48. package/src/client/application/app-shell-elements.js +7 -1
  49. package/src/client/application/diagram-chrome.js +161 -166
  50. package/src/client/application/diagram-preview-export.js +7 -34
  51. package/src/client/application/diagram-preview-hydrator.js +1 -19
  52. package/src/client/application/markdown-frontmatter.js +0 -2
  53. package/src/client/application/mermaid-preview-hydrator.js +1 -14
  54. package/src/client/application/plantuml-preview-hydrator.js +0 -10
  55. package/src/client/application/preview-diagram-utils.js +31 -2
  56. package/src/client/application/preview-render-compiler.js +2 -1
  57. package/src/client/application/preview-renderer.js +2 -2
  58. package/src/client/application/quick-switcher-loader.js +3 -1
  59. package/src/client/application/workspace-preview-controller.js +0 -3
  60. package/src/client/bootstrap/collabmd-app-shell.js +125 -39
  61. package/src/client/domain/excalidraw-collaboration.js +0 -2
  62. package/src/client/domain/room.js +38 -0
  63. package/src/client/export/export-pipeline.js +6 -34
  64. package/src/client/infrastructure/auth-client.js +4 -10
  65. package/src/client/infrastructure/browser-notification-port.js +33 -20
  66. package/src/client/infrastructure/browser-preferences-port.js +36 -9
  67. package/src/client/infrastructure/editor-view-adapter.js +87 -3
  68. package/src/client/infrastructure/lobby-presence.js +1 -0
  69. package/src/client/infrastructure/vault-api-client.js +25 -0
  70. package/src/client/infrastructure/workspace-sync-client.js +13 -1
  71. package/src/client/presentation/comment-overview-controller.js +18 -53
  72. package/src/client/presentation/comment-ui/comment-ui-card.js +1 -12
  73. package/src/client/presentation/comment-ui/comment-ui-layout.js +242 -219
  74. package/src/client/presentation/comment-ui/comment-ui-render.js +32 -45
  75. package/src/client/presentation/comment-ui/comment-ui-shared.js +65 -14
  76. package/src/client/presentation/comment-ui-controller.js +5 -1
  77. package/src/client/presentation/file-action-controller.js +32 -0
  78. package/src/client/presentation/file-explorer-controller.js +33 -3
  79. package/src/client/presentation/file-explorer-view.js +49 -5
  80. package/src/client/presentation/file-tree-state.js +10 -4
  81. package/src/client/presentation/quick-switcher-controller.js +243 -72
  82. package/src/client/presentation/quick-switcher-text-search.js +2 -2
  83. package/src/client/presentation/toast-controller.js +3 -0
  84. package/src/client/styles/components/feedback.css +6 -0
  85. package/src/client/styles/features/collaboration-chat.css +49 -53
  86. package/src/client/styles/features/collaboration-presence.css +9 -7
  87. package/src/client/styles/features/comment-card.css +25 -11
  88. package/src/client/styles/features/comment-overlays.css +0 -4
  89. package/src/client/styles/features/comment-overview.css +44 -21
  90. package/src/client/styles/features/comments-drawer.css +2 -100
  91. package/src/client/styles/features/diagram-preview.css +5 -18
  92. package/src/client/styles/features/embedded-preview.css +8 -33
  93. package/src/client/styles/features/quick-switcher.css +8 -0
  94. package/src/client/styles/foundation/tokens.css +1 -0
  95. package/src/client/styles/layout/editor-page.css +40 -0
  96. package/src/client/styles/layout/responsive.css +31 -1
  97. package/src/client/styles/layout/shell.css +25 -6
  98. package/src/client/styles/layout/sidebar.css +47 -15
  99. package/src/client/styles/overrides/codemirror.css +217 -15
  100. package/src/server/application/workspace-reconciliation.js +1 -1
  101. package/src/server/create-app-server.js +2 -3
  102. package/src/server/domain/bases/base-query-service.js +1 -77
  103. package/src/server/domain/comment-overview.js +10 -3
  104. package/src/server/domain/docx-exporter.js +24 -33
  105. package/src/server/domain/ripgrep-search-service.js +3 -1
  106. package/src/server/domain/workspace-state.js +32 -11
  107. package/src/server/infrastructure/git/diff-service.js +24 -13
  108. package/src/server/infrastructure/git/git-service.js +40 -10
  109. package/src/server/infrastructure/git/history-service.js +42 -29
  110. package/src/server/infrastructure/git/path-utils.js +1 -1
  111. package/src/server/infrastructure/git/responses.js +0 -95
  112. package/src/server/infrastructure/github/github-app-client.js +22 -15
  113. package/src/server/infrastructure/http/create-request-handler.js +2 -8
  114. package/src/server/infrastructure/http/create-vault-api-command-handler.js +5 -5
  115. package/src/server/infrastructure/http/http-errors.js +7 -1
  116. package/dist/client/assets/bases-preview-controller-2pLHk0uk.js +0 -143
  117. package/dist/client/assets/button-BCEiw4Rw.js +0 -1
  118. package/dist/client/assets/diagram-action-icons-aa_KOv9h.js +0 -36
  119. package/dist/client/assets/drawio-editor-DDvFoarP.js +0 -9
  120. package/dist/client/assets/drawio-embed-controller-BD1GTRwn.js +0 -1
  121. package/dist/client/assets/drawioEditor-Bu5grlH5.js +0 -2
  122. package/dist/client/assets/editor-session-DGlpiAsK.js +0 -16
  123. package/dist/client/assets/embedded-editor-base-C9roKYpW.css +0 -1
  124. package/dist/client/assets/excalidraw-editor-Cr_184EF.css +0 -1
  125. package/dist/client/assets/excalidraw-embed-controller-y2fenN_g.js +0 -1
  126. package/dist/client/assets/excalidraw-embed-reconciler-DGiagExg.js +0 -1
  127. package/dist/client/assets/excalidraw-scene-BvsQ6mLP.js +0 -176
  128. package/dist/client/assets/excalidrawEditor-4vFE--Uw.js +0 -2
  129. package/dist/client/assets/export-page-Cby8JzPO.js +0 -39
  130. package/dist/client/assets/exportDocument-C9v-bc7I.css +0 -1
  131. package/dist/client/assets/exportDocument-CRHCfsdo.js +0 -2
  132. package/dist/client/assets/file-history-view-controller-BDjEV9xJ.js +0 -112
  133. package/dist/client/assets/git-diff-view-controller-DgdM1aqb.js +0 -150
  134. package/dist/client/assets/git-panel-controller-BDTR2HVp.js +0 -207
  135. package/dist/client/assets/image-XGD7JQR6-XDUWHRpO.js +0 -1
  136. package/dist/client/assets/index-7xOyXDhP.css +0 -1
  137. package/dist/client/assets/index-Bz1KuQ6y.js +0 -2
  138. package/dist/client/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  139. package/dist/client/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  140. package/dist/client/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  141. package/dist/client/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  142. package/dist/client/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  143. package/dist/client/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  144. package/dist/client/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  145. package/dist/client/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
  146. package/dist/client/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
  147. package/dist/client/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
  148. package/dist/client/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
  149. package/dist/client/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
  150. package/dist/client/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  151. package/dist/client/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
  152. package/dist/client/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
  153. package/dist/client/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
  154. package/dist/client/assets/main-Ci07m9oP.js +0 -152
  155. package/dist/client/assets/preview-diagram-utils-n_bbJA9V.js +0 -1
  156. package/dist/client/assets/quick-switcher-controller-CoiYvllm.js +0 -12
  157. package/dist/client/assets/room-CDrmIdDt.js +0 -1
  158. package/dist/client/assets/runtime-config-CDgeuPWN.js +0 -1
  159. package/dist/client/assets/runtime-config-loader-BHGniHP5.js +0 -1
  160. package/dist/client/assets/runtime-paths-DvpihCEq.js +0 -1
  161. package/dist/client/assets/segmented-control-DJrHSz8M.js +0 -1
  162. package/dist/client/assets/vault-api-client-sLB2bo56.js +0 -1
  163. package/dist/client/assets/vault-paths-CVkuh0j-.js +0 -5
  164. package/src/client/bootstrap/lazy-controller-feature.js +0 -433
  165. package/src/client/infrastructure/backlinks-api-client.js +0 -16
  166. package/src/client/infrastructure/plantuml-api-client.js +0 -19
  167. package/src/client/infrastructure/runtime-config-loader.js +0 -56
  168. package/src/server/infrastructure/git/command-runner.js +0 -49
  169. package/src/server/infrastructure/git/errors.js +0 -8
  170. package/src/server/infrastructure/http/create-esm-proxy-handler.js +0 -130
@@ -1 +0,0 @@
1
- function e(e,t,n){let r=t.getAttribute(n);if(r===null){e.removeAttribute(n);return}e.setAttribute(n,r)}function t(e){let t=e.viewBox?.baseVal,n=Number.parseFloat(e.getAttribute(`width`)||``),r=Number.parseFloat(e.getAttribute(`height`)||``),i=e.getBoundingClientRect(),a=typeof e.getBBox==`function`?e.getBBox():null;return{height:t?.height||a?.height||r||i.height||480,width:t?.width||a?.width||n||i.width||640}}function n(e){if(!e||typeof e.getBBox!=`function`)return t(e);try{let n=e.getBBox();if(!Number.isFinite(n.width)||!Number.isFinite(n.height)||n.width<=0||n.height<=0)return t(e);let r=n.x-16,i=n.y-16,a=n.width+32,o=n.height+32;return e.setAttribute(`viewBox`,`${r} ${i} ${a} ${o}`),e.setAttribute(`width`,String(a)),e.setAttribute(`height`,String(o)),e.setAttribute(`preserveAspectRatio`,`xMinYMin meet`),{width:a,height:o}}catch{return t(e)}}function r(e){let t=window.getComputedStyle(e),n=Number.parseFloat(t.paddingLeft||`0`)+Number.parseFloat(t.paddingRight||`0`),r=Number.parseFloat(t.paddingTop||`0`)+Number.parseFloat(t.paddingBottom||`0`);return{height:Math.max(e.clientHeight-r,0),width:Math.max(e.clientWidth-n,0)}}function i(e){return 1-(1-e)**3}function a(e,{label:t=`Mermaid diagram`,message:n=`Loads when visible`}={}){let r=document.createElement(`div`);r.className=`mermaid-placeholder-card`;let i=document.createElement(`div`);i.className=`mermaid-placeholder-copy`;let a=document.createElement(`strong`);a.textContent=t;let o=document.createElement(`span`);o.textContent=n;let s=document.createElement(`button`);return s.type=`button`,s.className=`mermaid-placeholder-btn`,s.dataset.mermaidKey=e,s.textContent=`Render`,i.append(a,o),r.append(i,s),r}function o(e,t=`Renders server-side when visible`){let n=document.createElement(`div`);n.className=`plantuml-placeholder-card`;let r=document.createElement(`div`);r.className=`plantuml-placeholder-copy`;let i=document.createElement(`strong`);i.textContent=`PlantUML diagram`;let a=document.createElement(`span`);a.textContent=t;let o=document.createElement(`button`);return o.type=`button`,o.className=`plantuml-placeholder-btn`,o.dataset.plantumlKey=e,o.textContent=`Render`,r.append(i,a),n.append(r,o),n}function s(e=``){let t=String(e??``),n=t.match(/\bline(?:\s+number)?\s*[:#]?\s*(\d+)\b/i)?.[1]??``,r=t.match(/\bcol(?:umn)?(?:\s+number)?\s*[:#]?\s*(\d+)\b/i)?.[1]??``;return[n?`Line ${n}`:``,r?`column ${r}`:``].filter(Boolean).join(`, `)}function c(e,t=`Render failed`){return(e instanceof Error?e.message:String(e??``)).trim()||t}function l({key:e,kind:t,label:n=`Diagram`,message:r=`Render failed`,subtitle:i=`The current source could not be rendered.`}={}){let a=document.createElement(`div`);a.className=`${t}-placeholder-card diagram-preview-placeholder-card diagram-preview-error-card`,a.setAttribute(`role`,`alert`),a.setAttribute(`aria-live`,`assertive`);let o=document.createElement(`div`);o.className=`diagram-preview-placeholder-copy`;let c=document.createElement(`strong`);c.textContent=`${n} needs attention`;let l=document.createElement(`span`);l.textContent=i;let u=s(r),d=null;u&&(d=document.createElement(`span`),d.textContent=u);let f=document.createElement(`details`),p=document.createElement(`summary`);p.textContent=`Details`;let m=document.createElement(`code`);m.textContent=r,f.append(p,m);let h=document.createElement(`button`);return h.type=`button`,h.className=`${t}-placeholder-btn diagram-preview-placeholder-btn`,h.dataset[`${t}Key`]=e,h.textContent=`Retry`,o.append(c,l),d&&o.append(d),o.append(f),a.append(o,h),a}function u(e){let t=e.ownerDocument.createTreeWalker(e,128),n=[];for(;t.nextNode();)n.push(t.currentNode);n.forEach(e=>e.remove())}function d(e){if(!(e instanceof SVGSVGElement))throw Error(`Renderer returned invalid SVG`);return u(e),e.querySelectorAll(`script, foreignObject`).forEach(e=>{e.remove()}),[e,...Array.from(e.querySelectorAll(`*`))].forEach(e=>{Array.from(e.attributes).forEach(t=>{let n=t.name.toLowerCase(),r=t.value||``;if(n.startsWith(`on`)){e.removeAttribute(t.name);return}(n===`href`||n===`xlink:href`)&&/^\s*javascript:/i.test(r)&&e.removeAttribute(t.name)})}),e}function f(e){let t=d(e);return new XMLSerializer().serializeToString(t)}function p(e){let t=String(e??``).replace(/<!--[\s\S]*?-->/gu,``).replace(/&nbsp;/giu,`&#160;`),n=new DOMParser,r=n.parseFromString(t,`image/svg+xml`),i=r.documentElement;return i?.nodeName.toLowerCase()===`svg`&&!r.querySelector(`parsererror`)?i:n.parseFromString(t,`text/html`).querySelector(`svg`)}function m(e){let t=p(e);if(!(t instanceof SVGSVGElement))throw Error(`Renderer returned invalid SVG`);return f(t)}function h({nextSource:e=``,nextTarget:t=``,preservedSource:n=``,preservedTarget:r=``}={}){return e?e===n:t?t===r:!1}export{r as a,n as c,h as d,e as f,i,m as l,a as n,t as o,o as r,c as s,l as t,f as u};
@@ -1,12 +0,0 @@
1
- import{f as e}from"./file-kind-BKPOIRPE.js";import{n as t}from"./vault-utils-wdQ0RNR9.js";var n=50;function r(e=0){let t=Number(e)||0;return`${t} ${t===1?`match`:`matches`}`}function i(e={}){let t=[];return(e.files??[]).forEach(e=>{(e.snippets??[]).forEach(n=>{t.push({column:n.column,file:e.file,kind:e.kind,line:n.line,matchLength:Math.max((n.matchEnd??0)-(n.matchStart??0),0),snippet:n})})}),t}var a=class{constructor({debounceMs:e=220,resultLimit:t=n}={}){this.debounceMs=e,this.resultLimit=t,this.controller=null,this.timer=null,this.token=0}abort({invalidate:e=!0}={}){clearTimeout(this.timer),this.timer=null,e&&(this.token+=1),this.controller?.abort(),this.controller=null}schedule({isActive:e=()=>!0,onResults:t,onState:n,query:r=``,searchConfig:i={},searchText:a=null}={}){let o=Math.max(Number(i.minQueryLength)||2,1);if(this.abort(),!i.available){n?.(`Global text search requires ripgrep on the server.`);return}if(!a){n?.(`Global text search is unavailable.`);return}if(r.length<o){n?.(`Type at least ${o} characters to search file text.`);return}n?.(`Searching...`),this.timer=setTimeout(()=>{this.run({isActive:e,onResults:t,onState:n,query:r,searchText:a})},this.debounceMs)}async run({isActive:e=()=>!0,onResults:t,onState:n,query:r=``,searchText:i}={}){let a=this.token+1;this.token=a;let o=new AbortController;this.controller=o;let s=()=>e()&&a===this.token&&this.controller===o;try{let e=await i({limit:this.resultLimit,query:r,signal:o.signal});s()&&t?.(e,r)}catch(e){if(e?.name===`AbortError`||!s())return;n?.(e?.body?.error||e?.message||`Failed to search file text.`)}finally{this.controller===o&&(this.controller=null)}}},o=12;function s(t){let n=e(t),r=n.split(`/`).pop()||n;return{displayName:n,fileName:r,filePath:t,lowerDisplayName:n.toLowerCase(),lowerFileName:r.toLowerCase(),lowerPath:String(t).toLowerCase()}}function c(t){let n=e(t);return n.split(`/`).pop()||n}function l(t){let n=e(t);return n.includes(`/`)?n.substring(0,n.lastIndexOf(`/`)):``}var u=class{constructor({getFileList:e,getSearchConfig:t=()=>({}),onFileSelect:n,onTextMatchSelect:r=null,searchDebounceMs:i=220,searchText:o=null}){this.getFileList=e,this.getSearchConfig=t,this.onFileSelect=n,this.onTextMatchSelect=r,this.searchDebounceMs=i,this.searchText=o,this.overlay=document.getElementById(`quickSwitcher`),this.input=document.getElementById(`quickSwitcherInput`),this.resultsList=document.getElementById(`quickSwitcherResults`),this.hint=document.getElementById(`quickSwitcherHint`),this.modeTabs=Array.from(document.querySelectorAll?.(`[data-qs-mode]`)??[]),this.filteredFiles=[],this.fileCorpus=[],this.lastFileListRef=null,this.selectedIndex=0,this.selectedTextIndex=0,this.isOpen=!1,this.mode=`files`,this.textResults=null,this.textResultItems=[],this.textSearchRunner=new a({debounceMs:this.searchDebounceMs}),this.bindEvents()}bindEvents(){this.overlay?.addEventListener(`mousedown`,e=>{e.target===this.overlay&&this.close()}),this.modeTabs.forEach(e=>{e.addEventListener(`click`,()=>{this.setMode(e.dataset.qsMode===`text`?`text`:`files`,{preserveInput:!0})})}),this.input?.addEventListener(`input`,()=>{this.handleInput()}),this.input?.addEventListener(`keydown`,e=>{switch(e.key){case`ArrowDown`:e.preventDefault(),this.moveSelection(1);break;case`ArrowUp`:e.preventDefault(),this.moveSelection(-1);break;case`Enter`:e.preventDefault(),this.confirmSelection();break;case`Escape`:e.preventDefault(),this.close();break;case`Tab`:e.preventDefault(),this.modeTabs.length>1&&!e.shiftKey?this.setMode(this.mode===`files`?`text`:`files`,{preserveInput:!0}):this.moveSelection(e.shiftKey?-1:1)}})}open(){this.overlay&&(this.isOpen=!0,this.input.value=``,this.selectedIndex=0,this.selectedTextIndex=0,this.overlay.classList.add(`visible`),this.setMode(`files`,{preserveInput:!0}),this._focusAfterTransition())}_focusAfterTransition(){this._cancelPendingFocus();let e=()=>{this._focusCleanup=null,this.input?.focus(),this.isOpen&&this.input&&document.activeElement!==this.input&&setTimeout(()=>this.input?.focus(),50)},t=r=>{(r.propertyName===`visibility`||r.propertyName===`opacity`)&&(this.overlay.removeEventListener(`transitionend`,t),clearTimeout(n),e())};this.overlay.addEventListener(`transitionend`,t);let n=setTimeout(()=>{this.overlay.removeEventListener(`transitionend`,t),e()},160);this._focusCleanup=()=>{this.overlay.removeEventListener(`transitionend`,t),clearTimeout(n)}}_cancelPendingFocus(){this._focusCleanup&&=(this._focusCleanup(),null)}close(){this.overlay&&(this._cancelPendingFocus(),this.abortTextSearch(),this.isOpen=!1,this.overlay.classList.remove(`visible`),this.input.value=``,this.resultsList.innerHTML=``)}toggle(){this.isOpen?this.close():this.open()}setMode(e=`files`,{preserveInput:t=!1}={}){let n=e===`text`?`text`:`files`;this.mode=n,this.selectedIndex=0,this.selectedTextIndex=0,!t&&this.input&&(this.input.value=``),this.modeTabs.forEach(e=>{let t=e.dataset.qsMode===n;e.classList.toggle(`active`,t),e.setAttribute(`aria-selected`,t?`true`:`false`)}),this.input&&(this.input.placeholder=n===`text`?`Search text in files...`:`Search files...`),this.handleInput()}handleInput(){if(this.mode===`text`){this.scheduleTextSearch();return}this.abortTextSearch(),this.filterFiles()}filterFiles(){let e=this.input?.value.trim().toLowerCase()??``,t=this.getFileList?.()??[];if(t!==this.lastFileListRef&&(this.lastFileListRef=t,this.fileCorpus=t.map(e=>s(e))),!e)this.filteredFiles=this.fileCorpus.slice(0,o).map(e=>e.filePath);else{let t=[];this.fileCorpus.forEach(n=>{let r=this.fuzzyScore(n,e);if(r<=0)return;let i={filePath:n.filePath,score:r},a=!1;for(let e=0;e<t.length;e+=1){let o=t[e];if(r>o.score||r===o.score&&n.lowerPath<String(o.filePath).toLowerCase()){t.splice(e,0,i),a=!0;break}}!a&&t.length<o&&t.push(i),t.length>o&&(t.length=o)}),this.filteredFiles=t.map(e=>e.filePath)}this.selectedIndex=0,this.renderResults(e)}fuzzyScore(e,t){let n=e.lowerDisplayName,r=e.lowerFileName;if(r.includes(t))return 100+1/r.length;if(n.includes(t))return 50+1/n.length;let i=0,a=0,o=0;for(let e=0;e<n.length&&i<t.length;e++)n[e]===t[i]?(i++,o+=1,a+=o,(e===0||n[e-1]===`/`||n[e-1]===`-`||n[e-1]===`_`||n[e-1]===` `)&&(a+=5)):o=0;return i===t.length?a:0}renderResults(e){if(!this.resultsList)return;if(this.resultsList.innerHTML=``,this.filteredFiles.length===0){this.hint&&(this.hint.textContent=e?`No files found`:`No files in vault`,this.hint.classList.remove(`hidden`));return}this.hint&&this.hint.classList.add(`hidden`);let n=document.createDocumentFragment();this.filteredFiles.forEach((r,i)=>{let a=document.createElement(`button`);a.type=`button`,a.className=`qs-result-item`,i===this.selectedIndex&&a.classList.add(`selected`),a.dataset.index=String(i);let o=c(r),s=l(r);a.innerHTML=`
2
- <svg class="qs-result-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
3
- <span class="qs-result-name">${this.highlightMatch(o,e)}</span>
4
- ${s?`<span class="qs-result-path">${t(s)}</span>`:``}
5
- `,a.addEventListener(`click`,()=>{this.selectedIndex=i,this.confirmSelection()}),a.addEventListener(`mouseenter`,()=>{this.selectedIndex=i,this.updateSelection()}),n.appendChild(a)}),this.resultsList.appendChild(n)}highlightMatch(e,n){if(!n)return t(e);let r=e.toLowerCase().indexOf(n);if(r>=0){let i=e.slice(0,r),a=e.slice(r,r+n.length),o=e.slice(r+n.length);return`${t(i)}<mark>${t(a)}</mark>${t(o)}`}let i=``,a=0;for(let r=0;r<e.length;r++)a<n.length&&e[r].toLowerCase()===n[a]?(i+=`<mark>${t(e[r])}</mark>`,a++):i+=t(e[r]);return i}abortTextSearch({invalidate:e=!0}={}){this.textSearchRunner.abort({invalidate:e})}scheduleTextSearch(){let e=this.input?.value.trim()??``,t=this.getSearchConfig?.()??{};this.textResults=null,this.textResultItems=[],this.textSearchRunner.schedule({isActive:()=>this.isOpen&&this.mode===`text`,onResults:(e,t)=>{this.textResults=e,this.textResultItems=i(e),this.selectedTextIndex=0,this.renderTextResults(t)},onState:e=>this.renderTextState(e),query:e,searchConfig:t,searchText:this.searchText})}renderTextState(e){this.resultsList&&(this.resultsList.innerHTML=``,this.hint&&(this.hint.textContent=e,this.hint.classList.remove(`hidden`)))}renderTextResults(e=``){if(!this.resultsList)return;if(this.resultsList.innerHTML=``,!this.textResults?.files?.length||this.textResultItems.length===0){this.renderTextState(e?`No text matches found`:`Type to search file text`);return}this.hint&&(this.hint.classList.toggle(`hidden`,!this.textResults.truncated),this.hint.textContent=this.textResults.truncated?`Showing the first matches. Refine the query to narrow results.`:``);let n=document.createDocumentFragment(),i=0;this.textResults.files.forEach(e=>{let a=document.createElement(`section`);a.className=`qs-text-group`;let o=document.createElement(`div`);o.className=`qs-text-group-header`,o.innerHTML=`
6
- <span class="qs-text-file-name">${t(c(e.file))}</span>
7
- <span class="qs-text-file-meta">${t(l(e.file))}</span>
8
- <span class="qs-text-count">${t(r(e.matchCount))}</span>
9
- `,a.appendChild(o),(e.snippets??[]).forEach(e=>{let n=i,r=document.createElement(`button`);r.type=`button`,r.className=`qs-text-item`,n===this.selectedTextIndex&&r.classList.add(`selected`),r.dataset.textIndex=String(n),r.innerHTML=`
10
- <span class="qs-text-line">L${t(String(e.line??1))}</span>
11
- <span class="qs-text-snippet">${this.highlightSnippet(e)}</span>
12
- `,r.addEventListener(`click`,()=>{this.selectedTextIndex=n,this.confirmSelection()}),r.addEventListener(`mouseenter`,()=>{this.selectedTextIndex=n,this.updateSelection()}),a.appendChild(r),i+=1}),n.appendChild(a)}),this.resultsList.appendChild(n)}highlightSnippet(e={}){let n=String(e.text??``),r=Math.min(Math.max(Number(e.matchStart)||0,0),n.length),i=Math.min(Math.max(Number(e.matchEnd)||r,r),n.length);return`${t(n.slice(0,r))}<mark>${t(n.slice(r,i))}</mark>${t(n.slice(i))}`}moveSelection(e){if(this.mode===`text`){if(this.textResultItems.length===0)return;this.selectedTextIndex=(this.selectedTextIndex+e+this.textResultItems.length)%this.textResultItems.length,this.updateSelection();return}this.filteredFiles.length!==0&&(this.selectedIndex=(this.selectedIndex+e+this.filteredFiles.length)%this.filteredFiles.length,this.updateSelection())}updateSelection(){if(!this.resultsList)return;if(this.mode===`text`){let e=this.resultsList.querySelectorAll(`.qs-text-item`);e.forEach((e,t)=>{e.classList.toggle(`selected`,t===this.selectedTextIndex)}),e[this.selectedTextIndex]?.scrollIntoView({block:`nearest`});return}let e=this.resultsList.querySelectorAll(`.qs-result-item`);e.forEach((e,t)=>{e.classList.toggle(`selected`,t===this.selectedIndex)}),e[this.selectedIndex]?.scrollIntoView({block:`nearest`})}confirmSelection(){if(this.mode===`text`){let e=this.textResultItems[this.selectedTextIndex];e&&(this.close(),this.onTextMatchSelect?.(e));return}let e=this.filteredFiles[this.selectedIndex];e&&(this.close(),this.onFileSelect?.(e))}};export{u as QuickSwitcherController};
@@ -1 +0,0 @@
1
- var e=[`Alice`,`Bob`,`Charlie`,`Dana`,`Eve`,`Frank`,`Grace`,`Hank`,`Iris`,`Jack`,`Kim`,`Leo`,`Maya`,`Nate`,`Olivia`,`Pete`,`Quinn`,`Ruby`,`Sam`,`Tara`],t=[`#ef4444`,`#f97316`,`#eab308`,`#22c55e`,`#06b6d4`,`#3b82f6`,`#8b5cf6`,`#ec4899`,`#14b8a6`,`#f59e0b`,`#6366f1`,`#10b981`,`#f43f5e`,`#0ea5e9`,`#a855f7`],n=`collabmd-user-id`;function r(e){return e[Math.floor(Math.random()*e.length)]}function i(){let e=new Uint8Array(8);return globalThis.crypto?.getRandomValues?.(e),Array.from(e,e=>e.toString(16).padStart(2,`0`)).join(``)}function a(){return globalThis.crypto?.randomUUID?globalThis.crypto.randomUUID():`${i()}-${Date.now().toString(36)}`}var o=null,s=null;function c(){return o||=i(),o}function l(e=globalThis.localStorage){if(s)return s;try{let t=e?.getItem?.(n);if(t)return s=t,t}catch{}s=a();try{e?.setItem?.(n,s)}catch{}return s}function u(e){return String(e??``).trim().replace(/\s+/g,` `).slice(0,24)||null}function d(n=null){let i=r(t);return{color:i,colorLight:`${i}33`,name:u(n)??r(e),peerId:c(),userId:l()}}export{i as n,u as r,d as t};
@@ -1 +0,0 @@
1
- import{t as e}from"./runtime-paths-DvpihCEq.js";var t=Object.freeze({authError:`auth_error`,authPassword:`auth_password`,file:`file`,gitCommit:`git-commit`,gitDiff:`git-diff`,gitFileHistory:`git-file-history`,gitFilePreview:`git-file-preview`,gitHistory:`git-history`});function n(e=``){let t=String(e??``),n=t.startsWith(`#`)?t.slice(1):t;return new URLSearchParams(n)}function r(e=``){let t=String(e??``);return t.startsWith(`#`)?t.slice(1):t}function i(e=``){if(!r(e).trim().includes(`=`))return!1;let i=n(e);return Object.values(t).some(e=>i.has(e))}function a(e,{anchor:n=null,column:r=null,drawioMode:i=null,line:a=null,matchLength:o=null}={}){let s=new URLSearchParams;return e&&s.set(t.file,e),i&&s.set(`drawio`,i),n&&s.set(`anchor`,String(n).trim()),a!=null&&s.set(`line`,String(Math.max(1,Math.round(Number(a)||1)))),r!=null&&s.set(`column`,String(Math.max(1,Math.round(Number(r)||1)))),o!=null&&s.set(`matchLength`,String(Math.max(0,Math.round(Number(o)||0)))),s.toString()}function o(){return e()}function s(){return n(window.location.hash)}function c(e){return e===`staged`||e===`all`||e===`working-tree`?e:`all`}function l(){let e=s();if(e.has(t.gitFilePreview)){let n=e.get(t.gitFilePreview)||null;return{currentFilePath:e.get(`current`)||n,filePath:n,hash:e.get(`hash`)||null,type:`git-file-preview`}}if(e.has(t.gitFileHistory))return{filePath:e.get(t.gitFileHistory)||null,type:`git-file-history`};if(e.has(t.gitHistory))return{type:`git-history`};if(e.has(t.gitCommit))return{hash:e.get(t.gitCommit)||null,historyFilePath:e.get(`history`)||null,path:e.get(`path`)||null,type:`git-commit`};if(e.has(t.gitDiff)){let n=e.get(t.gitDiff)||null;return{filePath:n,scope:c(e.get(`scope`)||(n?`working-tree`:`all`)),type:`git-diff`}}return e.has(t.file)?{anchor:e.get(`anchor`)||null,column:e.has(`column`)&&Number(e.get(`column`))||null,drawioMode:e.get(`drawio`)||null,filePath:e.get(t.file),line:e.has(`line`)&&Number(e.get(`line`))||null,matchLength:e.has(`matchLength`)&&Number(e.get(`matchLength`))||null,type:`file`}:{type:`empty`}}function u(e,{anchor:t=null,column:n=null,drawioMode:r=null,line:i=null,matchLength:o=null}={}){window.location.hash=a(e,{anchor:t,column:n,drawioMode:r,line:i,matchLength:o})}function d({filePath:e=null,scope:t=`all`}={}){let n=new URLSearchParams;n.set(`git-diff`,e??``),n.set(`scope`,c(t)),window.location.hash=n.toString()}function f({hash:e,path:t=null,historyFilePath:n=null}={}){let r=String(e??``).trim(),i=new URLSearchParams;i.set(`git-commit`,r),n&&i.set(`history`,n),t&&i.set(`path`,t),window.location.hash=i.toString()}function p(){let e=new URLSearchParams;e.set(`git-history`,`1`),window.location.hash=e.toString()}function m({filePath:e}={}){let t=new URLSearchParams;t.set(`git-file-history`,e??``),window.location.hash=t.toString()}function h({hash:e,path:t,currentFilePath:n=null}={}){let r=String(e??``).trim(),i=new URLSearchParams;i.set(`git-file-preview`,t??``),n&&i.set(`current`,n),i.set(`hash`,r),window.location.hash=i.toString()}export{d as a,p as c,f as i,a as l,o as n,m as o,u as r,h as s,l as t,i as u};
@@ -1 +0,0 @@
1
- (function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e=null;function t(){return new URL(`./app-config.js`,window.location.href).toString()}function n(){let e=document.createElement(`script`);return e.src=t(),e.dataset.collabmdRuntimeConfig=`true`,e}function r(){return window.__COLLABMD_CONFIG__?Promise.resolve(window.__COLLABMD_CONFIG__):e||(e=new Promise((t,r)=>{let i=document.querySelector(`script[data-collabmd-runtime-config]`),a=i instanceof HTMLScriptElement?i:n(),o=()=>{a.removeEventListener(`error`,s),a.removeEventListener(`load`,c)},s=()=>{o(),e=null,r(Error(`Failed to load runtime config`))},c=()=>{o(),t(window.__COLLABMD_CONFIG__??{})};a.addEventListener(`error`,s,{once:!0}),a.addEventListener(`load`,c,{once:!0}),i?window.__COLLABMD_CONFIG__&&c():document.head.append(a)}),e)}export{r as t};
@@ -1 +0,0 @@
1
- function e(e){return e.endsWith(`/`)?e.slice(0,-1):e}function t(n){let r=e(String(n??``).trim());if(!r||r===`/`)return``;if(/^[a-zA-Z][a-zA-Z\d+.-]*:/u.test(r))try{return t(new URL(r).pathname)}catch{return``}return r.startsWith(`/`)?r:`/${r}`}function n(t,n){let r=e(String(t??``).trim());return!r||r===`/`?n:r.startsWith(`/`)?r:`/${r}`}function r(e,n){let r=t(e),i=String(n??``).trim();return i?/^[a-zA-Z][a-zA-Z\d+.-]*:/u.test(i)||r&&(i===r||i.startsWith(`${r}/`))?i:i===`/`?r||`/`:i.startsWith(`/`)?r?`${r}${i}`:i:r?`${r}/${i}`:`/${i}`:r||`/`}function i(){let e={auth:{enabled:!1,implemented:!0,loginEndpoint:`/api/auth/oidc/login`,provider:``,requiresLogin:!1,sessionEndpoint:`/api/auth/session`,statusEndpoint:`/api/auth/status`,strategy:`none`},basePath:``,build:{id:``,packageVersion:``},drawioBaseUrl:`https://embed.diagrams.net`,environment:`development`,gitEnabled:!0,publicWsBaseUrl:``,search:{available:!1,backend:`ripgrep`,minQueryLength:2,unavailableReason:`ripgrep search is unavailable`,version:``},wikiLinkAutoCreate:!0,wsBasePath:`/ws`,...window.__COLLABMD_CONFIG__??{}},i=t(e.basePath),a={enabled:!1,implemented:!0,loginEndpoint:`/api/auth/oidc/login`,provider:``,requiresLogin:!1,sessionEndpoint:`/api/auth/session`,statusEndpoint:`/api/auth/status`,strategy:`none`,...e.auth??{}},o={id:``,packageVersion:``,...e.build??{}};return{...e,auth:{...a,loginEndpoint:r(i,a.loginEndpoint),sessionEndpoint:r(i,a.sessionEndpoint),statusEndpoint:r(i,a.statusEndpoint)},basePath:i,build:o,wsBasePath:n(e.wsBasePath,`/ws`)}}function a(e=`/`,t=i()){return r(t.basePath,e)}function o(e=`/`,t=i()){return new URL(a(e,t),window.location.origin).toString()}function s(e=`/`,t=i()){let n=String(e??``).trim();return!n||n===`/`?a(`/api`,t):n.startsWith(`/api`)?a(n,t):a(`/api${n.startsWith(`/`)?n:`/${n}`}`,t)}function c(t=i()){let n=new URLSearchParams(window.location.search).get(`server`);return n?e(n):t.publicWsBaseUrl?e(t.publicWsBaseUrl):`${window.location.protocol===`https:`?`wss:`:`ws:`}//${window.location.host}${a(t.wsBasePath,t)}`}export{c as a,o as i,s as n,a as r,i as t};
@@ -1 +0,0 @@
1
- import{n as e}from"./button-BCEiw4Rw.js";function t(t={}){return e(`ui-segmented-control`,{"ui-segmented-control--pill":t.pill,hidden:t.hidden},t.extra??[])}function n(t={}){return e(`ui-segmented-btn`,{active:t.active,hidden:t.hidden},t.extra??[])}export{t as n,n as t};
@@ -1 +0,0 @@
1
- import{n as e}from"./runtime-paths-DvpihCEq.js";import{n as t}from"./runtime-config-CDgeuPWN.js";import{c as n}from"./vault-paths-CVkuh0j-.js";import{i as r,n as i}from"./browser-utils-CKtI_rZl.js";var a={enabled:!1,implemented:!0,loginEndpoint:`/api/auth/oidc/login`,passwordLabel:`Password`,provider:``,requiresLogin:!1,sessionEndpoint:`/api/auth/session`,statusEndpoint:`/api/auth/status`,strategy:`none`,submitLabel:`Continue`},o=`data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAIAAAABc2X6AAAGsklEQVR4Ae3cA3jsShgG4Gvbtu1js7aObdu2bdbudmvbtu1VtUg2ydw7x95mstnt5rZ5voflG80/fzL72L89bOsF94J7wWgb2dSgiAzpPHmwbfPK1qWzxDNsRdb6Ar2BgtF9hSbDRbYG4mk2beuXwm+Q89yV+TmAILgHptrb5DyPtg3LhBZjBCP+RovewNZlc2TOl8nGel0HA4LA4qPhkRSM6XcHoEYk86fIfT2AQqFzYIBjMncHofkoZBWNCM1GSq+cpdpadQIMKEoRzIeXIroEkW08TObpDAiiO8F4Tga85TBnoEc8xVKZm9UNYECS0stnBCP/Ud+AnJH/SC+eAiShPTDZ3CRZPIN9CUokC6ZSYqE2wHhmKhw/2TegR2RnSFSUaRaMJccLxg7QsAQhktkTAACaAmOxkbA80h2taKIZKWzR1BFWRAQLRvXhphYdDEtcWDxxU4sOhjdDkdVYbmrRwYAgJIums3RTNWrftbHz/AmZh5MiLBAGVqOdZ4+1790inmrFvpYZuPPEATWdknmT5f7eZEN9V2N7o9zPu3XNInQte2BlcYE6tVTbltXw4kf9h5QlhW3rliBr1QcDAODsjPFlhmelqfNvKQty4S9B0KoPVgTxmWk7Tx0COMZCF6GzA3ZC0LWMwJSsTWiOXj+O6iP382KzowAAvMOhaxmAqw/Ijr4tGPsHgnbsACwxlpNNPABIIv5LIvxpzOVlkdXPNMGK8CCudi2pFi+ovRFlwLOtc7/uUgvnxhxu05LpIyD17nTu+EAw8q9HaVtXzgcAcBUMcAER/sx9YBj5pdeExr897NLtT9TVcLgRTzVcgbyHBuc9L5n8PdLJzAEwmWP1KDCMMvTp9jWf3tbC1gdQKDgMBhRBRL0GYaojO35zxOo8fZjbz5ZAZz700Anm9pLI9g+yoY7bYKrJBWJoRpk8SJ0/fDoc13QuRuNdgMmydfTBZPkGdcDDd0q1EDkOVIKzTOiDKVGY7oPLmylVYCKlL30wIKW6D44tJlSCE76nC45+CwHXfWDfdKVKcMwHdMEJ33MC7JqEqwRHvEgXnDaYE+ArMayBB3ECDAennnVKn4tUDU74gS446k1OgB3i8Z41LHmkKHtW4eGfpRpctv5/VlomlxOsTR6kKQN1H1wnptiZHpYFv27pMbqus4kxOChbySzTz8loakfukhIkYKEBEBzw6SBXk79cLQ5lXv5XuxtJAaMDdA/v+JMydVs8irBnDvB+g9QbGeY1SUFg2gTn1JD0z+cdPIVaTbym0JemeQ6FzrtzJtdFm+DT4Rh9MD9DybxNmxL03mg3g/u0MP3cbWo6GrWjbZMBg/0Id6wqAcWwEX+F/10fVzPIe2jmRW3VTiP+VBjC4bU6KgMAID9qaQt9frl3P6hSndOaP7HrxdSYPQiH92QYhvAwTRH7KdSWBL9h5j4GeugkqDpWc1oZBqaelSGNwMWNJMLjUkHxBn//zwZeH3topr+7bWxDmia0AID17gok7aTTMrTnw1KsfZTPVMhAyj9uVl5lIexqcQLs4KFpYXjpSjQw3HwrIqCBQQ5mXsZInBWtoIOac1GOqrU4IsUJwOSllsmha5iZTf3npzXnqXka+1dFmzo4D9vZgQp2TsAZvrZUIC7729WSmRlmVfz+HGExKpUCVGJj1oSQlTd+SZ9Lm4bubqKvtTkmk+OAIRhu+zMu3jEwyqTQ1d7lofWdzV0VyWSxpPJkjpOB76z7fsPfjjOHHMhBb0QzAhMUMS18nRrgOzHkz96YdPR4toNTMT+gKjq4OtatNPBCvgfcp9PD1w/wsFP14y7WA4/zu9SudVWw8HKpUC4Zw5uOLmQ//c4fGrZL8iit+WEpvMmxAIZbtrCor7uNLpj/ubpk6N6Kh059M6tINl8Qh4UUHGa73wzjNGHQ4dj7wC6JOPtLACLqkvq4WeuE2cWi/+nLt0csOKnQ1CKP+IYMWELqgPnGiLVh6O7Go8GYZpfxpDbnwkaHjpj3JfLRV7Wgb01SARxIupc6wntyfGOG9pbikRQJmzvodRg7mRq2tkkm7IbFlhktBdaBS7SsPZx1haDIbltOSwGKXxl5px7UZGaEb8gXlerEgmmMxB2KfEciTKHRAsvbmPo0nVsST1BEdH3Kyrh9bJVlQ7wmbk05USSu0PUPPWjDOtxLg5bF7h7tM42B08x//o7U0/AmrCSV3PtYiwZpS3B13MHMS/DIz4rYaBO0VM93JpwbwaJtqNfEsbwZFgEL50VtgcJLBV6wK9aKtfd+cEkvuBfcC37k9h8VGR+csPdltgAAAABJRU5ErkJggg==`;function s(){return{...a,...t().auth??{}}}function c(){let e=window.location.hash.startsWith(`#`)?window.location.hash.slice(1):window.location.hash;return new URLSearchParams(e)}function l(){return c().get(`auth_password`)||``}function u(){let e=c();if(!e.has(`auth_password`))return;e.delete(`auth_password`);let t=e.toString(),n=`${window.location.pathname}${window.location.search}${t?`#${t}`:``}`;window.history.replaceState(null,``,n)}function d(e){let t=c(),n=t.get(e)||``;if(!n)return``;t.delete(e);let r=t.toString(),i=`${window.location.pathname}${window.location.search}${r?`#${r}`:``}`;return window.history.replaceState(null,``,i),n}function f(){return`${window.location.pathname}${window.location.search}${window.location.hash}`}async function p(e){let t=await fetch(e.statusEndpoint,{headers:{Accept:`application/json`}}),n=await t.json().catch(()=>({}));if(!t.ok)throw Error(n.error||`Failed to read auth status`);return n}function m(e){let t=e?.auth??{};if(t.strategy!==`oidc`||t.provider!==`google`)return;let n=String(e?.user?.name??``).trim();if(n)try{window.localStorage.setItem(`collabmd-user-name`,n)}catch{}}async function h(e,t){let n=await fetch(e.sessionEndpoint,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({password:t})}),r=await n.json().catch(()=>({}));if(!n.ok)throw Error(r.error||`Authentication failed`);return r}function g(){let e=document.createElement(`div`);e.className=`auth-gate-overlay`;let t=document.createElement(`section`);return t.className=`auth-gate-card`,e.append(t),{card:t,overlay:e}}function _(){let e=document.createElement(`span`);e.className=`auth-gate-button__icon`,e.setAttribute(`aria-hidden`,`true`);let t=document.createElement(`img`);return t.alt=``,t.decoding=`async`,t.height=20,t.loading=`eager`,t.src=o,t.width=20,e.append(t),e}function v(e,t,{errorMessage:n=``}){e.replaceChildren();let r=document.createElement(`h1`);r.textContent=`Authentication required`;let i=document.createElement(`p`);i.textContent=`Sign in with Google to join this session.`;let a=document.createElement(`div`);a.className=`auth-gate-actions`;let o=document.createElement(`button`);o.className=`ui-button ui-button--secondary auth-gate-button auth-gate-button--google`,o.type=`button`,o.append(_(),document.createTextNode(t.submitLabel||`Continue with Google`));let s=document.createElement(`div`);s.className=`auth-gate-error`,s.textContent=n,a.append(o),e.append(r,i,s,a),o.addEventListener(`click`,()=>{let e=new URL(t.loginEndpoint,window.location.origin);e.searchParams.set(`returnTo`,f()),window.location.assign(e.toString())})}function y(e,{title:t,body:n,secondaryActionLabel:r=``,onSecondaryAction:i=null}){e.replaceChildren();let a=document.createElement(`h1`);a.textContent=t;let o=document.createElement(`p`);if(o.textContent=n,e.append(a,o),r&&typeof i==`function`){let t=document.createElement(`button`);t.className=`ui-button ui-button--secondary auth-gate-secondary-button`,t.type=`button`,t.textContent=r,t.addEventListener(`click`,()=>{i()}),e.append(t)}}function b(e,t,{onSubmit:n}){e.replaceChildren();let r=document.createElement(`h1`);r.textContent=`Authentication required`;let i=document.createElement(`p`);i.textContent=`Enter the host password to join this shared session.`;let a=document.createElement(`form`);a.className=`auth-gate-form`;let o=document.createElement(`label`);o.className=`auth-gate-label`,o.textContent=t.passwordLabel;let s=document.createElement(`input`);s.className=`ui-input auth-gate-input`,s.type=`password`,s.name=`password`,s.autocomplete=`current-password`,s.required=!0;let c=document.createElement(`div`);c.className=`auth-gate-error`;let l=document.createElement(`div`);l.className=`auth-gate-actions`;let u=document.createElement(`button`);u.className=`ui-button ui-button--primary auth-gate-button`,u.type=`submit`,u.textContent=t.submitLabel,l.append(u),o.append(s),a.append(r,i,o,c,l),e.append(a),a.addEventListener(`submit`,e=>{e.preventDefault();let t=s.value;s.disabled=!0,u.disabled=!0,c.textContent=``,n(t).catch(e=>{c.textContent=e instanceof Error?e.message:`Authentication failed`,s.disabled=!1,u.disabled=!1,s.select(),s.focus()})}),queueMicrotask(()=>{s.focus()})}async function x(){let e=s();if(!e.enabled||e.strategy===`none`)return{authenticated:!0,auth:e};let{card:t,overlay:n}=g();document.body.append(n);let r=d(`auth_error`);return new Promise(i=>{let a=(t=null)=>{u(),m(t),n.remove(),i({authenticated:!0,auth:t?.auth??e,user:t?.user??null})};(async()=>{y(t,{body:`Checking access to this session…`,title:`CollabMD`});try{let t=await p(e);if(t.authenticated){a(t);return}}catch(e){y(t,{body:e instanceof Error?`${e.message} Refresh the page and try again.`:`Failed to contact the auth service. Refresh the page and try again.`,title:`Cannot verify access`});return}if(e.strategy===`password`){let n=l();if(n)try{u(),await h(e,n),a();return}catch{}b(t,e,{onSubmit:async t=>{await h(e,t),a()}});return}if(e.strategy===`oidc`){v(t,e,{errorMessage:r}),r=``;return}y(t,{body:`This authentication strategy is not available.`,title:`Authentication unavailable`})})()})}function S(e){return!e||e.repeat||!e.metaKey&&!e.ctrlKey||e.shiftKey||e.altKey?!1:String(e.key??``).toLowerCase()===`k`||e.code===`KeyK`}function C(e,t={}){let n={...t};return e&&(n[`X-CollabMD-Request-Id`]=String(e)),n}async function w(e,t){let n=await e.json().catch(()=>({}));if(!e.ok||n.ok===!1){let r=Error(n.error||t);throw r.status=e.status,r.body=n,typeof n?.code==`string`&&(r.code=n.code),r}return n}function T(e){return encodeURIComponent(String(e??``))}async function E(e,{fallbackError:t,fallbackFileName:n}={}){let a=await fetch(e);if(!a.ok){let e=await a.json().catch(()=>({}));throw Error(e.error||t)}let o=await a.blob();return i(o,r(a.headers.get(`content-disposition`)||``,n),{removeDelayMs:0,revokeDelayMs:0}),a}var D=new class{async readTree(){return w(await fetch(e(`/files`)),`Failed to load file tree`)}async readCommentOverview(){return w(await fetch(e(`/comments/overview`)),`Failed to load comment overview`)}async readFile(t){return w(await fetch(e(`/file?path=${encodeURIComponent(t)}`)),`Failed to read file`)}async searchText({limit:t=50,query:n=``,signal:r=null}={}){let i=new URLSearchParams({limit:String(t),q:String(n??``)});return w(await fetch(e(`/search?${i.toString()}`),{signal:r}),`Failed to search files`)}async queryBase({activeFilePath:t=``,path:n=``,search:r=``,source:i=null,sourcePath:a=``,view:o=``}={}){return w(await fetch(e(`/base/query`),{body:JSON.stringify({activeFilePath:t,path:n,search:r,source:i,sourcePath:a,view:o}),headers:{"Content-Type":`application/json`},method:`POST`}),`Failed to query base`)}async exportBaseCsv({activeFilePath:t=``,path:n=``,search:r=``,source:i=null,sourcePath:a=``,view:o=``}={}){let s=await fetch(e(`/base/export`),{body:JSON.stringify({activeFilePath:t,path:n,search:r,source:i,sourcePath:a,view:o}),headers:{"Content-Type":`application/json`},method:`POST`});if(!s.ok){let e=await s.json().catch(()=>({}));throw Error(e.error||`Failed to export base CSV`)}return{blob:await s.blob(),contentDisposition:s.headers.get(`content-disposition`)||``}}async queryBasePropertyValues({activeFilePath:t=``,path:n=``,propertyId:r=``,query:i=``,source:a=null,sourcePath:o=``,view:s=``}={}){return w(await fetch(e(`/base/property-values`),{body:JSON.stringify({activeFilePath:t,path:n,propertyId:r,query:i,source:a,sourcePath:o,view:s}),headers:{"Content-Type":`application/json`},method:`POST`}),`Failed to load base property values`)}async transformBase({activeFilePath:t=``,mutation:n=null,path:r=``,source:i=null,sourcePath:a=``,view:o=``}={}){return w(await fetch(e(`/base/transform`),{body:JSON.stringify({activeFilePath:t,mutation:n,path:r,source:i,sourcePath:a,view:o}),headers:{"Content-Type":`application/json`},method:`POST`}),`Failed to transform base`)}async createFile({content:t,path:n,requestId:r=null}){return w(await fetch(e(`/file`),{body:JSON.stringify({content:t,path:n}),headers:C(r,{"Content-Type":`application/json`}),method:`POST`}),`Failed to create file`)}async writeFile({content:t,path:n,requestId:r=null}){return w(await fetch(e(`/file`),{body:JSON.stringify({content:t,path:n}),headers:C(r,{"Content-Type":`application/json`}),method:`PUT`}),`Failed to write file`)}async renameFile({oldPath:t,newPath:n,requestId:r=null}){return w(await fetch(e(`/file`),{body:JSON.stringify({newPath:n,oldPath:t}),headers:C(r,{"Content-Type":`application/json`}),method:`PATCH`}),`Failed to rename file`)}async deleteFile(t,{requestId:n=null}={}){return w(await fetch(e(`/file?path=${encodeURIComponent(t)}`),{headers:n?C(n):void 0,method:`DELETE`}),`Failed to delete file`)}async createDirectory(t,{requestId:n=null}={}){return w(await fetch(e(`/directory`),{body:JSON.stringify({path:t}),headers:C(n,{"Content-Type":`application/json`}),method:`POST`}),`Failed to create folder`)}async renameDirectory({oldPath:t,newPath:n,requestId:r=null}){return w(await fetch(e(`/directory`),{body:JSON.stringify({newPath:n,oldPath:t}),headers:C(r,{"Content-Type":`application/json`}),method:`PATCH`}),`Failed to rename folder`)}async deleteDirectory(t,{recursive:n=!1,requestId:r=null}={}){let i=new URLSearchParams({path:String(t??``)});return n&&i.set(`recursive`,`1`),w(await fetch(e(`/directory?${i.toString()}`),{headers:r?C(r):void 0,method:`DELETE`}),`Failed to delete folder`)}async uploadImageAttachment({file:t,fileName:n=``,sourcePath:r}){return w(await fetch(e(`/attachments`),{body:t,headers:{"Content-Type":t?.type||`application/octet-stream`,"X-CollabMD-File-Name":T(n),"X-CollabMD-Source-Path":T(r)},method:`POST`}),`Failed to upload image`)}async downloadFile(t){let r=n(t)||`download`;return E(e(`/download/file?path=${encodeURIComponent(t)}`),{fallbackError:`Failed to download file`,fallbackFileName:r})}async downloadDirectory(t){let r=n(t)||`vault`;return E(e(`/download/directory?path=${encodeURIComponent(t)}`),{fallbackError:`Failed to download folder`,fallbackFileName:`${r}.zip`})}};export{x as a,S as i,C as n,w as r,D as t};
@@ -1,5 +0,0 @@
1
- import{d as e,f as t,i as n,o as r,u as i}from"./file-kind-BKPOIRPE.js";function a(e){let t=String(e??``).trim().replace(/\\/g,`/`).replace(/^\/+/u,``).split(`/`).map(e=>e.trim()).filter(Boolean);return t.some(e=>e===`.`||e===`..`)?``:t.join(`/`)}function o(e,t){let n=a(e),r=a(t);return n?r?`${n}/${r}`:n:r}function s(e=``){return String(e??``).replace(/\/+$/u,``).split(`/`).filter(Boolean).pop()||``}function c(e=``){let t=String(e??``).replace(/\/+$/u,``),n=t.lastIndexOf(`/`);return n>=0?t.slice(0,n):``}function l(e,t){return e.toLowerCase().endsWith(t.toLowerCase())?e:`${e}${t}`}function u(e){return`# ${t(String(e??``).split(`/`).pop()||``)||`Untitled`}\n\n`}function d(e){let t=a(e),r=n(t)?t:`${t}.base`;return{content:[`views:`,` - type: table`,` name: Table`,` order:`,` - file.name`,``].join(`
2
- `),path:r}}function f(e){let t=a(e),n=i(t)?t:`${t}.mmd`;return{content:[`flowchart TD`,` A[Start] --> B{Decide}`,` B -->|Yes| C[Ship it]`,` B -->|No| D[Revise]`,``].join(`
3
- `),path:n}}function p(e){let t=a(e),n=r(t)?t:`${t}.drawio`;return{content:[`<mxfile host="app.diagrams.net" modified="2026-01-01T00:00:00.000Z" agent="CollabMD" version="24.7.17">`,` <diagram id="page-1" name="Page-1">`,` <mxGraphModel dx="1200" dy="800" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">`,` <root>`,` <mxCell id="0" />`,` <mxCell id="1" parent="0" />`,` </root>`,` </mxGraphModel>`,` </diagram>`,`</mxfile>`,``].join(`
4
- `),path:n}}function m(t){let n=a(t),r=e(n)?n:`${n}.puml`;return{content:[`@startuml`,`Alice -> Bob: Hello`,`@enduml`,``].join(`
5
- `),path:r}}export{f as a,s as c,u as i,c as l,d as n,m as o,p as r,l as s,o as t,a as u};
@@ -1,433 +0,0 @@
1
- import { getVaultPathLeaf } from '../domain/vault-paths.js';
2
-
3
- function createLazyControllerProxy({
4
- createController,
5
- fallback = {},
6
- loadController,
7
- onControllerReady = null,
8
- shouldLoad = () => true,
9
- }) {
10
- let controller = null;
11
- let controllerPromise = null;
12
-
13
- const ensure = async () => {
14
- if (controller) {
15
- return controller;
16
- }
17
- if (!controllerPromise) {
18
- controllerPromise = loadController()
19
- .then((ControllerClass) => {
20
- controller = createController(ControllerClass);
21
- onControllerReady?.(controller);
22
- return controller;
23
- })
24
- .catch((error) => {
25
- controllerPromise = null;
26
- throw error;
27
- });
28
- }
29
- return controllerPromise;
30
- };
31
-
32
- const proxy = new Proxy({}, {
33
- get(_target, prop) {
34
- if (prop === 'then' || typeof prop !== 'string') {
35
- return undefined;
36
- }
37
- if (prop === 'ensure') {
38
- return ensure;
39
- }
40
- if (prop === 'current') {
41
- return controller;
42
- }
43
- if (controller && prop in controller) {
44
- const value = controller[prop];
45
- return typeof value === 'function' ? value.bind(controller) : value;
46
- }
47
- if (Object.hasOwn(fallback, prop)) {
48
- const value = fallback[prop];
49
- return typeof value === 'function' ? value.bind(proxy) : value;
50
- }
51
- return (...args) => {
52
- if (!shouldLoad(prop, args)) {
53
- return undefined;
54
- }
55
- return ensure().then((resolvedController) => {
56
- const value = resolvedController[prop];
57
- return typeof value === 'function' ? value.apply(resolvedController, args) : value;
58
- });
59
- };
60
- },
61
- });
62
-
63
- return proxy;
64
- }
65
-
66
- function hasPreviewSelector(previewElement, selector) {
67
- return Boolean(previewElement?.querySelector?.(selector));
68
- }
69
-
70
- export const lazyControllerFeature = {
71
- reportLazyControllerError(label, error) {
72
- console.error(`[lazy-controller] Failed to load ${label}.`, error);
73
- this.toastController?.show?.(`Failed to load ${label}. Try again.`, {
74
- dismissible: true,
75
- });
76
- },
77
-
78
- loadBasesPreviewController() {
79
- return import('../presentation/bases-preview-controller.js')
80
- .then((module) => module.BasesPreviewController);
81
- },
82
-
83
- loadDrawioEmbedController() {
84
- return import('../presentation/drawio-embed-controller.js')
85
- .then((module) => module.DrawioEmbedController);
86
- },
87
-
88
- loadExcalidrawEmbedController() {
89
- return import('../presentation/excalidraw-embed-controller.js')
90
- .then((module) => module.ExcalidrawEmbedController);
91
- },
92
-
93
- loadGitPanelController() {
94
- return import('../presentation/git-panel-controller.js')
95
- .then((module) => module.GitPanelController);
96
- },
97
-
98
- loadGitDiffViewController() {
99
- return import('../presentation/git-diff-view-controller.js')
100
- .then((module) => module.GitDiffViewController);
101
- },
102
-
103
- loadFileHistoryViewController() {
104
- return import('../presentation/file-history-view-controller.js')
105
- .then((module) => module.FileHistoryViewController);
106
- },
107
-
108
- createLazyBasesPreviewController() {
109
- let proxy;
110
- proxy = createLazyControllerProxy({
111
- createController: (BasesPreviewController) => new BasesPreviewController({
112
- getActiveFilePath: () => this.currentFilePath,
113
- getSession: () => this.session,
114
- onOpenFile: (filePath) => filePath && this.navigation.navigateToFile(filePath),
115
- previewElement: this.elements.previewContent,
116
- replaceBaseSource: ({ path, source }) => {
117
- if (path && path === this.currentFilePath) {
118
- this.session?.replaceText?.(source);
119
- }
120
- },
121
- toastController: this.toastController,
122
- vaultApiClient: this.vaultApiClient,
123
- }),
124
- fallback: {
125
- destroy: () => { },
126
- reconcileEmbeds: (previewElement = this.elements.previewContent) => {
127
- if (!hasPreviewSelector(previewElement, '.bases-embed-placeholder[data-base-key]')) {
128
- return;
129
- }
130
- void proxy.ensure()
131
- .then((controller) => controller.reconcileEmbeds(previewElement))
132
- .catch((error) => this.reportLazyControllerError('Bases preview', error));
133
- },
134
- renderStandalone: async (payload) => {
135
- const controller = await proxy.ensure();
136
- return controller.renderStandalone(payload);
137
- },
138
- },
139
- loadController: () => this.loadBasesPreviewController(),
140
- shouldLoad: (methodName) => methodName === 'renderStandalone',
141
- });
142
- return proxy;
143
- },
144
-
145
- createLazyDrawioEmbedController() {
146
- const state = {
147
- hydrationPaused: false,
148
- theme: null,
149
- };
150
- let proxy;
151
- proxy = createLazyControllerProxy({
152
- createController: (DrawioEmbedController) => new DrawioEmbedController({
153
- getLocalUser: () => this.lobby.getLocalUser(),
154
- getTheme: () => this.themeController.getTheme(),
155
- onOpenFile: (filePath) => filePath && this.navigation.navigateToFile(filePath),
156
- onOpenTextFile: (filePath) => filePath && this.navigation.navigateToFile(filePath, { drawioMode: 'text' }),
157
- onToggleQuickSwitcher: () => {
158
- void this.toggleQuickSwitcher();
159
- },
160
- previewContainer: this.elements.previewContainer,
161
- previewElement: this.elements.previewContent,
162
- toastController: this.toastController,
163
- vaultApiClient: this.vaultApiClient,
164
- }),
165
- fallback: {
166
- destroy: () => { },
167
- detachForCommit: () => { },
168
- hydrateVisibleEmbeds: () => { },
169
- reconcileEmbeds: (previewElement = this.elements.previewContent) => {
170
- if (!hasPreviewSelector(previewElement, '.drawio-embed-placeholder[data-drawio-key]')) {
171
- return;
172
- }
173
- void proxy.ensure()
174
- .then((controller) => {
175
- controller.reconcileEmbeds(previewElement);
176
- controller.hydrateVisibleEmbeds();
177
- controller.syncLayout();
178
- })
179
- .catch((error) => this.reportLazyControllerError('Draw.io preview', error));
180
- },
181
- setHydrationPaused: (paused) => {
182
- state.hydrationPaused = Boolean(paused);
183
- },
184
- syncLayout: () => { },
185
- updateLocalUser: () => { },
186
- updateTheme: (theme) => {
187
- state.theme = theme;
188
- },
189
- },
190
- loadController: () => this.loadDrawioEmbedController(),
191
- onControllerReady: (controller) => {
192
- controller.setHydrationPaused(state.hydrationPaused);
193
- if (state.theme) {
194
- controller.updateTheme(state.theme);
195
- }
196
- },
197
- });
198
- return proxy;
199
- },
200
-
201
- createLazyExcalidrawEmbedController() {
202
- const state = {
203
- hydrationPaused: false,
204
- localUser: null,
205
- theme: null,
206
- };
207
- let proxy;
208
- proxy = createLazyControllerProxy({
209
- createController: (ExcalidrawEmbedController) => new ExcalidrawEmbedController({
210
- getLocalUser: () => this.lobby.getLocalUser(),
211
- getTheme: () => this.themeController.getTheme(),
212
- onOpenFile: (filePath) => filePath && this.navigation.navigateToFile(filePath),
213
- onToggleQuickSwitcher: () => {
214
- void this.toggleQuickSwitcher();
215
- },
216
- previewContainer: this.elements.previewContainer,
217
- previewElement: this.elements.previewContent,
218
- toastController: this.toastController,
219
- }),
220
- fallback: {
221
- destroy: () => { },
222
- detachForCommit: () => { },
223
- hydrateVisibleEmbeds: () => { },
224
- prepareFileDisconnect: async () => false,
225
- reconcileEmbeds: (previewElement = this.elements.previewContent, options = {}) => {
226
- if (!hasPreviewSelector(previewElement, '.excalidraw-embed-placeholder[data-embed-key]')) {
227
- return;
228
- }
229
- void proxy.ensure()
230
- .then((controller) => {
231
- controller.reconcileEmbeds(previewElement, options);
232
- controller.hydrateVisibleEmbeds();
233
- controller.syncLayout();
234
- })
235
- .catch((error) => this.reportLazyControllerError('Excalidraw preview', error));
236
- },
237
- setHydrationPaused: (paused) => {
238
- state.hydrationPaused = Boolean(paused);
239
- },
240
- syncLayout: () => { },
241
- updateLocalUser: (user) => {
242
- state.localUser = user;
243
- },
244
- updateTheme: (theme) => {
245
- state.theme = theme;
246
- },
247
- },
248
- loadController: () => this.loadExcalidrawEmbedController(),
249
- onControllerReady: (controller) => {
250
- controller.setHydrationPaused(state.hydrationPaused);
251
- if (state.theme) {
252
- controller.updateTheme(state.theme);
253
- }
254
- if (state.localUser) {
255
- controller.updateLocalUser(state.localUser);
256
- }
257
- },
258
- });
259
- return proxy;
260
- },
261
-
262
- createLazyGitPanelController() {
263
- const state = {
264
- active: false,
265
- mode: 'changes',
266
- selection: {},
267
- };
268
- let proxy;
269
- proxy = createLazyControllerProxy({
270
- createController: (GitPanelController) => new GitPanelController({
271
- enabled: this.runtimeConfig.gitEnabled !== false,
272
- gitApiClient: this.gitApiClient,
273
- onCommitStaged: () => this.openGitCommitDialog(),
274
- onOpenPullBackup: (filePath) => filePath && this.navigation.navigateToFile(filePath),
275
- onPullBranch: () => this.pullGitBranch(),
276
- onPushBranch: () => this.pushGitBranch(),
277
- onRepoChange: (isGitRepo, status) => this.handleGitRepoChange(isGitRepo, status),
278
- onResetFile: (filePath, { scope }) => this.openGitResetDialog(filePath, { scope }),
279
- onSelectCommit: (hash, { path }) => this.handleGitCommitSelection(hash, { closeSidebarOnMobile: true, path }),
280
- onSelectDiff: (filePath, { scope }) => this.handleGitDiffSelection(filePath, { closeSidebarOnMobile: true, scope }),
281
- onStageFile: (filePath, { scope }) => this.stageGitFile(filePath, { scope }),
282
- onUnstageFile: (filePath, { scope }) => this.unstageGitFile(filePath, { scope }),
283
- onViewAllDiff: () => this.handleGitDiffSelection(null, { closeSidebarOnMobile: true, scope: 'all' }),
284
- searchInput: this.elements.gitSearchInput,
285
- toastController: this.toastController,
286
- }),
287
- fallback: {
288
- initialize: () => { },
289
- refresh: async (options) => {
290
- const controller = await proxy.ensure();
291
- return controller.refresh(options);
292
- },
293
- setActive: (active) => {
294
- state.active = Boolean(active);
295
- if (state.active) {
296
- void proxy.ensure().catch((error) => this.reportLazyControllerError('Git panel', error));
297
- }
298
- },
299
- setMode: (mode) => {
300
- state.mode = mode;
301
- if (state.active) {
302
- void proxy.ensure().catch((error) => this.reportLazyControllerError('Git panel', error));
303
- }
304
- },
305
- setSelection: (selection = {}) => {
306
- state.selection = selection;
307
- if (state.active) {
308
- void proxy.ensure().catch((error) => this.reportLazyControllerError('Git panel', error));
309
- }
310
- },
311
- status: null,
312
- },
313
- loadController: () => this.loadGitPanelController(),
314
- onControllerReady: (controller) => {
315
- controller.initialize();
316
- void controller.setMode(state.mode);
317
- controller.setSelection(state.selection);
318
- controller.setActive(state.active);
319
- if (state.active) {
320
- void controller.refresh({ force: true });
321
- }
322
- },
323
- });
324
- return proxy;
325
- },
326
-
327
- createLazyGitDiffViewController() {
328
- const state = {
329
- repoStatus: null,
330
- };
331
- let proxy;
332
- proxy = createLazyControllerProxy({
333
- createController: (GitDiffViewController) => new GitDiffViewController({
334
- gitApiClient: this.gitApiClient,
335
- onBackToHistory: ({ historyFilePath } = {}) => {
336
- if (historyFilePath) {
337
- this.navigation.navigateToGitFileHistory({ filePath: historyFilePath });
338
- return;
339
- }
340
- this.navigation.navigateToGitHistory();
341
- },
342
- onCommitStaged: () => this.openGitCommitDialog(),
343
- onOpenFile: (filePath) => filePath && this.navigation.navigateToFile(filePath),
344
- onStageFile: (filePath, { scope }) => this.stageGitFile(filePath, { scope }),
345
- onUnstageFile: (filePath, { scope }) => this.unstageGitFile(filePath, { scope }),
346
- toastController: this.toastController,
347
- }),
348
- fallback: {
349
- getToolbarTitle: ({ commitHash = null, filePath = null, path = null, scope = 'all', source = 'workspace' } = {}) => {
350
- if (source === 'commit') {
351
- if (path) return getVaultPathLeaf(path) || String(path ?? '') || 'File';
352
- return commitHash ? `Commit ${String(commitHash).slice(0, 7)}` : 'Commit Diff';
353
- }
354
- if (filePath) return getVaultPathLeaf(filePath) || String(filePath ?? '') || 'File';
355
- if (scope === 'staged') return 'Staged Changes';
356
- if (scope === 'working-tree') return 'Working Tree Changes';
357
- return 'All Changes';
358
- },
359
- hide: () => { },
360
- initialize: () => { },
361
- setRepoStatus: (status) => {
362
- state.repoStatus = status;
363
- },
364
- },
365
- loadController: () => this.loadGitDiffViewController(),
366
- onControllerReady: (controller) => {
367
- controller.initialize();
368
- controller.setRepoStatus(state.repoStatus);
369
- },
370
- });
371
- return proxy;
372
- },
373
-
374
- createLazyFileHistoryViewController() {
375
- let proxy;
376
- proxy = createLazyControllerProxy({
377
- createController: (FileHistoryViewController) => new FileHistoryViewController({
378
- diffRenderer: this.gitDiffView,
379
- gitApiClient: this.gitApiClient,
380
- onOpenCommitDiff: (hash, { historyFilePath, path }) => this.handleGitCommitSelection(hash, {
381
- closeSidebarOnMobile: false,
382
- historyFilePath,
383
- path,
384
- }),
385
- onOpenFile: (filePath) => filePath && this.navigation.navigateToFile(filePath),
386
- onOpenPreview: ({ hash, path, currentFilePath }) => this.handleGitFilePreviewSelection({
387
- hash,
388
- path,
389
- currentFilePath,
390
- }),
391
- onOpenWorkspaceDiff: (filePath) => this.handleGitDiffSelection(filePath, { closeSidebarOnMobile: false, scope: 'all' }),
392
- toastController: this.toastController,
393
- }),
394
- fallback: {
395
- hide: () => { },
396
- initialize: () => { },
397
- },
398
- loadController: () => this.loadFileHistoryViewController(),
399
- onControllerReady: (controller) => {
400
- controller.initialize();
401
- },
402
- });
403
- return proxy;
404
- },
405
-
406
- async ensureGitControllers() {
407
- await Promise.all([
408
- this.gitPanel.ensure(),
409
- this.gitDiffView.ensure(),
410
- this.fileHistoryView.ensure(),
411
- ]);
412
- },
413
-
414
- scheduleGitControllerPrewarm({ timeout = 2500 } = {}) {
415
- if (this.runtimeConfig.gitEnabled === false || this._gitControllerPrewarmHandle) {
416
- return;
417
- }
418
-
419
- const runPrewarm = () => {
420
- this._gitControllerPrewarmHandle = null;
421
- void this.gitPanel.ensure()
422
- .then((controller) => controller.refresh({ force: true }))
423
- .catch((error) => this.reportLazyControllerError('Git tools', error));
424
- };
425
-
426
- if (typeof window.requestIdleCallback === 'function') {
427
- this._gitControllerPrewarmHandle = window.requestIdleCallback(runPrewarm, { timeout });
428
- return;
429
- }
430
-
431
- this._gitControllerPrewarmHandle = window.setTimeout(runPrewarm, 0);
432
- },
433
- };
@@ -1,16 +0,0 @@
1
- import { resolveApiUrl } from '../domain/runtime-paths.js';
2
-
3
- export const backlinksApiClient = {
4
- async readBacklinks(filePath, { signal } = {}) {
5
- const response = await fetch(
6
- resolveApiUrl(`/backlinks?file=${encodeURIComponent(filePath)}`),
7
- { signal },
8
- );
9
- const data = await response.json().catch(() => ({}));
10
- if (!response.ok) {
11
- throw new Error(data.error || 'Failed to load backlinks');
12
- }
13
-
14
- return Array.isArray(data.backlinks) ? data.backlinks : [];
15
- },
16
- };
@@ -1,19 +0,0 @@
1
- import { resolveApiUrl } from '../domain/runtime-paths.js';
2
-
3
- export const plantUmlApiClient = {
4
- async renderSvg(source) {
5
- const response = await fetch(resolveApiUrl('/plantuml/render'), {
6
- body: JSON.stringify({ source }),
7
- headers: {
8
- 'Content-Type': 'application/json',
9
- },
10
- method: 'POST',
11
- });
12
- const data = await response.json().catch(() => null);
13
- if (!response.ok || !data?.ok || typeof data.svg !== 'string') {
14
- throw new Error(data?.error || 'Failed to render PlantUML');
15
- }
16
-
17
- return data.svg;
18
- },
19
- };
@@ -1,56 +0,0 @@
1
- let runtimeConfigLoadPromise = null;
2
-
3
- function getRuntimeConfigScriptUrl() {
4
- return new URL('./app-config.js', window.location.href).toString();
5
- }
6
-
7
- function createRuntimeConfigScript() {
8
- const script = document.createElement('script');
9
- script.src = getRuntimeConfigScriptUrl();
10
- script.dataset.collabmdRuntimeConfig = 'true';
11
- return script;
12
- }
13
-
14
- export function ensureRuntimeConfigLoaded() {
15
- if (window.__COLLABMD_CONFIG__) {
16
- return Promise.resolve(window.__COLLABMD_CONFIG__);
17
- }
18
-
19
- if (runtimeConfigLoadPromise) {
20
- return runtimeConfigLoadPromise;
21
- }
22
-
23
- runtimeConfigLoadPromise = new Promise((resolve, reject) => {
24
- const existingScript = document.querySelector('script[data-collabmd-runtime-config]');
25
- const script = existingScript instanceof HTMLScriptElement
26
- ? existingScript
27
- : createRuntimeConfigScript();
28
-
29
- const cleanup = () => {
30
- script.removeEventListener('error', handleError);
31
- script.removeEventListener('load', handleLoad);
32
- };
33
-
34
- const handleError = () => {
35
- cleanup();
36
- runtimeConfigLoadPromise = null;
37
- reject(new Error('Failed to load runtime config'));
38
- };
39
-
40
- const handleLoad = () => {
41
- cleanup();
42
- resolve(window.__COLLABMD_CONFIG__ ?? {});
43
- };
44
-
45
- script.addEventListener('error', handleError, { once: true });
46
- script.addEventListener('load', handleLoad, { once: true });
47
-
48
- if (!existingScript) {
49
- document.head.append(script);
50
- } else if (window.__COLLABMD_CONFIG__) {
51
- handleLoad();
52
- }
53
- });
54
-
55
- return runtimeConfigLoadPromise;
56
- }