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
@@ -15,12 +15,12 @@
15
15
  document.documentElement.setAttribute('data-initial-file-requested', 'true');
16
16
  }
17
17
  </script>
18
- <script type="module" crossorigin src="./assets/index-Bz1KuQ6y.js"></script>
19
- <link rel="modulepreload" crossorigin href="./assets/runtime-config-loader-BHGniHP5.js">
18
+ <script type="module" crossorigin src="./assets/index-D2wXraJ1.js"></script>
19
+ <link rel="modulepreload" crossorigin href="./assets/modulepreload-polyfill-P2Xu9kJm.js">
20
20
  <link rel="modulepreload" crossorigin href="./assets/preload-helper-HclGiUj8.js">
21
21
  <link rel="modulepreload" crossorigin href="./assets/base-CxPEiHuy.js">
22
22
  <link rel="stylesheet" crossorigin href="./assets/base-CaIEJUF9.css">
23
- <link rel="stylesheet" crossorigin href="./assets/index-7xOyXDhP.css">
23
+ <link rel="stylesheet" crossorigin href="./assets/index-C3YnUgMD.css">
24
24
  </head>
25
25
  <body>
26
26
 
@@ -61,6 +61,21 @@
61
61
  <span class="sidebar-create-btn-label">Create</span>
62
62
  </button>
63
63
  </div>
64
+ <button
65
+ class="ui-icon-button sidebar-options-btn"
66
+ id="fileExplorerOptionsBtn"
67
+ type="button"
68
+ aria-label="File explorer options"
69
+ aria-expanded="false"
70
+ aria-haspopup="menu"
71
+ title="File explorer options"
72
+ >
73
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true">
74
+ <circle cx="12" cy="5" r="1"></circle>
75
+ <circle cx="12" cy="12" r="1"></circle>
76
+ <circle cx="12" cy="19" r="1"></circle>
77
+ </svg>
78
+ </button>
64
79
  </div>
65
80
  </div>
66
81
  <div class="ui-nav-tabs" id="sidebarTabs">
@@ -117,6 +132,19 @@
117
132
  <nav id="fileTree" class="file-tree" aria-label="File explorer"></nav>
118
133
  <section id="commentOverviewPanel" class="comment-overview-panel hidden" aria-label="Open comments"></section>
119
134
  <div id="gitPanel" class="git-panel hidden" aria-label="Git changes"></div>
135
+ <div
136
+ class="sidebar-resizer"
137
+ id="sidebarResizer"
138
+ role="separator"
139
+ aria-orientation="vertical"
140
+ aria-label="Resize sidebar"
141
+ aria-controls="sidebar"
142
+ aria-valuemin="220"
143
+ aria-valuemax="420"
144
+ aria-valuenow="260"
145
+ tabindex="0"
146
+ title="Drag to resize sidebar"
147
+ ></div>
120
148
  </aside>
121
149
 
122
150
  <button
@@ -144,7 +172,24 @@
144
172
  </div>
145
173
 
146
174
  <div class="toolbar-center" id="toolbarCenter">
147
- <div class="ui-segmented-control view-toggle" role="group" aria-label="View mode">
175
+ <button
176
+ class="ui-button ui-button--secondary ui-button--compact toolbar-search-trigger"
177
+ id="toolbarSearchBtn"
178
+ type="button"
179
+ aria-label="Search files and text"
180
+ aria-controls="quickSwitcher"
181
+ aria-haspopup="dialog"
182
+ aria-keyshortcuts="Meta+K Control+K"
183
+ title="Search files and text (⌘K)"
184
+ >
185
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true">
186
+ <circle cx="11" cy="11" r="7"></circle>
187
+ <line x1="20" y1="20" x2="16.65" y2="16.65"></line>
188
+ </svg>
189
+ <span class="toolbar-search-label">Search</span>
190
+ <kbd class="toolbar-search-kbd">⌘K</kbd>
191
+ </button>
192
+ <div class="ui-segmented-control view-toggle" id="toolbarViewToggle" role="group" aria-label="View mode">
148
193
  <button class="ui-segmented-btn active view-btn" data-view="split" aria-label="Split view" aria-pressed="true" title="Split view">
149
194
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
150
195
  <rect x="3" y="3" width="18" height="18" rx="2"></rect>
@@ -192,7 +237,7 @@
192
237
 
