@lijian-ui/dsh-file-manager 0.1.20
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/LICENSE +38 -0
- package/README.i18n.yaml +6 -0
- package/README.md +66 -0
- package/README.zh.md +66 -0
- package/cordis.patch.yml +13 -0
- package/lib/assets/mermaid.min.js +3587 -0
- package/lib/client.js +7621 -0
- package/lib/client.js.map +1 -0
- package/lib/index.js +3207 -0
- package/lib/tsconfig.client.tsbuildinfo +1 -0
- package/lib/tsconfig.host.tsbuildinfo +1 -0
- package/lib/types/client/FileManagerSettingsCard.d.ts +56 -0
- package/lib/types/client/FileManagerSettingsCard.d.ts.map +1 -0
- package/lib/types/client/PluginSettingsCard.d.ts +104 -0
- package/lib/types/client/PluginSettingsCard.d.ts.map +1 -0
- package/lib/types/client/api.d.ts +75 -0
- package/lib/types/client/api.d.ts.map +1 -0
- package/lib/types/client/chat/AttachedFilesDock.d.ts +51 -0
- package/lib/types/client/chat/AttachedFilesDock.d.ts.map +1 -0
- package/lib/types/client/chat/file-ref.d.ts +35 -0
- package/lib/types/client/chat/file-ref.d.ts.map +1 -0
- package/lib/types/client/chat/mermaid-chat.d.ts +30 -0
- package/lib/types/client/chat/mermaid-chat.d.ts.map +1 -0
- package/lib/types/client/chat/placeholder-hint.d.ts +16 -0
- package/lib/types/client/chat/placeholder-hint.d.ts.map +1 -0
- package/lib/types/client/components/ExplorerPanel.d.ts +26 -0
- package/lib/types/client/components/ExplorerPanel.d.ts.map +1 -0
- package/lib/types/client/components/FileIcon.d.ts +15 -0
- package/lib/types/client/components/FileIcon.d.ts.map +1 -0
- package/lib/types/client/components/ScmPanel.d.ts +23 -0
- package/lib/types/client/components/ScmPanel.d.ts.map +1 -0
- package/lib/types/client/components/a11y.d.ts +12 -0
- package/lib/types/client/components/a11y.d.ts.map +1 -0
- package/lib/types/client/components/icons.d.ts +41 -0
- package/lib/types/client/components/icons.d.ts.map +1 -0
- package/lib/types/client/components/overlay.d.ts +45 -0
- package/lib/types/client/components/overlay.d.ts.map +1 -0
- package/lib/types/client/drag/DragFileInlay.d.ts +31 -0
- package/lib/types/client/drag/DragFileInlay.d.ts.map +1 -0
- package/lib/types/client/drag/file-drag.d.ts +47 -0
- package/lib/types/client/drag/file-drag.d.ts.map +1 -0
- package/lib/types/client/drag.d.ts +31 -0
- package/lib/types/client/drag.d.ts.map +1 -0
- package/lib/types/client/file-source.d.ts +29 -0
- package/lib/types/client/file-source.d.ts.map +1 -0
- package/lib/types/client/fileType.d.ts +31 -0
- package/lib/types/client/fileType.d.ts.map +1 -0
- package/lib/types/client/floating.d.ts +27 -0
- package/lib/types/client/floating.d.ts.map +1 -0
- package/lib/types/client/hooks/useResizableSplit.d.ts +37 -0
- package/lib/types/client/hooks/useResizableSplit.d.ts.map +1 -0
- package/lib/types/client/hooks/useStore.d.ts +10 -0
- package/lib/types/client/hooks/useStore.d.ts.map +1 -0
- package/lib/types/client/index.d.ts +57 -0
- package/lib/types/client/index.d.ts.map +1 -0
- package/lib/types/client/layout.d.ts +104 -0
- package/lib/types/client/layout.d.ts.map +1 -0
- package/lib/types/client/locales.d.ts +125 -0
- package/lib/types/client/locales.d.ts.map +1 -0
- package/lib/types/client/maximize.d.ts +24 -0
- package/lib/types/client/maximize.d.ts.map +1 -0
- package/lib/types/client/mention.d.ts +44 -0
- package/lib/types/client/mention.d.ts.map +1 -0
- package/lib/types/client/mount.d.ts +22 -0
- package/lib/types/client/mount.d.ts.map +1 -0
- package/lib/types/client/persist.d.ts +55 -0
- package/lib/types/client/persist.d.ts.map +1 -0
- package/lib/types/client/picker/FilePickerModal.d.ts +47 -0
- package/lib/types/client/picker/FilePickerModal.d.ts.map +1 -0
- package/lib/types/client/picker/file-picker.d.ts +62 -0
- package/lib/types/client/picker/file-picker.d.ts.map +1 -0
- package/lib/types/client/preview/PreviewPanel.d.ts +17 -0
- package/lib/types/client/preview/PreviewPanel.d.ts.map +1 -0
- package/lib/types/client/preview/PreviewTabs.d.ts +30 -0
- package/lib/types/client/preview/PreviewTabs.d.ts.map +1 -0
- package/lib/types/client/preview/PreviewToolbar.d.ts +37 -0
- package/lib/types/client/preview/PreviewToolbar.d.ts.map +1 -0
- package/lib/types/client/preview/content.d.ts +43 -0
- package/lib/types/client/preview/content.d.ts.map +1 -0
- package/lib/types/client/preview/markdown.d.ts +60 -0
- package/lib/types/client/preview/markdown.d.ts.map +1 -0
- package/lib/types/client/preview/mermaid.d.ts +78 -0
- package/lib/types/client/preview/mermaid.d.ts.map +1 -0
- package/lib/types/client/preview/selection.d.ts +26 -0
- package/lib/types/client/preview/selection.d.ts.map +1 -0
- package/lib/types/client/reference.d.ts +75 -0
- package/lib/types/client/reference.d.ts.map +1 -0
- package/lib/types/client/settings-form.d.ts +206 -0
- package/lib/types/client/settings-form.d.ts.map +1 -0
- package/lib/types/client/store.d.ts +279 -0
- package/lib/types/client/store.d.ts.map +1 -0
- package/lib/types/core/types.d.ts +132 -0
- package/lib/types/core/types.d.ts.map +1 -0
- package/lib/types/host/fs-service.d.ts +96 -0
- package/lib/types/host/fs-service.d.ts.map +1 -0
- package/lib/types/host/gate.d.ts +45 -0
- package/lib/types/host/gate.d.ts.map +1 -0
- package/lib/types/host/git-runner.d.ts +80 -0
- package/lib/types/host/git-runner.d.ts.map +1 -0
- package/lib/types/host/git-service.d.ts +130 -0
- package/lib/types/host/git-service.d.ts.map +1 -0
- package/lib/types/host/loopback.d.ts +25 -0
- package/lib/types/host/loopback.d.ts.map +1 -0
- package/lib/types/host/poll-guard.d.ts +55 -0
- package/lib/types/host/poll-guard.d.ts.map +1 -0
- package/lib/types/host/routes.d.ts +54 -0
- package/lib/types/host/routes.d.ts.map +1 -0
- package/lib/types/index.d.ts +35 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/mount-once.d.ts +25 -0
- package/lib/types/mount-once.d.ts.map +1 -0
- package/package.json +85 -0
- package/src/client/FileManagerSettingsCard.tsx +117 -0
- package/src/client/PluginSettingsCard.tsx +337 -0
- package/src/client/api.ts +141 -0
- package/src/client/chat/file-ref.ts +144 -0
- package/src/client/chat/mermaid-chat.tsx +102 -0
- package/src/client/chat/placeholder-hint.tsx +46 -0
- package/src/client/components/ExplorerPanel.tsx +534 -0
- package/src/client/components/FileIcon.tsx +46 -0
- package/src/client/components/ScmPanel.tsx +480 -0
- package/src/client/components/a11y.ts +20 -0
- package/src/client/components/icons.tsx +274 -0
- package/src/client/components/overlay.tsx +225 -0
- package/src/client/css-modules.d.ts +5 -0
- package/src/client/drag/DragFileInlay.tsx +89 -0
- package/src/client/drag/file-drag.ts +67 -0
- package/src/client/drag.ts +154 -0
- package/src/client/file-source.ts +58 -0
- package/src/client/fileType.ts +129 -0
- package/src/client/floating.ts +63 -0
- package/src/client/hooks/useResizableSplit.ts +91 -0
- package/src/client/hooks/useStore.ts +15 -0
- package/src/client/index.ts +389 -0
- package/src/client/layout.ts +546 -0
- package/src/client/locales.ts +247 -0
- package/src/client/maximize.ts +34 -0
- package/src/client/mount.tsx +74 -0
- package/src/client/persist.ts +194 -0
- package/src/client/picker/FilePickerModal.tsx +506 -0
- package/src/client/picker/file-picker.ts +86 -0
- package/src/client/preview/PreviewPanel.tsx +233 -0
- package/src/client/preview/PreviewTabs.tsx +159 -0
- package/src/client/preview/PreviewToolbar.tsx +160 -0
- package/src/client/preview/content.tsx +617 -0
- package/src/client/preview/markdown.ts +351 -0
- package/src/client/preview/mermaid.ts +274 -0
- package/src/client/preview/selection.ts +82 -0
- package/src/client/reference.ts +161 -0
- package/src/client/settings-card.module.css +316 -0
- package/src/client/settings-form.ts +451 -0
- package/src/client/store.ts +1290 -0
- package/src/client/styles/chip.module.css +38 -0
- package/src/client/styles/drag.module.css +30 -0
- package/src/client/styles/explorer.module.css +371 -0
- package/src/client/styles/picker.module.css +344 -0
- package/src/client/styles/preview.module.css +904 -0
- package/src/client/styles/scm.module.css +380 -0
- package/src/client/styles/tokens.module.css +480 -0
- package/src/core/types.ts +162 -0
- package/src/host/fs-service.ts +513 -0
- package/src/host/gate.ts +74 -0
- package/src/host/git-runner.ts +116 -0
- package/src/host/git-service.ts +395 -0
- package/src/host/loopback.ts +63 -0
- package/src/host/poll-guard.ts +109 -0
- package/src/host/routes.ts +695 -0
- package/src/index.ts +97 -0
- package/src/mount-once.ts +48 -0
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The panel design system: FileManager's measured tokens (light/dark), scoped to
|
|
3
|
+
* the plugin's own root elements so they never leak into the shell. Light
|
|
4
|
+
* values are the defaults; the controller flips `data-filemgr-dark` on every
|
|
5
|
+
* root element when the GUI theme is dark (the shell's theme service emits
|
|
6
|
+
* theme/change; the controller mirrors it).
|
|
7
|
+
*
|
|
8
|
+
* The two rules at the top are intentionally GLOBAL (hence the :global()
|
|
9
|
+
* wrapper): the token variables must be readable by DOM-created chrome — the
|
|
10
|
+
* panel columns and drag handles are appended by the layout controller outside
|
|
11
|
+
* any React subtree — so they live on :root. Every other rule below is still
|
|
12
|
+
* scoped to `.filemgr-root` / the plugin's own class names.
|
|
13
|
+
*
|
|
14
|
+
* Values are the browser-measured ones from the research report (section 5.2)
|
|
15
|
+
* — including the aou ramp reversal in dark mode and the missing --bg-7.
|
|
16
|
+
*/
|
|
17
|
+
:global(:root) {
|
|
18
|
+
--aion-bg-base: #ffffff;
|
|
19
|
+
--aion-bg-1: #f9fafb;
|
|
20
|
+
--aion-bg-2: #f2f3f5;
|
|
21
|
+
--aion-bg-3: #e5e6eb;
|
|
22
|
+
--aion-bg-hover: #f3f4f6;
|
|
23
|
+
--aion-bg-active: #e5e6eb;
|
|
24
|
+
--aion-text-primary: #000000;
|
|
25
|
+
--aion-text-secondary: #454d5f;
|
|
26
|
+
--aion-text-tertiary: #86909c;
|
|
27
|
+
--aion-text-disabled: #c9cdd4;
|
|
28
|
+
--aion-primary: #165dff;
|
|
29
|
+
--aion-success: #00b42a;
|
|
30
|
+
--aion-warning: #ff7d00;
|
|
31
|
+
--aion-danger: #f53f3f;
|
|
32
|
+
--aion-brand: #7583b2;
|
|
33
|
+
--aion-aou-1: #eff0f6;
|
|
34
|
+
--aion-aou-2: #e5e7f0;
|
|
35
|
+
--aion-aou-3: #d1d5e5;
|
|
36
|
+
--aion-aou-4: #b5bcd6;
|
|
37
|
+
--aion-aou-5: #97a0c5;
|
|
38
|
+
--aion-aou-6: #7583b2;
|
|
39
|
+
--aion-fill-2: #f2f3f5;
|
|
40
|
+
--aion-fill-3: #e5e6eb;
|
|
41
|
+
--aion-border-base: #e5e6eb;
|
|
42
|
+
--aion-overlay-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
|
|
43
|
+
--aion-font-sans: -apple-system, "system-ui", "Segoe UI", Roboto, "Helvetica Neue",
|
|
44
|
+
"PingFang SC", "Microsoft YaHei", sans-serif;
|
|
45
|
+
--aion-font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas,
|
|
46
|
+
"Liberation Mono", monospace;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* The shell marks dark mode with body[data-ds-dark-theme]; the panel tokens
|
|
50
|
+
follow it with zero JS wiring (the theme service toggles the attribute).
|
|
51
|
+
Scoped to body so third-party themes cannot override them from :root.
|
|
52
|
+
Global by intent (tokens reach the DOM-added columns/handles); the dark
|
|
53
|
+
color-scheme is only asserted here so the host's own light default wins. */
|
|
54
|
+
:global(body[data-ds-dark-theme]) {
|
|
55
|
+
--aion-bg-base: #0e0e0e;
|
|
56
|
+
--aion-bg-1: #1a1a1a;
|
|
57
|
+
--aion-bg-2: #262626;
|
|
58
|
+
--aion-bg-3: #333333;
|
|
59
|
+
--aion-bg-hover: #1f1f1f;
|
|
60
|
+
--aion-bg-active: #2d2d2d;
|
|
61
|
+
--aion-text-primary: #ffffff;
|
|
62
|
+
--aion-text-secondary: #ced3da;
|
|
63
|
+
--aion-text-tertiary: #737373;
|
|
64
|
+
--aion-text-disabled: #737373;
|
|
65
|
+
--aion-primary: #4d9fff;
|
|
66
|
+
--aion-success: #23c343;
|
|
67
|
+
--aion-warning: #ff9a2e;
|
|
68
|
+
--aion-danger: #f76560;
|
|
69
|
+
--aion-brand: #a1aacb;
|
|
70
|
+
--aion-aou-1: #2a2a2a;
|
|
71
|
+
--aion-aou-2: #3d4150;
|
|
72
|
+
--aion-aou-3: #525a77;
|
|
73
|
+
--aion-aou-4: #6a749b;
|
|
74
|
+
--aion-aou-5: #838fba;
|
|
75
|
+
--aion-aou-6: #a1aacb;
|
|
76
|
+
--aion-fill-2: rgba(255, 255, 255, 0.08);
|
|
77
|
+
--aion-fill-3: rgba(255, 255, 255, 0.12);
|
|
78
|
+
--aion-border-base: #333333;
|
|
79
|
+
--aion-overlay-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
|
|
80
|
+
color-scheme: dark;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
/* Shared base for every plugin-owned surface. */
|
|
85
|
+
:global(.filemgr-root) {
|
|
86
|
+
font-family: var(--aion-font-sans);
|
|
87
|
+
font-size: 13px;
|
|
88
|
+
color: var(--aion-text-primary);
|
|
89
|
+
background-color: var(--aion-bg-1);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
:global(.filemgr-root *),
|
|
93
|
+
:global(.filemgr-root *::before),
|
|
94
|
+
:global(.filemgr-root *::after) {
|
|
95
|
+
box-sizing: border-box;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/* Thin scrollbars matching the shell look. */
|
|
99
|
+
:global(.filemgr-root ::-webkit-scrollbar) {
|
|
100
|
+
width: 8px;
|
|
101
|
+
height: 8px;
|
|
102
|
+
}
|
|
103
|
+
:global(.filemgr-root ::-webkit-scrollbar-thumb) {
|
|
104
|
+
background: var(--aion-bg-3);
|
|
105
|
+
border-radius: 4px;
|
|
106
|
+
}
|
|
107
|
+
:global(.filemgr-root ::-webkit-scrollbar-thumb:hover) {
|
|
108
|
+
background: var(--aion-bg-4, #c9cdd4);
|
|
109
|
+
}
|
|
110
|
+
:global(.filemgr-root ::-webkit-scrollbar-track) {
|
|
111
|
+
background: transparent;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* prefers-reduced-motion: kill every panel animation globally. */
|
|
115
|
+
@media (prefers-reduced-motion: reduce) {
|
|
116
|
+
:global(.filemgr-root *),
|
|
117
|
+
:global(.filemgr-root *::before),
|
|
118
|
+
:global(.filemgr-root *::after) {
|
|
119
|
+
animation: none !important;
|
|
120
|
+
transition: none !important;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* ── frame-level chrome (created by the layout controller) ──────────────── */
|
|
125
|
+
|
|
126
|
+
/* The shell frame's grid transition must not animate panel width changes. */
|
|
127
|
+
:global([data-dsh-frame][data-filemgr-instant]) {
|
|
128
|
+
transition: none !important;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/* Panel columns are plain grid items; overflow hidden so width 0 clips.
|
|
132
|
+
z-index 30 lifts the columns above the shell.overlay slot layer (the core
|
|
133
|
+
AppFrame renders it as ::global(.overlayLayer) at z-index 20, inset:0 over
|
|
134
|
+
the whole frame). Right-edge overlay plugins would otherwise paint on top of
|
|
135
|
+
the Explorer / Preview columns' content (issue #195). Kept below dialogs
|
|
136
|
+
(1000+) so modals/toasts still stack above the panels. Matches the tab-bar
|
|
137
|
+
z-index 30 convention (issues #169 / #87), so the three stay consistent.
|
|
138
|
+
Full-screen drawer overlays (e.g. the biaoqingbao emoji manager) must
|
|
139
|
+
therefore render at the ROOT stacking context (portal to document.body,
|
|
140
|
+
z in (100, 1000)) to cover the panels AND the frame chrome (drag handles
|
|
141
|
+
and the floating expand button stack at 30/100 — they overlap the column
|
|
142
|
+
tracks, so lowering them below the columns would bury them under the
|
|
143
|
+
opaque panels and kill drag/click hit-testing, issue #234 follow-up). */
|
|
144
|
+
:global(.filemgr-preview-col),
|
|
145
|
+
:global(.filemgr-explorer-col) {
|
|
146
|
+
min-width: 0;
|
|
147
|
+
overflow: hidden;
|
|
148
|
+
display: flex;
|
|
149
|
+
flex-direction: column;
|
|
150
|
+
background-color: var(--aion-bg-1);
|
|
151
|
+
z-index: 30;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
:global(.filemgr-preview-col) {
|
|
155
|
+
/* 1px left border only — no outer margins (FileManager contract). */
|
|
156
|
+
border-left: 1px solid var(--aion-bg-3);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/* Maximized narrow-screen overlay (issue #315): on viewports below the
|
|
160
|
+
breakpoint the maximized column leaves the grid and covers the whole
|
|
161
|
+
window (mobile-friendly full-screen mode). The layout controller toggles
|
|
162
|
+
this class; removing it restores the normal grid position. Above the
|
|
163
|
+
columns/chrome (60) and below dialogs (1000+). */
|
|
164
|
+
:global(.filemgr-preview-col.filemgr-maximized),
|
|
165
|
+
:global(.filemgr-explorer-col.filemgr-maximized) {
|
|
166
|
+
position: fixed !important;
|
|
167
|
+
inset: 0;
|
|
168
|
+
z-index: 60;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
:global(.filemgr-explorer-col) {
|
|
172
|
+
border-left: 1px solid var(--aion-bg-3);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* Preview region enter animation (0.25s, translateX(20px) + fade). */
|
|
176
|
+
:global(.filemgr-preview-col.filemgr-preview-enter) {
|
|
177
|
+
animation: filemgr-preview-enter 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
@keyframes filemgr-preview-enter {
|
|
181
|
+
from {
|
|
182
|
+
transform: translateX(20px);
|
|
183
|
+
opacity: 0;
|
|
184
|
+
}
|
|
185
|
+
to {
|
|
186
|
+
transform: translateX(0);
|
|
187
|
+
opacity: 1;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/* Drag handles: 2px visual line, 6px + brand on hover/active. */
|
|
192
|
+
:global(.filemgr-explorer-handle),
|
|
193
|
+
:global(.filemgr-preview-handle) {
|
|
194
|
+
touch-action: none;
|
|
195
|
+
}
|
|
196
|
+
:global(.filemgr-explorer-handle::after),
|
|
197
|
+
:global(.filemgr-preview-handle::after) {
|
|
198
|
+
content: "";
|
|
199
|
+
position: absolute;
|
|
200
|
+
top: 0;
|
|
201
|
+
bottom: 0;
|
|
202
|
+
left: 0;
|
|
203
|
+
width: 2px;
|
|
204
|
+
border-radius: 9999px;
|
|
205
|
+
background-color: var(--aion-bg-3);
|
|
206
|
+
opacity: 0.9;
|
|
207
|
+
transition: width 0.15s cubic-bezier(0.4, 0, 0.2, 1),
|
|
208
|
+
background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
|
|
209
|
+
pointer-events: none;
|
|
210
|
+
}
|
|
211
|
+
:global(.filemgr-explorer-handle:hover::after),
|
|
212
|
+
:global(.filemgr-explorer-handle:active::after),
|
|
213
|
+
:global(.filemgr-preview-handle:hover::after),
|
|
214
|
+
:global(.filemgr-preview-handle:active::after) {
|
|
215
|
+
width: 6px;
|
|
216
|
+
background-color: var(--aion-brand);
|
|
217
|
+
}
|
|
218
|
+
/* The preview handle's line sits at its right edge (its hit zone extends
|
|
219
|
+
left); the explorer's at its left edge. */
|
|
220
|
+
:global(.filemgr-preview-handle::after) {
|
|
221
|
+
left: auto;
|
|
222
|
+
right: 0;
|
|
223
|
+
opacity: 0.3;
|
|
224
|
+
}
|
|
225
|
+
:global(.filemgr-preview-handle:hover::after),
|
|
226
|
+
:global(.filemgr-preview-handle:active::after) {
|
|
227
|
+
opacity: 1;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/* Floating expand button (explorer collapsed). Docked at the viewport's
|
|
231
|
+
top-right corner, just below the shell header's bottom divider (the
|
|
232
|
+
horizontal line under the "Session log" row) — the layout controller
|
|
233
|
+
sets an inline top for that, so the button never overlaps the header
|
|
234
|
+
chrome (issues #374 / #292). Above the columns (z 30): when the preview
|
|
235
|
+
region is open it overlaps the rightmost column track, so anything
|
|
236
|
+
lower would be painted under the opaque column and stop receiving
|
|
237
|
+
clicks (issue #234 follow-up). Full-screen overlay drawers must render
|
|
238
|
+
at the ROOT stacking context (z 100~1000) to cover it.
|
|
239
|
+
The top below is only the pre-JS fallback (the chevron row); the
|
|
240
|
+
controller overwrites it inline. */
|
|
241
|
+
:global(.filemgr-floating-expand) {
|
|
242
|
+
position: fixed;
|
|
243
|
+
top: calc(6px + env(titlebar-area-height, 0px));
|
|
244
|
+
right: 8px;
|
|
245
|
+
width: 24px;
|
|
246
|
+
height: 24px;
|
|
247
|
+
display: none;
|
|
248
|
+
align-items: center;
|
|
249
|
+
justify-content: center;
|
|
250
|
+
border: none;
|
|
251
|
+
border-radius: 4px;
|
|
252
|
+
background-color: var(--aion-bg-2);
|
|
253
|
+
color: var(--aion-text-secondary);
|
|
254
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
|
|
255
|
+
cursor: pointer;
|
|
256
|
+
z-index: 100;
|
|
257
|
+
transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
|
|
258
|
+
}
|
|
259
|
+
:global(.filemgr-floating-expand:hover) {
|
|
260
|
+
background-color: var(--aion-bg-3);
|
|
261
|
+
color: var(--aion-text-primary);
|
|
262
|
+
}
|
|
263
|
+
:global(.filemgr-floating-expand:active) {
|
|
264
|
+
background-color: var(--aion-bg-active);
|
|
265
|
+
}
|
|
266
|
+
:global(.filemgr-floating-expand:focus-visible) {
|
|
267
|
+
outline: 2px solid var(--aion-primary);
|
|
268
|
+
outline-offset: 2px;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/* The collapse chevron inside the explorer tab bar (top-right). It rides
|
|
272
|
+
the explorer column's stacking context (the column stacks at z 30), so
|
|
273
|
+
its own z-index only orders it against tab-bar siblings; full-screen
|
|
274
|
+
overlay drawers must render at the ROOT stacking context (z 100~1000)
|
|
275
|
+
to cover it (issue #234). */
|
|
276
|
+
:global(.filemgr-collapse-chevron) {
|
|
277
|
+
position: absolute;
|
|
278
|
+
/* In desktop wrappers with the Window Controls Overlay, the native
|
|
279
|
+
window buttons occupy the top-right corner of the webview; shift the
|
|
280
|
+
chevron below that strip. Browsers report 0px, so layout is
|
|
281
|
+
unchanged there (issue #169). */
|
|
282
|
+
top: calc(6px + env(titlebar-area-height, 0px));
|
|
283
|
+
right: 8px;
|
|
284
|
+
z-index: 30;
|
|
285
|
+
width: 24px;
|
|
286
|
+
height: 24px;
|
|
287
|
+
display: flex;
|
|
288
|
+
align-items: center;
|
|
289
|
+
justify-content: center;
|
|
290
|
+
border: none;
|
|
291
|
+
border-radius: 4px;
|
|
292
|
+
background: transparent;
|
|
293
|
+
color: var(--aion-text-secondary);
|
|
294
|
+
cursor: pointer;
|
|
295
|
+
transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
|
|
296
|
+
}
|
|
297
|
+
:global(.filemgr-collapse-chevron:hover) {
|
|
298
|
+
background-color: var(--aion-bg-3);
|
|
299
|
+
color: var(--aion-text-primary);
|
|
300
|
+
}
|
|
301
|
+
:global(.filemgr-collapse-chevron:active) {
|
|
302
|
+
background-color: var(--aion-bg-active);
|
|
303
|
+
}
|
|
304
|
+
:global(.filemgr-collapse-chevron:focus-visible) {
|
|
305
|
+
outline: 2px solid var(--aion-primary);
|
|
306
|
+
outline-offset: 2px;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/* Confirm dialog backdrop + card. */
|
|
310
|
+
:global(.filemgr-overlay) {
|
|
311
|
+
position: fixed;
|
|
312
|
+
inset: 0;
|
|
313
|
+
z-index: 1000;
|
|
314
|
+
display: flex;
|
|
315
|
+
align-items: center;
|
|
316
|
+
justify-content: center;
|
|
317
|
+
background: rgba(0, 0, 0, 0.35);
|
|
318
|
+
}
|
|
319
|
+
:global(.filemgr-dialog) {
|
|
320
|
+
width: 400px;
|
|
321
|
+
max-width: calc(100vw - 48px);
|
|
322
|
+
border-radius: 16px;
|
|
323
|
+
background: var(--aion-bg-base);
|
|
324
|
+
box-shadow: var(--aion-overlay-shadow);
|
|
325
|
+
overflow: hidden;
|
|
326
|
+
font-family: var(--aion-font-sans);
|
|
327
|
+
}
|
|
328
|
+
:global(.filemgr-dialog-title) {
|
|
329
|
+
font-size: 14px;
|
|
330
|
+
font-weight: 600;
|
|
331
|
+
color: var(--aion-text-primary);
|
|
332
|
+
padding: 16px 20px 8px;
|
|
333
|
+
}
|
|
334
|
+
:global(.filemgr-dialog-body) {
|
|
335
|
+
font-size: 13px;
|
|
336
|
+
color: var(--aion-text-secondary);
|
|
337
|
+
padding: 0 20px;
|
|
338
|
+
line-height: 1.6;
|
|
339
|
+
}
|
|
340
|
+
:global(.filemgr-dialog-actions) {
|
|
341
|
+
display: flex;
|
|
342
|
+
justify-content: flex-end;
|
|
343
|
+
gap: 8px;
|
|
344
|
+
padding: 16px 20px 20px;
|
|
345
|
+
}
|
|
346
|
+
:global(.filemgr-btn) {
|
|
347
|
+
height: 28px;
|
|
348
|
+
padding: 0 14px;
|
|
349
|
+
border: 1px solid var(--aion-bg-3);
|
|
350
|
+
border-radius: 4px;
|
|
351
|
+
background: var(--aion-bg-base);
|
|
352
|
+
color: var(--aion-text-primary);
|
|
353
|
+
font-size: 13px;
|
|
354
|
+
cursor: pointer;
|
|
355
|
+
transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
|
|
356
|
+
}
|
|
357
|
+
:global(.filemgr-btn:hover) {
|
|
358
|
+
background: var(--aion-bg-hover);
|
|
359
|
+
}
|
|
360
|
+
:global(.filemgr-btn:active) {
|
|
361
|
+
background: var(--aion-bg-active);
|
|
362
|
+
}
|
|
363
|
+
:global(.filemgr-btn:focus-visible) {
|
|
364
|
+
outline: 2px solid var(--aion-primary);
|
|
365
|
+
outline-offset: 2px;
|
|
366
|
+
}
|
|
367
|
+
:global(.filemgr-btn-primary) {
|
|
368
|
+
background: var(--aion-primary);
|
|
369
|
+
border-color: var(--aion-primary);
|
|
370
|
+
color: #ffffff;
|
|
371
|
+
}
|
|
372
|
+
:global(.filemgr-btn-primary:hover) {
|
|
373
|
+
background: var(--aion-primary);
|
|
374
|
+
opacity: 0.9;
|
|
375
|
+
}
|
|
376
|
+
:global(.filemgr-btn-primary:active) {
|
|
377
|
+
opacity: 0.75;
|
|
378
|
+
filter: saturate(0.9);
|
|
379
|
+
}
|
|
380
|
+
:global(.filemgr-btn-danger) {
|
|
381
|
+
background: var(--aion-danger);
|
|
382
|
+
border-color: var(--aion-danger);
|
|
383
|
+
color: #ffffff;
|
|
384
|
+
}
|
|
385
|
+
:global(.filemgr-btn-danger:hover) {
|
|
386
|
+
opacity: 0.9;
|
|
387
|
+
}
|
|
388
|
+
:global(.filemgr-btn-danger:active) {
|
|
389
|
+
opacity: 0.75;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/* Context menu (tab right-click / tree right-click). */
|
|
393
|
+
:global(.filemgr-menu) {
|
|
394
|
+
position: fixed;
|
|
395
|
+
z-index: 1100;
|
|
396
|
+
min-width: 160px;
|
|
397
|
+
padding: 4px;
|
|
398
|
+
border-radius: 8px;
|
|
399
|
+
background: var(--aion-bg-base);
|
|
400
|
+
box-shadow: var(--aion-overlay-shadow);
|
|
401
|
+
border: 1px solid var(--aion-bg-3);
|
|
402
|
+
font-family: var(--aion-font-sans);
|
|
403
|
+
}
|
|
404
|
+
:global(.filemgr-menu-item) {
|
|
405
|
+
display: flex;
|
|
406
|
+
align-items: center;
|
|
407
|
+
height: 28px;
|
|
408
|
+
padding: 0 10px;
|
|
409
|
+
border-radius: 4px;
|
|
410
|
+
font-size: 13px;
|
|
411
|
+
color: var(--aion-text-primary);
|
|
412
|
+
cursor: pointer;
|
|
413
|
+
white-space: nowrap;
|
|
414
|
+
}
|
|
415
|
+
:global(.filemgr-menu-item:hover) {
|
|
416
|
+
background: var(--aion-fill-2);
|
|
417
|
+
}
|
|
418
|
+
:global(.filemgr-menu-item:focus-visible) {
|
|
419
|
+
outline: 2px solid var(--aion-primary);
|
|
420
|
+
outline-offset: -2px;
|
|
421
|
+
}
|
|
422
|
+
:global(.filemgr-menu-item-disabled) {
|
|
423
|
+
color: var(--aion-text-disabled);
|
|
424
|
+
cursor: default;
|
|
425
|
+
}
|
|
426
|
+
:global(.filemgr-menu-item-disabled:hover) {
|
|
427
|
+
background: transparent;
|
|
428
|
+
}
|
|
429
|
+
:global(.filemgr-menu-sep) {
|
|
430
|
+
height: 1px;
|
|
431
|
+
margin: 4px 8px;
|
|
432
|
+
background: var(--aion-bg-3);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/* Prompt dialog text input. */
|
|
436
|
+
:global(.filemgr-input) {
|
|
437
|
+
width: 100%;
|
|
438
|
+
height: 32px;
|
|
439
|
+
padding: 0 10px;
|
|
440
|
+
border: 1px solid var(--aion-bg-3);
|
|
441
|
+
border-radius: 6px;
|
|
442
|
+
background: var(--aion-bg-base);
|
|
443
|
+
color: var(--aion-text-primary);
|
|
444
|
+
font-size: 13px;
|
|
445
|
+
font-family: var(--aion-font-sans);
|
|
446
|
+
outline: none;
|
|
447
|
+
box-sizing: border-box;
|
|
448
|
+
}
|
|
449
|
+
:global(.filemgr-input:focus) {
|
|
450
|
+
border-color: var(--aion-primary);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/* Toast. */
|
|
454
|
+
:global(.filemgr-toast) {
|
|
455
|
+
position: fixed;
|
|
456
|
+
bottom: 32px;
|
|
457
|
+
left: 50%;
|
|
458
|
+
transform: translateX(-50%);
|
|
459
|
+
z-index: 1200;
|
|
460
|
+
max-width: 70vw;
|
|
461
|
+
padding: 8px 14px;
|
|
462
|
+
border-radius: 6px;
|
|
463
|
+
background: var(--aion-bg-base);
|
|
464
|
+
color: var(--aion-text-primary);
|
|
465
|
+
font-size: 13px;
|
|
466
|
+
font-family: var(--aion-font-sans);
|
|
467
|
+
box-shadow: var(--aion-overlay-shadow);
|
|
468
|
+
border: 1px solid var(--aion-bg-3);
|
|
469
|
+
animation: filemgr-toast-in 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
470
|
+
}
|
|
471
|
+
@keyframes filemgr-toast-in {
|
|
472
|
+
from {
|
|
473
|
+
opacity: 0;
|
|
474
|
+
transform: translateX(-50%) translateY(8px);
|
|
475
|
+
}
|
|
476
|
+
to {
|
|
477
|
+
opacity: 1;
|
|
478
|
+
transform: translateX(-50%) translateY(0);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire vocabulary shared by the host data services and the browser client:
|
|
3
|
+
* the request/response shapes of the /filemgr/* routes and the stable
|
|
4
|
+
* error codes the client maps onto copy. Pure types — no runtime code.
|
|
5
|
+
*
|
|
6
|
+
* The design follows FileManager's right-panel system (Apache-2.0, re-implemented
|
|
7
|
+
* from measured behavior, not copied code): the explorer column is a lazy
|
|
8
|
+
* directory tree, the preview column opens files as tabs, and the SCM tab
|
|
9
|
+
* reads the repository's real working-tree state.
|
|
10
|
+
* @module dsh-filemgr/core/types
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** Envelope every /filemgr JSON response carries. */
|
|
14
|
+
export type PanelEnvelope<T> =
|
|
15
|
+
| { ok: true; value: T }
|
|
16
|
+
| { ok: false; error: PanelError }
|
|
17
|
+
|
|
18
|
+
/** Stable rejection codes (host-authored; the client prefers its own copy by code). */
|
|
19
|
+
export type PanelErrorCode =
|
|
20
|
+
| 'workspace-unknown'
|
|
21
|
+
| 'path-outside-root'
|
|
22
|
+
| 'not-found'
|
|
23
|
+
| 'is-directory'
|
|
24
|
+
| 'read-failed'
|
|
25
|
+
| 'write-conflict'
|
|
26
|
+
| 'write-failed'
|
|
27
|
+
| 'search-failed'
|
|
28
|
+
| 'git-unavailable'
|
|
29
|
+
| 'git-failed'
|
|
30
|
+
| 'internal'
|
|
31
|
+
|
|
32
|
+
/** One rejection with a human-readable host message. */
|
|
33
|
+
export interface PanelError {
|
|
34
|
+
code: PanelErrorCode
|
|
35
|
+
message: string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** One filesystem entry in a directory listing (path is relative to the root). */
|
|
39
|
+
export interface FsEntry {
|
|
40
|
+
/** Display name (basename). */
|
|
41
|
+
name: string
|
|
42
|
+
/** Path relative to the project root, '/' separated; '' is the root itself. */
|
|
43
|
+
path: string
|
|
44
|
+
isDir: boolean
|
|
45
|
+
/** Size in bytes (0 for directories). */
|
|
46
|
+
size: number
|
|
47
|
+
/** Last-modified epoch millis (0 for directories). */
|
|
48
|
+
mtime: number
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** The listing of one directory. */
|
|
52
|
+
export interface DirListing {
|
|
53
|
+
/** Canonical root path the listing is relative to. */
|
|
54
|
+
root: string
|
|
55
|
+
/** Sorted entries (directories first, then files, both case-insensitive alpha). */
|
|
56
|
+
entries: FsEntry[]
|
|
57
|
+
/** True when the entry count was capped at MAX_ENTRIES (a giant flat dir). */
|
|
58
|
+
truncated: boolean
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** The result of reading one file for preview. */
|
|
62
|
+
export interface FileRead {
|
|
63
|
+
/** Text content (decoded utf-8), or a data URL for image kinds. */
|
|
64
|
+
content: string
|
|
65
|
+
/** True when the text was truncated at the preview ceiling. */
|
|
66
|
+
truncated: boolean
|
|
67
|
+
/** Total size in bytes. */
|
|
68
|
+
size: number
|
|
69
|
+
/** Last-modified epoch millis (the write-conflict base). */
|
|
70
|
+
mtime: number
|
|
71
|
+
/** Image dimensions when the file is an image (host decodes via probe). */
|
|
72
|
+
image?: { width: number; height: number }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** One filename-search hit. */
|
|
76
|
+
export interface SearchHit {
|
|
77
|
+
/** Path relative to the root. */
|
|
78
|
+
path: string
|
|
79
|
+
/** Display name (basename). */
|
|
80
|
+
name: string
|
|
81
|
+
isDir: boolean
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** The filename-search result. */
|
|
85
|
+
export interface SearchView {
|
|
86
|
+
/** The query the hits were ranked for. */
|
|
87
|
+
query: string
|
|
88
|
+
hits: SearchHit[]
|
|
89
|
+
/** True when the hit cap cut the result stream. */
|
|
90
|
+
truncated: boolean
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Working-tree state of one change row. */
|
|
94
|
+
export type GitFileState = 'created' | 'modified' | 'deleted' | 'renamed' | 'conflicted' | 'untracked' | 'unknown'
|
|
95
|
+
|
|
96
|
+
/** One change row in a git status. */
|
|
97
|
+
export interface GitChangeRow {
|
|
98
|
+
/** Path relative to the repo root. */
|
|
99
|
+
path: string
|
|
100
|
+
/** Original path for renames (old -> new). */
|
|
101
|
+
oldPath?: string
|
|
102
|
+
state: GitFileState
|
|
103
|
+
/** True when the change sits in the index (staged). */
|
|
104
|
+
staged: boolean
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** The git status view of one repo root. */
|
|
108
|
+
export interface GitStatusView {
|
|
109
|
+
/** Repo root (git rev-parse --show-toplevel). */
|
|
110
|
+
root: string
|
|
111
|
+
/** Current branch name; '' when detached. */
|
|
112
|
+
branch: string
|
|
113
|
+
/** Staged changes (index vs HEAD). */
|
|
114
|
+
staged: GitChangeRow[]
|
|
115
|
+
/** Unstaged changes (worktree vs index). */
|
|
116
|
+
unstaged: GitChangeRow[]
|
|
117
|
+
/** Untracked files (worktree, not in index). */
|
|
118
|
+
untracked: GitChangeRow[]
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** The result of a stage/unstage/discard batch. */
|
|
122
|
+
export interface GitBatchResult {
|
|
123
|
+
/** Rows the operation actually changed (post-op status snapshot for these paths). */
|
|
124
|
+
applied: string[]
|
|
125
|
+
/** Paths the host refused to touch. */
|
|
126
|
+
failed: string[]
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** One preview tab identity as persisted. */
|
|
130
|
+
export interface PreviewTabMeta {
|
|
131
|
+
/** Stable tab id (root + path + type). */
|
|
132
|
+
id: string
|
|
133
|
+
/** Display title (basename). */
|
|
134
|
+
title: string
|
|
135
|
+
/** Project root the file belongs to. */
|
|
136
|
+
root: string
|
|
137
|
+
/** File path relative to the root. */
|
|
138
|
+
path: string
|
|
139
|
+
contentType: PreviewContentType
|
|
140
|
+
/** Whether the tab carries unsaved edits. */
|
|
141
|
+
dirty?: boolean
|
|
142
|
+
/** Last write timestamp the tab's content was based on (conflict base). */
|
|
143
|
+
mtime?: number
|
|
144
|
+
/** When the tab was last touched (LRU ordering within a scope). */
|
|
145
|
+
savedAt: number
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Preview content kinds the panel can render. */
|
|
149
|
+
export type PreviewContentType =
|
|
150
|
+
| 'markdown'
|
|
151
|
+
| 'html'
|
|
152
|
+
| 'code'
|
|
153
|
+
| 'diff'
|
|
154
|
+
| 'csv'
|
|
155
|
+
| 'pdf'
|
|
156
|
+
| 'word'
|
|
157
|
+
| 'excel'
|
|
158
|
+
| 'ppt'
|
|
159
|
+
| 'image'
|
|
160
|
+
| 'text'
|
|
161
|
+
| 'url'
|
|
162
|
+
| 'unsupported'
|