dsh-plugin-workbench 0.0.4 → 0.0.5
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/CHANGELOG.md +34 -2
- package/README.md +14 -5
- package/lib/client.js +462 -53
- package/lib/client.js.map +1 -1
- package/lib/index.js +169 -6
- package/package.json +1 -1
- package/src/client/FileExplorer.tsx +232 -4
- package/src/client/FilePreview.tsx +97 -11
- package/src/client/files.module.css +110 -3
- package/src/client/index.ts +5 -1
- package/src/client/locales.ts +28 -0
- package/src/client/store.ts +25 -0
- package/src/dsh.d.ts +9 -0
- package/src/index.ts +204 -6
package/lib/client.js
CHANGED
|
@@ -30,7 +30,7 @@ window.__ModuleLoader__.load({
|
|
|
30
30
|
let react = require("react");
|
|
31
31
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
32
32
|
//#region \0dsh-css:src/client/files.module.css.mjs
|
|
33
|
-
const css$1 = "[data-fe-theme=light]{--fe-bg:#fff;--fe-sidebar-bg:#f3f3f3;--fe-fg:#1f1f1f;--fe-muted:#6e6e6e;--fe-faint:#9d9d9d;--fe-border:#e5e5e5;--fe-border-strong:#c8c8c8;--fe-accent:#005fb8;--fe-hover:#e8e8e8;--fe-selection:#add6ff;--fe-token-keyword:#00f;--fe-token-string:#a31515;--fe-token-comment:green;--fe-token-number:#098658;--fe-token-function:#795e26;--fe-token-type:#267f99;--fe-token-variable:#001080;--fe-token-tag:maroon;--fe-token-meta:#6e6e6e}[data-fe-theme=dark]{--fe-bg:#1e1e1e;--fe-sidebar-bg:#252526;--fe-fg:#d4d4d4;--fe-muted:#ccc;--fe-faint:#9d9d9d;--fe-border:#3c3c3c;--fe-border-strong:#454545;--fe-accent:#007acc;--fe-hover:#2a2d2e;--fe-selection:#264f78;--fe-token-keyword:#569cd6;--fe-token-string:#ce9178;--fe-token-comment:#6a9955;--fe-token-number:#b5cea8;--fe-token-function:#dcdcaa;--fe-token-type:#4ec9b0;--fe-token-variable:#9cdcfe;--fe-token-tag:#569cd6;--fe-token-meta:#9b9b9b}.Myjg4a_column{box-sizing:border-box;background:var(--fe-sidebar-bg);min-width:0;height:100%;color:var(--fe-fg);flex-direction:column;font-size:13px;display:flex;overflow:hidden}.Myjg4a_header{box-sizing:border-box;border-bottom:1px solid var(--fe-border);flex:none;align-items:center;gap:6px;height:34px;padding:0 8px;display:flex}.Myjg4a_headerTitle{text-overflow:ellipsis;white-space:nowrap;text-transform:uppercase;letter-spacing:.04em;min-width:0;color:var(--fe-muted);flex:1;font-size:11px;font-weight:600;overflow:hidden}.Myjg4a_headerActions{flex:none;align-items:center;gap:2px;display:flex}.Myjg4a_action{appearance:none;color:var(--fe-muted);cursor:pointer;background:0 0;border:none;border-radius:5px;justify-content:center;align-items:center;width:22px;height:22px;padding:0;font-size:13px;line-height:1;display:inline-flex}.Myjg4a_action:hover:not(:disabled){background:var(--fe-hover);color:var(--fe-fg)}.Myjg4a_action:disabled{opacity:.5;cursor:default}.Myjg4a_treeArea{flex:1;min-height:0;padding:4px;overflow-y:auto}.Myjg4a_row{cursor:pointer;user-select:none;white-space:nowrap;height:22px;color:var(--fe-fg);border-radius:3px;align-items:center;gap:6px;font-size:13px;display:flex}.Myjg4a_row:hover{background:var(--fe-hover)}.Myjg4a_rowSelected{background:var(--fe-selection)}.Myjg4a_rowSelected .Myjg4a_name{color:var(--fe-fg)}.Myjg4a_chevron{text-align:center;width:12px;color:var(--fe-muted);flex:none;font-size:10px;line-height:22px}.Myjg4a_icon{text-align:center;flex:none;width:16px;font-size:13px;line-height:22px}.Myjg4a_fileBadge{letter-spacing:-.3px;box-sizing:border-box;vertical-align:middle;user-select:none;border-radius:3px;justify-content:center;align-items:center;width:16px;height:15px;padding:0 1px;font-size:8px;font-weight:700;line-height:1;display:inline-flex}.Myjg4a_fileBadgeLong{letter-spacing:-.4px;font-size:6.5px}.Myjg4a_name{text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.Myjg4a_size{color:var(--fe-faint);flex:none;font-size:11px}.Myjg4a_actions{opacity:0;flex:none;align-items:center;gap:2px;transition:opacity .12s;display:flex}.Myjg4a_row:hover .Myjg4a_actions,.Myjg4a_row:focus-within .Myjg4a_actions{opacity:1}.Myjg4a_rowHint{color:var(--fe-faint);padding:2px 8px 2px 0;font-size:12px;line-height:20px}.Myjg4a_rowError{color:#f48771;padding:2px 8px 2px 0;font-size:12px;line-height:18px}.Myjg4a_preview{border-right:1px solid var(--fe-border);background:var(--fe-bg);flex-direction:column;flex:0 0 55%;min-width:240px;min-height:0;animation:.18s Myjg4a_fe-preview-in;display:flex;overflow:hidden}.Myjg4a_previewClosing{animation:.2s forwards Myjg4a_fe-preview-out}@keyframes Myjg4a_fe-preview-in{0%{opacity:0}to{opacity:1}}@keyframes Myjg4a_fe-preview-out{0%{opacity:1}to{opacity:0}}.Myjg4a_handle{cursor:col-resize;touch-action:none;z-index:2;background:0 0;flex:none;width:6px;margin-left:-4px;margin-right:-2px}.Myjg4a_handle:hover,.Myjg4a_handle:active{background:var(--fe-accent);opacity:.35}.Myjg4a_tabBar{border-bottom:1px solid var(--fe-border);background:var(--fe-sidebar-bg);flex:none;align-items:stretch;height:34px;display:flex}.Myjg4a_tabScroller{scrollbar-width:thin;flex:1;align-items:stretch;min-width:0;display:flex;overflow-x:auto}.Myjg4a_collapse,.Myjg4a_tabAction{appearance:none;color:var(--fe-muted);cursor:pointer;background:0 0;border:none;border-radius:4px;flex:none;justify-content:center;align-items:center;width:26px;height:26px;margin:auto 4px;padding:0;font-size:14px;line-height:1;display:inline-flex}.Myjg4a_collapse:hover,.Myjg4a_tabAction:hover{background:var(--fe-hover);color:var(--fe-fg)}.Myjg4a_tabActionActive{background:var(--fe-hover);color:var(--fe-accent)}.Myjg4a_tab{max-width:180px;color:var(--fe-muted);border-right:1px solid var(--fe-border);cursor:pointer;user-select:none;white-space:nowrap;flex:none;align-items:center;gap:6px;padding:0 8px 0 12px;font-size:13px;display:flex}.Myjg4a_tab:hover{background:var(--fe-hover)}.Myjg4a_tabActive{background:var(--fe-bg);color:var(--fe-fg);box-shadow:inset 0 -1px 0 var(--fe-accent)}.Myjg4a_tabName{text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.Myjg4a_tabIcon{flex:none;justify-content:center;align-items:center;width:16px;font-size:13px;line-height:1;display:inline-flex}.Myjg4a_tabClose{appearance:none;color:var(--fe-faint);cursor:pointer;background:0 0;border:none;border-radius:3px;justify-content:center;align-items:center;width:16px;height:16px;padding:0;font-size:11px;display:inline-flex}.Myjg4a_tabClose:hover{background:var(--fe-hover);color:var(--fe-fg)}.Myjg4a_tabDot{background:var(--fe-fg);opacity:.85;border-radius:50%;flex:none;width:8px;height:8px}.Myjg4a_previewBody{flex:1;min-height:0;overflow:auto}.Myjg4a_editor{contain:layout paint;height:100%;min-height:0;position:relative}.Myjg4a_editorPlain .Myjg4a_editorTextarea{color:var(--fe-fg)}.Myjg4a_editorHint{background:var(--fe-hover);color:var(--fe-muted);pointer-events:none;border-radius:4px;padding:4px 10px;font-size:11px;position:absolute;bottom:8px;left:8px}.Myjg4a_editorHighlight{pointer-events:none;white-space:pre;tab-size:2;color:var(--fe-fg);background:0 0;margin:0;padding:12px 12px calc(12px + 1.5em);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;line-height:1.5;position:absolute;inset:0;overflow:auto}.Myjg4a_editorHighlight code{font-family:inherit;font-size:inherit;line-height:inherit;white-space:inherit}.Myjg4a_editorTextarea{box-sizing:border-box;resize:none;color:#0000;caret-color:var(--fe-fg);white-space:pre;tab-size:2;background:0 0;border:none;outline:none;margin:0;padding:12px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;line-height:1.5;position:absolute;inset:0;overflow:auto}.Myjg4a_editor[data-wrap=on] .Myjg4a_editorHighlight,.Myjg4a_editor[data-wrap=on] .Myjg4a_editorTextarea{white-space:pre-wrap;overflow-wrap:anywhere}.Myjg4a_editor[data-wrap=on] .Myjg4a_editorTextarea{overflow-x:hidden}.Myjg4a_saveError{color:#1e1e1e;background:#f48771;border-radius:4px;padding:4px 10px;font-size:12px;position:absolute;bottom:8px;right:8px}.Myjg4a_previewHint{color:var(--fe-faint);padding:12px;font-size:12px;line-height:18px}.Myjg4a_previewMeta{color:var(--fe-faint);font-size:11px}.Myjg4a_placeholder{text-align:center;color:var(--fe-faint);flex:1;justify-content:center;align-items:center;padding:16px;font-size:12px;line-height:18px;display:flex}.Myjg4a_editorHighlight .hljs-keyword,.Myjg4a_editorHighlight .hljs-selector-tag,.Myjg4a_editorHighlight .hljs-literal{color:var(--fe-token-keyword)}.Myjg4a_editorHighlight .hljs-string,.Myjg4a_editorHighlight .hljs-regexp,.Myjg4a_editorHighlight .hljs-addition{color:var(--fe-token-string)}.Myjg4a_editorHighlight .hljs-comment,.Myjg4a_editorHighlight .hljs-quote{color:var(--fe-token-comment);font-style:italic}.Myjg4a_editorHighlight .hljs-number,.Myjg4a_editorHighlight .hljs-symbol,.Myjg4a_editorHighlight .hljs-bullet{color:var(--fe-token-number)}.Myjg4a_editorHighlight .hljs-title,.Myjg4a_editorHighlight .hljs-section,.Myjg4a_editorHighlight .hljs-title.function_{color:var(--fe-token-function)}.Myjg4a_editorHighlight .hljs-type,.Myjg4a_editorHighlight .hljs-built_in,.Myjg4a_editorHighlight .hljs-class .hljs-title{color:var(--fe-token-type)}.Myjg4a_editorHighlight .hljs-attr,.Myjg4a_editorHighlight .hljs-attribute,.Myjg4a_editorHighlight .hljs-variable,.Myjg4a_editorHighlight .hljs-template-variable,.Myjg4a_editorHighlight .hljs-params{color:var(--fe-token-variable)}.Myjg4a_editorHighlight .hljs-tag,.Myjg4a_editorHighlight .hljs-name{color:var(--fe-token-tag)}.Myjg4a_editorHighlight .hljs-meta{color:var(--fe-token-meta)}.Myjg4a_editorHighlight .hljs-emphasis{font-style:italic}.Myjg4a_editorHighlight .hljs-strong{color:var(--fe-accent);font-weight:inherit}body[data-dsh-maid-atelier] [data-skin-chrome=top-trim],body[data-dsh-maid-atelier] [data-skin-chrome=bottom-trim]{translate:calc(var(--maid-sidebar-width,0px) + var(--dsh-explorer-width,0px) + var(--dsh-preview-width,0px)) 0!important}[class*=explorerCol]{border-right:1px solid var(--fe-border)!important}";
|
|
33
|
+
const css$1 = "[data-fe-theme=light]{--fe-bg:#fff;--fe-sidebar-bg:#f3f3f3;--fe-fg:#1f1f1f;--fe-muted:#6e6e6e;--fe-faint:#9d9d9d;--fe-border:#e5e5e5;--fe-border-strong:#c8c8c8;--fe-accent:#005fb8;--fe-hover:#e8e8e8;--fe-selection:#add6ff;--fe-token-keyword:#00f;--fe-token-string:#a31515;--fe-token-comment:green;--fe-token-number:#098658;--fe-token-function:#795e26;--fe-token-type:#267f99;--fe-token-variable:#001080;--fe-token-tag:maroon;--fe-token-meta:#6e6e6e}[data-fe-theme=dark]{--fe-bg:#1e1e1e;--fe-sidebar-bg:#252526;--fe-fg:#d4d4d4;--fe-muted:#ccc;--fe-faint:#9d9d9d;--fe-border:#3c3c3c;--fe-border-strong:#454545;--fe-accent:#007acc;--fe-hover:#2a2d2e;--fe-selection:#264f78;--fe-token-keyword:#569cd6;--fe-token-string:#ce9178;--fe-token-comment:#6a9955;--fe-token-number:#b5cea8;--fe-token-function:#dcdcaa;--fe-token-type:#4ec9b0;--fe-token-variable:#9cdcfe;--fe-token-tag:#569cd6;--fe-token-meta:#9b9b9b}.Myjg4a_column{box-sizing:border-box;background:var(--fe-sidebar-bg);min-width:0;height:100%;color:var(--fe-fg);flex-direction:column;font-size:13px;display:flex;overflow:hidden}.Myjg4a_header{box-sizing:border-box;border-bottom:1px solid var(--fe-border);flex:none;align-items:center;gap:6px;height:34px;padding:0 8px;display:flex}.Myjg4a_headerTitle{text-overflow:ellipsis;white-space:nowrap;text-transform:uppercase;letter-spacing:.04em;min-width:0;color:var(--fe-muted);flex:1;font-size:11px;font-weight:600;overflow:hidden}.Myjg4a_headerActions{flex:none;align-items:center;gap:2px;display:flex}.Myjg4a_action{appearance:none;color:var(--fe-muted);cursor:pointer;background:0 0;border:none;border-radius:5px;justify-content:center;align-items:center;width:22px;height:22px;padding:0;font-size:13px;line-height:1;display:inline-flex}.Myjg4a_action:hover:not(:disabled){background:var(--fe-hover);color:var(--fe-fg)}.Myjg4a_action:disabled{opacity:.5;cursor:default}.Myjg4a_treeArea{flex:1;min-height:0;padding:4px;overflow-y:auto}.Myjg4a_row{cursor:pointer;user-select:none;white-space:nowrap;height:22px;color:var(--fe-fg);border-radius:3px;align-items:center;gap:6px;font-size:13px;display:flex}.Myjg4a_row:hover{background:var(--fe-hover)}.Myjg4a_rowSelected{background:var(--fe-selection)}.Myjg4a_rowSelected .Myjg4a_name{color:var(--fe-fg)}.Myjg4a_chevron{text-align:center;width:12px;color:var(--fe-muted);flex:none;font-size:10px;line-height:22px}.Myjg4a_icon{text-align:center;flex:none;width:16px;font-size:13px;line-height:22px}.Myjg4a_fileBadge{letter-spacing:-.3px;box-sizing:border-box;vertical-align:middle;user-select:none;border-radius:3px;justify-content:center;align-items:center;width:16px;height:15px;padding:0 1px;font-size:8px;font-weight:700;line-height:1;display:inline-flex}.Myjg4a_fileBadgeLong{letter-spacing:-.4px;font-size:6.5px}.Myjg4a_name{text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.Myjg4a_size{color:var(--fe-faint);flex:none;font-size:11px}.Myjg4a_actions{opacity:0;flex:none;align-items:center;gap:2px;transition:opacity .12s;display:flex}.Myjg4a_row:hover .Myjg4a_actions,.Myjg4a_row:focus-within .Myjg4a_actions{opacity:1}.Myjg4a_rowHint{color:var(--fe-faint);padding:2px 8px 2px 0;font-size:12px;line-height:20px}.Myjg4a_rowError{color:#f48771;padding:2px 8px 2px 0;font-size:12px;line-height:18px}.Myjg4a_contextMenu{z-index:10000;box-sizing:border-box;border:1px solid var(--fe-border-strong);user-select:none;border-radius:6px;min-width:180px;padding:4px;font-size:13px;position:fixed;box-shadow:0 6px 24px #00000047;background:var(--fe-bg)!important;color:var(--fe-fg)!important}.Myjg4a_contextMenuItem{cursor:pointer;white-space:nowrap;color:inherit;border-radius:4px;align-items:center;gap:8px;padding:5px 10px;display:flex}.Myjg4a_contextMenuItem:hover{background:var(--fe-selection)!important;color:var(--fe-fg)!important}.Myjg4a_contextMenuItemDanger{color:#f48771!important}.Myjg4a_contextMenuDivider{background:var(--fe-border);height:1px;margin:4px 6px}.Myjg4a_preview{border-right:1px solid var(--fe-border);background:var(--fe-bg);flex-direction:column;flex:0 0 55%;min-width:240px;min-height:0;animation:.18s Myjg4a_fe-preview-in;display:flex;overflow:hidden}.Myjg4a_previewClosing{animation:.2s forwards Myjg4a_fe-preview-out}@keyframes Myjg4a_fe-preview-in{0%{opacity:0}to{opacity:1}}@keyframes Myjg4a_fe-preview-out{0%{opacity:1}to{opacity:0}}.Myjg4a_handle{cursor:col-resize;touch-action:none;z-index:2;background:0 0;flex:none;width:6px;margin-left:-4px;margin-right:-2px}.Myjg4a_handle:hover,.Myjg4a_handle:active{background:var(--fe-accent);opacity:.35}.Myjg4a_tabBar{border-bottom:1px solid var(--fe-border);background:var(--fe-sidebar-bg);flex:none;align-items:stretch;height:34px;display:flex}.Myjg4a_tabScroller{scrollbar-width:thin;flex:1;align-items:stretch;min-width:0;display:flex;overflow-x:auto}.Myjg4a_collapse,.Myjg4a_tabAction{appearance:none;color:var(--fe-muted);cursor:pointer;background:0 0;border:none;border-radius:4px;flex:none;justify-content:center;align-items:center;width:26px;height:26px;margin:auto 4px;padding:0;font-size:14px;line-height:1;display:inline-flex}.Myjg4a_collapse:hover,.Myjg4a_tabAction:hover{background:var(--fe-hover);color:var(--fe-fg)}.Myjg4a_tabActionActive{background:var(--fe-hover);color:var(--fe-accent)}.Myjg4a_tab{max-width:180px;color:var(--fe-muted);border-right:1px solid var(--fe-border);cursor:pointer;user-select:none;white-space:nowrap;flex:none;align-items:center;gap:6px;padding:0 8px 0 12px;font-size:13px;display:flex}.Myjg4a_tab:hover{background:var(--fe-hover)}.Myjg4a_tabActive{background:var(--fe-bg);color:var(--fe-fg);box-shadow:inset 0 -1px 0 var(--fe-accent)}.Myjg4a_tabName{text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.Myjg4a_tabIcon{flex:none;justify-content:center;align-items:center;width:16px;font-size:13px;line-height:1;display:inline-flex}.Myjg4a_tabClose{appearance:none;color:var(--fe-faint);cursor:pointer;background:0 0;border:none;border-radius:3px;justify-content:center;align-items:center;width:16px;height:16px;padding:0;font-size:11px;display:inline-flex}.Myjg4a_tabClose:hover{background:var(--fe-hover);color:var(--fe-fg)}.Myjg4a_tabDot{background:var(--fe-fg);opacity:.85;border-radius:50%;flex:none;width:8px;height:8px}.Myjg4a_previewBody{flex:1;min-height:0;overflow:auto}.Myjg4a_editor{--fe-gutter:44px;contain:layout paint;height:100%;min-height:0;position:relative}.Myjg4a_gutter{width:var(--fe-gutter);box-sizing:border-box;border-right:1px solid var(--fe-border);background:var(--fe-sidebar-bg);color:var(--fe-faint);user-select:none;pointer-events:none;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;line-height:1.5;position:absolute;top:0;bottom:0;left:0;overflow:hidden}.Myjg4a_gutterNumbers{white-space:pre;text-align:right;padding:12px 8px}.Myjg4a_editorPlain .Myjg4a_editorTextarea{color:var(--fe-fg)}.Myjg4a_editorHint{left:calc(var(--fe-gutter) + 8px);background:var(--fe-hover);color:var(--fe-muted);pointer-events:none;border-radius:4px;padding:4px 10px;font-size:11px;position:absolute;bottom:8px}.Myjg4a_editorHighlight{top:0;bottom:0;left:var(--fe-gutter);pointer-events:none;white-space:pre;tab-size:2;color:var(--fe-fg);background:0 0;margin:0;padding:12px 12px calc(12px + 1.5em);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;line-height:1.5;position:absolute;right:0;overflow:auto}.Myjg4a_editorHighlight code{font-family:inherit;font-size:inherit;line-height:inherit;white-space:inherit}.Myjg4a_editorTextarea{top:0;bottom:0;left:var(--fe-gutter);box-sizing:border-box;resize:none;color:#0000;caret-color:var(--fe-fg);white-space:pre;tab-size:2;background:0 0;border:none;outline:none;margin:0;padding:12px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;line-height:1.5;position:absolute;right:0;overflow:auto}.Myjg4a_editor[data-wrap=on] .Myjg4a_editorHighlight,.Myjg4a_editor[data-wrap=on] .Myjg4a_editorTextarea{white-space:pre-wrap;overflow-wrap:anywhere}.Myjg4a_editor[data-wrap=on] .Myjg4a_editorTextarea{overflow-x:hidden}.Myjg4a_saveError{color:#1e1e1e;background:#f48771;border-radius:4px;padding:4px 10px;font-size:12px;position:absolute;bottom:8px;right:8px}.Myjg4a_previewHint{color:var(--fe-faint);padding:12px;font-size:12px;line-height:18px}.Myjg4a_imageView{box-sizing:border-box;background:var(--fe-bg);flex-direction:column;justify-content:center;align-items:center;gap:8px;height:100%;min-height:0;padding:12px;display:flex;overflow:auto}.Myjg4a_image{object-fit:contain;max-width:100%;max-height:100%;box-shadow:0 0 0 1px var(--fe-border);border-radius:4px}.Myjg4a_previewMeta{color:var(--fe-faint);font-size:11px}.Myjg4a_placeholder{text-align:center;color:var(--fe-faint);flex:1;justify-content:center;align-items:center;padding:16px;font-size:12px;line-height:18px;display:flex}.Myjg4a_editorHighlight .hljs-keyword,.Myjg4a_editorHighlight .hljs-selector-tag,.Myjg4a_editorHighlight .hljs-literal{color:var(--fe-token-keyword)}.Myjg4a_editorHighlight .hljs-string,.Myjg4a_editorHighlight .hljs-regexp,.Myjg4a_editorHighlight .hljs-addition{color:var(--fe-token-string)}.Myjg4a_editorHighlight .hljs-comment,.Myjg4a_editorHighlight .hljs-quote{color:var(--fe-token-comment);font-style:italic}.Myjg4a_editorHighlight .hljs-number,.Myjg4a_editorHighlight .hljs-symbol,.Myjg4a_editorHighlight .hljs-bullet{color:var(--fe-token-number)}.Myjg4a_editorHighlight .hljs-title,.Myjg4a_editorHighlight .hljs-section,.Myjg4a_editorHighlight .hljs-title.function_{color:var(--fe-token-function)}.Myjg4a_editorHighlight .hljs-type,.Myjg4a_editorHighlight .hljs-built_in,.Myjg4a_editorHighlight .hljs-class .hljs-title{color:var(--fe-token-type)}.Myjg4a_editorHighlight .hljs-attr,.Myjg4a_editorHighlight .hljs-attribute,.Myjg4a_editorHighlight .hljs-variable,.Myjg4a_editorHighlight .hljs-template-variable,.Myjg4a_editorHighlight .hljs-params{color:var(--fe-token-variable)}.Myjg4a_editorHighlight .hljs-tag,.Myjg4a_editorHighlight .hljs-name{color:var(--fe-token-tag)}.Myjg4a_editorHighlight .hljs-meta{color:var(--fe-token-meta)}.Myjg4a_editorHighlight .hljs-emphasis{font-style:italic}.Myjg4a_editorHighlight .hljs-strong{color:var(--fe-accent);font-weight:inherit}body[data-dsh-maid-atelier] [data-skin-chrome=top-trim],body[data-dsh-maid-atelier] [data-skin-chrome=bottom-trim]{translate:calc(var(--maid-sidebar-width,0px) + var(--dsh-explorer-width,0px) + var(--dsh-preview-width,0px)) 0!important}[class*=explorerCol]{border-right:1px solid var(--fe-border)!important}";
|
|
34
34
|
const tagId = "dsh-plugin-workbench/files.module.css";
|
|
35
35
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
36
36
|
const tag = document.createElement("style");
|
|
@@ -45,6 +45,10 @@ window.__ModuleLoader__.load({
|
|
|
45
45
|
"chevron": "Myjg4a_chevron",
|
|
46
46
|
"collapse": "Myjg4a_collapse",
|
|
47
47
|
"column": "Myjg4a_column",
|
|
48
|
+
"contextMenu": "Myjg4a_contextMenu",
|
|
49
|
+
"contextMenuDivider": "Myjg4a_contextMenuDivider",
|
|
50
|
+
"contextMenuItem": "Myjg4a_contextMenuItem",
|
|
51
|
+
"contextMenuItemDanger": "Myjg4a_contextMenuItemDanger",
|
|
48
52
|
"editor": "Myjg4a_editor",
|
|
49
53
|
"editorHighlight": "Myjg4a_editorHighlight",
|
|
50
54
|
"editorHint": "Myjg4a_editorHint",
|
|
@@ -54,11 +58,15 @@ window.__ModuleLoader__.load({
|
|
|
54
58
|
"fe-preview-out": "Myjg4a_fe-preview-out",
|
|
55
59
|
"fileBadge": "Myjg4a_fileBadge",
|
|
56
60
|
"fileBadgeLong": "Myjg4a_fileBadgeLong",
|
|
61
|
+
"gutter": "Myjg4a_gutter",
|
|
62
|
+
"gutterNumbers": "Myjg4a_gutterNumbers",
|
|
57
63
|
"handle": "Myjg4a_handle",
|
|
58
64
|
"header": "Myjg4a_header",
|
|
59
65
|
"headerActions": "Myjg4a_headerActions",
|
|
60
66
|
"headerTitle": "Myjg4a_headerTitle",
|
|
61
67
|
"icon": "Myjg4a_icon",
|
|
68
|
+
"image": "Myjg4a_image",
|
|
69
|
+
"imageView": "Myjg4a_imageView",
|
|
62
70
|
"name": "Myjg4a_name",
|
|
63
71
|
"placeholder": "Myjg4a_placeholder",
|
|
64
72
|
"preview": "Myjg4a_preview",
|
|
@@ -668,6 +676,37 @@ window.__ModuleLoader__.load({
|
|
|
668
676
|
active: path
|
|
669
677
|
});
|
|
670
678
|
}
|
|
679
|
+
/** Point any open tab at a new path after a rename (the disk path changed). */
|
|
680
|
+
function retargetFile(oldPath, newPath) {
|
|
681
|
+
updateCurrent((ws) => {
|
|
682
|
+
if (!ws.tabs.includes(oldPath)) return ws;
|
|
683
|
+
const tabs = ws.tabs.map((t) => t === oldPath ? newPath : t);
|
|
684
|
+
return {
|
|
685
|
+
...ws,
|
|
686
|
+
tabs,
|
|
687
|
+
active: ws.active === oldPath ? newPath : ws.active
|
|
688
|
+
};
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
/** Close every open tab at or under a path (used after deleting it). */
|
|
692
|
+
function closeFilesUnder(path) {
|
|
693
|
+
updateCurrent((ws) => {
|
|
694
|
+
const sep = path.includes("\\") ? "\\" : "/";
|
|
695
|
+
const prefix = path.endsWith("\\") || path.endsWith("/") ? path : path + sep;
|
|
696
|
+
const kept = ws.tabs.filter((t) => t !== path && !t.startsWith(prefix));
|
|
697
|
+
if (kept.length === ws.tabs.length) return ws;
|
|
698
|
+
let active = ws.active;
|
|
699
|
+
if (active !== void 0 && (active === path || active.startsWith(prefix))) {
|
|
700
|
+
const index = ws.tabs.indexOf(active);
|
|
701
|
+
active = kept[Math.min(index, kept.length - 1)];
|
|
702
|
+
}
|
|
703
|
+
return {
|
|
704
|
+
...ws,
|
|
705
|
+
tabs: kept,
|
|
706
|
+
active
|
|
707
|
+
};
|
|
708
|
+
});
|
|
709
|
+
}
|
|
671
710
|
/** Move a tab before another tab (drag-to-reorder). */
|
|
672
711
|
function moveTab(dragged, target) {
|
|
673
712
|
updateCurrent((ws) => {
|
|
@@ -728,6 +767,16 @@ window.__ModuleLoader__.load({
|
|
|
728
767
|
const idx = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\"));
|
|
729
768
|
return idx >= 0 ? trimmed.slice(idx + 1) : trimmed;
|
|
730
769
|
}
|
|
770
|
+
/** Parent directory of a path ('' for a bare drive root — never used for such). */
|
|
771
|
+
function parentOf(path) {
|
|
772
|
+
const idx = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
|
|
773
|
+
return idx > 0 ? path.slice(0, idx) : path;
|
|
774
|
+
}
|
|
775
|
+
/** Append a child name to a directory path, honoring its separator style. */
|
|
776
|
+
function joinPath(dir, name) {
|
|
777
|
+
const sep = dir.includes("\\") ? "\\" : "/";
|
|
778
|
+
return dir.endsWith("\\") || dir.endsWith("/") ? dir + name : dir + sep + name;
|
|
779
|
+
}
|
|
731
780
|
function formatSize$1(bytes) {
|
|
732
781
|
if (!Number.isFinite(bytes) || bytes < 0) return "";
|
|
733
782
|
if (bytes < 1024) return `${bytes} B`;
|
|
@@ -754,13 +803,14 @@ window.__ModuleLoader__.load({
|
|
|
754
803
|
* full of files, re-rendering the whole tree on every click is what made
|
|
755
804
|
* opening files feel laggy.
|
|
756
805
|
*/
|
|
757
|
-
const TreeRow = (0, react.memo)(function TreeRow({ entry, depth, isActive, isExpanded, onToggleDir, onRefreshDir, onSelect, onDoubleClick, onOpenExternal, t }) {
|
|
806
|
+
const TreeRow = (0, react.memo)(function TreeRow({ entry, depth, isActive, isExpanded, onToggleDir, onRefreshDir, onSelect, onDoubleClick, onOpenExternal, onContextMenu, t }) {
|
|
758
807
|
const isDir = entry.kind === "dir";
|
|
759
808
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
760
809
|
className: `${files_module_css_default.row} ${isActive ? files_module_css_default.rowSelected : ""}`,
|
|
761
810
|
style: { paddingLeft: 8 + depth * 14 },
|
|
762
811
|
onClick: () => onSelect(entry),
|
|
763
812
|
onDoubleClick: () => onDoubleClick(entry),
|
|
813
|
+
onContextMenu: (e) => onContextMenu(e, entry),
|
|
764
814
|
role: "treeitem",
|
|
765
815
|
"aria-selected": isActive,
|
|
766
816
|
"aria-expanded": isDir ? isExpanded : void 0,
|
|
@@ -811,7 +861,7 @@ window.__ModuleLoader__.load({
|
|
|
811
861
|
]
|
|
812
862
|
});
|
|
813
863
|
});
|
|
814
|
-
function FileExplorer({ width, useSessions, t, listDir, openPath }) {
|
|
864
|
+
function FileExplorer({ width, useSessions, t, listDir, openPath, createFile, createDir, renameFile, removePath }) {
|
|
815
865
|
const sessionList = useSessions((s) => s);
|
|
816
866
|
const currentId = sessionList.current;
|
|
817
867
|
const cwd = currentId !== void 0 ? sessionList.byId[currentId]?.cwd : void 0;
|
|
@@ -826,6 +876,42 @@ window.__ModuleLoader__.load({
|
|
|
826
876
|
const [children, setChildren] = (0, react.useState)({});
|
|
827
877
|
const [loadingDirs, setLoadingDirs] = (0, react.useState)(/* @__PURE__ */ new Set());
|
|
828
878
|
const [dirErrors, setDirErrors] = (0, react.useState)({});
|
|
879
|
+
const [menu, setMenu] = (0, react.useState)(void 0);
|
|
880
|
+
const [menuPos, setMenuPos] = (0, react.useState)(void 0);
|
|
881
|
+
const menuRef = (0, react.useRef)(null);
|
|
882
|
+
(0, react.useLayoutEffect)(() => {
|
|
883
|
+
if (menu === void 0) {
|
|
884
|
+
setMenuPos(void 0);
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
const el = menuRef.current;
|
|
888
|
+
if (el === null) return;
|
|
889
|
+
const rect = el.getBoundingClientRect();
|
|
890
|
+
setMenuPos({
|
|
891
|
+
x: Math.max(4, Math.min(menu.x, window.innerWidth - rect.width - 4)),
|
|
892
|
+
y: Math.max(4, Math.min(menu.y, window.innerHeight - rect.height - 4))
|
|
893
|
+
});
|
|
894
|
+
}, [menu]);
|
|
895
|
+
(0, react.useEffect)(() => {
|
|
896
|
+
if (menu === void 0) return void 0;
|
|
897
|
+
const onKeyDown = (e) => {
|
|
898
|
+
if (e.key === "Escape") setMenu(void 0);
|
|
899
|
+
};
|
|
900
|
+
const onMouseDown = (e) => {
|
|
901
|
+
const el = menuRef.current;
|
|
902
|
+
if (el !== null && e.target instanceof Node && el.contains(e.target)) return;
|
|
903
|
+
setMenu(void 0);
|
|
904
|
+
};
|
|
905
|
+
const onBlur = () => setMenu(void 0);
|
|
906
|
+
document.addEventListener("keydown", onKeyDown);
|
|
907
|
+
document.addEventListener("mousedown", onMouseDown);
|
|
908
|
+
window.addEventListener("blur", onBlur);
|
|
909
|
+
return () => {
|
|
910
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
911
|
+
document.removeEventListener("mousedown", onMouseDown);
|
|
912
|
+
window.removeEventListener("blur", onBlur);
|
|
913
|
+
};
|
|
914
|
+
}, [menu]);
|
|
829
915
|
const treeRef = (0, react.useRef)({
|
|
830
916
|
root,
|
|
831
917
|
children,
|
|
@@ -992,6 +1078,88 @@ window.__ModuleLoader__.load({
|
|
|
992
1078
|
});
|
|
993
1079
|
loadDir(dirPath);
|
|
994
1080
|
}, [loadDir]);
|
|
1081
|
+
const openContextMenu = (0, react.useCallback)((e, entry) => {
|
|
1082
|
+
e.preventDefault();
|
|
1083
|
+
e.stopPropagation();
|
|
1084
|
+
setMenu({
|
|
1085
|
+
kind: entry.kind === "dir" ? "dir" : "file",
|
|
1086
|
+
path: entry.path,
|
|
1087
|
+
x: e.clientX,
|
|
1088
|
+
y: e.clientY
|
|
1089
|
+
});
|
|
1090
|
+
}, []);
|
|
1091
|
+
const runAction = (0, react.useCallback)((action) => {
|
|
1092
|
+
setMenu(void 0);
|
|
1093
|
+
action();
|
|
1094
|
+
}, []);
|
|
1095
|
+
const applyMutation = (0, react.useCallback)(async (op, refreshPath) => {
|
|
1096
|
+
try {
|
|
1097
|
+
await op();
|
|
1098
|
+
refreshDir(refreshPath);
|
|
1099
|
+
} catch (error) {
|
|
1100
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1101
|
+
if (refreshPath === root) setRootError(message);
|
|
1102
|
+
else setDirErrors((prev) => ({
|
|
1103
|
+
...prev,
|
|
1104
|
+
[refreshPath]: message
|
|
1105
|
+
}));
|
|
1106
|
+
}
|
|
1107
|
+
}, [refreshDir, root]);
|
|
1108
|
+
const onNewFile = (0, react.useCallback)((dirPath) => {
|
|
1109
|
+
const name = window.prompt(`${t("prompt.newFileName")}:`, "");
|
|
1110
|
+
if (name === null) return;
|
|
1111
|
+
const trimmed = name.trim();
|
|
1112
|
+
if (trimmed === "") return;
|
|
1113
|
+
applyMutation(() => createFile(joinPath(dirPath, trimmed)), dirPath);
|
|
1114
|
+
}, [
|
|
1115
|
+
applyMutation,
|
|
1116
|
+
createFile,
|
|
1117
|
+
t
|
|
1118
|
+
]);
|
|
1119
|
+
const onNewFolder = (0, react.useCallback)((dirPath) => {
|
|
1120
|
+
const name = window.prompt(`${t("prompt.newFolderName")}:`, "");
|
|
1121
|
+
if (name === null) return;
|
|
1122
|
+
const trimmed = name.trim();
|
|
1123
|
+
if (trimmed === "") return;
|
|
1124
|
+
applyMutation(() => createDir(joinPath(dirPath, trimmed)), dirPath);
|
|
1125
|
+
}, [
|
|
1126
|
+
applyMutation,
|
|
1127
|
+
createDir,
|
|
1128
|
+
t
|
|
1129
|
+
]);
|
|
1130
|
+
const onRename = (0, react.useCallback)((path) => {
|
|
1131
|
+
const current = basenameOf$1(path);
|
|
1132
|
+
const name = window.prompt(`${t("prompt.renameTo")}:`, current);
|
|
1133
|
+
if (name === null) return;
|
|
1134
|
+
const trimmed = name.trim();
|
|
1135
|
+
if (trimmed === "" || trimmed === current) return;
|
|
1136
|
+
const parent = parentOf(path);
|
|
1137
|
+
const to = joinPath(parent, trimmed);
|
|
1138
|
+
applyMutation(async () => {
|
|
1139
|
+
await renameFile(path, to);
|
|
1140
|
+
retargetFile(path, to);
|
|
1141
|
+
}, parent);
|
|
1142
|
+
}, [
|
|
1143
|
+
applyMutation,
|
|
1144
|
+
renameFile,
|
|
1145
|
+
t
|
|
1146
|
+
]);
|
|
1147
|
+
const onDelete = (0, react.useCallback)((path, kind) => {
|
|
1148
|
+
const name = basenameOf$1(path);
|
|
1149
|
+
const message = kind === "dir" ? t("confirm.deleteDir", { name }) : t("confirm.deleteFile", { name });
|
|
1150
|
+
if (!window.confirm(message)) return;
|
|
1151
|
+
applyMutation(async () => {
|
|
1152
|
+
await removePath(path);
|
|
1153
|
+
closeFilesUnder(path);
|
|
1154
|
+
}, parentOf(path));
|
|
1155
|
+
}, [
|
|
1156
|
+
applyMutation,
|
|
1157
|
+
removePath,
|
|
1158
|
+
t
|
|
1159
|
+
]);
|
|
1160
|
+
const onCopyPath = (0, react.useCallback)((path) => {
|
|
1161
|
+
navigator.clipboard.writeText(path).catch(() => {});
|
|
1162
|
+
}, []);
|
|
995
1163
|
const onRowClick = (0, react.useCallback)((entry) => {
|
|
996
1164
|
if (entry.kind === "dir") {
|
|
997
1165
|
toggleDir(entry.path);
|
|
@@ -1029,6 +1197,7 @@ window.__ModuleLoader__.load({
|
|
|
1029
1197
|
onSelect: onRowClick,
|
|
1030
1198
|
onDoubleClick: onRowDoubleClick,
|
|
1031
1199
|
onOpenExternal: openPath,
|
|
1200
|
+
onContextMenu: openContextMenu,
|
|
1032
1201
|
t
|
|
1033
1202
|
}), isDir && isExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
1034
1203
|
isLoading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -1049,61 +1218,173 @@ window.__ModuleLoader__.load({
|
|
|
1049
1218
|
childEntries !== void 0 && renderEntries(childEntries, depth + 1)
|
|
1050
1219
|
] })] }, entry.path);
|
|
1051
1220
|
});
|
|
1221
|
+
const menuItems = (m) => {
|
|
1222
|
+
if (m.kind === "file") return [
|
|
1223
|
+
{
|
|
1224
|
+
label: t("menu.open"),
|
|
1225
|
+
onClick: () => openFile(m.path)
|
|
1226
|
+
},
|
|
1227
|
+
"divider",
|
|
1228
|
+
{
|
|
1229
|
+
label: t("menu.copyPath"),
|
|
1230
|
+
onClick: () => onCopyPath(m.path)
|
|
1231
|
+
},
|
|
1232
|
+
{
|
|
1233
|
+
label: t("menu.openSystem"),
|
|
1234
|
+
onClick: () => void openPath(m.path)
|
|
1235
|
+
},
|
|
1236
|
+
"divider",
|
|
1237
|
+
{
|
|
1238
|
+
label: t("menu.rename"),
|
|
1239
|
+
onClick: () => onRename(m.path)
|
|
1240
|
+
},
|
|
1241
|
+
{
|
|
1242
|
+
label: t("menu.delete"),
|
|
1243
|
+
danger: true,
|
|
1244
|
+
onClick: () => onDelete(m.path, "file")
|
|
1245
|
+
}
|
|
1246
|
+
];
|
|
1247
|
+
if (m.kind === "dir") return [
|
|
1248
|
+
{
|
|
1249
|
+
label: t("menu.newFile"),
|
|
1250
|
+
onClick: () => onNewFile(m.path)
|
|
1251
|
+
},
|
|
1252
|
+
{
|
|
1253
|
+
label: t("menu.newFolder"),
|
|
1254
|
+
onClick: () => onNewFolder(m.path)
|
|
1255
|
+
},
|
|
1256
|
+
"divider",
|
|
1257
|
+
{
|
|
1258
|
+
label: t("menu.copyPath"),
|
|
1259
|
+
onClick: () => onCopyPath(m.path)
|
|
1260
|
+
},
|
|
1261
|
+
{
|
|
1262
|
+
label: t("menu.openSystem"),
|
|
1263
|
+
onClick: () => void openPath(m.path)
|
|
1264
|
+
},
|
|
1265
|
+
{
|
|
1266
|
+
label: t("menu.refresh"),
|
|
1267
|
+
onClick: () => refreshDir(m.path)
|
|
1268
|
+
},
|
|
1269
|
+
"divider",
|
|
1270
|
+
{
|
|
1271
|
+
label: t("menu.rename"),
|
|
1272
|
+
onClick: () => onRename(m.path)
|
|
1273
|
+
},
|
|
1274
|
+
{
|
|
1275
|
+
label: t("menu.delete"),
|
|
1276
|
+
danger: true,
|
|
1277
|
+
onClick: () => onDelete(m.path, "dir")
|
|
1278
|
+
}
|
|
1279
|
+
];
|
|
1280
|
+
return [
|
|
1281
|
+
{
|
|
1282
|
+
label: t("menu.newFile"),
|
|
1283
|
+
onClick: () => onNewFile(m.path)
|
|
1284
|
+
},
|
|
1285
|
+
{
|
|
1286
|
+
label: t("menu.newFolder"),
|
|
1287
|
+
onClick: () => onNewFolder(m.path)
|
|
1288
|
+
},
|
|
1289
|
+
"divider",
|
|
1290
|
+
{
|
|
1291
|
+
label: t("menu.copyPath"),
|
|
1292
|
+
onClick: () => onCopyPath(m.path)
|
|
1293
|
+
},
|
|
1294
|
+
{
|
|
1295
|
+
label: t("menu.refresh"),
|
|
1296
|
+
onClick: () => refreshDir(m.path)
|
|
1297
|
+
}
|
|
1298
|
+
];
|
|
1299
|
+
};
|
|
1052
1300
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1053
1301
|
className: files_module_css_default.column,
|
|
1054
1302
|
style: { width: width > 0 ? width : void 0 },
|
|
1055
1303
|
"data-pane": "explorer",
|
|
1056
1304
|
"data-fe-theme": theme,
|
|
1057
|
-
children: [
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1305
|
+
children: [
|
|
1306
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1307
|
+
className: files_module_css_default.header,
|
|
1308
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1309
|
+
className: files_module_css_default.headerTitle,
|
|
1310
|
+
title: root ?? cwd,
|
|
1311
|
+
children: basenameOf$1(root ?? cwd)
|
|
1312
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1313
|
+
className: files_module_css_default.headerActions,
|
|
1314
|
+
children: [
|
|
1315
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1316
|
+
type: "button",
|
|
1317
|
+
className: files_module_css_default.action,
|
|
1318
|
+
title: t("action.theme"),
|
|
1319
|
+
onClick: toggleTheme,
|
|
1320
|
+
children: theme === "dark" ? "☀" : "🌙"
|
|
1321
|
+
}),
|
|
1322
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1323
|
+
type: "button",
|
|
1324
|
+
className: files_module_css_default.action,
|
|
1325
|
+
title: t("action.open"),
|
|
1326
|
+
onClick: () => void openPath(cwd),
|
|
1327
|
+
children: "↗"
|
|
1328
|
+
}),
|
|
1329
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1330
|
+
type: "button",
|
|
1331
|
+
className: files_module_css_default.action,
|
|
1332
|
+
title: t("tab.expand"),
|
|
1333
|
+
onClick: expandPreview,
|
|
1334
|
+
children: ">"
|
|
1335
|
+
})
|
|
1336
|
+
]
|
|
1337
|
+
})]
|
|
1338
|
+
}),
|
|
1339
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1340
|
+
className: files_module_css_default.treeArea,
|
|
1341
|
+
onContextMenu: (e) => {
|
|
1342
|
+
e.preventDefault();
|
|
1343
|
+
const target = root ?? cwd;
|
|
1344
|
+
if (target === void 0) return;
|
|
1345
|
+
setMenu({
|
|
1346
|
+
kind: "root",
|
|
1347
|
+
path: target,
|
|
1348
|
+
x: e.clientX,
|
|
1349
|
+
y: e.clientY
|
|
1350
|
+
});
|
|
1351
|
+
},
|
|
1065
1352
|
children: [
|
|
1066
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
title: t("action.theme"),
|
|
1070
|
-
onClick: toggleTheme,
|
|
1071
|
-
children: theme === "dark" ? "☀" : "🌙"
|
|
1353
|
+
rootLoading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1354
|
+
className: files_module_css_default.rowHint,
|
|
1355
|
+
children: t("preview.loading")
|
|
1072
1356
|
}),
|
|
1073
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
title: t("action.open"),
|
|
1077
|
-
onClick: () => void openPath(cwd),
|
|
1078
|
-
children: "↗"
|
|
1357
|
+
rootError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1358
|
+
className: files_module_css_default.rowError,
|
|
1359
|
+
children: rootError
|
|
1079
1360
|
}),
|
|
1080
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
children: ">"
|
|
1086
|
-
})
|
|
1361
|
+
!rootLoading && rootError === void 0 && root !== void 0 && children[root] !== void 0 && children[root].length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1362
|
+
className: files_module_css_default.rowHint,
|
|
1363
|
+
children: t("preview.emptyDir")
|
|
1364
|
+
}),
|
|
1365
|
+
root !== void 0 && children[root] !== void 0 && renderEntries(children[root], 0)
|
|
1087
1366
|
]
|
|
1088
|
-
})
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1367
|
+
}),
|
|
1368
|
+
menu !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1369
|
+
ref: menuRef,
|
|
1370
|
+
className: files_module_css_default.contextMenu,
|
|
1371
|
+
role: "menu",
|
|
1372
|
+
style: menuPos !== void 0 ? {
|
|
1373
|
+
left: menuPos.x,
|
|
1374
|
+
top: menuPos.y
|
|
1375
|
+
} : {
|
|
1376
|
+
left: menu.x,
|
|
1377
|
+
top: menu.y,
|
|
1378
|
+
visibility: "hidden"
|
|
1379
|
+
},
|
|
1380
|
+
children: menuItems(menu).map((item, index) => item === "divider" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: files_module_css_default.contextMenuDivider }, index) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1381
|
+
role: "menuitem",
|
|
1382
|
+
className: `${files_module_css_default.contextMenuItem}${item.danger ? ` ${files_module_css_default.contextMenuItemDanger}` : ""}`,
|
|
1383
|
+
onClick: () => runAction(item.onClick),
|
|
1384
|
+
children: item.label
|
|
1385
|
+
}, index))
|
|
1386
|
+
})
|
|
1387
|
+
]
|
|
1107
1388
|
});
|
|
1108
1389
|
}
|
|
1109
1390
|
var core_default = (/* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
@@ -8736,6 +9017,30 @@ window.__ModuleLoader__.load({
|
|
|
8736
9017
|
const PREVIEW_MIN = 240;
|
|
8737
9018
|
const CHAT_MIN = 240;
|
|
8738
9019
|
const PREVIEW_TOO_LARGE_LABEL = "512KB";
|
|
9020
|
+
/** Same-origin raw-bytes route registered by the host half (see src/index.ts). */
|
|
9021
|
+
const RAW_PREFIX = "/dsh-plugin-files/raw";
|
|
9022
|
+
const IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
9023
|
+
"png",
|
|
9024
|
+
"jpg",
|
|
9025
|
+
"jpeg",
|
|
9026
|
+
"gif",
|
|
9027
|
+
"webp",
|
|
9028
|
+
"avif",
|
|
9029
|
+
"bmp",
|
|
9030
|
+
"ico",
|
|
9031
|
+
"svg"
|
|
9032
|
+
]);
|
|
9033
|
+
/**
|
|
9034
|
+
* Same-origin URL serving the file's bytes when it is a previewable image;
|
|
9035
|
+
* undefined otherwise. Image tabs never go through the text RPC read — the
|
|
9036
|
+
* host route resolves the path through the sandboxed fs service itself.
|
|
9037
|
+
*/
|
|
9038
|
+
function imageSrcOf(path) {
|
|
9039
|
+
const idx = path.lastIndexOf(".");
|
|
9040
|
+
if (idx < 0 || idx === path.length - 1) return void 0;
|
|
9041
|
+
const ext = path.slice(idx + 1).toLowerCase();
|
|
9042
|
+
return IMAGE_EXTENSIONS.has(ext) ? `${RAW_PREFIX}/${encodeURIComponent(path)}` : void 0;
|
|
9043
|
+
}
|
|
8739
9044
|
/**
|
|
8740
9045
|
* Above this size the overlay editor (syntax-highlight layer + transparent
|
|
8741
9046
|
* textarea) falls back to a plain textarea: re-injecting and re-laying out
|
|
@@ -8783,6 +9088,18 @@ window.__ModuleLoader__.load({
|
|
|
8783
9088
|
size: result.size
|
|
8784
9089
|
};
|
|
8785
9090
|
}
|
|
9091
|
+
/**
|
|
9092
|
+
* Gutter text for an editor: one logical line number per source line, as a
|
|
9093
|
+
* single pre-formatted block (VS Code shows logical numbers even when soft
|
|
9094
|
+
* wrap makes a line occupy several visual rows).
|
|
9095
|
+
*/
|
|
9096
|
+
function lineNumbersOf(content) {
|
|
9097
|
+
const count = content.split("\n").length;
|
|
9098
|
+
if (count <= 1) return "1";
|
|
9099
|
+
const parts = new Array(count);
|
|
9100
|
+
for (let i = 0; i < count; i += 1) parts[i] = String(i + 1);
|
|
9101
|
+
return parts.join("\n");
|
|
9102
|
+
}
|
|
8786
9103
|
function FilePreview({ t, readFile, writeFile }) {
|
|
8787
9104
|
const { tabs, active, theme, collapsed, wrap } = useTabsState();
|
|
8788
9105
|
const [previewWidth, setPreviewWidth] = (0, react.useState)(null);
|
|
@@ -8792,10 +9109,12 @@ window.__ModuleLoader__.load({
|
|
|
8792
9109
|
const cacheRef = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
8793
9110
|
const hasOpenedRef = (0, react.useRef)(false);
|
|
8794
9111
|
const [, bump] = (0, react.useState)(0);
|
|
9112
|
+
const [imageFailed, setImageFailed] = (0, react.useState)(void 0);
|
|
8795
9113
|
const previewRef = (0, react.useRef)(null);
|
|
8796
9114
|
const handleRef = (0, react.useRef)(null);
|
|
8797
9115
|
const highlightRef = (0, react.useRef)(null);
|
|
8798
9116
|
const textareaRef = (0, react.useRef)(null);
|
|
9117
|
+
const gutterRef = (0, react.useRef)(null);
|
|
8799
9118
|
const refresh = (0, react.useCallback)(() => bump((v) => v + 1), []);
|
|
8800
9119
|
(0, react.useEffect)(() => {
|
|
8801
9120
|
const cache = cacheRef.current;
|
|
@@ -8806,6 +9125,11 @@ window.__ModuleLoader__.load({
|
|
|
8806
9125
|
return;
|
|
8807
9126
|
}
|
|
8808
9127
|
const controller = new AbortController();
|
|
9128
|
+
if (imageSrcOf(target) !== void 0) {
|
|
9129
|
+
cache.set(target, { status: "image" });
|
|
9130
|
+
refresh();
|
|
9131
|
+
return () => controller.abort();
|
|
9132
|
+
}
|
|
8809
9133
|
cache.set(target, { status: "loading" });
|
|
8810
9134
|
readFile(target, controller.signal).then((result) => {
|
|
8811
9135
|
if (!controller.signal.aborted) {
|
|
@@ -8830,6 +9154,9 @@ window.__ModuleLoader__.load({
|
|
|
8830
9154
|
readFile,
|
|
8831
9155
|
refresh
|
|
8832
9156
|
]);
|
|
9157
|
+
(0, react.useEffect)(() => {
|
|
9158
|
+
setImageFailed(void 0);
|
|
9159
|
+
}, [active]);
|
|
8833
9160
|
if (tabs.length > 0) hasOpenedRef.current = true;
|
|
8834
9161
|
(0, react.useEffect)(() => {
|
|
8835
9162
|
if (tabs.length > 0) {
|
|
@@ -8850,14 +9177,19 @@ window.__ModuleLoader__.load({
|
|
|
8850
9177
|
const language = active !== void 0 ? detectLanguage(active) : void 0;
|
|
8851
9178
|
const tooBig = (activeData?.size ?? 0) > HIGHLIGHT_MAX_BYTES;
|
|
8852
9179
|
const plain = language === void 0 || tooBig || language !== void 0 && PLAIN_LANGUAGES.has(language);
|
|
9180
|
+
const gutterNumbers = (0, react.useMemo)(() => activeData?.status === "loaded" ? lineNumbersOf(activeData.draft ?? "") : "", [activeData?.status, activeData?.draft]);
|
|
8853
9181
|
(0, react.useEffect)(() => {
|
|
8854
9182
|
const pre = highlightRef.current;
|
|
8855
9183
|
const ta = textareaRef.current;
|
|
8856
|
-
|
|
9184
|
+
const gutter = gutterRef.current;
|
|
9185
|
+
if (ta === null || gutter === null) return void 0;
|
|
8857
9186
|
let raf = 0;
|
|
8858
9187
|
const tick = () => {
|
|
8859
|
-
pre
|
|
8860
|
-
|
|
9188
|
+
if (pre !== null) {
|
|
9189
|
+
pre.scrollTop = ta.scrollTop;
|
|
9190
|
+
pre.scrollLeft = ta.scrollLeft;
|
|
9191
|
+
}
|
|
9192
|
+
gutter.scrollTop = ta.scrollTop;
|
|
8861
9193
|
raf = requestAnimationFrame(tick);
|
|
8862
9194
|
};
|
|
8863
9195
|
raf = requestAnimationFrame(tick);
|
|
@@ -8943,11 +9275,13 @@ window.__ModuleLoader__.load({
|
|
|
8943
9275
|
}, [onSave]);
|
|
8944
9276
|
const onTextareaScroll = (0, react.useCallback)((e) => {
|
|
8945
9277
|
const pre = highlightRef.current;
|
|
9278
|
+
const gutter = gutterRef.current;
|
|
8946
9279
|
const ta = e.currentTarget;
|
|
8947
9280
|
if (pre !== null) {
|
|
8948
9281
|
pre.scrollTop = ta.scrollTop;
|
|
8949
9282
|
pre.scrollLeft = ta.scrollLeft;
|
|
8950
9283
|
}
|
|
9284
|
+
if (gutter !== null) gutter.scrollTop = ta.scrollTop;
|
|
8951
9285
|
}, []);
|
|
8952
9286
|
const onTabDragStart = (0, react.useCallback)((e, path) => {
|
|
8953
9287
|
setDragPath(path);
|
|
@@ -8979,6 +9313,15 @@ window.__ModuleLoader__.load({
|
|
|
8979
9313
|
className: `${files_module_css_default.editor}${plain ? ` ${files_module_css_default.editorPlain}` : ""}`,
|
|
8980
9314
|
"data-wrap": wrap ? "on" : "off",
|
|
8981
9315
|
children: [
|
|
9316
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9317
|
+
ref: gutterRef,
|
|
9318
|
+
className: files_module_css_default.gutter,
|
|
9319
|
+
"aria-hidden": "true",
|
|
9320
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9321
|
+
className: files_module_css_default.gutterNumbers,
|
|
9322
|
+
children: gutterNumbers
|
|
9323
|
+
})
|
|
9324
|
+
}),
|
|
8982
9325
|
!plain && active !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
8983
9326
|
ref: highlightRef,
|
|
8984
9327
|
className: files_module_css_default.editorHighlight,
|
|
@@ -9005,6 +9348,33 @@ window.__ModuleLoader__.load({
|
|
|
9005
9348
|
})
|
|
9006
9349
|
]
|
|
9007
9350
|
});
|
|
9351
|
+
case "image": {
|
|
9352
|
+
const src = active !== void 0 ? imageSrcOf(active) : void 0;
|
|
9353
|
+
const name = active !== void 0 ? basenameOf(active) : "";
|
|
9354
|
+
if (src === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9355
|
+
className: files_module_css_default.previewHint,
|
|
9356
|
+
children: t("preview.binary")
|
|
9357
|
+
});
|
|
9358
|
+
if (imageFailed === active) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9359
|
+
className: files_module_css_default.previewHint,
|
|
9360
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: t("preview.imageFailed") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9361
|
+
className: files_module_css_default.previewMeta,
|
|
9362
|
+
children: name
|
|
9363
|
+
})]
|
|
9364
|
+
});
|
|
9365
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9366
|
+
className: files_module_css_default.imageView,
|
|
9367
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
9368
|
+
className: files_module_css_default.image,
|
|
9369
|
+
src,
|
|
9370
|
+
alt: name,
|
|
9371
|
+
onError: () => setImageFailed(active)
|
|
9372
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9373
|
+
className: files_module_css_default.previewMeta,
|
|
9374
|
+
children: name
|
|
9375
|
+
})]
|
|
9376
|
+
});
|
|
9377
|
+
}
|
|
9008
9378
|
case "binary": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9009
9379
|
className: files_module_css_default.previewHint,
|
|
9010
9380
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: t("preview.binary") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -9117,8 +9487,22 @@ window.__ModuleLoader__.load({
|
|
|
9117
9487
|
"tab.close": "关闭标签页",
|
|
9118
9488
|
"tab.collapse": "收起文件详情",
|
|
9119
9489
|
"tab.expand": "弹出文件详情",
|
|
9490
|
+
"menu.open": "打开预览",
|
|
9491
|
+
"menu.newFile": "新建文件",
|
|
9492
|
+
"menu.newFolder": "新建文件夹",
|
|
9493
|
+
"menu.rename": "重命名",
|
|
9494
|
+
"menu.delete": "删除",
|
|
9495
|
+
"menu.copyPath": "复制路径",
|
|
9496
|
+
"menu.refresh": "刷新",
|
|
9497
|
+
"menu.openSystem": "在系统中打开",
|
|
9498
|
+
"prompt.newFileName": "新文件名",
|
|
9499
|
+
"prompt.newFolderName": "新文件夹名",
|
|
9500
|
+
"prompt.renameTo": "重命名为",
|
|
9501
|
+
"confirm.deleteFile": "确定删除文件「{name}」吗?",
|
|
9502
|
+
"confirm.deleteDir": "确定删除文件夹「{name}」及其全部内容吗?",
|
|
9120
9503
|
"preview.loading": "加载中…",
|
|
9121
9504
|
"preview.binary": "二进制文件,无法预览",
|
|
9505
|
+
"preview.imageFailed": "图片加载失败",
|
|
9122
9506
|
"preview.tooLarge": "文件过大,仅支持预览不超过 {limit}",
|
|
9123
9507
|
"preview.emptyDir": "空目录",
|
|
9124
9508
|
"preview.error": "加载失败",
|
|
@@ -9136,8 +9520,22 @@ window.__ModuleLoader__.load({
|
|
|
9136
9520
|
"tab.close": "Close tab",
|
|
9137
9521
|
"tab.collapse": "Collapse file details",
|
|
9138
9522
|
"tab.expand": "Expand file details",
|
|
9523
|
+
"menu.open": "Open preview",
|
|
9524
|
+
"menu.newFile": "New File",
|
|
9525
|
+
"menu.newFolder": "New Folder",
|
|
9526
|
+
"menu.rename": "Rename",
|
|
9527
|
+
"menu.delete": "Delete",
|
|
9528
|
+
"menu.copyPath": "Copy Path",
|
|
9529
|
+
"menu.refresh": "Refresh",
|
|
9530
|
+
"menu.openSystem": "Open in System",
|
|
9531
|
+
"prompt.newFileName": "New file name",
|
|
9532
|
+
"prompt.newFolderName": "New folder name",
|
|
9533
|
+
"prompt.renameTo": "Rename to",
|
|
9534
|
+
"confirm.deleteFile": "Delete file \"{name}\"?",
|
|
9535
|
+
"confirm.deleteDir": "Delete folder \"{name}\" and all its contents?",
|
|
9139
9536
|
"preview.loading": "Loading…",
|
|
9140
9537
|
"preview.binary": "Binary file, cannot preview",
|
|
9538
|
+
"preview.imageFailed": "Failed to load image",
|
|
9141
9539
|
"preview.tooLarge": "File too large to preview (limit {limit})",
|
|
9142
9540
|
"preview.emptyDir": "Empty directory",
|
|
9143
9541
|
"preview.error": "Load failed",
|
|
@@ -9165,13 +9563,24 @@ window.__ModuleLoader__.load({
|
|
|
9165
9563
|
path,
|
|
9166
9564
|
content
|
|
9167
9565
|
}, signal));
|
|
9566
|
+
const createFile = (path, signal) => unwrap(ctx.connection.rpc.call(CHANNEL, "createFile", { path }, signal));
|
|
9567
|
+
const createDir = (path, signal) => unwrap(ctx.connection.rpc.call(CHANNEL, "createDir", { path }, signal));
|
|
9568
|
+
const renameFile = (path, to, signal) => unwrap(ctx.connection.rpc.call(CHANNEL, "rename", {
|
|
9569
|
+
path,
|
|
9570
|
+
to
|
|
9571
|
+
}, signal));
|
|
9572
|
+
const removePath = (path, signal) => unwrap(ctx.connection.rpc.call(CHANNEL, "delete", { path }, signal));
|
|
9168
9573
|
const openPath = (path) => ctx.workspaces.openPath(path);
|
|
9169
9574
|
ctx.slots.inject("explorer", () => ctx.slots.register({
|
|
9170
9575
|
name: "explorer",
|
|
9171
9576
|
locale: NS,
|
|
9172
9577
|
inject: () => ({
|
|
9173
9578
|
listDir,
|
|
9174
|
-
openPath
|
|
9579
|
+
openPath,
|
|
9580
|
+
createFile,
|
|
9581
|
+
createDir,
|
|
9582
|
+
renameFile,
|
|
9583
|
+
removePath
|
|
9175
9584
|
})
|
|
9176
9585
|
}, FileExplorer));
|
|
9177
9586
|
ctx.slots.inject("explorer.preview", () => ctx.slots.register({
|