193
238
  <div class="user-avatars toolbar-presence-cluster" id="userAvatars"></div>
194
239
 
195
- <section class="presence-panel hidden" id="presencePanel" aria-label="Online users" aria-hidden="true">
240
+ <section class="collaboration-popover presence-panel hidden" id="presencePanel" aria-label="Online users" aria-hidden="true">
196
241
  <div class="presence-panel-header">
197
242
  <div>
198
243
  <h2 class="presence-panel-title">Online now</h2>
@@ -203,7 +248,7 @@
203
248
  </section>
204
249
 
205
250
  <div class="chat-container" id="chatContainer">
206
- <button class="ui-button ui-button--ghost ui-button--toolbar chat-toggle-btn" id="chatToggleBtn" aria-label="Open team chat" aria-expanded="false" title="Team chat">
251
+ <button type="button" class="ui-button ui-button--ghost ui-button--toolbar chat-toggle-btn" id="chatToggleBtn" aria-label="Open team chat" aria-controls="chatPanel" aria-expanded="false" title="Team chat">
207
252
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
208
253
  <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
209
254
  </svg>
@@ -212,23 +257,44 @@
212
257
  </button>
213
258
  <div class="toast-container chat-toast-container" id="chatToastContainer" aria-live="polite" aria-atomic="true"></div>
214
259
 
215
- <section class="chat-panel hidden" id="chatPanel" aria-label="Team chat">
260
+ <section class="collaboration-popover chat-panel hidden" id="chatPanel" role="dialog" aria-labelledby="chatPanelTitle">
216
261
  <div class="chat-panel-header">
217
- <div>
218
- <h2 class="chat-panel-title">Team chat</h2>
219
- <p class="chat-panel-status" id="chatStatus">Syncing...</p>
262
+ <div class="chat-panel-heading">
263
+ <h2 class="chat-panel-title" id="chatPanelTitle">Team chat</h2>
264
+ <p class="chat-panel-status" id="chatStatus" role="status" aria-live="polite" aria-atomic="true">Syncing...</p>
265
+ </div>
266
+ <div class="chat-panel-actions">
267
+ <span class="ui-status-badge ui-status-badge--accent chat-notification-status hidden" id="chatNotificationStatus" role="status"></span>
268
+ <button
269
+ type="button"
270
+ class="ui-button ui-button--ghost ui-button--compact chat-notification-action"
271
+ id="chatNotificationBtn"
272
+ >Enable desktop alerts</button>
273
+ <button
274
+ type="button"
275
+ class="ui-icon-button chat-notification-mute-action hidden"
276
+ id="chatNotificationMuteBtn"
277
+ aria-label="Mute desktop alerts for one hour"
278
+ aria-pressed="false"
279
+ title="Mute desktop alerts for one hour"
280
+ >
281
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
282
+ <path d="M18 8a6 6 0 0 0-12 0c0 7-3 7-3 9h18c0-2-3-2-3-9"></path>
283
+ <path d="M13.73 21a2 2 0 0 1-3.46 0"></path>
284
+ <path class="chat-notification-mute-slash" d="m4 4 16 16"></path>
285
+ </svg>
286
+ </button>
287
+ <button type="button" class="ui-icon-button chat-close-btn" id="chatCloseBtn" aria-label="Close team chat" title="Close team chat">
288
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true">
289
+ <line x1="18" y1="6" x2="6" y2="18"></line>
290
+ <line x1="6" y1="6" x2="18" y2="18"></line>
291
+ </svg>
292
+ </button>
220
293
  </div>
221
- <button
222
- class="ui-button ui-button--secondary ui-button--compact ui-button--action ui-button--surface ui-button--pill chat-notification-action"
223
- id="chatNotificationBtn"
224
- type="button"
225
- >
226
- Enable alerts
227
- </button>
228
294
  </div>
229
295
 
230
- <div class="chat-empty-state" id="chatEmptyState">
231
- Temporary room chat for whoever is online right now.
296
+ <div class="ui-empty-state ui-empty-state--compact chat-empty-state" id="chatEmptyState">
297
+ Messages are visible to everyone in this room.
232
298
  </div>
233
299
  <div class="chat-messages hidden" id="chatMessages" role="log" aria-live="polite" aria-relevant="additions text"></div>
234
300
 
@@ -237,10 +303,11 @@
237
303
  type="text"
