@lijian-ui/dsh-file-manager 0.2.2 → 0.2.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.
Files changed (101) hide show
  1. package/LICENSE +38 -38
  2. package/README.i18n.yaml +6 -6
  3. package/README.md +66 -66
  4. package/README.zh.md +66 -66
  5. package/cordis.patch.yml +13 -13
  6. package/lib/client.js +27354 -355
  7. package/lib/client.js.map +1 -1
  8. package/lib/index.js +474 -42
  9. package/lib/tsconfig.client.tsbuildinfo +1 -1
  10. package/lib/tsconfig.host.tsbuildinfo +1 -1
  11. package/lib/types/client/file-source.d.ts +10 -0
  12. package/lib/types/client/file-source.d.ts.map +1 -1
  13. package/lib/types/client/fileType.d.ts +19 -4
  14. package/lib/types/client/fileType.d.ts.map +1 -1
  15. package/lib/types/client/index.d.ts +0 -1
  16. package/lib/types/client/index.d.ts.map +1 -1
  17. package/lib/types/client/locales.d.ts +3 -0
  18. package/lib/types/client/locales.d.ts.map +1 -1
  19. package/lib/types/client/mount.d.ts +1 -1
  20. package/lib/types/client/mount.d.ts.map +1 -1
  21. package/lib/types/client/picker/FilePickerModal.d.ts +8 -6
  22. package/lib/types/client/picker/FilePickerModal.d.ts.map +1 -1
  23. package/lib/types/client/preview/PreviewPanel.d.ts +2 -1
  24. package/lib/types/client/preview/PreviewPanel.d.ts.map +1 -1
  25. package/lib/types/client/preview/PreviewToolbar.d.ts +3 -1
  26. package/lib/types/client/preview/PreviewToolbar.d.ts.map +1 -1
  27. package/lib/types/client/preview/content.d.ts +3 -1
  28. package/lib/types/client/preview/content.d.ts.map +1 -1
  29. package/lib/types/client/preview/office.d.ts +23 -0
  30. package/lib/types/client/preview/office.d.ts.map +1 -0
  31. package/lib/types/client/reference.d.ts +23 -10
  32. package/lib/types/client/reference.d.ts.map +1 -1
  33. package/lib/types/client/store.d.ts.map +1 -1
  34. package/lib/types/host/fs-service.d.ts.map +1 -1
  35. package/lib/types/host/office-preview.d.ts +13 -0
  36. package/lib/types/host/office-preview.d.ts.map +1 -0
  37. package/lib/types/host/routes.d.ts.map +1 -1
  38. package/lib/types/index.d.ts.map +1 -1
  39. package/package.json +19 -4
  40. package/src/client/DockItem.tsx +1 -1
  41. package/src/client/FileManagerSettingsCard.tsx +117 -117
  42. package/src/client/PluginSettingsCard.tsx +337 -337
  43. package/src/client/chat/file-ref.ts +144 -144
  44. package/src/client/chat/mermaid-chat.tsx +102 -102
  45. package/src/client/chat/placeholder-hint.tsx +46 -46
  46. package/src/client/components/ExplorerPanel.tsx +534 -534
  47. package/src/client/components/FileIcon.tsx +46 -46
  48. package/src/client/components/ScmPanel.tsx +480 -480
  49. package/src/client/components/a11y.ts +20 -20
  50. package/src/client/components/icons.tsx +274 -274
  51. package/src/client/components/overlay.tsx +225 -225
  52. package/src/client/drag/DragFileInlay.tsx +89 -89
  53. package/src/client/drag/file-drag.ts +67 -67
  54. package/src/client/drag.ts +154 -154
  55. package/src/client/file-source.ts +34 -0
  56. package/src/client/fileType.ts +32 -5
  57. package/src/client/hooks/useResizableSplit.ts +91 -91
  58. package/src/client/hooks/useStore.ts +15 -15
  59. package/src/client/index.ts +45 -17
  60. package/src/client/layout.ts +523 -523
  61. package/src/client/locales.ts +6 -0
  62. package/src/client/maximize.ts +34 -34
  63. package/src/client/mount.tsx +2 -1
  64. package/src/client/persist.ts +194 -194
  65. package/src/client/picker/FilePickerModal.tsx +526 -507
  66. package/src/client/picker/file-picker.ts +86 -86
  67. package/src/client/preview/PreviewPanel.tsx +8 -1
  68. package/src/client/preview/PreviewTabs.tsx +159 -159
  69. package/src/client/preview/PreviewToolbar.tsx +3 -2
  70. package/src/client/preview/content.tsx +7 -2
  71. package/src/client/preview/markdown.ts +351 -351
  72. package/src/client/preview/mermaid.ts +274 -274
  73. package/src/client/preview/office.tsx +321 -0
  74. package/src/client/reference.ts +62 -8
  75. package/src/client/settings-card.module.css +316 -316
  76. package/src/client/settings-form.ts +451 -451
  77. package/src/client/store.ts +17 -12
  78. package/src/client/styles/drag.module.css +30 -30
  79. package/src/client/styles/explorer.module.css +371 -371
  80. package/src/client/styles/picker.module.css +344 -344
  81. package/src/client/styles/preview.module.css +18 -11
  82. package/src/client/styles/scm.module.css +380 -380
  83. package/src/client/styles/tokens.module.css +376 -367
  84. package/src/core/types.ts +162 -162
  85. package/src/host/fs-service.ts +7 -1
  86. package/src/host/gate.ts +73 -73
  87. package/src/host/git-runner.ts +116 -116
  88. package/src/host/git-service.ts +395 -395
  89. package/src/host/loopback.ts +63 -63
  90. package/src/host/office-preview.ts +399 -0
  91. package/src/host/poll-guard.ts +109 -109
  92. package/src/host/routes.ts +72 -1
  93. package/src/index.ts +3 -1
  94. package/src/mount-once.ts +48 -48
  95. package/lib/types/client/chat/AttachedFilesDock.d.ts +0 -51
  96. package/lib/types/client/chat/AttachedFilesDock.d.ts.map +0 -1
  97. package/lib/types/client/floating.d.ts +0 -27
  98. package/lib/types/client/floating.d.ts.map +0 -1
  99. package/lib/types/client/mention.d.ts +0 -44
  100. package/lib/types/client/mention.d.ts.map +0 -1
  101. package/src/client/styles/chip.module.css +0 -38
