dsh-plugin-workbench 0.0.2 → 0.0.4
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 +32 -0
- package/README.md +5 -2
- package/lib/client.js +723 -154
- package/lib/client.js.map +1 -1
- package/package.json +3 -2
- package/scripts/verify-alignment.mjs +180 -0
- package/src/client/FileExplorer.tsx +127 -59
- package/src/client/FilePreview.tsx +97 -36
- package/src/client/fileIcons.tsx +144 -0
- package/src/client/files.module.css +96 -4
- package/src/client/locales.ts +6 -0
- package/src/client/store.ts +32 -2
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_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{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{background:var(--fe-hover);color:var(--fe-fg)}.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_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{height:100%;min-height:0;position:relative}.Myjg4a_editorHighlight{pointer-events:none;white-space:pre;color:var(--fe-fg);background:0 0;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:
|
|
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}";
|
|
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");
|
|
@@ -47,9 +47,13 @@ window.__ModuleLoader__.load({
|
|
|
47
47
|
"column": "Myjg4a_column",
|
|
48
48
|
"editor": "Myjg4a_editor",
|
|
49
49
|
"editorHighlight": "Myjg4a_editorHighlight",
|
|
50
|
+
"editorHint": "Myjg4a_editorHint",
|
|
51
|
+
"editorPlain": "Myjg4a_editorPlain",
|
|
50
52
|
"editorTextarea": "Myjg4a_editorTextarea",
|
|
51
53
|
"fe-preview-in": "Myjg4a_fe-preview-in",
|
|
52
54
|
"fe-preview-out": "Myjg4a_fe-preview-out",
|
|
55
|
+
"fileBadge": "Myjg4a_fileBadge",
|
|
56
|
+
"fileBadgeLong": "Myjg4a_fileBadgeLong",
|
|
53
57
|
"handle": "Myjg4a_handle",
|
|
54
58
|
"header": "Myjg4a_header",
|
|
55
59
|
"headerActions": "Myjg4a_headerActions",
|
|
@@ -69,15 +73,465 @@ window.__ModuleLoader__.load({
|
|
|
69
73
|
"saveError": "Myjg4a_saveError",
|
|
70
74
|
"size": "Myjg4a_size",
|
|
71
75
|
"tab": "Myjg4a_tab",
|
|
76
|
+
"tabAction": "Myjg4a_tabAction",
|
|
77
|
+
"tabActionActive": "Myjg4a_tabActionActive",
|
|
72
78
|
"tabActive": "Myjg4a_tabActive",
|
|
73
79
|
"tabBar": "Myjg4a_tabBar",
|
|
74
80
|
"tabClose": "Myjg4a_tabClose",
|
|
75
81
|
"tabDot": "Myjg4a_tabDot",
|
|
82
|
+
"tabIcon": "Myjg4a_tabIcon",
|
|
76
83
|
"tabName": "Myjg4a_tabName",
|
|
77
84
|
"tabScroller": "Myjg4a_tabScroller",
|
|
78
85
|
"treeArea": "Myjg4a_treeArea"
|
|
79
86
|
};
|
|
80
87
|
//#endregion
|
|
88
|
+
//#region src/client/fileIcons.tsx
|
|
89
|
+
/**
|
|
90
|
+
* File-type icons for the explorer tree rows and the preview tabs.
|
|
91
|
+
*
|
|
92
|
+
* Code/config files render as small colored badges with an extension label
|
|
93
|
+
* (VS Code "Minimal"-theme style); media, archives and installer files use
|
|
94
|
+
* emoji; anything unknown falls back to a generic document glyph. No icon
|
|
95
|
+
* assets are shipped — badges are pure CSS (per-language colors) and emoji
|
|
96
|
+
* come from the platform font.
|
|
97
|
+
*/
|
|
98
|
+
/** lowercase extension (no dot) → badge colors. */
|
|
99
|
+
const BADGES = {
|
|
100
|
+
ts: {
|
|
101
|
+
label: "TS",
|
|
102
|
+
bg: "#3178c6",
|
|
103
|
+
fg: "#ffffff"
|
|
104
|
+
},
|
|
105
|
+
mts: {
|
|
106
|
+
label: "TS",
|
|
107
|
+
bg: "#3178c6",
|
|
108
|
+
fg: "#ffffff"
|
|
109
|
+
},
|
|
110
|
+
cts: {
|
|
111
|
+
label: "TS",
|
|
112
|
+
bg: "#3178c6",
|
|
113
|
+
fg: "#ffffff"
|
|
114
|
+
},
|
|
115
|
+
tsx: {
|
|
116
|
+
label: "TSX",
|
|
117
|
+
bg: "#61dafb",
|
|
118
|
+
fg: "#06283d"
|
|
119
|
+
},
|
|
120
|
+
js: {
|
|
121
|
+
label: "JS",
|
|
122
|
+
bg: "#f7df1e",
|
|
123
|
+
fg: "#1e1e1e"
|
|
124
|
+
},
|
|
125
|
+
mjs: {
|
|
126
|
+
label: "JS",
|
|
127
|
+
bg: "#f7df1e",
|
|
128
|
+
fg: "#1e1e1e"
|
|
129
|
+
},
|
|
130
|
+
cjs: {
|
|
131
|
+
label: "JS",
|
|
132
|
+
bg: "#f7df1e",
|
|
133
|
+
fg: "#1e1e1e"
|
|
134
|
+
},
|
|
135
|
+
jsx: {
|
|
136
|
+
label: "JSX",
|
|
137
|
+
bg: "#61dafb",
|
|
138
|
+
fg: "#06283d"
|
|
139
|
+
},
|
|
140
|
+
json: {
|
|
141
|
+
label: "{}",
|
|
142
|
+
bg: "#cbcb41",
|
|
143
|
+
fg: "#1e1e1e"
|
|
144
|
+
},
|
|
145
|
+
jsonc: {
|
|
146
|
+
label: "{}",
|
|
147
|
+
bg: "#cbcb41",
|
|
148
|
+
fg: "#1e1e1e"
|
|
149
|
+
},
|
|
150
|
+
html: {
|
|
151
|
+
label: "HTML",
|
|
152
|
+
bg: "#e44d26",
|
|
153
|
+
fg: "#ffffff"
|
|
154
|
+
},
|
|
155
|
+
htm: {
|
|
156
|
+
label: "HTML",
|
|
157
|
+
bg: "#e44d26",
|
|
158
|
+
fg: "#ffffff"
|
|
159
|
+
},
|
|
160
|
+
css: {
|
|
161
|
+
label: "CSS",
|
|
162
|
+
bg: "#2965f1",
|
|
163
|
+
fg: "#ffffff"
|
|
164
|
+
},
|
|
165
|
+
scss: {
|
|
166
|
+
label: "SCSS",
|
|
167
|
+
bg: "#cc6699",
|
|
168
|
+
fg: "#ffffff"
|
|
169
|
+
},
|
|
170
|
+
less: {
|
|
171
|
+
label: "LESS",
|
|
172
|
+
bg: "#2a4d80",
|
|
173
|
+
fg: "#ffffff"
|
|
174
|
+
},
|
|
175
|
+
md: {
|
|
176
|
+
label: "MD",
|
|
177
|
+
bg: "#519aba",
|
|
178
|
+
fg: "#ffffff"
|
|
179
|
+
},
|
|
180
|
+
markdown: {
|
|
181
|
+
label: "MD",
|
|
182
|
+
bg: "#519aba",
|
|
183
|
+
fg: "#ffffff"
|
|
184
|
+
},
|
|
185
|
+
py: {
|
|
186
|
+
label: "PY",
|
|
187
|
+
bg: "#3572a5",
|
|
188
|
+
fg: "#ffffff"
|
|
189
|
+
},
|
|
190
|
+
pyw: {
|
|
191
|
+
label: "PY",
|
|
192
|
+
bg: "#3572a5",
|
|
193
|
+
fg: "#ffffff"
|
|
194
|
+
},
|
|
195
|
+
go: {
|
|
196
|
+
label: "GO",
|
|
197
|
+
bg: "#00add8",
|
|
198
|
+
fg: "#06283d"
|
|
199
|
+
},
|
|
200
|
+
rs: {
|
|
201
|
+
label: "RS",
|
|
202
|
+
bg: "#dea584",
|
|
203
|
+
fg: "#1e1e1e"
|
|
204
|
+
},
|
|
205
|
+
java: {
|
|
206
|
+
label: "JAVA",
|
|
207
|
+
bg: "#b07219",
|
|
208
|
+
fg: "#ffffff"
|
|
209
|
+
},
|
|
210
|
+
c: {
|
|
211
|
+
label: "C",
|
|
212
|
+
bg: "#6e6e6e",
|
|
213
|
+
fg: "#ffffff"
|
|
214
|
+
},
|
|
215
|
+
h: {
|
|
216
|
+
label: "H",
|
|
217
|
+
bg: "#6e6e6e",
|
|
218
|
+
fg: "#ffffff"
|
|
219
|
+
},
|
|
220
|
+
cpp: {
|
|
221
|
+
label: "CPP",
|
|
222
|
+
bg: "#f34b7d",
|
|
223
|
+
fg: "#ffffff"
|
|
224
|
+
},
|
|
225
|
+
cc: {
|
|
226
|
+
label: "CPP",
|
|
227
|
+
bg: "#f34b7d",
|
|
228
|
+
fg: "#ffffff"
|
|
229
|
+
},
|
|
230
|
+
cxx: {
|
|
231
|
+
label: "CPP",
|
|
232
|
+
bg: "#f34b7d",
|
|
233
|
+
fg: "#ffffff"
|
|
234
|
+
},
|
|
235
|
+
hpp: {
|
|
236
|
+
label: "HPP",
|
|
237
|
+
bg: "#f34b7d",
|
|
238
|
+
fg: "#ffffff"
|
|
239
|
+
},
|
|
240
|
+
hxx: {
|
|
241
|
+
label: "HPP",
|
|
242
|
+
bg: "#f34b7d",
|
|
243
|
+
fg: "#ffffff"
|
|
244
|
+
},
|
|
245
|
+
cs: {
|
|
246
|
+
label: "CS",
|
|
247
|
+
bg: "#178600",
|
|
248
|
+
fg: "#ffffff"
|
|
249
|
+
},
|
|
250
|
+
sh: {
|
|
251
|
+
label: "SH",
|
|
252
|
+
bg: "#89e051",
|
|
253
|
+
fg: "#1e1e1e"
|
|
254
|
+
},
|
|
255
|
+
bash: {
|
|
256
|
+
label: "SH",
|
|
257
|
+
bg: "#89e051",
|
|
258
|
+
fg: "#1e1e1e"
|
|
259
|
+
},
|
|
260
|
+
zsh: {
|
|
261
|
+
label: "SH",
|
|
262
|
+
bg: "#89e051",
|
|
263
|
+
fg: "#1e1e1e"
|
|
264
|
+
},
|
|
265
|
+
ps1: {
|
|
266
|
+
label: "PS1",
|
|
267
|
+
bg: "#012456",
|
|
268
|
+
fg: "#ffffff"
|
|
269
|
+
},
|
|
270
|
+
psm1: {
|
|
271
|
+
label: "PS1",
|
|
272
|
+
bg: "#012456",
|
|
273
|
+
fg: "#ffffff"
|
|
274
|
+
},
|
|
275
|
+
psd1: {
|
|
276
|
+
label: "PS1",
|
|
277
|
+
bg: "#012456",
|
|
278
|
+
fg: "#ffffff"
|
|
279
|
+
},
|
|
280
|
+
bat: {
|
|
281
|
+
label: "BAT",
|
|
282
|
+
bg: "#6e6e6e",
|
|
283
|
+
fg: "#ffffff"
|
|
284
|
+
},
|
|
285
|
+
cmd: {
|
|
286
|
+
label: "BAT",
|
|
287
|
+
bg: "#6e6e6e",
|
|
288
|
+
fg: "#ffffff"
|
|
289
|
+
},
|
|
290
|
+
sql: {
|
|
291
|
+
label: "SQL",
|
|
292
|
+
bg: "#e38c00",
|
|
293
|
+
fg: "#ffffff"
|
|
294
|
+
},
|
|
295
|
+
yml: {
|
|
296
|
+
label: "YML",
|
|
297
|
+
bg: "#cb171e",
|
|
298
|
+
fg: "#ffffff"
|
|
299
|
+
},
|
|
300
|
+
yaml: {
|
|
301
|
+
label: "YML",
|
|
302
|
+
bg: "#cb171e",
|
|
303
|
+
fg: "#ffffff"
|
|
304
|
+
},
|
|
305
|
+
toml: {
|
|
306
|
+
label: "TOML",
|
|
307
|
+
bg: "#8b8b8b",
|
|
308
|
+
fg: "#ffffff"
|
|
309
|
+
},
|
|
310
|
+
ini: {
|
|
311
|
+
label: "INI",
|
|
312
|
+
bg: "#8b8b8b",
|
|
313
|
+
fg: "#ffffff"
|
|
314
|
+
},
|
|
315
|
+
conf: {
|
|
316
|
+
label: "INI",
|
|
317
|
+
bg: "#8b8b8b",
|
|
318
|
+
fg: "#ffffff"
|
|
319
|
+
},
|
|
320
|
+
cfg: {
|
|
321
|
+
label: "INI",
|
|
322
|
+
bg: "#8b8b8b",
|
|
323
|
+
fg: "#ffffff"
|
|
324
|
+
},
|
|
325
|
+
xml: {
|
|
326
|
+
label: "XML",
|
|
327
|
+
bg: "#a074c4",
|
|
328
|
+
fg: "#ffffff"
|
|
329
|
+
},
|
|
330
|
+
xsl: {
|
|
331
|
+
label: "XML",
|
|
332
|
+
bg: "#a074c4",
|
|
333
|
+
fg: "#ffffff"
|
|
334
|
+
},
|
|
335
|
+
svg: {
|
|
336
|
+
label: "SVG",
|
|
337
|
+
bg: "#e37933",
|
|
338
|
+
fg: "#ffffff"
|
|
339
|
+
},
|
|
340
|
+
vue: {
|
|
341
|
+
label: "VUE",
|
|
342
|
+
bg: "#41b883",
|
|
343
|
+
fg: "#06283d"
|
|
344
|
+
},
|
|
345
|
+
lock: {
|
|
346
|
+
label: "LOCK",
|
|
347
|
+
bg: "#9d9d9d",
|
|
348
|
+
fg: "#1e1e1e"
|
|
349
|
+
},
|
|
350
|
+
env: {
|
|
351
|
+
label: "ENV",
|
|
352
|
+
bg: "#f05033",
|
|
353
|
+
fg: "#ffffff"
|
|
354
|
+
},
|
|
355
|
+
gitignore: {
|
|
356
|
+
label: "GIT",
|
|
357
|
+
bg: "#f05033",
|
|
358
|
+
fg: "#ffffff"
|
|
359
|
+
},
|
|
360
|
+
gitattributes: {
|
|
361
|
+
label: "GIT",
|
|
362
|
+
bg: "#f05033",
|
|
363
|
+
fg: "#ffffff"
|
|
364
|
+
},
|
|
365
|
+
gitmodules: {
|
|
366
|
+
label: "GIT",
|
|
367
|
+
bg: "#f05033",
|
|
368
|
+
fg: "#ffffff"
|
|
369
|
+
},
|
|
370
|
+
editorconfig: {
|
|
371
|
+
label: "CFG",
|
|
372
|
+
bg: "#8b8b8b",
|
|
373
|
+
fg: "#ffffff"
|
|
374
|
+
},
|
|
375
|
+
npmrc: {
|
|
376
|
+
label: "CFG",
|
|
377
|
+
bg: "#8b8b8b",
|
|
378
|
+
fg: "#ffffff"
|
|
379
|
+
},
|
|
380
|
+
pnpmrc: {
|
|
381
|
+
label: "CFG",
|
|
382
|
+
bg: "#8b8b8b",
|
|
383
|
+
fg: "#ffffff"
|
|
384
|
+
},
|
|
385
|
+
yarnrc: {
|
|
386
|
+
label: "CFG",
|
|
387
|
+
bg: "#8b8b8b",
|
|
388
|
+
fg: "#ffffff"
|
|
389
|
+
},
|
|
390
|
+
mk: {
|
|
391
|
+
label: "MK",
|
|
392
|
+
bg: "#6d8086",
|
|
393
|
+
fg: "#ffffff"
|
|
394
|
+
},
|
|
395
|
+
makefile: {
|
|
396
|
+
label: "MK",
|
|
397
|
+
bg: "#6d8086",
|
|
398
|
+
fg: "#ffffff"
|
|
399
|
+
},
|
|
400
|
+
txt: {
|
|
401
|
+
label: "TXT",
|
|
402
|
+
bg: "#9d9d9d",
|
|
403
|
+
fg: "#ffffff"
|
|
404
|
+
},
|
|
405
|
+
log: {
|
|
406
|
+
label: "TXT",
|
|
407
|
+
bg: "#9d9d9d",
|
|
408
|
+
fg: "#ffffff"
|
|
409
|
+
},
|
|
410
|
+
pdf: {
|
|
411
|
+
label: "PDF",
|
|
412
|
+
bg: "#e74c3c",
|
|
413
|
+
fg: "#ffffff"
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
/** lowercase extension (no dot) → emoji glyph. */
|
|
417
|
+
const EMOJI = {
|
|
418
|
+
png: "🖼️",
|
|
419
|
+
jpg: "🖼️",
|
|
420
|
+
jpeg: "🖼️",
|
|
421
|
+
gif: "🖼️",
|
|
422
|
+
webp: "🖼️",
|
|
423
|
+
bmp: "🖼️",
|
|
424
|
+
ico: "🖼️",
|
|
425
|
+
avif: "🖼️",
|
|
426
|
+
jfif: "🖼️",
|
|
427
|
+
tif: "🖼️",
|
|
428
|
+
tiff: "🖼️",
|
|
429
|
+
mp3: "🎵",
|
|
430
|
+
wav: "🎵",
|
|
431
|
+
flac: "🎵",
|
|
432
|
+
ogg: "🎵",
|
|
433
|
+
oga: "🎵",
|
|
434
|
+
m4a: "🎵",
|
|
435
|
+
aac: "🎵",
|
|
436
|
+
wma: "🎵",
|
|
437
|
+
opus: "🎵",
|
|
438
|
+
mid: "🎵",
|
|
439
|
+
mp4: "🎬",
|
|
440
|
+
mkv: "🎬",
|
|
441
|
+
avi: "🎬",
|
|
442
|
+
mov: "🎬",
|
|
443
|
+
webm: "🎬",
|
|
444
|
+
flv: "🎬",
|
|
445
|
+
wmv: "🎬",
|
|
446
|
+
m4v: "🎬",
|
|
447
|
+
mpg: "🎬",
|
|
448
|
+
mpeg: "🎬",
|
|
449
|
+
zip: "🗜️",
|
|
450
|
+
rar: "🗜️",
|
|
451
|
+
"7z": "🗜️",
|
|
452
|
+
tar: "🗜️",
|
|
453
|
+
gz: "🗜️",
|
|
454
|
+
bz2: "🗜️",
|
|
455
|
+
xz: "🗜️",
|
|
456
|
+
tgz: "🗜️",
|
|
457
|
+
tbz2: "🗜️",
|
|
458
|
+
zst: "🗜️",
|
|
459
|
+
doc: "📘",
|
|
460
|
+
docx: "📘",
|
|
461
|
+
odt: "📘",
|
|
462
|
+
rtf: "📘",
|
|
463
|
+
xls: "📗",
|
|
464
|
+
xlsx: "📗",
|
|
465
|
+
ods: "📗",
|
|
466
|
+
csv: "📗",
|
|
467
|
+
ppt: "📙",
|
|
468
|
+
pptx: "📙",
|
|
469
|
+
odp: "📙",
|
|
470
|
+
epub: "📖",
|
|
471
|
+
mobi: "📖",
|
|
472
|
+
exe: "📦",
|
|
473
|
+
msi: "📦",
|
|
474
|
+
dmg: "📦",
|
|
475
|
+
app: "📦",
|
|
476
|
+
deb: "📦",
|
|
477
|
+
rpm: "📦",
|
|
478
|
+
apk: "📦",
|
|
479
|
+
iso: "📦"
|
|
480
|
+
};
|
|
481
|
+
/** Well-known extension-less names (lowercase) → emoji. */
|
|
482
|
+
const NAMED_EMOJI = { dockerfile: "🐳" };
|
|
483
|
+
/** Resolve a file name to its icon spec (badge colors or an emoji glyph). */
|
|
484
|
+
function fileIconFor(name) {
|
|
485
|
+
const lower = name.trim().toLowerCase();
|
|
486
|
+
if (lower === "") return {
|
|
487
|
+
kind: "emoji",
|
|
488
|
+
char: "📄"
|
|
489
|
+
};
|
|
490
|
+
const namedEmoji = NAMED_EMOJI[lower];
|
|
491
|
+
if (namedEmoji !== void 0) return {
|
|
492
|
+
kind: "emoji",
|
|
493
|
+
char: namedEmoji
|
|
494
|
+
};
|
|
495
|
+
let key;
|
|
496
|
+
if (lower.startsWith(".")) {
|
|
497
|
+
const rest = lower.slice(1);
|
|
498
|
+
key = rest.startsWith("env.") ? "env" : rest;
|
|
499
|
+
} else {
|
|
500
|
+
const dot = lower.lastIndexOf(".");
|
|
501
|
+
key = dot > 0 ? lower.slice(dot + 1) : lower;
|
|
502
|
+
}
|
|
503
|
+
const badge = BADGES[key];
|
|
504
|
+
if (badge !== void 0) return {
|
|
505
|
+
kind: "badge",
|
|
506
|
+
label: badge.label,
|
|
507
|
+
bg: badge.bg,
|
|
508
|
+
fg: badge.fg
|
|
509
|
+
};
|
|
510
|
+
const emoji = EMOJI[key];
|
|
511
|
+
if (emoji !== void 0) return {
|
|
512
|
+
kind: "emoji",
|
|
513
|
+
char: emoji
|
|
514
|
+
};
|
|
515
|
+
return {
|
|
516
|
+
kind: "emoji",
|
|
517
|
+
char: "📄"
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
/** Render a file's icon: a colored extension badge or an emoji glyph. */
|
|
521
|
+
function FileIcon({ name }) {
|
|
522
|
+
const icon = fileIconFor(name);
|
|
523
|
+
if (icon.kind === "emoji") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: icon.char });
|
|
524
|
+
const className = icon.label.length >= 4 ? `${files_module_css_default.fileBadge} ${files_module_css_default.fileBadgeLong}` : files_module_css_default.fileBadge;
|
|
525
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
526
|
+
className,
|
|
527
|
+
style: {
|
|
528
|
+
background: icon.bg,
|
|
529
|
+
color: icon.fg
|
|
530
|
+
},
|
|
531
|
+
children: icon.label
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
//#endregion
|
|
81
535
|
//#region src/client/store.ts
|
|
82
536
|
/**
|
|
83
537
|
* Module-local store shared by the explorer tree (FileExplorer) and the split
|
|
@@ -93,15 +547,29 @@ window.__ModuleLoader__.load({
|
|
|
93
547
|
active: void 0,
|
|
94
548
|
collapsed: false
|
|
95
549
|
};
|
|
550
|
+
const WRAP_KEY = "dsh-plugin-workbench:wrap";
|
|
551
|
+
/** Read the persisted wrap preference; defaults to soft wrap ON. */
|
|
552
|
+
function storedWrap() {
|
|
553
|
+
try {
|
|
554
|
+
if (typeof window === "undefined") return true;
|
|
555
|
+
const stored = window.localStorage.getItem(WRAP_KEY);
|
|
556
|
+
return stored === null ? true : stored === "1";
|
|
557
|
+
} catch {
|
|
558
|
+
return true;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
const initialWrap = storedWrap();
|
|
96
562
|
let state = {
|
|
97
563
|
currentCwd: void 0,
|
|
98
564
|
workspaces: {},
|
|
99
|
-
theme: "dark"
|
|
565
|
+
theme: "dark",
|
|
566
|
+
wrap: initialWrap
|
|
100
567
|
};
|
|
101
568
|
let view = {
|
|
102
569
|
tabs: EMPTY_TABS,
|
|
103
570
|
active: void 0,
|
|
104
571
|
collapsed: false,
|
|
572
|
+
wrap: initialWrap,
|
|
105
573
|
theme: "dark",
|
|
106
574
|
cwd: void 0
|
|
107
575
|
};
|
|
@@ -128,10 +596,11 @@ window.__ModuleLoader__.load({
|
|
|
128
596
|
tabs: ws.tabs,
|
|
129
597
|
active: ws.active,
|
|
130
598
|
collapsed: ws.collapsed,
|
|
599
|
+
wrap: state.wrap,
|
|
131
600
|
theme: state.theme,
|
|
132
601
|
cwd: state.currentCwd
|
|
133
602
|
};
|
|
134
|
-
if (nextView.tabs === view.tabs && nextView.active === view.active && nextView.collapsed === view.collapsed && nextView.theme === view.theme && nextView.cwd === view.cwd) return;
|
|
603
|
+
if (nextView.tabs === view.tabs && nextView.active === view.active && nextView.collapsed === view.collapsed && nextView.wrap === view.wrap && nextView.theme === view.theme && nextView.cwd === view.cwd) return;
|
|
135
604
|
view = nextView;
|
|
136
605
|
for (const listener of [...listeners]) listener();
|
|
137
606
|
}
|
|
@@ -236,6 +705,17 @@ window.__ModuleLoader__.load({
|
|
|
236
705
|
theme: state.theme === "dark" ? "light" : "dark"
|
|
237
706
|
});
|
|
238
707
|
}
|
|
708
|
+
/** Toggle display-only soft wrap for the editor (global, persisted). */
|
|
709
|
+
function toggleWrap() {
|
|
710
|
+
const wrap = !state.wrap;
|
|
711
|
+
try {
|
|
712
|
+
window.localStorage.setItem(WRAP_KEY, wrap ? "1" : "0");
|
|
713
|
+
} catch {}
|
|
714
|
+
commit({
|
|
715
|
+
...state,
|
|
716
|
+
wrap
|
|
717
|
+
});
|
|
718
|
+
}
|
|
239
719
|
//#endregion
|
|
240
720
|
//#region src/client/FileExplorer.tsx
|
|
241
721
|
/**
|
|
@@ -257,6 +737,10 @@ window.__ModuleLoader__.load({
|
|
|
257
737
|
}
|
|
258
738
|
/** How often the visible tree is re-listed to pick up disk changes. */
|
|
259
739
|
const REFRESH_MS = 2e3;
|
|
740
|
+
/** How many previously-expanded folders to re-list at once on workspace switch. */
|
|
741
|
+
const DIR_LOAD_BATCH = 4;
|
|
742
|
+
/** Pause between batches when restoring expanded folders. */
|
|
743
|
+
const DIR_LOAD_GAP_MS = 50;
|
|
260
744
|
const EMPTY_EXPANDED = /* @__PURE__ */ new Set();
|
|
261
745
|
/** True when two directory listings are identical (name/kind/size). */
|
|
262
746
|
function sameEntries(a, b) {
|
|
@@ -264,6 +748,69 @@ window.__ModuleLoader__.load({
|
|
|
264
748
|
for (let i = 0; i < a.length; i += 1) if (a[i].name !== b[i].name || a[i].kind !== b[i].kind || a[i].size !== b[i].size) return false;
|
|
265
749
|
return true;
|
|
266
750
|
}
|
|
751
|
+
/**
|
|
752
|
+
* One tree row, memoized so opening/activating a file (which changes the
|
|
753
|
+
* active-path highlight) re-renders only the affected row — with a workspace
|
|
754
|
+
* full of files, re-rendering the whole tree on every click is what made
|
|
755
|
+
* opening files feel laggy.
|
|
756
|
+
*/
|
|
757
|
+
const TreeRow = (0, react.memo)(function TreeRow({ entry, depth, isActive, isExpanded, onToggleDir, onRefreshDir, onSelect, onDoubleClick, onOpenExternal, t }) {
|
|
758
|
+
const isDir = entry.kind === "dir";
|
|
759
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
760
|
+
className: `${files_module_css_default.row} ${isActive ? files_module_css_default.rowSelected : ""}`,
|
|
761
|
+
style: { paddingLeft: 8 + depth * 14 },
|
|
762
|
+
onClick: () => onSelect(entry),
|
|
763
|
+
onDoubleClick: () => onDoubleClick(entry),
|
|
764
|
+
role: "treeitem",
|
|
765
|
+
"aria-selected": isActive,
|
|
766
|
+
"aria-expanded": isDir ? isExpanded : void 0,
|
|
767
|
+
title: entry.name,
|
|
768
|
+
children: [
|
|
769
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
770
|
+
className: files_module_css_default.chevron,
|
|
771
|
+
onClick: (e) => {
|
|
772
|
+
e.stopPropagation();
|
|
773
|
+
if (isDir) onToggleDir(entry.path);
|
|
774
|
+
},
|
|
775
|
+
children: isDir ? isExpanded ? "▾" : "▸" : ""
|
|
776
|
+
}),
|
|
777
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
778
|
+
className: files_module_css_default.icon,
|
|
779
|
+
children: isDir ? isExpanded ? "📂" : "📁" : entry.kind === "file" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FileIcon, { name: entry.name }) : "·"
|
|
780
|
+
}),
|
|
781
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
782
|
+
className: files_module_css_default.name,
|
|
783
|
+
children: entry.name
|
|
784
|
+
}),
|
|
785
|
+
entry.kind === "file" && entry.size !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
786
|
+
className: files_module_css_default.size,
|
|
787
|
+
children: formatSize$1(entry.size)
|
|
788
|
+
}),
|
|
789
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
790
|
+
className: files_module_css_default.actions,
|
|
791
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
792
|
+
type: "button",
|
|
793
|
+
className: files_module_css_default.action,
|
|
794
|
+
title: t("action.open"),
|
|
795
|
+
onClick: (e) => {
|
|
796
|
+
e.stopPropagation();
|
|
797
|
+
onOpenExternal(entry.path);
|
|
798
|
+
},
|
|
799
|
+
children: "↗"
|
|
800
|
+
}), isDir && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
801
|
+
type: "button",
|
|
802
|
+
className: files_module_css_default.action,
|
|
803
|
+
title: t("action.refresh"),
|
|
804
|
+
onClick: (e) => {
|
|
805
|
+
e.stopPropagation();
|
|
806
|
+
onRefreshDir(entry.path);
|
|
807
|
+
},
|
|
808
|
+
children: "⟳"
|
|
809
|
+
})]
|
|
810
|
+
})
|
|
811
|
+
]
|
|
812
|
+
});
|
|
813
|
+
});
|
|
267
814
|
function FileExplorer({ width, useSessions, t, listDir, openPath }) {
|
|
268
815
|
const sessionList = useSessions((s) => s);
|
|
269
816
|
const currentId = sessionList.current;
|
|
@@ -291,6 +838,8 @@ window.__ModuleLoader__.load({
|
|
|
291
838
|
expanded,
|
|
292
839
|
rootLoading
|
|
293
840
|
};
|
|
841
|
+
const childrenRef = (0, react.useRef)(children);
|
|
842
|
+
childrenRef.current = children;
|
|
294
843
|
(0, react.useEffect)(() => {
|
|
295
844
|
document.body.style.setProperty("--dsh-explorer-width", `${width}px`);
|
|
296
845
|
return () => {
|
|
@@ -312,12 +861,18 @@ window.__ModuleLoader__.load({
|
|
|
312
861
|
setRootLoading(true);
|
|
313
862
|
const controller = new AbortController();
|
|
314
863
|
rootAbortRef.current = controller;
|
|
315
|
-
listDir(cwd, controller.signal).then((result) => {
|
|
864
|
+
listDir(cwd, controller.signal).then(async (result) => {
|
|
316
865
|
if (controller.signal.aborted) return;
|
|
317
866
|
setRoot(result.root);
|
|
318
867
|
setChildren({ [result.root]: result.entries });
|
|
319
868
|
setRootError(void 0);
|
|
320
|
-
|
|
869
|
+
const dirs = [...expanded].filter((dirPath) => dirPath !== result.root);
|
|
870
|
+
for (let i = 0; i < dirs.length; i += DIR_LOAD_BATCH) {
|
|
871
|
+
if (controller.signal.aborted) return;
|
|
872
|
+
const batch = dirs.slice(i, i + DIR_LOAD_BATCH);
|
|
873
|
+
await Promise.all(batch.map((dirPath) => loadDir(dirPath)));
|
|
874
|
+
if (i + DIR_LOAD_BATCH < dirs.length) await new Promise((resolve) => setTimeout(resolve, DIR_LOAD_GAP_MS));
|
|
875
|
+
}
|
|
321
876
|
}).catch((error) => {
|
|
322
877
|
if (controller.signal.aborted) return;
|
|
323
878
|
setRootError(error instanceof Error ? error.message : String(error));
|
|
@@ -427,12 +982,8 @@ window.__ModuleLoader__.load({
|
|
|
427
982
|
[cwdKey]: next
|
|
428
983
|
};
|
|
429
984
|
});
|
|
430
|
-
if (!
|
|
431
|
-
}, [
|
|
432
|
-
cwdKey,
|
|
433
|
-
children,
|
|
434
|
-
loadDir
|
|
435
|
-
]);
|
|
985
|
+
if (!childrenRef.current[dirPath]) loadDir(dirPath);
|
|
986
|
+
}, [cwdKey, loadDir]);
|
|
436
987
|
const refreshDir = (0, react.useCallback)((dirPath) => {
|
|
437
988
|
setChildren((prev) => {
|
|
438
989
|
const next = { ...prev };
|
|
@@ -468,59 +1019,17 @@ window.__ModuleLoader__.load({
|
|
|
468
1019
|
const isLoading = isDir && loadingDirs.has(entry.path);
|
|
469
1020
|
const childEntries = isDir && isExpanded ? children[entry.path] : void 0;
|
|
470
1021
|
const error = isDir ? dirErrors[entry.path] : void 0;
|
|
471
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
className: files_module_css_default.chevron,
|
|
483
|
-
onClick: (e) => {
|
|
484
|
-
e.stopPropagation();
|
|
485
|
-
if (isDir) toggleDir(entry.path);
|
|
486
|
-
},
|
|
487
|
-
children: isDir ? isExpanded ? "▾" : "▸" : ""
|
|
488
|
-
}),
|
|
489
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
490
|
-
className: files_module_css_default.icon,
|
|
491
|
-
children: isDir ? "📁" : entry.kind === "file" ? "📄" : "·"
|
|
492
|
-
}),
|
|
493
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
494
|
-
className: files_module_css_default.name,
|
|
495
|
-
children: entry.name
|
|
496
|
-
}),
|
|
497
|
-
entry.kind === "file" && entry.size !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
498
|
-
className: files_module_css_default.size,
|
|
499
|
-
children: formatSize$1(entry.size)
|
|
500
|
-
}),
|
|
501
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
502
|
-
className: files_module_css_default.actions,
|
|
503
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
504
|
-
type: "button",
|
|
505
|
-
className: files_module_css_default.action,
|
|
506
|
-
title: t("action.open"),
|
|
507
|
-
onClick: (e) => {
|
|
508
|
-
e.stopPropagation();
|
|
509
|
-
openPath(entry.path);
|
|
510
|
-
},
|
|
511
|
-
children: "↗"
|
|
512
|
-
}), isDir && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
513
|
-
type: "button",
|
|
514
|
-
className: files_module_css_default.action,
|
|
515
|
-
title: t("action.refresh"),
|
|
516
|
-
onClick: (e) => {
|
|
517
|
-
e.stopPropagation();
|
|
518
|
-
refreshDir(entry.path);
|
|
519
|
-
},
|
|
520
|
-
children: "⟳"
|
|
521
|
-
})]
|
|
522
|
-
})
|
|
523
|
-
]
|
|
1022
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TreeRow, {
|
|
1023
|
+
entry,
|
|
1024
|
+
depth,
|
|
1025
|
+
isActive: entry.kind === "file" && activePath === entry.path,
|
|
1026
|
+
isExpanded,
|
|
1027
|
+
onToggleDir: toggleDir,
|
|
1028
|
+
onRefreshDir: refreshDir,
|
|
1029
|
+
onSelect: onRowClick,
|
|
1030
|
+
onDoubleClick: onRowDoubleClick,
|
|
1031
|
+
onOpenExternal: openPath,
|
|
1032
|
+
t
|
|
524
1033
|
}), isDir && isExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
525
1034
|
isLoading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
526
1035
|
className: files_module_css_default.rowHint,
|
|
@@ -8227,6 +8736,20 @@ window.__ModuleLoader__.load({
|
|
|
8227
8736
|
const PREVIEW_MIN = 240;
|
|
8228
8737
|
const CHAT_MIN = 240;
|
|
8229
8738
|
const PREVIEW_TOO_LARGE_LABEL = "512KB";
|
|
8739
|
+
/**
|
|
8740
|
+
* Above this size the overlay editor (syntax-highlight layer + transparent
|
|
8741
|
+
* textarea) falls back to a plain textarea: re-injecting and re-laying out
|
|
8742
|
+
* hundreds of KB of wrapped text on every keystroke is what makes the page
|
|
8743
|
+
* lag. The plain textarea keeps editing, wrapping and scrolling — it only
|
|
8744
|
+
* loses the colors, which files this big rarely need anyway.
|
|
8745
|
+
*/
|
|
8746
|
+
const HIGHLIGHT_MAX_BYTES = 65536;
|
|
8747
|
+
/**
|
|
8748
|
+
* Languages always rendered as a plain textarea, never the overlay: the
|
|
8749
|
+
* highlight layer costs a full extra layout pass (and with CJK text a
|
|
8750
|
+
* fragile alignment surface) for prose formats where colors add little.
|
|
8751
|
+
*/
|
|
8752
|
+
const PLAIN_LANGUAGES = /* @__PURE__ */ new Set(["markdown"]);
|
|
8230
8753
|
function basenameOf(path) {
|
|
8231
8754
|
const trimmed = path.replace(/[\\/]+$/, "");
|
|
8232
8755
|
const idx = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\"));
|
|
@@ -8261,7 +8784,7 @@ window.__ModuleLoader__.load({
|
|
|
8261
8784
|
};
|
|
8262
8785
|
}
|
|
8263
8786
|
function FilePreview({ t, readFile, writeFile }) {
|
|
8264
|
-
const { tabs, active, theme, collapsed } = useTabsState();
|
|
8787
|
+
const { tabs, active, theme, collapsed, wrap } = useTabsState();
|
|
8265
8788
|
const [previewWidth, setPreviewWidth] = (0, react.useState)(null);
|
|
8266
8789
|
const [closing, setClosing] = (0, react.useState)(false);
|
|
8267
8790
|
const [dragPath, setDragPath] = (0, react.useState)(void 0);
|
|
@@ -8272,35 +8795,38 @@ window.__ModuleLoader__.load({
|
|
|
8272
8795
|
const previewRef = (0, react.useRef)(null);
|
|
8273
8796
|
const handleRef = (0, react.useRef)(null);
|
|
8274
8797
|
const highlightRef = (0, react.useRef)(null);
|
|
8798
|
+
const textareaRef = (0, react.useRef)(null);
|
|
8275
8799
|
const refresh = (0, react.useCallback)(() => bump((v) => v + 1), []);
|
|
8276
8800
|
(0, react.useEffect)(() => {
|
|
8277
8801
|
const cache = cacheRef.current;
|
|
8278
8802
|
for (const [path] of cache) if (!tabs.includes(path)) cache.delete(path);
|
|
8279
|
-
const
|
|
8280
|
-
|
|
8281
|
-
|
|
8282
|
-
|
|
8283
|
-
const controller = new AbortController();
|
|
8284
|
-
controllers.push(controller);
|
|
8285
|
-
readFile(path, controller.signal).then((result) => {
|
|
8286
|
-
if (!controller.signal.aborted) {
|
|
8287
|
-
cache.set(path, previewDataOf(result));
|
|
8288
|
-
refresh();
|
|
8289
|
-
}
|
|
8290
|
-
}).catch((error) => {
|
|
8291
|
-
if (!controller.signal.aborted) {
|
|
8292
|
-
cache.set(path, {
|
|
8293
|
-
status: "error",
|
|
8294
|
-
message: error instanceof Error ? error.message : String(error)
|
|
8295
|
-
});
|
|
8296
|
-
refresh();
|
|
8297
|
-
}
|
|
8298
|
-
});
|
|
8803
|
+
const target = active ?? tabs[0];
|
|
8804
|
+
if (target === void 0 || cache.has(target)) {
|
|
8805
|
+
refresh();
|
|
8806
|
+
return;
|
|
8299
8807
|
}
|
|
8808
|
+
const controller = new AbortController();
|
|
8809
|
+
cache.set(target, { status: "loading" });
|
|
8810
|
+
readFile(target, controller.signal).then((result) => {
|
|
8811
|
+
if (!controller.signal.aborted) {
|
|
8812
|
+
cache.set(target, previewDataOf(result));
|
|
8813
|
+
if (result.size > HIGHLIGHT_MAX_BYTES) requestAnimationFrame(refresh);
|
|
8814
|
+
else refresh();
|
|
8815
|
+
}
|
|
8816
|
+
}).catch((error) => {
|
|
8817
|
+
if (!controller.signal.aborted) {
|
|
8818
|
+
cache.set(target, {
|
|
8819
|
+
status: "error",
|
|
8820
|
+
message: error instanceof Error ? error.message : String(error)
|
|
8821
|
+
});
|
|
8822
|
+
refresh();
|
|
8823
|
+
}
|
|
8824
|
+
});
|
|
8300
8825
|
refresh();
|
|
8301
|
-
return () =>
|
|
8826
|
+
return () => controller.abort();
|
|
8302
8827
|
}, [
|
|
8303
8828
|
tabs,
|
|
8829
|
+
active,
|
|
8304
8830
|
readFile,
|
|
8305
8831
|
refresh
|
|
8306
8832
|
]);
|
|
@@ -8320,6 +8846,28 @@ window.__ModuleLoader__.load({
|
|
|
8320
8846
|
}
|
|
8321
8847
|
}, [tabs.length]);
|
|
8322
8848
|
const isOpen = !collapsed && (tabs.length > 0 || closing || hasOpenedRef.current);
|
|
8849
|
+
const activeData = active !== void 0 ? cacheRef.current.get(active) : void 0;
|
|
8850
|
+
const language = active !== void 0 ? detectLanguage(active) : void 0;
|
|
8851
|
+
const tooBig = (activeData?.size ?? 0) > HIGHLIGHT_MAX_BYTES;
|
|
8852
|
+
const plain = language === void 0 || tooBig || language !== void 0 && PLAIN_LANGUAGES.has(language);
|
|
8853
|
+
(0, react.useEffect)(() => {
|
|
8854
|
+
const pre = highlightRef.current;
|
|
8855
|
+
const ta = textareaRef.current;
|
|
8856
|
+
if (pre === null || ta === null || plain) return void 0;
|
|
8857
|
+
let raf = 0;
|
|
8858
|
+
const tick = () => {
|
|
8859
|
+
pre.scrollTop = ta.scrollTop;
|
|
8860
|
+
pre.scrollLeft = ta.scrollLeft;
|
|
8861
|
+
raf = requestAnimationFrame(tick);
|
|
8862
|
+
};
|
|
8863
|
+
raf = requestAnimationFrame(tick);
|
|
8864
|
+
return () => cancelAnimationFrame(raf);
|
|
8865
|
+
}, [
|
|
8866
|
+
isOpen,
|
|
8867
|
+
active,
|
|
8868
|
+
activeData?.status,
|
|
8869
|
+
plain
|
|
8870
|
+
]);
|
|
8323
8871
|
(0, react.useEffect)(() => {
|
|
8324
8872
|
if (!isOpen) {
|
|
8325
8873
|
document.body.style.removeProperty("--dsh-preview-width");
|
|
@@ -8416,7 +8964,6 @@ window.__ModuleLoader__.load({
|
|
|
8416
8964
|
const onTabDragEnd = (0, react.useCallback)(() => {
|
|
8417
8965
|
setDragPath(void 0);
|
|
8418
8966
|
}, []);
|
|
8419
|
-
const activeData = active !== void 0 ? cacheRef.current.get(active) : void 0;
|
|
8420
8967
|
if (!isOpen) return null;
|
|
8421
8968
|
const renderBody = () => {
|
|
8422
8969
|
if (activeData === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -8428,34 +8975,36 @@ window.__ModuleLoader__.load({
|
|
|
8428
8975
|
className: files_module_css_default.previewHint,
|
|
8429
8976
|
children: t("preview.loading")
|
|
8430
8977
|
});
|
|
8431
|
-
case "loaded": {
|
|
8432
|
-
|
|
8433
|
-
|
|
8434
|
-
|
|
8435
|
-
|
|
8436
|
-
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
|
|
8448
|
-
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
8453
|
-
|
|
8454
|
-
|
|
8455
|
-
|
|
8456
|
-
|
|
8457
|
-
|
|
8458
|
-
|
|
8978
|
+
case "loaded": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8979
|
+
className: `${files_module_css_default.editor}${plain ? ` ${files_module_css_default.editorPlain}` : ""}`,
|
|
8980
|
+
"data-wrap": wrap ? "on" : "off",
|
|
8981
|
+
children: [
|
|
8982
|
+
!plain && active !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
8983
|
+
ref: highlightRef,
|
|
8984
|
+
className: files_module_css_default.editorHighlight,
|
|
8985
|
+
"aria-hidden": "true",
|
|
8986
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", { dangerouslySetInnerHTML: { __html: highlightCode(activeData.draft ?? "", active) } })
|
|
8987
|
+
}),
|
|
8988
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
8989
|
+
ref: textareaRef,
|
|
8990
|
+
className: files_module_css_default.editorTextarea,
|
|
8991
|
+
value: activeData.draft ?? "",
|
|
8992
|
+
onChange: (e) => onTextareaChange(e.target.value),
|
|
8993
|
+
onScroll: onTextareaScroll,
|
|
8994
|
+
onKeyDown,
|
|
8995
|
+
spellCheck: false,
|
|
8996
|
+
wrap: wrap ? "soft" : "off"
|
|
8997
|
+
}),
|
|
8998
|
+
language !== void 0 && tooBig && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8999
|
+
className: files_module_css_default.editorHint,
|
|
9000
|
+
children: t("preview.highlightOff")
|
|
9001
|
+
}),
|
|
9002
|
+
saveError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9003
|
+
className: files_module_css_default.saveError,
|
|
9004
|
+
children: saveError
|
|
9005
|
+
})
|
|
9006
|
+
]
|
|
9007
|
+
});
|
|
8459
9008
|
case "binary": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8460
9009
|
className: files_module_css_default.previewHint,
|
|
8461
9010
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: t("preview.binary") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -8488,44 +9037,58 @@ window.__ModuleLoader__.load({
|
|
|
8488
9037
|
"data-fe-theme": theme,
|
|
8489
9038
|
children: [tabs.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8490
9039
|
className: files_module_css_default.tabBar,
|
|
8491
|
-
children: [
|
|
8492
|
-
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
|
|
8506
|
-
|
|
8507
|
-
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
|
|
8516
|
-
|
|
8517
|
-
|
|
8518
|
-
|
|
8519
|
-
|
|
8520
|
-
|
|
9040
|
+
children: [
|
|
9041
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9042
|
+
className: files_module_css_default.tabScroller,
|
|
9043
|
+
children: tabs.map((path) => {
|
|
9044
|
+
const data = cacheRef.current.get(path);
|
|
9045
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9046
|
+
className: `${files_module_css_default.tab} ${path === active ? files_module_css_default.tabActive : ""}`,
|
|
9047
|
+
onClick: () => activateFile(path),
|
|
9048
|
+
draggable: true,
|
|
9049
|
+
onDragStart: (e) => onTabDragStart(e, path),
|
|
9050
|
+
onDragOver: (e) => onTabDragOver(e, path),
|
|
9051
|
+
onDragEnd: onTabDragEnd,
|
|
9052
|
+
title: path,
|
|
9053
|
+
children: [
|
|
9054
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9055
|
+
className: files_module_css_default.tabIcon,
|
|
9056
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FileIcon, { name: basenameOf(path) })
|
|
9057
|
+
}),
|
|
9058
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9059
|
+
className: files_module_css_default.tabName,
|
|
9060
|
+
children: basenameOf(path)
|
|
9061
|
+
}),
|
|
9062
|
+
data?.dirty === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: files_module_css_default.tabDot }),
|
|
9063
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9064
|
+
type: "button",
|
|
9065
|
+
className: files_module_css_default.tabClose,
|
|
9066
|
+
title: t("tab.close"),
|
|
9067
|
+
onClick: (e) => {
|
|
9068
|
+
e.stopPropagation();
|
|
9069
|
+
closeFile(path);
|
|
9070
|
+
},
|
|
9071
|
+
children: "✕"
|
|
9072
|
+
})
|
|
9073
|
+
]
|
|
9074
|
+
}, path);
|
|
9075
|
+
})
|
|
9076
|
+
}),
|
|
9077
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9078
|
+
type: "button",
|
|
9079
|
+
className: `${files_module_css_default.tabAction}${wrap ? ` ${files_module_css_default.tabActionActive}` : ""}`,
|
|
9080
|
+
title: wrap ? t("action.wrapOff") : t("action.wrapOn"),
|
|
9081
|
+
onClick: toggleWrap,
|
|
9082
|
+
children: "⤶"
|
|
9083
|
+
}),
|
|
9084
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9085
|
+
type: "button",
|
|
9086
|
+
className: files_module_css_default.collapse,
|
|
9087
|
+
title: t("tab.collapse"),
|
|
9088
|
+
onClick: collapsePreview,
|
|
9089
|
+
children: "<"
|
|
8521
9090
|
})
|
|
8522
|
-
|
|
8523
|
-
type: "button",
|
|
8524
|
-
className: files_module_css_default.collapse,
|
|
8525
|
-
title: t("tab.collapse"),
|
|
8526
|
-
onClick: collapsePreview,
|
|
8527
|
-
children: "<"
|
|
8528
|
-
})]
|
|
9091
|
+
]
|
|
8529
9092
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8530
9093
|
className: files_module_css_default.previewBody,
|
|
8531
9094
|
children: renderBody()
|
|
@@ -8549,6 +9112,8 @@ window.__ModuleLoader__.load({
|
|
|
8549
9112
|
"action.open": "在系统中打开",
|
|
8550
9113
|
"action.theme": "切换浅色/暗色主题",
|
|
8551
9114
|
"action.saveHint": "Ctrl+S 保存",
|
|
9115
|
+
"action.wrapOn": "开启自动换行(显示层换行,不改文件)",
|
|
9116
|
+
"action.wrapOff": "关闭自动换行(长行横向滚动)",
|
|
8552
9117
|
"tab.close": "关闭标签页",
|
|
8553
9118
|
"tab.collapse": "收起文件详情",
|
|
8554
9119
|
"tab.expand": "弹出文件详情",
|
|
@@ -8556,7 +9121,8 @@ window.__ModuleLoader__.load({
|
|
|
8556
9121
|
"preview.binary": "二进制文件,无法预览",
|
|
8557
9122
|
"preview.tooLarge": "文件过大,仅支持预览不超过 {limit}",
|
|
8558
9123
|
"preview.emptyDir": "空目录",
|
|
8559
|
-
"preview.error": "加载失败"
|
|
9124
|
+
"preview.error": "加载失败",
|
|
9125
|
+
"preview.highlightOff": "大文件:已关闭语法高亮(仍可编辑)"
|
|
8560
9126
|
};
|
|
8561
9127
|
const en = {
|
|
8562
9128
|
"placeholder.noSession": "No session",
|
|
@@ -8565,6 +9131,8 @@ window.__ModuleLoader__.load({
|
|
|
8565
9131
|
"action.open": "Open in system",
|
|
8566
9132
|
"action.theme": "Toggle light/dark theme",
|
|
8567
9133
|
"action.saveHint": "Ctrl+S to save",
|
|
9134
|
+
"action.wrapOn": "Enable word wrap (display only, file unchanged)",
|
|
9135
|
+
"action.wrapOff": "Disable word wrap (long lines scroll horizontally)",
|
|
8568
9136
|
"tab.close": "Close tab",
|
|
8569
9137
|
"tab.collapse": "Collapse file details",
|
|
8570
9138
|
"tab.expand": "Expand file details",
|
|
@@ -8572,7 +9140,8 @@ window.__ModuleLoader__.load({
|
|
|
8572
9140
|
"preview.binary": "Binary file, cannot preview",
|
|
8573
9141
|
"preview.tooLarge": "File too large to preview (limit {limit})",
|
|
8574
9142
|
"preview.emptyDir": "Empty directory",
|
|
8575
|
-
"preview.error": "Load failed"
|
|
9143
|
+
"preview.error": "Load failed",
|
|
9144
|
+
"preview.highlightOff": "Large file: syntax highlighting off (still editable)"
|
|
8576
9145
|
};
|
|
8577
9146
|
//#endregion
|
|
8578
9147
|
//#region src/client/index.ts
|