238
304
  class="ui-input chat-input"
239
305
  id="chatInput"
240
- placeholder="Send a quick update..."
306
+ placeholder="Message the room..."
241
307
  autocomplete="off"
242
308
  spellcheck="true"
243
309
  maxlength="280"
310
+ enterkeyhint="send"
244
311
  aria-label="Team chat message"
245
312
  >
246
313
  <button type="submit" class="ui-button ui-button--primary chat-send-btn">Send</button>
@@ -652,28 +719,31 @@
652
719
 
653
720
  <div class="toast-container" id="toastContainer"></div>
654
721
 
655
- <div class="qs-overlay" id="quickSwitcher">
722
+ <div class="qs-overlay" id="quickSwitcher" role="dialog" aria-modal="true" aria-labelledby="quickSwitcherTitle" aria-hidden="true">
656
723
  <div class="qs-modal">
724
+ <h2 class="sr-only" id="quickSwitcherTitle">Search files and text</h2>
657
725
  <div class="qs-mode-tabs" role="tablist" aria-label="Search mode">
658
- <button class="qs-mode-tab active" type="button" role="tab" aria-selected="true" data-qs-mode="files">Files</button>
659
- <button class="qs-mode-tab" type="button" role="tab" aria-selected="false" data-qs-mode="text">Text</button>
726
+ <button class="qs-mode-tab active" id="quickSwitcherFilesTab" type="button" role="tab" aria-controls="quickSwitcherResults" aria-selected="true" data-qs-mode="files">Files</button>
727
+ <button class="qs-mode-tab" id="quickSwitcherTextTab" type="button" role="tab" aria-controls="quickSwitcherResults" aria-selected="false" data-qs-mode="text">Text</button>
660
728
  </div>
661
729
  <div class="qs-input-wrap">
662
730
  <svg class="qs-search-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
663
731
  <circle cx="11" cy="11" r="8"></circle>
664
732
  <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
665
733
  </svg>
666
- <input type="text" class="qs-input" id="quickSwitcherInput" placeholder="Search files..." autocomplete="off" spellcheck="false">
734
+ <input type="text" class="qs-input" id="quickSwitcherInput" placeholder="Search files..." aria-label="Search files" aria-controls="quickSwitcherResults" aria-describedby="quickSwitcherHint quickSwitcherScope" autocomplete="off" spellcheck="false">
667
735
  <kbd class="qs-kbd">esc</kbd>
668
736
  </div>
669
- <div class="qs-results" id="quickSwitcherResults"></div>
670
- <div class="qs-hint" id="quickSwitcherHint">Type to search files</div>
671
- <div class="qs-footer" aria-hidden="true">
737
+ <div class="qs-scope hidden" id="quickSwitcherScope" role="note" aria-hidden="true">Exact, case-insensitive text in Markdown, Base, Mermaid, PlantUML, and Draw.io files. Images and Excalidraw are excluded.</div>
738
+ <div class="qs-results" id="quickSwitcherResults" role="listbox" aria-label="Search results" aria-busy="false" tabindex="-1"></div>
739
+ <div class="qs-hint" id="quickSwitcherHint" role="status" aria-live="polite" aria-atomic="true">Type to search files</div>
740
+ <div class="qs-footer">
672
741
  <span><kbd>↑</kbd><kbd>↓</kbd> Navigate</span>
673
742
  <span><kbd>↵</kbd> Open</span>
674
743
  <span><kbd>Tab</kbd> Switch mode</span>
675
744
  </div>
676
745
  </div>
677
746
  </div>
747
+ <script src="./app-config.js"></script>
678
748
  </body>
679
749
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "collabmd",
3
- "version": "0.1.44",
3
+ "version": "0.1.45",
4
4
  "type": "module",
5
5
  "description": "Collaborative markdown vault — like Obsidian, but online. Serve any directory of markdown files for realtime collaborative editing.",