@@ -1,367 +1,376 @@
1
- /**
2
- * The panel design system: FileManager's tokens, scoped to the plugin's own
3
- * root elements so they never leak into the shell. The `--aion-*` names are
4
- * kept as an alias layer that forwards to the official `--dsw-*` token system
5
- * — dark-mode adaptation is handled by `--dsw-*` itself, so no per-theme
6
- * override block is needed.
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
- :global(:root) {
15
- --aion-bg-base: var(--dsw-alias-bg-base);
16
- --aion-bg-1: var(--dsw-alias-bg-layer-1);
17
- --aion-bg-2: var(--dsw-alias-bg-layer-2);
18
- --aion-bg-3: var(--dsw-alias-bg-layer-3);
19
- --aion-bg-4: var(--dsw-alias-label-dimmed);
20
- --aion-bg-hover: var(--dsw-alias-interactive-bg-hover);
21
- --aion-bg-active: var(--dsw-alias-interactive-bg-active);
22
- --aion-text-primary: var(--dsw-alias-label-primary);
23
- --aion-text-secondary: var(--dsw-alias-label-secondary);
24
- --aion-text-tertiary: var(--dsw-alias-label-tertiary);
25
- --aion-text-disabled: var(--dsw-alias-label-dimmed);
26
- --aion-primary: var(--dsw-alias-state-business-primary);
27
- --aion-success: var(--dsw-alias-state-success-primary);
28
- --aion-warning: var(--dsw-alias-state-warn-primary);
29
- --aion-danger: var(--dsw-alias-state-error-primary);
30
- --aion-brand: var(--dsw-alias-brand-primary);
31
- --aion-aou-2: var(--dsw-alias-bg-layer-2);
32
- --aion-aou-6: var(--dsw-alias-brand-primary);
33
- --aion-fill-2: var(--dsw-alias-interactive-bg-hover);
34
- --aion-fill-3: var(--dsw-alias-interactive-bg-hover-solid);
35
- --aion-border-base: var(--dsw-alias-border-l2);
36
- --aion-overlay-shadow: var(--dsw-shadow-lv2);
37
- --aion-font-sans: -apple-system, "system-ui", "Segoe UI", Roboto, "Helvetica Neue",
38
- "PingFang SC", "Microsoft YaHei", sans-serif;
39
- --aion-font-mono: var(--dsw-alias-font-family-mono);
40
- }
41
-
42
-
43
- /* Shared base for every plugin-owned surface. */
44
- :global(.filemgr-root) {
45
- font-family: var(--aion-font-sans);
46
- font-size: 13px;
47
- color: var(--aion-text-primary);
48
- background-color: var(--aion-bg-1);
49
- }
50
-
51
- :global(.filemgr-root *),
52
- :global(.filemgr-root *::before),
53
- :global(.filemgr-root *::after) {
54
- box-sizing: border-box;
55
- }
56
-
57
- /* Thin scrollbars matching the shell look. */
58
- :global(.filemgr-root ::-webkit-scrollbar) {
59
- width: 8px;
60
- height: 8px;
61
- }
62
- :global(.filemgr-root ::-webkit-scrollbar-thumb) {
63
- background: var(--aion-bg-3);
64
- border-radius: 4px;
65
- }
66
- :global(.filemgr-root ::-webkit-scrollbar-thumb:hover) {
67
- background: var(--aion-bg-4);
68
- }
69
- :global(.filemgr-root ::-webkit-scrollbar-track) {
70
- background: transparent;
71
- }
72
-
73
- /* prefers-reduced-motion: kill every panel animation globally. */
74
- @media (prefers-reduced-motion: reduce) {
75
- :global(.filemgr-root *),
76
- :global(.filemgr-root *::before),
77
- :global(.filemgr-root *::after) {
78
- animation: none !important;
79
- transition: none !important;
80
- }
81
- }
82
-
83
- /* ── frame-level chrome (created by the layout controller) ──────────────── */
84
-
85
- /* The shell frame's grid transition must not animate panel width changes. */
86
- :global([data-dsh-frame][data-filemgr-instant]) {
87
- transition: none !important;
88
- }
89
-
90
- /* Panel columns are plain grid items; overflow hidden so width 0 clips.
91
- z-index 30 lifts the columns above the shell.overlay slot layer (the core
92
- AppFrame renders it as ::global(.overlayLayer) at z-index 20, inset:0 over
93
- the whole frame). Right-edge overlay plugins would otherwise paint on top of
94
- the Explorer / Preview columns' content (issue #195). Kept below dialogs
95
- (1000+) so modals/toasts still stack above the panels. Matches the tab-bar
96
- z-index 30 convention (issues #169 / #87), so the three stay consistent.
97
- Full-screen drawer overlays (e.g. the biaoqingbao emoji manager) must
98
- therefore render at the ROOT stacking context (portal to document.body,
99
- z in (100, 1000)) to cover the panels AND the frame chrome (drag handles
100
- and the floating expand button stack at 30/100 they overlap the column
101
- tracks, so lowering them below the columns would bury them under the
102
- opaque panels and kill drag/click hit-testing, issue #234 follow-up). */
103
- :global(.filemgr-preview-col),
104
- :global(.filemgr-explorer-col) {
105
- min-width: 0;
106
- overflow: hidden;
107
- display: flex;
108
- flex-direction: column;
109
- background-color: var(--aion-bg-1);
110
- z-index: 30;
111
- }
112
-
113
- :global(.filemgr-preview-col) {
114
- /* 1px left border only — no outer margins (FileManager contract). */
115
- border-left: 1px solid var(--aion-bg-3);
116
- }
117
-
118
- /* Maximized narrow-screen overlay (issue #315): on viewports below the
119
- breakpoint the maximized column leaves the grid and covers the whole
120
- window (mobile-friendly full-screen mode). The layout controller toggles
121
- this class; removing it restores the normal grid position. Above the
122
- columns/chrome (60) and below dialogs (1000+). */
123
- :global(.filemgr-preview-col.filemgr-maximized),
124
- :global(.filemgr-explorer-col.filemgr-maximized) {
125
- position: fixed !important;
126
- inset: 0;
127
- z-index: 60;
128
- }
129
-
130
- :global(.filemgr-explorer-col) {
131
- border-left: 1px solid var(--aion-bg-3);
132
- }
133
-
134
- /* Preview region enter animation (0.25s, translateX(20px) + fade). */
135
- :global(.filemgr-preview-col.filemgr-preview-enter) {
136
- animation: filemgr-preview-enter 0.25s cubic-bezier(0.4, 0, 0.2, 1);
137
- }
138
-
139
- @keyframes filemgr-preview-enter {
140
- from {
141
- transform: translateX(20px);
142
- opacity: 0;
143
- }
144
- to {
145
- transform: translateX(0);
146
- opacity: 1;
147
- }
148
- }
149
-
150
- /* Drag handles: invisible, col-resize cursor only (like DSH native sidebar). */
151
- :global(.filemgr-explorer-handle),
152
- :global(.filemgr-preview-handle) {
153
- touch-action: none;
154
- cursor: col-resize;
155
- }
156
-
157
-
158
- /* The collapse chevron inside the explorer tab bar (top-right). It rides
159
- the explorer column's stacking context (the column stacks at z 30), so
160
- its own z-index only orders it against tab-bar siblings; full-screen
161
- overlay drawers must render at the ROOT stacking context (z 100~1000)
162
- to cover it (issue #234). */
163
- :global(.filemgr-collapse-chevron) {
164
- position: absolute;
165
- /* In desktop wrappers with the Window Controls Overlay, the native
166
- window buttons occupy the top-right corner of the webview; shift the
167
- chevron below that strip. Browsers report 0px, so layout is
168
- unchanged there (issue #169). */
169
- top: calc(6px + env(titlebar-area-height, 0px));
170
- right: 8px;
171
- z-index: 30;
172
- width: 24px;
173
- height: 24px;
174
- display: flex;
175
- align-items: center;
176
- justify-content: center;
177
- border: none;
178
- border-radius: 4px;
179
- background: transparent;
180
- color: var(--aion-text-secondary);
181
- cursor: pointer;
182
- transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
183
- }
184
- :global(.filemgr-collapse-chevron:hover) {
185
- background-color: var(--aion-bg-3);
186
- color: var(--aion-text-primary);
187
- }
188
- :global(.filemgr-collapse-chevron:active) {
189
- background-color: var(--aion-bg-active);
190
- }
191
- :global(.filemgr-collapse-chevron:focus-visible) {
192
- outline: 2px solid var(--aion-primary);
193
- outline-offset: 2px;
194
- }
195
-
196
- /* Confirm dialog backdrop + card. */
197
- :global(.filemgr-overlay) {
198
- position: fixed;
199
- inset: 0;
200
- z-index: 1000;
201
- display: flex;
202
- align-items: center;
203
- justify-content: center;
204
- background: rgba(0, 0, 0, 0.35);
205
- }
206
- :global(.filemgr-dialog) {
207
- width: 400px;
208
- max-width: calc(100vw - 48px);
209
- border-radius: 16px;
210
- background: var(--aion-bg-base);
211
- box-shadow: var(--aion-overlay-shadow);
212
- overflow: hidden;
213
- font-family: var(--aion-font-sans);
214
- }
215
- :global(.filemgr-dialog-title) {
216
- font-size: 14px;
217
- font-weight: 600;
218
- color: var(--aion-text-primary);
219
- padding: 16px 20px 8px;
220
- }
221
- :global(.filemgr-dialog-body) {
222
- font-size: 13px;
223
- color: var(--aion-text-secondary);
224
- padding: 0 20px;
225
- line-height: 1.6;
226
- }
227
- :global(.filemgr-dialog-actions) {
228
- display: flex;
229
- justify-content: flex-end;
230
- gap: 8px;
231
- padding: 16px 20px 20px;
232
- }
233
- :global(.filemgr-btn) {
234
- height: 28px;
235
- padding: 0 14px;
236
- border: 1px solid var(--aion-bg-3);
237
- border-radius: 4px;
238
- background: var(--aion-bg-base);
239
- color: var(--aion-text-primary);
240
- font-size: 13px;
241
- cursor: pointer;
242
- transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
243
- }
244
- :global(.filemgr-btn:hover) {
245
- background: var(--aion-bg-hover);
246
- }
247
- :global(.filemgr-btn:active) {
248
- background: var(--aion-bg-active);
249
- }
250
- :global(.filemgr-btn:focus-visible) {
251
- outline: 2px solid var(--aion-primary);
252
- outline-offset: 2px;
253
- }
254
- :global(.filemgr-btn-primary) {
255
- background: var(--aion-primary);
256
- border-color: var(--aion-primary);
257
- color: #ffffff;
258
- }
259
- :global(.filemgr-btn-primary:hover) {
260
- background: var(--aion-primary);
261
- opacity: 0.9;
262
- }
263
- :global(.filemgr-btn-primary:active) {
264
- opacity: 0.75;
265
- filter: saturate(0.9);
266
- }
267
- :global(.filemgr-btn-danger) {
268
- background: var(--aion-danger);
269
- border-color: var(--aion-danger);
270
- color: #ffffff;
271
- }
272
- :global(.filemgr-btn-danger:hover) {
273
- opacity: 0.9;
274
- }
275
- :global(.filemgr-btn-danger:active) {
276
- opacity: 0.75;
277
- }
278
-
279
- /* Context menu (tab right-click / tree right-click). */
280
- :global(.filemgr-menu) {
281
- position: fixed;
282
- z-index: 1100;
283
- min-width: 160px;
284
- padding: 4px;
285
- border-radius: 8px;
286
- background: var(--aion-bg-base);
287
- box-shadow: var(--aion-overlay-shadow);
288
- border: 1px solid var(--aion-bg-3);
289
- font-family: var(--aion-font-sans);
290
- }
291
- :global(.filemgr-menu-item) {
292
- display: flex;
293
- align-items: center;
294
- height: 28px;
295
- padding: 0 10px;
296
- border-radius: 4px;
297
- font-size: 13px;
298
- color: var(--aion-text-primary);
299
- cursor: pointer;
300
- white-space: nowrap;
301
- }
302
- :global(.filemgr-menu-item:hover) {
303
- background: var(--aion-fill-2);
304
- }
305
- :global(.filemgr-menu-item:focus-visible) {
306
- outline: 2px solid var(--aion-primary);
307
- outline-offset: -2px;
308
- }
309
- :global(.filemgr-menu-item-disabled) {
310
- color: var(--aion-text-disabled);
311
- cursor: default;
312
- }
313
- :global(.filemgr-menu-item-disabled:hover) {
314
- background: transparent;
315
- }
316
- :global(.filemgr-menu-sep) {
317
- height: 1px;
318
- margin: 4px 8px;
319
- background: var(--aion-bg-3);
320
- }
321
-
322
- /* Prompt dialog text input. */
323
- :global(.filemgr-input) {
324
- width: 100%;
325
- height: 32px;
326
- padding: 0 10px;
327
- border: 1px solid var(--aion-bg-3);
328
- border-radius: 6px;
329
- background: var(--aion-bg-base);
330
- color: var(--aion-text-primary);
331
- font-size: 13px;
332
- font-family: var(--aion-font-sans);
333
- outline: none;
334
- box-sizing: border-box;
335
- }
336
- :global(.filemgr-input:focus) {
337
- border-color: var(--aion-primary);
338
- }
339
-
340
- /* Toast. */
341
- :global(.filemgr-toast) {
342
- position: fixed;
343
- bottom: 32px;
344
- left: 50%;
345
- transform: translateX(-50%);
346
- z-index: 1200;
347
- max-width: 70vw;
348
- padding: 8px 14px;
349
- border-radius: 6px;
350
- background: var(--aion-bg-base);
351
- color: var(--aion-text-primary);
352
- font-size: 13px;
353
- font-family: var(--aion-font-sans);
354
- box-shadow: var(--aion-overlay-shadow);
355
- border: 1px solid var(--aion-bg-3);
356
- animation: filemgr-toast-in 0.2s cubic-bezier(0.4, 0, 0.2, 1);
357
- }
358
- @keyframes filemgr-toast-in {
359
- from {
360
- opacity: 0;
361
- transform: translateX(-50%) translateY(8px);
362
- }
363
- to {
364
- opacity: 1;
365
- transform: translateX(-50%) translateY(0);
366
- }
367
- }
1
+ /**
2
+ * The panel design system: FileManager's tokens, scoped to the plugin's own
3
+ * root elements so they never leak into the shell. The `--aion-*` names are
4
+ * kept as an alias layer that forwards to the official `--dsw-*` token system
5
+ * — dark-mode adaptation is handled by `--dsw-*` itself, so no per-theme
6
+ * override block is needed.
7
+ *
8
+ * Scoped to BODY, not :root: since the official theme rc.2 the `--dsw-*`
9
+ * semantic tokens live on `body` (not html), so an alias defined at :root
10
+ * would substitute var() against an undefined name and compute to the
11
+ * guaranteed-invalid value (""), killing every background that consumes it.
12
+ * On body the dsw tokens resolve and the aliases inherit to all visible
13
+ * elements — including the DOM-created chrome (panel columns, drag handles,
14
+ * the '@' picker portal) appended outside any React subtree.
15
+ */
16
+ :global(body) {
17
+ --aion-bg-base: var(--dsw-alias-bg-base);
18
+ --aion-bg-1: var(--dsw-alias-bg-layer-1);
19
+ --aion-bg-2: var(--dsw-alias-bg-layer-2);
20
+ --aion-bg-3: var(--dsw-alias-bg-layer-3);
21
+ --aion-bg-4: var(--dsw-alias-label-dimmed);
22
+ --aion-bg-hover: var(--dsw-alias-interactive-bg-hover);
23
+ --aion-bg-active: var(--dsw-alias-interactive-bg-active);
24
+ --aion-text-primary: var(--dsw-alias-label-primary);
25
+ --aion-text-secondary: var(--dsw-alias-label-secondary);
26
+ --aion-text-tertiary: var(--dsw-alias-label-tertiary);
27
+ --aion-text-disabled: var(--dsw-alias-label-dimmed);
28
+ --aion-primary: var(--dsw-alias-state-business-primary);
29
+ --aion-success: var(--dsw-alias-state-success-primary);
30
+ --aion-warning: var(--dsw-alias-state-warn-primary);
31
+ --aion-danger: var(--dsw-alias-state-error-primary);
32
+ --aion-brand: var(--dsw-alias-brand-primary);
33
+ --aion-aou-2: var(--dsw-alias-bg-layer-2);
34
+ --aion-aou-6: var(--dsw-alias-brand-primary);
35
+ --aion-fill-2: var(--dsw-alias-interactive-bg-hover);
36
+ --aion-fill-3: var(--dsw-alias-interactive-bg-hover-solid);
37
+ --aion-border-base: var(--dsw-alias-border-l2);
38
+ --aion-overlay-shadow: var(--dsw-shadow-lv2);
39
+ /* 官方字体 token;mono 用本地栈 —— 当前主题版本尚无 --dsw-alias-font-family-mono */
40
+ --aion-font-sans: var(--dsw-font-family);
41
+ --aion-font-mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
42
+ }
43
+
44
+
45
+ /* Shared base for every plugin-owned surface. */
46
+ :global(.filemgr-root) {
47
+ font-family: var(--aion-font-sans);
48
+ font-size: 13px;
49
+ color: var(--aion-text-primary);
50
+ background-color: var(--aion-bg-1);
51
+ }
52
+
53
+ :global(.filemgr-root *),
54
+ :global(.filemgr-root *::before),
55
+ :global(.filemgr-root *::after) {
56
+ box-sizing: border-box;
57
+ }
58
+
59
+ /* Thin scrollbars matching the shell look. */
60
+ :global(.filemgr-root ::-webkit-scrollbar) {
61
+ width: 8px;
62
+ height: 8px;
63
+ }
64
+ :global(.filemgr-root ::-webkit-scrollbar-thumb) {
65
+ background: var(--aion-bg-3);
66
+ border-radius: 4px;
67
+ }
68
+ :global(.filemgr-root ::-webkit-scrollbar-thumb:hover) {
69
+ background: var(--aion-bg-4);
70
+ }
71
+ :global(.filemgr-root ::-webkit-scrollbar-track) {
72
+ background: transparent;
73
+ }
74
+
75
+ /* prefers-reduced-motion: kill every panel animation globally. */
76
+ @media (prefers-reduced-motion: reduce) {
77
+ :global(.filemgr-root *),
78
+ :global(.filemgr-root *::before),
79
+ :global(.filemgr-root *::after) {
80
+ animation: none !important;
81
+ transition: none !important;
82
+ }
83
+ }
84
+
85
+ /* ── frame-level chrome (created by the layout controller) ──────────────── */
86
+
87
+ /* The shell frame's grid transition must not animate panel width changes. */
88
+ :global([data-dsh-frame][data-filemgr-instant]) {
89
+ transition: none !important;
90
+ }
91
+
92
+ /* Panel columns are plain grid items; overflow hidden so width 0 clips.
93
+ z-index 30 lifts the columns above the shell.overlay slot layer (the core
94
+ AppFrame renders it as ::global(.overlayLayer) at z-index 20, inset:0 over
95
+ the whole frame). Right-edge overlay plugins would otherwise paint on top of
96
+ the Explorer / Preview columns' content (issue #195). Kept below dialogs
97
+ (1000+) so modals/toasts still stack above the panels. Matches the tab-bar
98
+ z-index 30 convention (issues #169 / #87), so the three stay consistent.
99
+ Full-screen drawer overlays (e.g. the biaoqingbao emoji manager) must
100
+ therefore render at the ROOT stacking context (portal to document.body,
101
+ z in (100, 1000)) to cover the panels AND the frame chrome (drag handles
102
+ and the floating expand button stack at 30/100 they overlap the column
103
+ tracks, so lowering them below the columns would bury them under the
104
+ opaque panels and kill drag/click hit-testing, issue #234 follow-up). */
105
+ :global(.filemgr-preview-col),
106
+ :global(.filemgr-explorer-col) {
107
+ min-width: 0;
108
+ overflow: hidden;
109
+ display: flex;
110
+ flex-direction: column;
111
+ background-color: var(--aion-bg-1);
112
+ z-index: 30;
113
+ }
114
+
115
+ :global(.filemgr-preview-col) {
116
+ /* 1px left border only — no outer margins (FileManager contract).
117
+ Use the semantic divider color (border-l2), NOT the bg-layer-3
118
+ background hint: bg-layer-3 is nearly indistinguishable from the
119
+ panel's own bg-layer-1 on both light and dark themes, so the
120
+ boundary vs. the shell was not visible. border-l2 is a real
121
+ stroke level with visible contrast in both themes. */
122
+ border-left: 1px solid var(--aion-border-base);
123
+ }
124
+
125
+ /* Maximized narrow-screen overlay (issue #315): on viewports below the
126
+ breakpoint the maximized column leaves the grid and covers the whole
127
+ window (mobile-friendly full-screen mode). The layout controller toggles
128
+ this class; removing it restores the normal grid position. Above the
129
+ columns/chrome (60) and below dialogs (1000+). */
130
+ :global(.filemgr-preview-col.filemgr-maximized),
131
+ :global(.filemgr-explorer-col.filemgr-maximized) {
132
+ position: fixed !important;
133
+ inset: 0;
134
+ z-index: 60;
135
+ }
136
+
137
+ :global(.filemgr-explorer-col) {
138
+ border-left: 1px solid var(--aion-border-base);
139
+ }
140
+
141
+ /* Preview region enter animation (0.25s, translateX(20px) + fade). */
142
+ :global(.filemgr-preview-col.filemgr-preview-enter) {
143
+ animation: filemgr-preview-enter 0.25s cubic-bezier(0.4, 0, 0.2, 1);
144
+ }
145
+
146
+ @keyframes filemgr-preview-enter {
147
+ from {
148
+ transform: translateX(20px);
149
+ opacity: 0;
150
+ }
151
+ to {
152
+ transform: translateX(0);
153
+ opacity: 1;
154
+ }
155
+ }
156
+
157
+ /* Drag handles: invisible, col-resize cursor only (like DSH native sidebar). */
158
+ :global(.filemgr-explorer-handle),
159
+ :global(.filemgr-preview-handle) {
160
+ touch-action: none;
161
+ cursor: col-resize;
162
+ }
163
+
164
+
165
+ /* The collapse chevron inside the explorer tab bar (top-right). It rides
166
+ the explorer column's stacking context (the column stacks at z 30), so
167
+ its own z-index only orders it against tab-bar siblings; full-screen
168
+ overlay drawers must render at the ROOT stacking context (z 100~1000)
169
+ to cover it (issue #234). */
170
+ :global(.filemgr-collapse-chevron) {
171
+ position: absolute;
172
+ /* In desktop wrappers with the Window Controls Overlay, the native
173
+ window buttons occupy the top-right corner of the webview; shift the
174
+ chevron below that strip. Browsers report 0px, so layout is
175
+ unchanged there (issue #169). */
176
+ top: calc(6px + env(titlebar-area-height, 0px));
177
+ right: 8px;
178
+ z-index: 30;
179
+ width: 24px;
180
+ height: 24px;
181
+ display: flex;
182
+ align-items: center;
183
+ justify-content: center;
184
+ border: none;
185
+ border-radius: 4px;
186
+ background: transparent;
187
+ color: var(--aion-text-secondary);
188
+ cursor: pointer;
189
+ transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
190
+ }
191
+ :global(.filemgr-collapse-chevron:hover) {
192
+ background-color: var(--aion-bg-3);
193
+ color: var(--aion-text-primary);
194
+ }
195
+ :global(.filemgr-collapse-chevron:active) {
196
+ background-color: var(--aion-bg-active);
197
+ }
198
+ :global(.filemgr-collapse-chevron:focus-visible) {
199
+ outline: 2px solid var(--aion-primary);
200
+ outline-offset: 2px;
201
+ }
202
+
203
+ /* Confirm dialog backdrop + card. */
204
+ :global(.filemgr-overlay) {
205
+ position: fixed;
206
+ inset: 0;
207
+ z-index: 1000;
208
+ display: flex;
209
+ align-items: center;
210
+ justify-content: center;
211
+ background: var(--dsw-alias-bg-mask-1);
212
+ }
213
+ :global(.filemgr-dialog) {
214
+ width: 400px;
215
+ max-width: calc(100vw - 48px);
216
+ border-radius: 16px;
217
+ background: var(--aion-bg-base);
218
+ box-shadow: var(--aion-overlay-shadow);
219
+ overflow: hidden;
220
+ font-family: var(--aion-font-sans);
221
+ }
222
+ :global(.filemgr-dialog-title) {
223
+ font-size: 14px;
224
+ font-weight: 600;
225
+ color: var(--aion-text-primary);
226
+ padding: 16px 20px 8px;
227
+ }
228
+ :global(.filemgr-dialog-body) {
229
+ font-size: 13px;
230
+ color: var(--aion-text-secondary);
231
+ padding: 0 20px;
232
+ line-height: 1.6;
233
+ }
234
+ :global(.filemgr-dialog-actions) {
235
+ display: flex;
236
+ justify-content: flex-end;
237
+ gap: 8px;
238
+ padding: 16px 20px 20px;
239
+ }
240
+ :global(.filemgr-btn) {
241
+ height: 28px;
242
+ padding: 0 14px;
243
+ border: 1px solid var(--aion-bg-3);
244
+ border-radius: 4px;
245
+ background: var(--aion-bg-base);
246
+ color: var(--aion-text-primary);
247
+ font-size: 13px;
248
+ cursor: pointer;
249
+ transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
250
+ }
251
+ :global(.filemgr-btn:hover) {
252
+ background: var(--aion-bg-hover);
253
+ }
254
+ :global(.filemgr-btn:active) {
255
+ background: var(--aion-bg-active);
256
+ }
257
+ :global(.filemgr-btn:focus-visible) {
258
+ outline: 2px solid var(--aion-primary);
259
+ outline-offset: 2px;
260
+ }
261
+ :global(.filemgr-btn-primary) {
262
+ background: var(--dsw-alias-button-primary-fill);
263
+ border-color: var(--dsw-alias-button-primary-fill);
264
+ color: var(--dsw-alias-label-primary-foreground);
265
+ }
266
+ :global(.filemgr-btn-primary:hover) {
267
+ background: var(--dsw-alias-button-primary-hover);
268
+ border-color: var(--dsw-alias-button-primary-hover);
269
+ }
270
+ :global(.filemgr-btn-primary:active) {
271
+ background: var(--dsw-alias-button-primary-hover);
272
+ border-color: var(--dsw-alias-button-primary-hover);
273
+ }
274
+ :global(.filemgr-btn-danger) {
275
+ background: var(--aion-danger);
276
+ border-color: var(--aion-danger);
277
+ color: var(--dsw-alias-label-primary-foreground);
278
+ }
279
+ :global(.filemgr-btn-danger:hover) {
280
+ background: color-mix(in srgb, var(--aion-danger) 88%, black);
281
+ border-color: color-mix(in srgb, var(--aion-danger) 88%, black);
282
+ }
283
+ :global(.filemgr-btn-danger:active) {
284
+ background: color-mix(in srgb, var(--aion-danger) 78%, black);
285
+ border-color: color-mix(in srgb, var(--aion-danger) 78%, black);
286
+ }
287
+
288
+ /* Context menu (tab right-click / tree right-click). */
289
+ :global(.filemgr-menu) {
290
+ position: fixed;
291
+ z-index: 1100;
292
+ min-width: 160px;
293
+ padding: 4px;
294
+ border-radius: 8px;
295
+ background: var(--aion-bg-base);
296
+ box-shadow: var(--aion-overlay-shadow);
297
+ border: 1px solid var(--aion-bg-3);
298
+ font-family: var(--aion-font-sans);
299
+ }
300
+ :global(.filemgr-menu-item) {
301
+ display: flex;
302
+ align-items: center;
303
+ height: 28px;
304
+ padding: 0 10px;
305
+ border-radius: 4px;
306
+ font-size: 13px;
307
+ color: var(--aion-text-primary);
308
+ cursor: pointer;
309
+ white-space: nowrap;
310
+ }
311
+ :global(.filemgr-menu-item:hover) {
312
+ background: var(--aion-fill-2);
313
+ }
314
+ :global(.filemgr-menu-item:focus-visible) {
315
+ outline: 2px solid var(--aion-primary);
316
+ outline-offset: -2px;
317
+ }
318
+ :global(.filemgr-menu-item-disabled) {
319
+ color: var(--aion-text-disabled);
320
+ cursor: default;
321
+ }
322
+ :global(.filemgr-menu-item-disabled:hover) {
323
+ background: transparent;
324
+ }
325
+ :global(.filemgr-menu-sep) {
326
+ height: 1px;
327
+ margin: 4px 8px;
328
+ background: var(--aion-bg-3);
329
+ }
330
+
331
+ /* Prompt dialog text input. */
332
+ :global(.filemgr-input) {
333
+ width: 100%;
334
+ height: 32px;
335
+ padding: 0 10px;
336
+ border: 1px solid var(--aion-bg-3);
337
+ border-radius: 6px;
338
+ background: var(--aion-bg-base);
339
+ color: var(--aion-text-primary);
340
+ font-size: 13px;
341
+ font-family: var(--aion-font-sans);
342
+ outline: none;
343
+ box-sizing: border-box;
344
+ }
345
+ :global(.filemgr-input:focus) {
346
+ border-color: var(--aion-primary);
347
+ }
348
+
349
+ /* Toast. */
350
+ :global(.filemgr-toast) {
351
+ position: fixed;
352
+ bottom: 32px;
353
+ left: 50%;
354
+ transform: translateX(-50%);
355
+ z-index: 1200;
356
+ max-width: 70vw;
357
+ padding: 8px 14px;
358
+ border-radius: 6px;
359
+ background: var(--aion-bg-base);
360
+ color: var(--aion-text-primary);
361
+ font-size: 13px;
362
+ font-family: var(--aion-font-sans);
363
+ box-shadow: var(--aion-overlay-shadow);
364
+ border: 1px solid var(--aion-bg-3);
365
+ animation: filemgr-toast-in 0.2s cubic-bezier(0.4, 0, 0.2, 1);
366
+ }
367
+ @keyframes filemgr-toast-in {
368
+ from {
369
+ opacity: 0;
370
+ transform: translateX(-50%) translateY(8px);
371
+ }
372
+ to {
373
+ opacity: 1;
374
+ transform: translateX(-50%) translateY(0);
375
+ }
376
+ }