@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.
Files changed (169) hide show
  1. package/LICENSE +38 -0
  2. package/README.i18n.yaml +6 -0
  3. package/README.md +66 -0
  4. package/README.zh.md +66 -0
  5. package/cordis.patch.yml +13 -0
  6. package/lib/assets/mermaid.min.js +3587 -0
  7. package/lib/client.js +7621 -0
  8. package/lib/client.js.map +1 -0
  9. package/lib/index.js +3207 -0
  10. package/lib/tsconfig.client.tsbuildinfo +1 -0
  11. package/lib/tsconfig.host.tsbuildinfo +1 -0
  12. package/lib/types/client/FileManagerSettingsCard.d.ts +56 -0
  13. package/lib/types/client/FileManagerSettingsCard.d.ts.map +1 -0
  14. package/lib/types/client/PluginSettingsCard.d.ts +104 -0
  15. package/lib/types/client/PluginSettingsCard.d.ts.map +1 -0
  16. package/lib/types/client/api.d.ts +75 -0
  17. package/lib/types/client/api.d.ts.map +1 -0
  18. package/lib/types/client/chat/AttachedFilesDock.d.ts +51 -0
  19. package/lib/types/client/chat/AttachedFilesDock.d.ts.map +1 -0
  20. package/lib/types/client/chat/file-ref.d.ts +35 -0
  21. package/lib/types/client/chat/file-ref.d.ts.map +1 -0
  22. package/lib/types/client/chat/mermaid-chat.d.ts +30 -0
  23. package/lib/types/client/chat/mermaid-chat.d.ts.map +1 -0
  24. package/lib/types/client/chat/placeholder-hint.d.ts +16 -0
  25. package/lib/types/client/chat/placeholder-hint.d.ts.map +1 -0
  26. package/lib/types/client/components/ExplorerPanel.d.ts +26 -0
  27. package/lib/types/client/components/ExplorerPanel.d.ts.map +1 -0
  28. package/lib/types/client/components/FileIcon.d.ts +15 -0
  29. package/lib/types/client/components/FileIcon.d.ts.map +1 -0
  30. package/lib/types/client/components/ScmPanel.d.ts +23 -0
  31. package/lib/types/client/components/ScmPanel.d.ts.map +1 -0
  32. package/lib/types/client/components/a11y.d.ts +12 -0
  33. package/lib/types/client/components/a11y.d.ts.map +1 -0
  34. package/lib/types/client/components/icons.d.ts +41 -0
  35. package/lib/types/client/components/icons.d.ts.map +1 -0
  36. package/lib/types/client/components/overlay.d.ts +45 -0
  37. package/lib/types/client/components/overlay.d.ts.map +1 -0
  38. package/lib/types/client/drag/DragFileInlay.d.ts +31 -0
  39. package/lib/types/client/drag/DragFileInlay.d.ts.map +1 -0
  40. package/lib/types/client/drag/file-drag.d.ts +47 -0
  41. package/lib/types/client/drag/file-drag.d.ts.map +1 -0
  42. package/lib/types/client/drag.d.ts +31 -0
  43. package/lib/types/client/drag.d.ts.map +1 -0
  44. package/lib/types/client/file-source.d.ts +29 -0
  45. package/lib/types/client/file-source.d.ts.map +1 -0
  46. package/lib/types/client/fileType.d.ts +31 -0
  47. package/lib/types/client/fileType.d.ts.map +1 -0
  48. package/lib/types/client/floating.d.ts +27 -0
  49. package/lib/types/client/floating.d.ts.map +1 -0
  50. package/lib/types/client/hooks/useResizableSplit.d.ts +37 -0
  51. package/lib/types/client/hooks/useResizableSplit.d.ts.map +1 -0
  52. package/lib/types/client/hooks/useStore.d.ts +10 -0
  53. package/lib/types/client/hooks/useStore.d.ts.map +1 -0
  54. package/lib/types/client/index.d.ts +57 -0
  55. package/lib/types/client/index.d.ts.map +1 -0
  56. package/lib/types/client/layout.d.ts +104 -0
  57. package/lib/types/client/layout.d.ts.map +1 -0
  58. package/lib/types/client/locales.d.ts +125 -0
  59. package/lib/types/client/locales.d.ts.map +1 -0
  60. package/lib/types/client/maximize.d.ts +24 -0
  61. package/lib/types/client/maximize.d.ts.map +1 -0
  62. package/lib/types/client/mention.d.ts +44 -0
  63. package/lib/types/client/mention.d.ts.map +1 -0
  64. package/lib/types/client/mount.d.ts +22 -0
  65. package/lib/types/client/mount.d.ts.map +1 -0
  66. package/lib/types/client/persist.d.ts +55 -0
  67. package/lib/types/client/persist.d.ts.map +1 -0
  68. package/lib/types/client/picker/FilePickerModal.d.ts +47 -0
  69. package/lib/types/client/picker/FilePickerModal.d.ts.map +1 -0
  70. package/lib/types/client/picker/file-picker.d.ts +62 -0
  71. package/lib/types/client/picker/file-picker.d.ts.map +1 -0
  72. package/lib/types/client/preview/PreviewPanel.d.ts +17 -0
  73. package/lib/types/client/preview/PreviewPanel.d.ts.map +1 -0
  74. package/lib/types/client/preview/PreviewTabs.d.ts +30 -0
  75. package/lib/types/client/preview/PreviewTabs.d.ts.map +1 -0
  76. package/lib/types/client/preview/PreviewToolbar.d.ts +37 -0
  77. package/lib/types/client/preview/PreviewToolbar.d.ts.map +1 -0
  78. package/lib/types/client/preview/content.d.ts +43 -0
  79. package/lib/types/client/preview/content.d.ts.map +1 -0
  80. package/lib/types/client/preview/markdown.d.ts +60 -0
  81. package/lib/types/client/preview/markdown.d.ts.map +1 -0
  82. package/lib/types/client/preview/mermaid.d.ts +78 -0
  83. package/lib/types/client/preview/mermaid.d.ts.map +1 -0
  84. package/lib/types/client/preview/selection.d.ts +26 -0
  85. package/lib/types/client/preview/selection.d.ts.map +1 -0
  86. package/lib/types/client/reference.d.ts +75 -0
  87. package/lib/types/client/reference.d.ts.map +1 -0
  88. package/lib/types/client/settings-form.d.ts +206 -0
  89. package/lib/types/client/settings-form.d.ts.map +1 -0
  90. package/lib/types/client/store.d.ts +279 -0
  91. package/lib/types/client/store.d.ts.map +1 -0
  92. package/lib/types/core/types.d.ts +132 -0
  93. package/lib/types/core/types.d.ts.map +1 -0
  94. package/lib/types/host/fs-service.d.ts +96 -0
  95. package/lib/types/host/fs-service.d.ts.map +1 -0
  96. package/lib/types/host/gate.d.ts +45 -0
  97. package/lib/types/host/gate.d.ts.map +1 -0
  98. package/lib/types/host/git-runner.d.ts +80 -0
  99. package/lib/types/host/git-runner.d.ts.map +1 -0
  100. package/lib/types/host/git-service.d.ts +130 -0
  101. package/lib/types/host/git-service.d.ts.map +1 -0
  102. package/lib/types/host/loopback.d.ts +25 -0
  103. package/lib/types/host/loopback.d.ts.map +1 -0
  104. package/lib/types/host/poll-guard.d.ts +55 -0
  105. package/lib/types/host/poll-guard.d.ts.map +1 -0
  106. package/lib/types/host/routes.d.ts +54 -0
  107. package/lib/types/host/routes.d.ts.map +1 -0
  108. package/lib/types/index.d.ts +35 -0
  109. package/lib/types/index.d.ts.map +1 -0
  110. package/lib/types/mount-once.d.ts +25 -0
  111. package/lib/types/mount-once.d.ts.map +1 -0
  112. package/package.json +85 -0
  113. package/src/client/FileManagerSettingsCard.tsx +117 -0
  114. package/src/client/PluginSettingsCard.tsx +337 -0
  115. package/src/client/api.ts +141 -0
  116. package/src/client/chat/file-ref.ts +144 -0
  117. package/src/client/chat/mermaid-chat.tsx +102 -0
  118. package/src/client/chat/placeholder-hint.tsx +46 -0
  119. package/src/client/components/ExplorerPanel.tsx +534 -0
  120. package/src/client/components/FileIcon.tsx +46 -0
  121. package/src/client/components/ScmPanel.tsx +480 -0
  122. package/src/client/components/a11y.ts +20 -0
  123. package/src/client/components/icons.tsx +274 -0
  124. package/src/client/components/overlay.tsx +225 -0
  125. package/src/client/css-modules.d.ts +5 -0
  126. package/src/client/drag/DragFileInlay.tsx +89 -0
  127. package/src/client/drag/file-drag.ts +67 -0
  128. package/src/client/drag.ts +154 -0
  129. package/src/client/file-source.ts +58 -0
  130. package/src/client/fileType.ts +129 -0
  131. package/src/client/floating.ts +63 -0
  132. package/src/client/hooks/useResizableSplit.ts +91 -0
  133. package/src/client/hooks/useStore.ts +15 -0
  134. package/src/client/index.ts +389 -0
  135. package/src/client/layout.ts +546 -0
  136. package/src/client/locales.ts +247 -0
  137. package/src/client/maximize.ts +34 -0
  138. package/src/client/mount.tsx +74 -0
  139. package/src/client/persist.ts +194 -0
  140. package/src/client/picker/FilePickerModal.tsx +506 -0
  141. package/src/client/picker/file-picker.ts +86 -0
  142. package/src/client/preview/PreviewPanel.tsx +233 -0
  143. package/src/client/preview/PreviewTabs.tsx +159 -0
  144. package/src/client/preview/PreviewToolbar.tsx +160 -0
  145. package/src/client/preview/content.tsx +617 -0
  146. package/src/client/preview/markdown.ts +351 -0
  147. package/src/client/preview/mermaid.ts +274 -0
  148. package/src/client/preview/selection.ts +82 -0
  149. package/src/client/reference.ts +161 -0
  150. package/src/client/settings-card.module.css +316 -0
  151. package/src/client/settings-form.ts +451 -0
  152. package/src/client/store.ts +1290 -0
  153. package/src/client/styles/chip.module.css +38 -0
  154. package/src/client/styles/drag.module.css +30 -0
  155. package/src/client/styles/explorer.module.css +371 -0
  156. package/src/client/styles/picker.module.css +344 -0
  157. package/src/client/styles/preview.module.css +904 -0
  158. package/src/client/styles/scm.module.css +380 -0
  159. package/src/client/styles/tokens.module.css +480 -0
  160. package/src/core/types.ts +162 -0
  161. package/src/host/fs-service.ts +513 -0
  162. package/src/host/gate.ts +74 -0
  163. package/src/host/git-runner.ts +116 -0
  164. package/src/host/git-service.ts +395 -0
  165. package/src/host/loopback.ts +63 -0
  166. package/src/host/poll-guard.ts +109 -0
  167. package/src/host/routes.ts +695 -0
  168. package/src/index.ts +97 -0
  169. 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'