6
6
  "repository": {
@@ -43,10 +43,10 @@
43
43
  "test:e2e:headed": "npm run build && playwright test --headed",
44
44
  "test:e2e:prebuilt": "playwright test",
45
45
  "test:excalidraw:stress": "node scripts/run-excalidraw-reliability-stress.mjs",
46
- "test:guardrails": "node --test tests/node/style-system-guardrails.test.js",
47
- "test:integration": "npm run build && node scripts/run-node-tests.mjs integration",
48
- "test:integration:prebuilt": "node scripts/run-node-tests.mjs integration",
49
- "test:unit": "npm run build && node scripts/run-node-tests.mjs fast",
46
+ "test:guardrails": "node --test tests/node/guardrails/*.test.js",
47
+ "test:integration": "npm run build && npm run test:integration:prebuilt",
48
+ "test:integration:prebuilt": "node --test --test-force-exit --test-concurrency=2 tests/node/integration/*.test.js",
49
+ "test:unit": "npm run build && node --test --test-force-exit tests/node/*.test.js",
50
50
  "tunnel": "node scripts/cloudflare-tunnel.mjs"
51
51
  },
52
52
  "keywords": [
@@ -73,9 +73,7 @@
73
73
  "@codemirror/state": "^6.7.1",
74
74
  "@codemirror/theme-one-dark": "^6.1.3",
75
75
  "@codemirror/view": "^6.43.8",
76
- "@excalidraw/excalidraw": "0.18.0-ab0255f",
77
- "@fontsource-variable/inter": "^5.3.0",
78
- "@fontsource/jetbrains-mono": "^5.3.0",
76
+ "@excalidraw/excalidraw": "0.18.0-4872083",
79
77
  "@turbodocx/html-to-docx": "^1.22.0",
80
78
  "archiver": "^8.0.0",
81
79
  "highlight.js": "^11.11.1",
@@ -87,10 +85,10 @@
87
85
  "react": "^19.2.8",
88
86
  "react-dom": "^19.2.8",
89
87
  "sharp": "^0.35.3",
90
- "ws": "^8.21.2",
88
+ "ws": "^8.21.3",
91
89
  "y-codemirror.next": "^0.3.5",
92
90
  "y-protocols": "^1.0.7",
93
- "y-websocket": "^3.0.0",
91
+ "y-websocket": "^3.1.0",
94
92
  "yjs": "^13.6.32"
95
93
  },
96
94
  "overrides": {
@@ -103,9 +101,9 @@
103
101
  "@playwright/test": "^1.62.1",
104
102
  "@vitest/browser": "^4.1.10",
105
103
  "@vitest/browser-playwright": "^4.1.10",
106
- "eslint": "^10.8.0",
104
+ "eslint": "^10.8.1",
107
105
  "globals": "^17.9.0",
108
- "vite": "^8.2.0",
106
+ "vite": "^8.2.1",
109
107
  "vitest": "^4.1.10"
110
108
  }
111
109
  }
@@ -1,4 +1 @@
1
- import { ensureRuntimeConfigLoaded } from '../infrastructure/runtime-config-loader.js';
2
-
3
- await ensureRuntimeConfigLoaded();
4
1
  await import('../drawio-editor.js');
@@ -9,6 +9,7 @@
9
9
  <div id="root">
10
10
  <div class="drawio-loading" id="loadingState">Loading draw.io…</div>
11
11
  </div>
12
+ <script vite-ignore src="./app-config.js"></script>
12
13
  <script type="module" src="./drawio-editor-entry.js"></script>
13
14
  </body>
14
15
  </html>
@@ -1,4 +1 @@
1
- import { ensureRuntimeConfigLoaded } from '../infrastructure/runtime-config-loader.js';
2
-
3
- await ensureRuntimeConfigLoaded();
4
1
  await import('../excalidraw-editor.js');
@@ -9,6 +9,7 @@
9
9
  <div id="root">
10
10
  <div class="loading-state" id="loadingState">Loading Excalidraw...</div>
11
11
  </div>
12
+ <script vite-ignore src="./app-config.js"></script>
12
13
  <script type="module" src="./excalidraw-editor-entry.js"></script>
13
14
  </body>
14
15
  </html>
@@ -6,8 +6,6 @@ import '../styles/features/preview-markdown.css';
6
6
  import '../styles/overrides/highlightjs.css';
7
7
  import '../styles/export-document.css';
8
8
 
