collabmd 0.1.44 → 0.1.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -19
- package/bin/collabmd.js +27 -1
- package/dist/client/assets/CodeMirrorEditor-UCMRAMCV-CYM5nxUi.js +1 -0
- package/dist/client/assets/browser-utils--H_DkyEF.js +1 -0
- package/dist/client/assets/chunk-ERSWUTIN-hHdvnhaY.js +41 -0
- package/dist/client/assets/{chunk-CZQZEIFA-DT3N9fo7.js → chunk-YGJVY4SA-CjSe7Bx7.js} +2 -2
- package/dist/client/assets/comment-thread-store-CdcwrObc.js +1 -0
- package/dist/client/assets/comment-threads-9J6Em-_y.js +4 -0
- package/dist/client/assets/comment-ui-shared-BC4pt4w8.js +7 -0
- package/dist/client/assets/dist-B5HTH2BO.js +1 -0
- package/dist/client/assets/{dist-DhLvC8DS.js → dist-B5Jf1SLZ.js} +2 -2
- package/dist/client/assets/{dist-CnL7Y2sM.js → dist-BDt3rz7l.js} +1 -1
- package/dist/client/assets/dist-BEwK4csK.js +1 -0
- package/dist/client/assets/dist-BKW4PALF.js +1 -0
- package/dist/client/assets/dist-BWcHHOx-.js +1 -0
- package/dist/client/assets/{dist-CYZmbokb.js → dist-BalScOwZ.js} +9 -9
- package/dist/client/assets/dist-Bf8f4HmM.js +6 -0
- package/dist/client/assets/dist-BjHJDtyU.js +1 -0
- package/dist/client/assets/dist-Bm6pf9Bl.js +1 -0
- package/dist/client/assets/dist-BoVBdSjk.js +1 -0
- package/dist/client/assets/dist-CC5IrQMG.js +1 -0
- package/dist/client/assets/{dist-C11hHqv_.js → dist-CCP_AKPG.js} +12 -12
- package/dist/client/assets/dist-CZgOmxK6.js +1 -0
- package/dist/client/assets/{dist-D2AQ-76g.js → dist-Cqhv5LAk.js} +1 -1
- package/dist/client/assets/{dist-MvcV4190.js → dist-D-Z6FLem.js} +1 -1
- package/dist/client/assets/dist-DLMiIsNC.js +11 -0
- package/dist/client/assets/{dist-3bgCp7iY.js → dist-DZKu9Cs8.js} +1 -1
- package/dist/client/assets/dist-DaYdhcVs.js +1 -0
- package/dist/client/assets/dist-FWJsgGYI.js +1 -0
- package/dist/client/assets/dist-Kh2COra_.js +1 -0
- package/dist/client/assets/{dist-JYEDRrPT.js → dist-PDZ3bSqm.js} +1 -1
- package/dist/client/assets/{dist-Drp8uu5J.js → dist-TjMh8n1u.js} +1 -1
- package/dist/client/assets/{dist-DGb27Dl6.js → dist-dtAdgL39.js} +1 -1
- package/dist/client/assets/dist-jv4WdPnK.js +9 -0
- package/dist/client/assets/{dist-DK5Gs2wa.js → dist-rGBmqxC7.js} +1 -1
- package/dist/client/assets/{dist-DCzuX1AF.js → dist-shrl6K_0.js} +1 -1
- package/dist/client/assets/dist-tOaegDYS2.js +1 -0
- package/dist/client/assets/dist-ule2n6ak.js +1 -0
- package/dist/client/assets/dist-xElaxbia.js +1 -0
- package/dist/client/assets/drawio-editor-FzY1cVw8.js +9 -0
- package/dist/client/assets/drawioEditor-BjiKJqlc.js +2 -0
- package/dist/client/assets/editor-session-Cm9ekeNo.js +54 -0
- package/dist/client/assets/embedded-editor-base-CwTkk911.css +1 -0
- package/dist/client/assets/{en-GADW4C6J-DQ6zyCEM.js → en-7NFCYGKX-BrgYZAEe.js} +1 -1
- package/dist/client/assets/{preview-render-profile-BZzGSg6K.js → es-DXGV3RHd.js} +13 -13
- package/dist/client/assets/excalidraw-editor-B46zsTFI.js +9 -0
- package/dist/client/assets/excalidraw-editor-Bt7gMSoh.css +1 -0
- package/dist/client/assets/excalidraw-scene-BOben2gr.js +1 -0
- package/dist/client/assets/excalidrawEditor-CT2pHq7e.js +2 -0
- package/dist/client/assets/export-page-A7NHawJY.js +39 -0
- package/dist/client/assets/exportDocument-B2L8fe34.css +1 -0
- package/dist/client/assets/exportDocument-BaqcOAAW.js +2 -0
- package/dist/client/assets/file-icon-svg-CQAjlWjK.js +1 -0
- package/dist/client/assets/file-kind-BbqgGzpc.js +1 -0
- package/dist/client/assets/image-QXRYHUNP-SWEV8H0J.js +1 -0
- package/dist/client/assets/index-ClbjMBVt.js +2 -0
- package/dist/client/assets/index-Pum8ET-5.css +1 -0
- package/dist/client/assets/main-B3uPyqic.js +893 -0
- package/dist/client/assets/modulepreload-polyfill-P2Xu9kJm.js +1 -0
- package/dist/client/assets/pdf-BL9Pr2D5.js +54 -0
- package/dist/client/assets/pdf.worker-CLesOks4.mjs +64857 -0
- package/dist/client/assets/pdf_viewer-FVkkThnz.js +551 -0
- package/dist/client/assets/preview-diagram-utils-txBCoW8d.js +1 -0
- package/dist/client/assets/{preview-render-compiler-BSaQO_p3.js → preview-render-compiler-BD-XhkS2.js} +2 -2
- package/dist/client/assets/preview-render-compiler-BKedaMxx.js +1 -0
- package/dist/client/assets/preview-render-profile-CE-5rVTC.js +1 -0
- package/dist/client/assets/{preview-render-worker-B42LWvrD.js → preview-render-worker-CiPqc9n6.js} +20 -20
- package/dist/client/assets/prod-Dy20X7eT.js +1 -0
- package/dist/client/assets/prod-hnwh7wRM.js +177 -0
- package/dist/client/assets/quick-switcher-controller-fqOYR7qR.js +12 -0
- package/dist/client/assets/runtime-config-BLrEKVO1.js +1 -0
- package/dist/client/assets/vault-api-client-_LpV1aIn.js +6 -0
- package/dist/client/assets/{yjs-provider-reset-guard-Cox4nxwu.js → yjs-provider-reset-guard-DE0vINDP.js} +1 -1
- package/dist/client/drawio-editor.html +3 -2
- package/dist/client/excalidraw-editor.html +3 -2
- package/dist/client/export-document.html +4 -3
- package/dist/client/index.html +109 -27
- package/docker-compose.yml +42 -0
- package/package.json +26 -15
- package/scripts/local-structurizr-compose.mjs +101 -0
- package/src/client/app/drawio-editor-entry.js +0 -3
- package/src/client/app/drawio-editor.html +1 -0
- package/src/client/app/excalidraw-editor-entry.js +0 -3
- package/src/client/app/excalidraw-editor.html +1 -0
- package/src/client/app/export-document-entry.js +0 -3
- package/src/client/app/export-document.html +1 -0
- package/src/client/app/index.html +106 -24
- package/src/client/app/main-entry.js +0 -5
- package/src/client/application/app-shell/chat-feature.js +180 -124
- package/src/client/application/app-shell/comments-feature.js +20 -11
- package/src/client/application/app-shell/git-feature.js +16 -9
- package/src/client/application/app-shell/presence-feature.js +18 -11
- package/src/client/application/app-shell/ui-feature-shell.js +78 -17
- package/src/client/application/app-shell/ui-feature-sidebar.js +74 -1
- package/src/client/application/app-shell/ui-feature-tab-activity.js +2 -2
- package/src/client/application/app-shell/ui-feature-toolbar.js +2 -52
- package/src/client/application/app-shell/workspace-feature.js +27 -84
- package/src/client/application/app-shell-elements.js +9 -1
- package/src/client/application/diagram-chrome.js +161 -166
- package/src/client/application/diagram-preview-export.js +7 -34
- package/src/client/application/diagram-preview-hydrator.js +1 -19
- package/src/client/application/markdown-frontmatter.js +0 -2
- package/src/client/application/mermaid-preview-hydrator.js +1 -14
- package/src/client/application/pdf-preview-controller.js +992 -0
- package/src/client/application/plantuml-preview-hydrator.js +0 -10
- package/src/client/application/preview-diagram-utils.js +31 -2
- package/src/client/application/preview-render-compiler.js +2 -1
- package/src/client/application/preview-renderer.js +2 -2
- package/src/client/application/quick-switcher-loader.js +3 -1
- package/src/client/application/structurizr-preview-controller.js +395 -0
- package/src/client/application/workspace-coordinator.js +25 -3
- package/src/client/application/workspace-preview-controller.js +91 -5
- package/src/client/bootstrap/collabmd-app-shell.js +155 -43
- package/src/client/browser-utils.js +44 -0
- package/src/client/domain/excalidraw-collaboration.js +0 -2
- package/src/client/domain/room.js +38 -0
- package/src/client/domain/runtime-paths.js +26 -5
- package/src/client/domain/structurizr-language.js +99 -0
- package/src/client/domain/vault-paths.js +48 -0
- package/src/client/excalidraw-editor.js +833 -51
- package/src/client/export/export-pipeline.js +6 -34
- package/src/client/infrastructure/auth-client.js +4 -10
- package/src/client/infrastructure/browser-notification-port.js +33 -20
- package/src/client/infrastructure/browser-preferences-port.js +46 -9
- package/src/client/infrastructure/comment-thread-store.js +34 -13
- package/src/client/infrastructure/editor-session.js +10 -0
- package/src/client/infrastructure/editor-view-adapter.js +133 -5
- package/src/client/infrastructure/excalidraw-room-client.js +103 -14
- package/src/client/infrastructure/git-api-client.js +5 -0
- package/src/client/infrastructure/lobby-presence.js +1 -0
- package/src/client/infrastructure/vault-api-client.js +51 -0
- package/src/client/infrastructure/workspace-sync-client.js +13 -1
- package/src/client/presentation/comment-overview-controller.js +18 -53
- package/src/client/presentation/comment-ui/comment-ui-card.js +1 -12
- package/src/client/presentation/comment-ui/comment-ui-layout.js +242 -219
- package/src/client/presentation/comment-ui/comment-ui-render.js +32 -45
- package/src/client/presentation/comment-ui/comment-ui-shared.js +68 -13
- package/src/client/presentation/comment-ui-controller.js +5 -1
- package/src/client/presentation/drawio-embed-controller.js +9 -102
- package/src/client/presentation/drawio-viewer.js +118 -0
- package/src/client/presentation/excalidraw-embed-controller.js +74 -8
- package/src/client/presentation/file-action-controller.js +134 -0
- package/src/client/presentation/file-explorer-controller.js +33 -3
- package/src/client/presentation/file-explorer-view.js +59 -34
- package/src/client/presentation/file-icon-svg.js +40 -0
- package/src/client/presentation/file-tree-state.js +12 -4
- package/src/client/presentation/git-diff-view-controller.js +731 -3
- package/src/client/presentation/outline-controller.js +86 -0
- package/src/client/presentation/quick-switcher-controller.js +257 -74
- package/src/client/presentation/quick-switcher-text-search.js +3 -3
- package/src/client/presentation/toast-controller.js +3 -0
- package/src/client/styles/components/feedback.css +6 -0
- package/src/client/styles/components/navigation.css +11 -1
- package/src/client/styles/features/collaboration-chat.css +49 -53
- package/src/client/styles/features/collaboration-presence.css +9 -7
- package/src/client/styles/features/comment-card.css +25 -11
- package/src/client/styles/features/comment-overlays.css +0 -4
- package/src/client/styles/features/comment-overview.css +44 -21
- package/src/client/styles/features/comments-drawer.css +2 -100
- package/src/client/styles/features/diagram-preview.css +81 -18
- package/src/client/styles/features/diff-special.css +309 -0
- package/src/client/styles/features/embedded-preview.css +8 -33
- package/src/client/styles/features/quick-switcher.css +8 -0
- package/src/client/styles/foundation/themes.css +6 -0
- package/src/client/styles/foundation/tokens.css +1 -0
- package/src/client/styles/layout/editor-page.css +40 -0
- package/src/client/styles/layout/responsive.css +31 -1
- package/src/client/styles/layout/shell.css +383 -7
- package/src/client/styles/layout/sidebar.css +47 -15
- package/src/client/styles/layout/view-modes.css +1 -0
- package/src/client/styles/overrides/codemirror.css +217 -15
- package/src/client/styles/style.css +1 -0
- package/src/client/styles/surfaces/excalidraw-editor.css +294 -0
- package/src/domain/comment-threads.js +63 -5
- package/src/domain/excalidraw-room-codec.js +6 -4
- package/src/domain/file-kind.js +35 -3
- package/src/server/application/workspace-reconciliation.js +1 -1
- package/src/server/config/env.js +79 -0
- package/src/server/create-app-server.js +14 -3
- package/src/server/domain/bases/base-definition.js +1 -1
- package/src/server/domain/bases/base-expression-runtime.js +1 -4
- package/src/server/domain/bases/base-index-snapshot-store.js +1 -4
- package/src/server/domain/bases/base-query-service.js +1 -77
- package/src/server/domain/bases/base-transform.js +1 -4
- package/src/server/domain/collaboration/collaboration-room.js +55 -21
- package/src/server/domain/comment-overview.js +25 -8
- package/src/server/domain/docx-exporter.js +24 -33
- package/src/server/domain/ripgrep-search-service.js +7 -1
- package/src/server/domain/workspace-state.js +32 -11
- package/src/server/infrastructure/git/diff-service.js +29 -13
- package/src/server/infrastructure/git/git-service.js +61 -10
- package/src/server/infrastructure/git/history-service.js +96 -29
- package/src/server/infrastructure/git/image-mime.js +14 -0
- package/src/server/infrastructure/git/path-utils.js +1 -1
- package/src/server/infrastructure/git/responses.js +0 -95
- package/src/server/infrastructure/git/untracked-files.js +28 -1
- package/src/server/infrastructure/github/github-app-client.js +22 -15
- package/src/server/infrastructure/http/create-git-api-query-handler.js +31 -1
- package/src/server/infrastructure/http/create-request-handler.js +18 -31
- package/src/server/infrastructure/http/create-static-handler.js +5 -2
- package/src/server/infrastructure/http/create-structurizr-api-handler.js +145 -0
- package/src/server/infrastructure/http/create-vault-api-command-handler.js +70 -8
- package/src/server/infrastructure/http/create-vault-api-query-handler.js +51 -3
- package/src/server/infrastructure/http/http-errors.js +7 -1
- package/src/server/infrastructure/http/http-request-helpers.js +22 -0
- package/src/server/infrastructure/persistence/path-utils.js +1 -1
- package/src/server/infrastructure/persistence/vault-file-store.js +3 -0
- package/src/server/infrastructure/structurizr/structurizr-embed.css +43 -0
- package/src/server/infrastructure/structurizr/structurizr-workspace-service.js +374 -0
- package/src/server/infrastructure/websocket/attach-collaboration-gateway.js +4 -22
- package/dist/client/assets/CodeMirrorEditor-UCMRAMCV-CbSISC1w.js +0 -1
- package/dist/client/assets/bases-preview-controller-2pLHk0uk.js +0 -143
- package/dist/client/assets/browser-utils-CKtI_rZl.js +0 -1
- package/dist/client/assets/button-BCEiw4Rw.js +0 -1
- package/dist/client/assets/chunk-AXR3VHVW-0GTk_evH.js +0 -41
- package/dist/client/assets/comment-threads-D-iKphIp.js +0 -4
- package/dist/client/assets/diagram-action-icons-aa_KOv9h.js +0 -36
- package/dist/client/assets/dist-BH87JoHx.js +0 -11
- package/dist/client/assets/dist-BIkPRZO7.js +0 -6
- package/dist/client/assets/dist-BqCsFpx4.js +0 -1
- package/dist/client/assets/dist-C2JHCt8U.js +0 -1
- package/dist/client/assets/dist-CZjTtmTu.js +0 -1
- package/dist/client/assets/dist-Cig4Ov_X.js +0 -1
- package/dist/client/assets/dist-CqQEC8gR.js +0 -1
- package/dist/client/assets/dist-D4Rzqod1.js +0 -1
- package/dist/client/assets/dist-D5sn-mwk.js +0 -9
- package/dist/client/assets/dist-D7G-n87v.js +0 -1
- package/dist/client/assets/dist-DRqOrNgN.js +0 -1
- package/dist/client/assets/dist-DetkMS_4.js +0 -1
- package/dist/client/assets/dist-Dp6FVkQ1.js +0 -1
- package/dist/client/assets/dist-DtbjNB28.js +0 -1
- package/dist/client/assets/dist-DyrYcvpo2.js +0 -1
- package/dist/client/assets/dist-GrygD2zE.js +0 -1
- package/dist/client/assets/dist-HmEpWUow.js +0 -1
- package/dist/client/assets/dist-RTa81Km7.js +0 -1
- package/dist/client/assets/drawio-editor-DDvFoarP.js +0 -9
- package/dist/client/assets/drawio-embed-controller-BD1GTRwn.js +0 -1
- package/dist/client/assets/drawioEditor-Bu5grlH5.js +0 -2
- package/dist/client/assets/editor-session-DGlpiAsK.js +0 -16
- package/dist/client/assets/embedded-editor-base-C9roKYpW.css +0 -1
- package/dist/client/assets/excalidraw-editor-BHu6k8d4.js +0 -9
- package/dist/client/assets/excalidraw-editor-Cr_184EF.css +0 -1
- package/dist/client/assets/excalidraw-embed-controller-y2fenN_g.js +0 -1
- package/dist/client/assets/excalidraw-embed-reconciler-DGiagExg.js +0 -1
- package/dist/client/assets/excalidraw-scene-BvsQ6mLP.js +0 -176
- package/dist/client/assets/excalidrawEditor-4vFE--Uw.js +0 -2
- package/dist/client/assets/export-page-Cby8JzPO.js +0 -39
- package/dist/client/assets/exportDocument-C9v-bc7I.css +0 -1
- package/dist/client/assets/exportDocument-CRHCfsdo.js +0 -2
- package/dist/client/assets/file-history-view-controller-BDjEV9xJ.js +0 -112
- package/dist/client/assets/file-kind-BKPOIRPE.js +0 -1
- package/dist/client/assets/git-diff-view-controller-DgdM1aqb.js +0 -150
- package/dist/client/assets/git-panel-controller-BDTR2HVp.js +0 -207
- package/dist/client/assets/image-XGD7JQR6-XDUWHRpO.js +0 -1
- package/dist/client/assets/index-7xOyXDhP.css +0 -1
- package/dist/client/assets/index-Bz1KuQ6y.js +0 -2
- package/dist/client/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/dist/client/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/dist/client/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/dist/client/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/dist/client/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/dist/client/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/dist/client/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
- package/dist/client/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
- package/dist/client/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
- package/dist/client/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
- package/dist/client/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
- package/dist/client/assets/main-Ci07m9oP.js +0 -152
- package/dist/client/assets/preview-diagram-utils-n_bbJA9V.js +0 -1
- package/dist/client/assets/preview-render-compiler-csGM5ZFz.js +0 -1
- package/dist/client/assets/quick-switcher-controller-CoiYvllm.js +0 -12
- package/dist/client/assets/room-CDrmIdDt.js +0 -1
- package/dist/client/assets/runtime-config-CDgeuPWN.js +0 -1
- package/dist/client/assets/runtime-config-loader-BHGniHP5.js +0 -1
- package/dist/client/assets/runtime-paths-DvpihCEq.js +0 -1
- package/dist/client/assets/segmented-control-DJrHSz8M.js +0 -1
- package/dist/client/assets/vault-api-client-sLB2bo56.js +0 -1
- package/dist/client/assets/vault-paths-CVkuh0j-.js +0 -5
- package/src/client/bootstrap/lazy-controller-feature.js +0 -433
- package/src/client/infrastructure/backlinks-api-client.js +0 -16
- package/src/client/infrastructure/plantuml-api-client.js +0 -19
- package/src/client/infrastructure/runtime-config-loader.js +0 -56
- package/src/server/domain/collaboration/room-persistence-controller.js +0 -80
- package/src/server/infrastructure/git/command-runner.js +0 -49
- package/src/server/infrastructure/git/errors.js +0 -8
- package/src/server/infrastructure/http/create-esm-proxy-handler.js +0 -130
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getVaultFileExtension,
|
|
3
|
+
isVaultFilePath,
|
|
4
|
+
VAULT_FILE_EXTENSIONS,
|
|
3
5
|
} from '../../domain/file-kind.js';
|
|
6
|
+
import { pickFiles } from '../browser-utils.js';
|
|
4
7
|
import {
|
|
5
8
|
createBaseStarter,
|
|
6
9
|
composeVaultChildPath,
|
|
@@ -8,6 +11,7 @@ import {
|
|
|
8
11
|
createMarkdownStarter,
|
|
9
12
|
createMermaidStarter,
|
|
10
13
|
createPlantUmlStarter,
|
|
14
|
+
createStructurizrStarter,
|
|
11
15
|
ensureVaultExtension,
|
|
12
16
|
getVaultPathLeaf,
|
|
13
17
|
getVaultPathParent,
|
|
@@ -28,6 +32,8 @@ function formatCount(value, singularLabel, pluralLabel) {
|
|
|
28
32
|
return `${value} ${value === 1 ? singularLabel : pluralLabel}`;
|
|
29
33
|
}
|
|
30
34
|
|
|
35
|
+
const VAULT_FILE_PICKER_ACCEPT = VAULT_FILE_EXTENSIONS.join(',');
|
|
36
|
+
|
|
31
37
|
function createEmptyExcalidrawScene() {
|
|
32
38
|
return JSON.stringify({
|
|
33
39
|
type: 'excalidraw',
|
|
@@ -57,7 +63,9 @@ export class FileActionController {
|
|
|
57
63
|
: { matches: false },
|
|
58
64
|
onFileDelete,
|
|
59
65
|
onFileSelect,
|
|
66
|
+
onShowFileExtensionsChange,
|
|
60
67
|
pendingWorkspaceRequestIds = null,
|
|
68
|
+
showFileExtensions = false,
|
|
61
69
|
state,
|
|
62
70
|
toastController,
|
|
63
71
|
vaultClient,
|
|
@@ -66,13 +74,16 @@ export class FileActionController {
|
|
|
66
74
|
}) {
|
|
67
75
|
this.onFileDelete = onFileDelete;
|
|
68
76
|
this.onFileSelect = onFileSelect;
|
|
77
|
+
this.onShowFileExtensionsChange = onShowFileExtensionsChange;
|
|
69
78
|
this.pendingWorkspaceRequestIds = pendingWorkspaceRequestIds;
|
|
79
|
+
this.showFileExtensions = Boolean(showFileExtensions);
|
|
70
80
|
this.state = state;
|
|
71
81
|
this.toastController = toastController;
|
|
72
82
|
this.vaultClient = vaultClient;
|
|
73
83
|
this.view = view;
|
|
74
84
|
this.refresh = refresh;
|
|
75
85
|
this.createButton = document.getElementById('sidebarCreateBtn');
|
|
86
|
+
this.fileExplorerOptionsButton = document.getElementById('fileExplorerOptionsBtn');
|
|
76
87
|
this.actionDialog = document.getElementById('fileActionDialog');
|
|
77
88
|
this.actionForm = document.getElementById('fileActionForm');
|
|
78
89
|
this.actionTitle = document.getElementById('fileActionTitle');
|
|
@@ -87,6 +98,9 @@ export class FileActionController {
|
|
|
87
98
|
this.createMenu = new CreateMenuPresenter({
|
|
88
99
|
mobileBreakpointQuery,
|
|
89
100
|
});
|
|
101
|
+
this.fileExplorerOptionsMenu = new CreateMenuPresenter({
|
|
102
|
+
mobileBreakpointQuery,
|
|
103
|
+
});
|
|
90
104
|
this.pendingAction = null;
|
|
91
105
|
this.actionBusy = false;
|
|
92
106
|
}
|
|
@@ -95,6 +109,9 @@ export class FileActionController {
|
|
|
95
109
|
this.createButton?.addEventListener('click', () => {
|
|
96
110
|
this.openRootCreateMenu({ anchor: this.createButton });
|
|
97
111
|
});
|
|
112
|
+
this.fileExplorerOptionsButton?.addEventListener('click', () => {
|
|
113
|
+
this.openFileExplorerOptionsMenu({ anchor: this.fileExplorerOptionsButton });
|
|
114
|
+
});
|
|
98
115
|
this.actionCancelButton?.addEventListener('click', () => this.closeActionDialog());
|
|
99
116
|
this.actionForm?.addEventListener('submit', (event) => {
|
|
100
117
|
event.preventDefault();
|
|
@@ -105,6 +122,18 @@ export class FileActionController {
|
|
|
105
122
|
|
|
106
123
|
getCreateActions({ parentDir = '' } = {}) {
|
|
107
124
|
return [
|
|
125
|
+
{
|
|
126
|
+
contextLabel: 'Upload files',
|
|
127
|
+
group: 'File',
|
|
128
|
+
hint: 'Supported vault files',
|
|
129
|
+
icon: this.getCreateActionIcon('upload'),
|
|
130
|
+
id: 'upload',
|
|
131
|
+
label: 'Upload files',
|
|
132
|
+
meta: 'Multiple',
|
|
133
|
+
onSelect: () => {
|
|
134
|
+
void this.handleUploadFiles({ parentDir });
|
|
135
|
+
},
|
|
136
|
+
},
|
|
108
137
|
{
|
|
109
138
|
contextLabel: 'New markdown file',
|
|
110
139
|
group: 'Note',
|
|
@@ -165,6 +194,16 @@ export class FileActionController {
|
|
|
165
194
|
meta: '.puml',
|
|
166
195
|
onSelect: () => this.handleNewPlantUml({ parentDir }),
|
|
167
196
|
},
|
|
197
|
+
{
|
|
198
|
+
contextLabel: 'New Structurizr workspace',
|
|
199
|
+
group: 'Diagram',
|
|
200
|
+
hint: 'Structurizr DSL',
|
|
201
|
+
icon: this.getCreateActionIcon('structurizr'),
|
|
202
|
+
id: 'structurizr',
|
|
203
|
+
label: 'Structurizr workspace',
|
|
204
|
+
meta: '.dsl',
|
|
205
|
+
onSelect: () => this.handleNewStructurizr({ parentDir }),
|
|
206
|
+
},
|
|
168
207
|
{
|
|
169
208
|
contextLabel: 'New folder',
|
|
170
209
|
group: 'Structure',
|
|
@@ -230,10 +269,13 @@ export class FileActionController {
|
|
|
230
269
|
|
|
231
270
|
getCreateActionIcon(kind) {
|
|
232
271
|
switch (kind) {
|
|
272
|
+
case 'upload':
|
|
273
|
+
return '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 16V4"/><path d="m7 9 5-5 5 5"/><path d="M5 20h14"/></svg>';
|
|
233
274
|
case 'base':
|
|
234
275
|
return '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 4h7l5 5v11a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z"/><path d="M14 4v5h5"/><path d="M8 13h8"/><path d="M8 17h6"/><path d="M8 9h3"/></svg>';
|
|
235
276
|
case 'drawio':
|
|
236
277
|
case 'plantuml':
|
|
278
|
+
case 'structurizr':
|
|
237
279
|
return '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="7" height="6" rx="1"/><rect x="14" y="4" width="7" height="6" rx="1"/><rect x="8.5" y="14" width="7" height="6" rx="1"/><path d="M10 7h4"/><path d="M17.5 10v2.5"/><path d="M6.5 10v2.5"/><path d="M6.5 12.5h11"/></svg>';
|
|
238
280
|
case 'excalidraw':
|
|
239
281
|
return '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19l7-7 3 3-7 7-3-3z"/><path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"/><path d="M2 2l7.586 7.586"/><circle cx="11" cy="11" r="2"/></svg>';
|
|
@@ -313,6 +355,7 @@ export class FileActionController {
|
|
|
313
355
|
|
|
314
356
|
this.pendingAction = { requiresInput, emptyMessage, onSubmit };
|
|
315
357
|
this.createMenu.close({ restoreFocus: false });
|
|
358
|
+
this.fileExplorerOptionsMenu.close({ restoreFocus: false });
|
|
316
359
|
this.view?.removeContextMenu?.();
|
|
317
360
|
|
|
318
361
|
this.actionTitle.textContent = title;
|
|
@@ -464,6 +507,47 @@ export class FileActionController {
|
|
|
464
507
|
}
|
|
465
508
|
}
|
|
466
509
|
|
|
510
|
+
async uploadVaultFiles(files = [], { parentDir = '' } = {}) {
|
|
511
|
+
const normalizedParentDir = normalizeVaultPathInput(parentDir);
|
|
512
|
+
let uploaded = false;
|
|
513
|
+
|
|
514
|
+
for (const file of Array.from(files ?? [])) {
|
|
515
|
+
const fileName = getVaultPathLeaf(file?.name);
|
|
516
|
+
const filePath = composeVaultChildPath(normalizedParentDir, fileName);
|
|
517
|
+
if (!fileName || !isVaultFilePath(filePath)) {
|
|
518
|
+
this.showToast(`Unsupported file type: ${fileName || 'unnamed file'}`);
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
try {
|
|
523
|
+
await this.runWorkspaceMutation((requestId) => this.vaultClient.uploadFile({
|
|
524
|
+
file,
|
|
525
|
+
path: filePath,
|
|
526
|
+
requestId,
|
|
527
|
+
}));
|
|
528
|
+
uploaded = true;
|
|
529
|
+
this.state.expandDirectoryPath(filePath, { includeLeaf: false });
|
|
530
|
+
} catch (error) {
|
|
531
|
+
this.showToast(`${fileName}: ${error?.message || 'Failed to upload file'}`);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
if (uploaded) {
|
|
536
|
+
await this.refresh();
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
return uploaded;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
async handleUploadFiles({ parentDir = '' } = {}) {
|
|
543
|
+
const files = await pickFiles({ accept: VAULT_FILE_PICKER_ACCEPT, multiple: true });
|
|
544
|
+
if (files.length === 0) {
|
|
545
|
+
return false;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
return this.uploadVaultFiles(files, { parentDir });
|
|
549
|
+
}
|
|
550
|
+
|
|
467
551
|
async createVaultFile(filePath, content, { openAfterCreate = false, errorMessage = 'Failed to create file' } = {}) {
|
|
468
552
|
try {
|
|
469
553
|
await this.runWorkspaceMutation((requestId) => this.vaultClient.createFile(withRequestId({
|
|
@@ -716,6 +800,7 @@ export class FileActionController {
|
|
|
716
800
|
|
|
717
801
|
openCreateMenu({ anchor = this.createButton, parentDir = '' } = {}) {
|
|
718
802
|
this.view?.removeContextMenu?.();
|
|
803
|
+
this.fileExplorerOptionsMenu.close({ restoreFocus: false });
|
|
719
804
|
this.createMenu.toggle({
|
|
720
805
|
anchor,
|
|
721
806
|
items: this.getCreateActions({ parentDir }),
|
|
@@ -723,6 +808,25 @@ export class FileActionController {
|
|
|
723
808
|
});
|
|
724
809
|
}
|
|
725
810
|
|
|
811
|
+
openFileExplorerOptionsMenu({ anchor = this.fileExplorerOptionsButton } = {}) {
|
|
812
|
+
this.view?.removeContextMenu?.();
|
|
813
|
+
this.createMenu.close({ restoreFocus: false });
|
|
814
|
+
this.fileExplorerOptionsMenu.toggle({
|
|
815
|
+
anchor,
|
|
816
|
+
items: [{
|
|
817
|
+
icon: '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12s3.5-6 10-6 10 6 10 6-3.5 6-10 6S2 12 2 12Z"></path><circle cx="12" cy="12" r="2.5"></circle></svg>',
|
|
818
|
+
id: 'show-file-extensions',
|
|
819
|
+
label: 'Show file extensions',
|
|
820
|
+
meta: this.showFileExtensions ? 'On' : 'Off',
|
|
821
|
+
onSelect: () => {
|
|
822
|
+
this.showFileExtensions = !this.showFileExtensions;
|
|
823
|
+
this.onShowFileExtensionsChange?.(this.showFileExtensions);
|
|
824
|
+
},
|
|
825
|
+
}],
|
|
826
|
+
title: 'File explorer options',
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
|
|
726
830
|
handleNewFile({ parentDir = '' } = {}) {
|
|
727
831
|
const context = this.getCreateContext(parentDir);
|
|
728
832
|
|
|
@@ -921,6 +1025,36 @@ export class FileActionController {
|
|
|
921
1025
|
});
|
|
922
1026
|
}
|
|
923
1027
|
|
|
1028
|
+
handleNewStructurizr({ parentDir = '' } = {}) {
|
|
1029
|
+
const context = this.getCreateContext(parentDir);
|
|
1030
|
+
|
|
1031
|
+
this.openActionDialog({
|
|
1032
|
+
title: 'Create Structurizr workspace',
|
|
1033
|
+
copy: context.normalizedParentDir
|
|
1034
|
+
? 'Create a collaborative C4 workspace inside the selected folder.'
|
|
1035
|
+
: 'Create a collaborative C4 workspace in the vault.',
|
|
1036
|
+
label: `Workspace ${context.inputLabelSuffix}`,
|
|
1037
|
+
hint: `${context.hintPrefix} ".dsl" is added automatically. workspace.dsl is conventional; any workspace .dsl file can render.`,
|
|
1038
|
+
note: context.note,
|
|
1039
|
+
placeholder: 'workspace',
|
|
1040
|
+
submitLabel: 'Create workspace',
|
|
1041
|
+
emptyMessage: 'Workspace path is required',
|
|
1042
|
+
onSubmit: (value) => {
|
|
1043
|
+
const normalizedPath = normalizeVaultPathInput(value);
|
|
1044
|
+
if (!normalizedPath) {
|
|
1045
|
+
this.showToast('Workspace path is required');
|
|
1046
|
+
return false;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
const starter = createStructurizrStarter(composeVaultChildPath(context.normalizedParentDir, normalizedPath));
|
|
1050
|
+
return this.createVaultFile(starter.path, starter.content, {
|
|
1051
|
+
errorMessage: 'Failed to create Structurizr workspace',
|
|
1052
|
+
openAfterCreate: true,
|
|
1053
|
+
});
|
|
1054
|
+
},
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1057
|
+
|
|
924
1058
|
handleRenameFile(filePath) {
|
|
925
1059
|
const extension = getVaultFileExtension(filePath) || '.md';
|
|
926
1060
|
|
|
@@ -9,14 +9,18 @@ export class FileExplorerController {
|
|
|
9
9
|
onFileSelect,
|
|
10
10
|
onFileDelete,
|
|
11
11
|
pendingWorkspaceRequestIds = null,
|
|
12
|
+
onShowFileExtensionsChange,
|
|
13
|
+
showFileExtensions = false,
|
|
12
14
|
toastController,
|
|
13
15
|
vaultClient,
|
|
14
16
|
}) {
|
|
15
17
|
this.onFileSelect = onFileSelect;
|
|
16
18
|
this.onFileDelete = onFileDelete;
|
|
19
|
+
this.onShowFileExtensionsChange = onShowFileExtensionsChange;
|
|
17
20
|
this.toastController = toastController;
|
|
18
21
|
this.vaultClient = vaultClient;
|
|
19
22
|
this.state = new FileTreeState();
|
|
23
|
+
this.showFileExtensions = Boolean(showFileExtensions);
|
|
20
24
|
this.threadCounts = new Map();
|
|
21
25
|
this.view = new FileExplorerView({
|
|
22
26
|
mobileBreakpointQuery,
|
|
@@ -27,7 +31,12 @@ export class FileExplorerController {
|
|
|
27
31
|
},
|
|
28
32
|
onDirectoryToggle: (pathValue) => {
|
|
29
33
|
this.state.toggleDirectory(pathValue);
|
|
30
|
-
this.
|
|
34
|
+
if (!this.view.rerenderDirectoryBranch(pathValue, this.state.tree, {
|
|
35
|
+
activeFilePath: this.state.activeFilePath,
|
|
36
|
+
expandedDirs: this.state.expandedDirs,
|
|
37
|
+
})) {
|
|
38
|
+
this.renderTree();
|
|
39
|
+
}
|
|
31
40
|
},
|
|
32
41
|
onEntryDrop: (payload) => this.actionController.moveEntryByDrop(payload),
|
|
33
42
|
onFileContextMenu: (event, payload) => {
|
|
@@ -54,7 +63,13 @@ export class FileExplorerController {
|
|
|
54
63
|
mobileBreakpointQuery,
|
|
55
64
|
onFileDelete: this.onFileDelete,
|
|
56
65
|
onFileSelect: this.onFileSelect,
|
|
66
|
+
onShowFileExtensionsChange: (enabled) => {
|
|
67
|
+
this.showFileExtensions = Boolean(enabled);
|
|
68
|
+
this.onShowFileExtensionsChange?.(this.showFileExtensions);
|
|
69
|
+
this.renderTree();
|
|
70
|
+
},
|
|
57
71
|
pendingWorkspaceRequestIds,
|
|
72
|
+
showFileExtensions: this.showFileExtensions,
|
|
58
73
|
refresh: () => this.refresh(),
|
|
59
74
|
state: this.state,
|
|
60
75
|
toastController: this.toastController,
|
|
@@ -86,15 +101,25 @@ export class FileExplorerController {
|
|
|
86
101
|
}
|
|
87
102
|
|
|
88
103
|
setActiveFile(filePath) {
|
|
104
|
+
const expandedDirectoryCount = this.state.expandedDirs.size;
|
|
89
105
|
this.state.setActiveFile(filePath);
|
|
90
|
-
this.
|
|
106
|
+
if (this.state.searchQuery) {
|
|
107
|
+
this.view.setActiveFile(filePath);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (
|
|
111
|
+
this.state.expandedDirs.size !== expandedDirectoryCount
|
|
112
|
+
|| !this.view.setActiveFile(filePath)
|
|
113
|
+
) {
|
|
114
|
+
this.renderTree();
|
|
115
|
+
}
|
|
91
116
|
}
|
|
92
117
|
|
|
93
118
|
setThreadCounts(threadCounts = new Map()) {
|
|
94
119
|
this.threadCounts = threadCounts instanceof Map
|
|
95
120
|
? new Map(threadCounts)
|
|
96
121
|
: new Map(Object.entries(threadCounts ?? {}));
|
|
97
|
-
this.
|
|
122
|
+
this.view.setThreadCounts(this.threadCounts);
|
|
98
123
|
}
|
|
99
124
|
|
|
100
125
|
revealFile(filePath, { clearSearch = false } = {}) {
|
|
@@ -111,6 +136,10 @@ export class FileExplorerController {
|
|
|
111
136
|
return this.state.flatFiles;
|
|
112
137
|
}
|
|
113
138
|
|
|
139
|
+
get fileEntries() {
|
|
140
|
+
return this.state.flatFileEntries;
|
|
141
|
+
}
|
|
142
|
+
|
|
114
143
|
get flatDocumentFiles() {
|
|
115
144
|
return this.state.flatFiles.filter((path) => !isImageAttachmentFilePath(path));
|
|
116
145
|
}
|
|
@@ -126,6 +155,7 @@ export class FileExplorerController {
|
|
|
126
155
|
reset,
|
|
127
156
|
searchMatches: this.state.getSearchMatches(),
|
|
128
157
|
searchQuery: this.state.searchQuery,
|
|
158
|
+
showFileExtensions: this.showFileExtensions,
|
|
129
159
|
threadCounts: this.threadCounts,
|
|
130
160
|
tree: this.state.tree,
|
|
131
161
|
});
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
import { escapeHtml } from '../domain/vault-utils.js';
|
|
6
6
|
import { getVaultPathLeaf, getVaultPathParent } from '../domain/vault-paths.js';
|
|
7
7
|
import { buttonClassNames } from './components/ui/button.js';
|
|
8
|
+
import { getVaultFileIconSvg } from './file-icon-svg.js';
|
|
8
9
|
|
|
9
10
|
function findNodeByPath(nodes = [], pathValue = '') {
|
|
10
11
|
for (const node of nodes) {
|
|
@@ -52,6 +53,7 @@ export class FileExplorerView {
|
|
|
52
53
|
this.searchInput = document.getElementById('fileSearchInput');
|
|
53
54
|
this.renderedDirectoryWrappers = new Map();
|
|
54
55
|
this.renderedChildContainers = new Map();
|
|
56
|
+
this.renderedFileItems = new Map();
|
|
55
57
|
this.lastRenderMode = 'tree';
|
|
56
58
|
this.longPressTimer = 0;
|
|
57
59
|
this.longPressContext = null;
|
|
@@ -66,6 +68,7 @@ export class FileExplorerView {
|
|
|
66
68
|
this.autoExpandTargetPath = '';
|
|
67
69
|
this.rootDropZone = null;
|
|
68
70
|
this.threadCounts = new Map();
|
|
71
|
+
this.showFileExtensions = false;
|
|
69
72
|
}
|
|
70
73
|
|
|
71
74
|
initialize() {
|
|
@@ -120,17 +123,51 @@ export class FileExplorerView {
|
|
|
120
123
|
}
|
|
121
124
|
|
|
122
125
|
revealFile(filePath) {
|
|
123
|
-
|
|
124
|
-
.find((element) => element.dataset.path === filePath);
|
|
125
|
-
fileItem?.scrollIntoView({ block: 'nearest' });
|
|
126
|
+
this.renderedFileItems.get(filePath)?.scrollIntoView({ block: 'nearest' });
|
|
126
127
|
}
|
|
127
128
|
|
|
128
|
-
|
|
129
|
+
setActiveFile(filePath) {
|
|
130
|
+
this.treeContainer?.querySelector('.file-tree-file.active')?.classList.remove('active');
|
|
131
|
+
if (!filePath) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const fileItem = this.renderedFileItems.get(filePath);
|
|
136
|
+
fileItem?.classList.add('active');
|
|
137
|
+
return Boolean(fileItem);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
setThreadCounts(threadCounts) {
|
|
141
|
+
this.threadCounts = threadCounts instanceof Map ? threadCounts : new Map();
|
|
142
|
+
this.renderedFileItems.forEach((button, filePath) => {
|
|
143
|
+
const threadCount = Number(this.threadCounts.get(filePath) ?? 0) || 0;
|
|
144
|
+
let badge = button.querySelector('.file-tree-comment-count');
|
|
145
|
+
button.classList.toggle('has-comments', threadCount > 0);
|
|
146
|
+
|
|
147
|
+
if (threadCount <= 0) {
|
|
148
|
+
delete button.dataset.threadCount;
|
|
149
|
+
badge?.remove();
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
button.dataset.threadCount = String(threadCount);
|
|
154
|
+
if (!badge) {
|
|
155
|
+
badge = document.createElement('span');
|
|
156
|
+
badge.className = 'file-tree-comment-count';
|
|
157
|
+
button.appendChild(badge);
|
|
158
|
+
}
|
|
159
|
+
badge.textContent = String(threadCount);
|
|
160
|
+
badge.setAttribute('aria-label', `${threadCount} open comment thread${threadCount === 1 ? '' : 's'}`);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
render({ activeFilePath, changedPaths = null, expandedDirs, reset = false, searchMatches, searchQuery, showFileExtensions = false, threadCounts = new Map(), tree }) {
|
|
129
165
|
if (!this.treeContainer) {
|
|
130
166
|
return;
|
|
131
167
|
}
|
|
132
168
|
|
|
133
169
|
this.threadCounts = threadCounts instanceof Map ? threadCounts : new Map();
|
|
170
|
+
this.showFileExtensions = Boolean(showFileExtensions);
|
|
134
171
|
this.currentSearchQuery = String(searchQuery ?? '');
|
|
135
172
|
if (this.currentSearchQuery) {
|
|
136
173
|
this.clearDragFeedback();
|
|
@@ -248,6 +285,7 @@ export class FileExplorerView {
|
|
|
248
285
|
resetTreeIndexes() {
|
|
249
286
|
this.renderedDirectoryWrappers.clear();
|
|
250
287
|
this.renderedChildContainers.clear();
|
|
288
|
+
this.renderedFileItems.clear();
|
|
251
289
|
}
|
|
252
290
|
|
|
253
291
|
renderNodes(nodes, container, { activeFilePath, depth, expandedDirs }) {
|
|
@@ -408,6 +446,11 @@ export class FileExplorerView {
|
|
|
408
446
|
this.renderedChildContainers.delete(pathValue);
|
|
409
447
|
}
|
|
410
448
|
});
|
|
449
|
+
Array.from(this.renderedFileItems.keys()).forEach((pathValue) => {
|
|
450
|
+
if (pathValue.startsWith(prefix)) {
|
|
451
|
+
this.renderedFileItems.delete(pathValue);
|
|
452
|
+
}
|
|
453
|
+
});
|
|
411
454
|
}
|
|
412
455
|
|
|
413
456
|
createFileItem({ activeFilePath, depth, filePath, fileType = 'file', name }) {
|
|
@@ -418,8 +461,10 @@ export class FileExplorerView {
|
|
|
418
461
|
const isExcalidraw = fileType === 'excalidraw';
|
|
419
462
|
const isBase = fileType === 'base';
|
|
420
463
|
const isImage = fileType === 'image';
|
|
464
|
+
const isPdf = fileType === 'pdf';
|
|
421
465
|
const isMermaid = fileType === 'mermaid';
|
|
422
466
|
const isPlantUml = fileType === 'plantuml';
|
|
467
|
+
const isStructurizr = fileType === 'structurizr';
|
|
423
468
|
|
|
424
469
|
if (isBase) {
|
|
425
470
|
button.classList.add('is-base');
|
|
@@ -433,12 +478,18 @@ export class FileExplorerView {
|
|
|
433
478
|
if (isImage) {
|
|
434
479
|
button.classList.add('is-image');
|
|
435
480
|
}
|
|
481
|
+
if (isPdf) {
|
|
482
|
+
button.classList.add('is-pdf');
|
|
483
|
+
}
|
|
436
484
|
if (isMermaid) {
|
|
437
485
|
button.classList.add('is-mermaid');
|
|
438
486
|
}
|
|
439
487
|
if (isPlantUml) {
|
|
440
488
|
button.classList.add('is-plantuml');
|
|
441
489
|
}
|
|
490
|
+
if (isStructurizr) {
|
|
491
|
+
button.classList.add('is-structurizr');
|
|
492
|
+
}
|
|
442
493
|
if (filePath === activeFilePath) {
|
|
443
494
|
button.classList.add('active');
|
|
444
495
|
}
|
|
@@ -453,9 +504,10 @@ export class FileExplorerView {
|
|
|
453
504
|
if (threadCount > 0) {
|
|
454
505
|
button.dataset.threadCount = String(threadCount);
|
|
455
506
|
}
|
|
507
|
+
const displayName = this.showFileExtensions ? String(name ?? '') : stripVaultFileExtension(name);
|
|
456
508
|
button.innerHTML = `
|
|
457
|
-
${
|
|
458
|
-
<span class="file-tree-name">${escapeHtml(
|
|
509
|
+
${getVaultFileIconSvg(filePath)}
|
|
510
|
+
<span class="file-tree-name">${escapeHtml(displayName)}</span>
|
|
459
511
|
${threadCount > 0 ? `<span class="file-tree-comment-count" aria-label="${threadCount} open comment thread${threadCount === 1 ? '' : 's'}">${threadCount}</span>` : ''}
|
|
460
512
|
`;
|
|
461
513
|
this.configureDragSource(button, { path: filePath, type: 'file' });
|
|
@@ -474,6 +526,7 @@ export class FileExplorerView {
|
|
|
474
526
|
this.onFileContextMenu?.(this.createLongPressEvent(button), { filePath, type: 'file' });
|
|
475
527
|
});
|
|
476
528
|
|
|
529
|
+
this.renderedFileItems.set(filePath, button);
|
|
477
530
|
return button;
|
|
478
531
|
}
|
|
479
532
|
|
|
@@ -908,34 +961,6 @@ export class FileExplorerView {
|
|
|
908
961
|
return true;
|
|
909
962
|
}
|
|
910
963
|
|
|
911
|
-
getFileIconSvg({ isBase, isDrawio, isExcalidraw, isImage, isMermaid, isPlantUml }) {
|
|
912
|
-
if (isBase) {
|
|
913
|
-
return '<svg class="file-tree-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 4h7l5 5v11a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z"/><path d="M14 4v5h5"/><path d="M8 13h8"/><path d="M8 17h6"/><path d="M8 9h3"/></svg>';
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
if (isDrawio) {
|
|
917
|
-
return '<svg class="file-tree-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="7" height="6" rx="1"/><rect x="14" y="4" width="7" height="6" rx="1"/><rect x="8.5" y="14" width="7" height="6" rx="1"/><path d="M10 7h4"/><path d="M17.5 10v2.5"/><path d="M6.5 10v2.5"/><path d="M6.5 12.5h11"/></svg>';
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
if (isExcalidraw) {
|
|
921
|
-
return '<svg class="file-tree-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19l7-7 3 3-7 7-3-3z"/><path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"/><path d="M2 2l7.586 7.586"/><circle cx="11" cy="11" r="2"/></svg>';
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
if (isImage) {
|
|
925
|
-
return '<svg class="file-tree-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"/><circle cx="9" cy="10" r="1.5"/><path d="m21 16-5-5L7 20"/><path d="m14 14 2 2"/></svg>';
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
if (isMermaid) {
|
|
929
|
-
return '<svg class="file-tree-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 7.5c0-1.38 1.12-2.5 2.5-2.5 1.04 0 1.93.64 2.3 1.56A2.5 2.5 0 0 1 14 8.5v1"/><path d="M19 16.5c0 1.38-1.12 2.5-2.5 2.5-1.04 0-1.93-.64-2.3-1.56A2.5 2.5 0 0 1 10 15.5v-1"/><path d="M8 10.5h8"/><path d="M8 13.5h8"/><path d="M10 8.5v7"/><path d="M14 8.5v7"/></svg>';
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
if (isPlantUml) {
|
|
933
|
-
return '<svg class="file-tree-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="7" height="6" rx="1"/><rect x="14" y="4" width="7" height="6" rx="1"/><rect x="8.5" y="14" width="7" height="6" rx="1"/><path d="M10 7h4"/><path d="M17.5 10v2.5"/><path d="M6.5 10v2.5"/><path d="M6.5 12.5h11"/></svg>';
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
return '<svg class="file-tree-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>';
|
|
937
|
-
}
|
|
938
|
-
|
|
939
964
|
showContextMenu(event, items) {
|
|
940
965
|
this.removeContextMenu();
|
|
941
966
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { getVaultFileKind } from '../../domain/file-kind.js';
|
|
2
|
+
|
|
3
|
+
const SVG_ATTRIBUTES = 'width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"';
|
|
4
|
+
|
|
5
|
+
function createIcon(className, content) {
|
|
6
|
+
return `<svg class="${className}" ${SVG_ATTRIBUTES}>${content}</svg>`;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function getVaultFileIconSvg(filePath, {
|
|
10
|
+
className = 'file-tree-icon',
|
|
11
|
+
} = {}) {
|
|
12
|
+
const kind = getVaultFileKind(filePath) ?? 'file';
|
|
13
|
+
const iconClass = className;
|
|
14
|
+
|
|
15
|
+
if (kind === 'base') {
|
|
16
|
+
return createIcon(iconClass, '<path d="M7 4h7l5 5v11a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z"/><path d="M14 4v5h5"/><path d="M8 13h8"/><path d="M8 17h6"/><path d="M8 9h3"/>');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (kind === 'drawio' || kind === 'plantuml' || kind === 'structurizr') {
|
|
20
|
+
return createIcon(iconClass, '<rect x="3" y="4" width="7" height="6" rx="1"/><rect x="14" y="4" width="7" height="6" rx="1"/><rect x="8.5" y="14" width="7" height="6" rx="1"/><path d="M10 7h4"/><path d="M17.5 10v2.5"/><path d="M6.5 10v2.5"/><path d="M6.5 12.5h11"/>');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (kind === 'excalidraw') {
|
|
24
|
+
return createIcon(iconClass, '<path d="M12 19l7-7 3 3-7 7-3-3z"/><path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"/><path d="M2 2l7.586 7.586"/><circle cx="11" cy="11" r="2"/>');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (kind === 'image') {
|
|
28
|
+
return createIcon(iconClass, '<rect x="3" y="4" width="18" height="16" rx="2"/><circle cx="9" cy="10" r="1.5"/><path d="m21 16-5-5L7 20"/><path d="m14 14 2 2"/>');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (kind === 'pdf') {
|
|
32
|
+
return createIcon(iconClass, '<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"/><path d="M8 15h8"/><path d="M8 18h5"/>');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (kind === 'mermaid') {
|
|
36
|
+
return createIcon(iconClass, '<path d="M5 7.5c0-1.38 1.12-2.5 2.5-2.5 1.04 0 1.93.64 2.3 1.56A2.5 2.5 0 0 1 14 8.5v1"/><path d="M19 16.5c0 1.38-1.12 2.5-2.5 2.5-1.04 0-1.93-.64-2.3-1.56A2.5 2.5 0 0 1 10 15.5v-1"/><path d="M8 10.5h8"/><path d="M8 13.5h8"/><path d="M10 8.5v7"/><path d="M14 8.5v7"/>');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return createIcon(iconClass, '<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"/>');
|
|
40
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { normalizeVaultPathInput } from '../domain/vault-paths.js';
|
|
2
2
|
|
|
3
|
-
function flattenTree(nodes, files = [], searchEntries = []) {
|
|
3
|
+
function flattenTree(nodes, files = [], searchEntries = [], fileEntries = []) {
|
|
4
4
|
for (const node of nodes) {
|
|
5
5
|
if (!node?.path || !node?.type) {
|
|
6
6
|
continue;
|
|
@@ -20,18 +20,24 @@ function flattenTree(nodes, files = [], searchEntries = []) {
|
|
|
20
20
|
|| node.type === 'drawio'
|
|
21
21
|
|| node.type === 'mermaid'
|
|
22
22
|
|| node.type === 'plantuml'
|
|
23
|
+
|| node.type === 'structurizr'
|
|
24
|
+
|| node.type === 'pdf'
|
|
23
25
|
|| node.type === 'image'
|
|
24
26
|
) {
|
|
25
27
|
files.push(node.path);
|
|
28
|
+
fileEntries.push({
|
|
29
|
+
mtimeMs: node.mtimeMs,
|
|
30
|
+
path: node.path,
|
|
31
|
+
});
|
|
26
32
|
continue;
|
|
27
33
|
}
|
|
28
34
|
|
|
29
35
|
if (node.type === 'directory' && Array.isArray(node.children)) {
|
|
30
|
-
flattenTree(node.children, files, searchEntries);
|
|
36
|
+
flattenTree(node.children, files, searchEntries, fileEntries);
|
|
31
37
|
}
|
|
32
38
|
}
|
|
33
39
|
|
|
34
|
-
return { files, searchEntries };
|
|
40
|
+
return { fileEntries, files, searchEntries };
|
|
35
41
|
}
|
|
36
42
|
|
|
37
43
|
function findNodeByPath(nodes, pathValue) {
|
|
@@ -82,6 +88,7 @@ export class FileTreeState {
|
|
|
82
88
|
constructor() {
|
|
83
89
|
this.tree = [];
|
|
84
90
|
this.flatFiles = [];
|
|
91
|
+
this.flatFileEntries = [];
|
|
85
92
|
this.flatSearchEntries = [];
|
|
86
93
|
this.activeFilePath = null;
|
|
87
94
|
this.expandedDirs = new Set();
|
|
@@ -90,8 +97,9 @@ export class FileTreeState {
|
|
|
90
97
|
|
|
91
98
|
setTree(tree) {
|
|
92
99
|
this.tree = Array.isArray(tree) ? tree : [];
|
|
93
|
-
const flattened = flattenTree(this.tree, [], []);
|
|
100
|
+
const flattened = flattenTree(this.tree, [], [], []);
|
|
94
101
|
this.flatFiles = flattened.files;
|
|
102
|
+
this.flatFileEntries = flattened.fileEntries;
|
|
95
103
|
this.flatSearchEntries = flattened.searchEntries;
|
|
96
104
|
}
|
|
97
105
|
|