9
- import { ensureRuntimeConfigLoaded } from '../infrastructure/runtime-config-loader.js';
10
-
11
9
  function ensureHighlightThemeStylesheet() {
12
10
  let themeStylesheet = document.getElementById('hljs-theme');
13
11
  if (!(themeStylesheet instanceof HTMLLinkElement)) {
@@ -20,6 +18,5 @@ function ensureHighlightThemeStylesheet() {
20
18
  themeStylesheet.href = lightHighlightThemeUrl;
21
19
  }
22
20
 
23
- await ensureRuntimeConfigLoaded();
24
21
  ensureHighlightThemeStylesheet();
25
22
  await import('../export/export-page.js');
@@ -19,6 +19,7 @@
19
19
  </section>
20
20
  <article id="exportContent" class="preview-content export-content"></article>
21
21
  </main>
22
+ <script vite-ignore src="./app-config.js"></script>
22
23
  <script type="module" src="./export-document-entry.js"></script>
23
24
  </body>
24
25
  </html>
@@ -55,6 +55,21 @@
55
55
  <span class="sidebar-create-btn-label">Create</span>
56
56
  </button>
57
57
  </div>
58
+ <button
59
+ class="ui-icon-button sidebar-options-btn"
60
+ id="fileExplorerOptionsBtn"
61
+ type="button"
62
+ aria-label="File explorer options"
63
+ aria-expanded="false"
64
+ aria-haspopup="menu"
65
+ title="File explorer options"
66
+ >
67
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true">
68
+ <circle cx="12" cy="5" r="1"></circle>
69
+ <circle cx="12" cy="12" r="1"></circle>
70
+ <circle cx="12" cy="19" r="1"></circle>
71
+ </svg>
72
+ </button>
58
73
  </div>
59
74
  </div>
60
75
  <div class="ui-nav-tabs" id="sidebarTabs">
@@ -111,6 +126,19 @@
111
126
  <nav id="fileTree" class="file-tree" aria-label="File explorer"></nav>
112
127
  <section id="commentOverviewPanel" class="comment-overview-panel hidden" aria-label="Open comments"></section>
113
128
  <div id="gitPanel" class="git-panel hidden" aria-label="Git changes"></div>
129
+ <div
130
+ class="sidebar-resizer"
131
+ id="sidebarResizer"
132
+ role="separator"
133
+ aria-orientation="vertical"
134
+ aria-label="Resize sidebar"
135
+ aria-controls="sidebar"
136
+ aria-valuemin="220"
137
+ aria-valuemax="420"
138
+ aria-valuenow="260"
139
+ tabindex="0"
140
+ title="Drag to resize sidebar"
141
+ ></div>
114
142
  </aside>
115
143
 
116
144
  <button
@@ -138,7 +166,24 @@
138
166
  </div>
139
167
 
140
168
  <div class="toolbar-center" id="toolbarCenter">
141
- <div class="ui-segmented-control view-toggle" role="group" aria-label="View mode">
169
+ <button
170
+ class="ui-button ui-button--secondary ui-button--compact toolbar-search-trigger"
171
+ id="toolbarSearchBtn"
172
+ type="button"
173
+ aria-label="Search files and text"
174
+ aria-controls="quickSwitcher"
175
+ aria-haspopup="dialog"
176
+ aria-keyshortcuts="Meta+K Control+K"
177
+ title="Search files and text (⌘K)"
178
+ >
179
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true">
180
+ <circle cx="11" cy="11" r="7"></circle>
181
+ <line x1="20" y1="20" x2="16.65" y2="16.65"></line>
182
+ </svg>
183
+ <span class="toolbar-search-label">Search</span>
184
+ <kbd class="toolbar-search-kbd">⌘K</kbd>
185
+ </button>
186
+ <div class="ui-segmented-control view-toggle" id="toolbarViewToggle" role="group" aria-label="View mode">
142
187
  <button class="ui-segmented-btn active view-btn" data-view="split" aria-label="Split view" aria-pressed="true" title="Split view">
143
188
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
144
189
  <rect x="3" y="3" width="18" height="18" rx="2"></rect>
@@ -186,7 +231,7 @@
186
231
 
187
232
  <div class="user-avatars toolbar-presence-cluster" id="userAvatars"></div>
188
233
 
189
- <section class="presence-panel hidden" id="presencePanel" aria-label="Online users" aria-hidden="true">
234
+ <section class="collaboration-popover presence-panel hidden" id="presencePanel" aria-label="Online users" aria-hidden="true">
190
235
  <div class="presence-panel-header">
191
236
  <div>
192
237
  <h2 class="presence-panel-title">Online now</h2>
@@ -197,7 +242,7 @@
197
242
  </section>
198
243
 
199
244
  <div class="chat-container" id="chatContainer">
200
- <button class="ui-button ui-button--ghost ui-button--toolbar chat-toggle-btn" id="chatToggleBtn" aria-label="Open team chat" aria-expanded="false" title="Team chat">
245
+ <button type="button" class="ui-button ui-button--ghost ui-button--toolbar chat-toggle-btn" id="chatToggleBtn" aria-label="Open team chat" aria-controls="chatPanel" aria-expanded="false" title="Team chat">
201
246
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
202
247
  <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
203
248
  </svg>
@@ -206,23 +251,44 @@
206
251
  </button>
207
252
  <div class="toast-container chat-toast-container" id="chatToastContainer" aria-live="polite" aria-atomic="true"></div>
208
253
 
209
- <section class="chat-panel hidden" id="chatPanel" aria-label="Team chat">
254
+ <section class="collaboration-popover chat-panel hidden" id="chatPanel" role="dialog" aria-labelledby="chatPanelTitle">
210
255
  <div class="chat-panel-header">
211
- <div>
212
- <h2 class="chat-panel-title">Team chat</h2>
213
- <p class="chat-panel-status" id="chatStatus">Syncing...</p>
256
+ <div class="chat-panel-heading">
257
+ <h2 class="chat-panel-title" id="chatPanelTitle">Team chat</h2>
258
+ <p class="chat-panel-status" id="chatStatus" role="status" aria-live="polite" aria-atomic="true">Syncing...</p>
259
+ </div>
260
+ <div class="chat-panel-actions">
261
+ <span class="ui-status-badge ui-status-badge--accent chat-notification-status hidden" id="chatNotificationStatus" role="status"></span>
262
+ <button
263
+ type="button"
264
+ class="ui-button ui-button--ghost ui-button--compact chat-notification-action"
265
+ id="chatNotificationBtn"
266
+ >Enable desktop alerts</button>
267
+ <button
268
+ type="button"
269
+ class="ui-icon-button chat-notification-mute-action hidden"
270
+ id="chatNotificationMuteBtn"
271
+ aria-label="Mute desktop alerts for one hour"
272
+ aria-pressed="false"
273
+ title="Mute desktop alerts for one hour"
274
+ >
275
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
276
+ <path d="M18 8a6 6 0 0 0-12 0c0 7-3 7-3 9h18c0-2-3-2-3-9"></path>
277
+ <path d="M13.73 21a2 2 0 0 1-3.46 0"></path>
278
+ <path class="chat-notification-mute-slash" d="m4 4 16 16"></path>
279
+ </svg>
280
+ </button>
281
+ <button type="button" class="ui-icon-button chat-close-btn" id="chatCloseBtn" aria-label="Close team chat" title="Close team chat">
282
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true">
283
+ <line x1="18" y1="6" x2="6" y2="18"></line>
284
+ <line x1="6" y1="6" x2="18" y2="18"></line>
285
+ </svg>
286
+ </button>
214
287
  </div>
215
- <button
216
- class="ui-button ui-button--secondary ui-button--compact ui-button--action ui-button--surface ui-button--pill chat-notification-action"
217
- id="chatNotificationBtn"
218
- type="button"
219
- >
220
- Enable alerts
221
- </button>
222
288
  </div>
223
289
 
224
- <div class="chat-empty-state" id="chatEmptyState">
225
- Temporary room chat for whoever is online right now.
290
+ <div class="ui-empty-state ui-empty-state--compact chat-empty-state" id="chatEmptyState">
291
+ Messages are visible to everyone in this room.
226
292
  </div>
227
293
  <div class="chat-messages hidden" id="chatMessages" role="log" aria-live="polite" aria-relevant="additions text"></div>
228
294
 
@@ -231,10 +297,11 @@
231
297
  type="text"
232
298
  class="ui-input chat-input"
233
299
  id="chatInput"
234
- placeholder="Send a quick update..."
300
+ placeholder="Message the room..."
235
301
  autocomplete="off"
236
302
  spellcheck="true"
237
303
  maxlength="280"
304
+ enterkeyhint="send"
238
305
  aria-label="Team chat message"
239
306
  >
240
307
  <button type="submit" class="ui-button ui-button--primary chat-send-btn">Send</button>
@@ -646,29 +713,32 @@
646
713
 
647
714
  <div class="toast-container" id="toastContainer"></div>
648
715
 
649
- <div class="qs-overlay" id="quickSwitcher">
716
+ <div class="qs-overlay" id="quickSwitcher" role="dialog" aria-modal="true" aria-labelledby="quickSwitcherTitle" aria-hidden="true">
650
717
  <div class="qs-modal">
718
+ <h2 class="sr-only" id="quickSwitcherTitle">Search files and text</h2>
651
719
  <div class="qs-mode-tabs" role="tablist" aria-label="Search mode">
652
- <button class="qs-mode-tab active" type="button" role="tab" aria-selected="true" data-qs-mode="files">Files</button>
653
- <button class="qs-mode-tab" type="button" role="tab" aria-selected="false" data-qs-mode="text">Text</button>
720
+ <button class="qs-mode-tab active" id="quickSwitcherFilesTab" type="button" role="tab" aria-controls="quickSwitcherResults" aria-selected="true" data-qs-mode="files">Files</button>
721
+ <button class="qs-mode-tab" id="quickSwitcherTextTab" type="button" role="tab" aria-controls="quickSwitcherResults" aria-selected="false" data-qs-mode="text">Text</button>
654
722
  </div>
655
723
  <div class="qs-input-wrap">
656
724
  <svg class="qs-search-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
657
725
  <circle cx="11" cy="11" r="8"></circle>
658
726
  <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
659
727
  </svg>
660
- <input type="text" class="qs-input" id="quickSwitcherInput" placeholder="Search files..." autocomplete="off" spellcheck="false">
728
+ <input type="text" class="qs-input" id="quickSwitcherInput" placeholder="Search files..." aria-label="Search files" aria-controls="quickSwitcherResults" aria-describedby="quickSwitcherHint quickSwitcherScope" autocomplete="off" spellcheck="false">
661
729
  <kbd class="qs-kbd">esc</kbd>
662
730
  </div>
663
- <div class="qs-results" id="quickSwitcherResults"></div>
664
- <div class="qs-hint" id="quickSwitcherHint">Type to search files</div>
665
- <div class="qs-footer" aria-hidden="true">
731
+ <div class="qs-scope hidden" id="quickSwitcherScope" role="note" aria-hidden="true">Exact, case-insensitive text in Markdown, Base, Mermaid, PlantUML, and Draw.io files. Images and Excalidraw are excluded.</div>
732
+ <div class="qs-results" id="quickSwitcherResults" role="listbox" aria-label="Search results" aria-busy="false" tabindex="-1"></div>
733
+ <div class="qs-hint" id="quickSwitcherHint" role="status" aria-live="polite" aria-atomic="true">Type to search files</div>
734
+ <div class="qs-footer">
666
735
  <span><kbd>↑</kbd><kbd>↓</kbd> Navigate</span>
667
736
  <span><kbd>↵</kbd> Open</span>
668
737
  <span><kbd>Tab</kbd> Switch mode</span>
669
738
  </div>
670
739
  </div>
671
740
  </div>
741
+ <script vite-ignore src="./app-config.js"></script>
672
742
  <script type="module" src="./main-entry.js"></script>
673
743
  </body>
674
744
  </html>
@@ -1,12 +1,8 @@
1
1
  import darkHighlightThemeUrl from '../assets/vendor/highlight/github-dark.min.css?url';
2
2
  import lightHighlightThemeUrl from '../assets/vendor/highlight/github.min.css?url';
3
- import '@fontsource-variable/inter';
4
- import '@fontsource/jetbrains-mono';
5
3
  import '../styles/base.css';
6
4
  import '../styles/style.css';
7
5
 
8
- import { ensureRuntimeConfigLoaded } from '../infrastructure/runtime-config-loader.js';
9
-
10
6
  function ensureHighlightThemeStylesheet() {
11
7
  let themeStylesheet = document.getElementById('hljs-theme');
12
8
  if (!(themeStylesheet instanceof HTMLLinkElement)) {
@@ -21,6 +17,5 @@ function ensureHighlightThemeStylesheet() {
21
17
  themeStylesheet.dataset.lightHref = lightHighlightThemeUrl;
22
18
  }
23
19
 
24
- await ensureRuntimeConfigLoaded();
25
20
  ensureHighlightThemeStylesheet();
26
21
  await import('../main.js');