@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,904 @@
1
+ /**
2
+ * Preview panel styles — FileManager measured values: tab bar 36px + 1px bottom
3
+ * border, tabs max-width 180px (padding 0 10, gap 6, 12px title), toolbar
4
+ * 32px (padding 0 10), 32px overflow fades, 40px split-pane headers.
5
+ */
6
+
7
+ .panel {
8
+ display: flex;
9
+ flex-direction: column;
10
+ height: 100%;
11
+ min-height: 0;
12
+ background: var(--aion-bg-1);
13
+ }
14
+
15
+ /* ── tab bar ────────────────────────────────────────────────────────────── */
16
+
17
+ .tabBar {
18
+ position: relative;
19
+ /* Above third-party skin fixed decoration layers (z-index ~20) so the tab
20
+ bar buttons and the close buttons stay clickable (issue #169). Low
21
+ enough to stay below overlays/dialogs (1000+). */
22
+ z-index: 30;
23
+ display: flex;
24
+ align-items: stretch;
25
+ flex-shrink: 0;
26
+ height: 36px;
27
+ background: var(--aion-bg-2);
28
+ border-bottom: 1px solid var(--aion-bg-3);
29
+ }
30
+
31
+ .tabScroll {
32
+ display: flex;
33
+ align-items: stretch;
34
+ flex: 1;
35
+ min-width: 0;
36
+ overflow-x: auto;
37
+ overflow-y: hidden;
38
+ scrollbar-width: none;
39
+ }
40
+
41
+ .tabScroll::-webkit-scrollbar {
42
+ display: none;
43
+ }
44
+
45
+ .tab {
46
+ display: flex;
47
+ align-items: center;
48
+ gap: 6px;
49
+ padding: 0 10px;
50
+ max-width: 180px;
51
+ height: 100%;
52
+ flex-shrink: 0;
53
+ cursor: pointer;
54
+ transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
55
+ user-select: none;
56
+ border-right: 1px solid transparent;
57
+ }
58
+
59
+ .tabActive {
60
+ background: var(--aion-bg-1);
61
+ color: var(--aion-text-primary);
62
+ }
63
+
64
+ .tabInactive {
65
+ color: var(--aion-text-secondary);
66
+ }
67
+
68
+ .tabInactive:hover {
69
+ background: var(--aion-bg-3);
70
+ }
71
+
72
+ .tab:active {
73
+ background: var(--aion-bg-active);
74
+ }
75
+
76
+ .tab:focus-visible {
77
+ box-shadow: inset 0 0 0 2px var(--aion-primary);
78
+ }
79
+
80
+ .tabTitle {
81
+ font-size: 12px;
82
+ overflow: hidden;
83
+ text-overflow: ellipsis;
84
+ white-space: nowrap;
85
+ min-width: 0;
86
+ }
87
+
88
+ .tabFavicon {
89
+ width: 12px;
90
+ height: 12px;
91
+ border-radius: 2px;
92
+ flex-shrink: 0;
93
+ object-fit: contain;
94
+ }
95
+
96
+ .tabDot {
97
+ width: 6px;
98
+ height: 6px;
99
+ border-radius: 9999px;
100
+ flex-shrink: 0;
101
+ }
102
+
103
+ .tabDotDirty {
104
+ width: 6px;
105
+ height: 6px;
106
+ border-radius: 9999px;
107
+ flex-shrink: 0;
108
+ background: var(--aion-primary);
109
+ }
110
+
111
+ .tabDotAgent {
112
+ width: 6px;
113
+ height: 6px;
114
+ border-radius: 9999px;
115
+ flex-shrink: 0;
116
+ background: var(--aion-success);
117
+ animation: filemgr-pulse 1.6s ease-in-out infinite;
118
+ }
119
+
120
+ @keyframes filemgr-pulse {
121
+ 0%, 100% { opacity: 1; }
122
+ 50% { opacity: 0.4; }
123
+ }
124
+
125
+ .tabClose {
126
+ display: flex;
127
+ align-items: center;
128
+ justify-content: center;
129
+ width: 16px;
130
+ height: 16px;
131
+ border-radius: 4px;
132
+ flex-shrink: 0;
133
+ color: var(--aion-text-secondary);
134
+ transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
135
+ }
136
+
137
+ .tabClose:hover {
138
+ background: var(--aion-bg-3);
139
+ color: var(--aion-text-primary);
140
+ }
141
+
142
+ .tabClose:active {
143
+ background: var(--aion-bg-active);
144
+ }
145
+
146
+ .tabClose:focus-visible {
147
+ box-shadow: inset 0 0 0 2px var(--aion-primary);
148
+ }
149
+
150
+ .tabPlus {
151
+ display: flex;
152
+ align-items: center;
153
+ justify-content: center;
154
+ width: 24px;
155
+ height: 24px;
156
+ margin: 0 4px;
157
+ border-radius: 4px;
158
+ color: var(--aion-text-secondary);
159
+ cursor: pointer;
160
+ align-self: center;
161
+ flex-shrink: 0;
162
+ transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
163
+ }
164
+
165
+ .tabPlus:hover {
166
+ background: var(--aion-bg-3);
167
+ color: var(--aion-text-primary);
168
+ }
169
+
170
+ .tabPlus:active {
171
+ background: var(--aion-bg-active);
172
+ }
173
+
174
+ .tabPlus:focus-visible {
175
+ box-shadow: inset 0 0 0 2px var(--aion-primary);
176
+ }
177
+
178
+ .tabBarRight {
179
+ display: flex;
180
+ align-items: center;
181
+ gap: 6px;
182
+ padding: 0 10px;
183
+ flex-shrink: 0;
184
+ }
185
+
186
+
187
+
188
+ .panelCollapse,
189
+ .panelMaximize {
190
+ display: flex;
191
+ align-items: center;
192
+ justify-content: center;
193
+ width: 20px;
194
+ height: 20px;
195
+ border-radius: 4px;
196
+ color: var(--aion-text-secondary);
197
+ cursor: pointer;
198
+ transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
199
+ }
200
+
201
+ .panelCollapse:hover,
202
+ .panelMaximize:hover {
203
+ background: var(--aion-bg-3);
204
+ color: var(--aion-text-primary);
205
+ }
206
+
207
+ .panelCollapse:active,
208
+ .panelMaximize:active {
209
+ background: var(--aion-bg-active);
210
+ }
211
+
212
+ .panelCollapse:focus-visible,
213
+ .panelMaximize:focus-visible {
214
+ box-shadow: inset 0 0 0 2px var(--aion-primary);
215
+ }
216
+
217
+ .tabFade {
218
+ position: absolute;
219
+ top: 0;
220
+ bottom: 0;
221
+ width: 32px;
222
+ pointer-events: none;
223
+ z-index: 2;
224
+ }
225
+
226
+ .tabFadeLeft {
227
+ position: absolute;
228
+ top: 0;
229
+ bottom: 0;
230
+ width: 32px;
231
+ pointer-events: none;
232
+ z-index: 2;
233
+ left: 0;
234
+ background: linear-gradient(90deg, var(--aion-bg-2) 0%, transparent 100%);
235
+ }
236
+
237
+ .tabFadeRight {
238
+ position: absolute;
239
+ top: 0;
240
+ bottom: 0;
241
+ width: 32px;
242
+ pointer-events: none;
243
+ z-index: 2;
244
+ right: 0;
245
+ background: linear-gradient(270deg, var(--aion-bg-2) 0%, transparent 100%);
246
+ }
247
+
248
+ .noTabs {
249
+ display: flex;
250
+ align-items: center;
251
+ flex: 1;
252
+ padding: 0 10px;
253
+ font-size: 12px;
254
+ color: var(--aion-text-tertiary);
255
+ }
256
+
257
+ /* ── toolbar ────────────────────────────────────────────────────────────── */
258
+
259
+ .toolbar {
260
+ display: flex;
261
+ align-items: center;
262
+ gap: 2px;
263
+ height: 32px;
264
+ padding: 0 10px;
265
+ flex-shrink: 0;
266
+ background: var(--aion-bg-2);
267
+ border-bottom: 1px solid var(--aion-bg-3);
268
+ overflow-x: auto;
269
+ scrollbar-width: none;
270
+ }
271
+
272
+ .toolbar::-webkit-scrollbar {
273
+ display: none;
274
+ }
275
+
276
+ .toolbarSpacer {
277
+ flex: 1;
278
+ }
279
+
280
+ .toolbarBtn {
281
+ display: flex;
282
+ align-items: center;
283
+ gap: 4px;
284
+ height: 24px;
285
+ padding: 0 8px;
286
+ border: none;
287
+ border-radius: 4px;
288
+ background: transparent;
289
+ color: var(--aion-text-secondary);
290
+ font-size: 12px;
291
+ font-family: var(--aion-font-sans);
292
+ cursor: pointer;
293
+ white-space: nowrap;
294
+ flex-shrink: 0;
295
+ transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1), color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
296
+ }
297
+
298
+ .toolbarBtn:hover {
299
+ background: var(--aion-bg-3);
300
+ color: var(--aion-text-primary);
301
+ }
302
+
303
+ .toolbarBtn:active {
304
+ background: var(--aion-bg-active);
305
+ color: var(--aion-text-primary);
306
+ }
307
+
308
+ .toolbarBtn:focus-visible {
309
+ outline: 2px solid var(--aion-primary);
310
+ outline-offset: 2px;
311
+ }
312
+
313
+ .toolbarBtn:disabled {
314
+ opacity: 0.4;
315
+ cursor: default;
316
+ }
317
+
318
+ .toolbarBtn:disabled:hover {
319
+ background: transparent;
320
+ color: var(--aion-text-secondary);
321
+ }
322
+
323
+ .toolbarBtnActive {
324
+ color: var(--aion-brand);
325
+ background: var(--aion-aou-2);
326
+ border-bottom: 4px solid var(--aion-brand);
327
+ }
328
+
329
+ .toolbarBtnWarn {
330
+ color: var(--aion-warning);
331
+ }
332
+
333
+ /* ── content region ─────────────────────────────────────────────────────── */
334
+
335
+ .content {
336
+ flex: 1;
337
+ min-height: 0;
338
+ display: flex;
339
+ flex-direction: column;
340
+ position: relative;
341
+ }
342
+
343
+ /* Markdown viewer. */
344
+ .mdViewer {
345
+ flex: 1;
346
+ min-height: 0;
347
+ overflow-y: auto;
348
+ overflow-x: hidden;
349
+ padding: 16px 20px 32px;
350
+ font-size: 15px;
351
+ line-height: 1.7;
352
+ color: var(--aion-text-primary);
353
+ word-wrap: break-word;
354
+ }
355
+
356
+ .mdViewer h1 {
357
+ font-size: 24px;
358
+ font-weight: 600;
359
+ margin: 24px 0 12px;
360
+ padding-bottom: 8px;
361
+ border-bottom: 1px solid var(--aion-bg-3);
362
+ line-height: 1.3;
363
+ }
364
+
365
+ .mdViewer h1:first-child {
366
+ margin-top: 4px;
367
+ }
368
+
369
+ .mdViewer h2 {
370
+ font-size: 20px;
371
+ font-weight: 600;
372
+ margin: 22px 0 10px;
373
+ line-height: 1.3;
374
+ }
375
+
376
+ .mdViewer h3 {
377
+ font-size: 17px;
378
+ font-weight: 600;
379
+ margin: 18px 0 8px;
380
+ line-height: 1.3;
381
+ }
382
+
383
+ .mdViewer h4,
384
+ .mdViewer h5,
385
+ .mdViewer h6 {
386
+ font-size: 15px;
387
+ font-weight: 600;
388
+ margin: 14px 0 6px;
389
+ line-height: 1.3;
390
+ }
391
+
392
+ .mdViewer p {
393
+ margin: 8px 0;
394
+ }
395
+
396
+ .mdViewer ul,
397
+ .mdViewer ol {
398
+ margin: 8px 0;
399
+ padding-left: 24px;
400
+ }
401
+
402
+ .mdViewer li {
403
+ margin: 3px 0;
404
+ }
405
+
406
+ .mdViewer code {
407
+ font-family: var(--aion-font-mono);
408
+ font-size: 0.9em;
409
+ background: var(--aion-bg-2);
410
+ border-radius: 3px;
411
+ padding: 1px 5px;
412
+ color: var(--aion-text-primary);
413
+ }
414
+
415
+ .mdViewer pre {
416
+ margin: 10px 0;
417
+ padding: 12px 14px;
418
+ background: var(--aion-bg-2);
419
+ border-radius: 6px;
420
+ overflow-x: auto;
421
+ line-height: 1.5;
422
+ }
423
+
424
+ .mdViewer pre code {
425
+ background: transparent;
426
+ padding: 0;
427
+ font-size: 13px;
428
+ color: var(--aion-text-primary);
429
+ }
430
+
431
+ /* ── mermaid diagrams ──────────────────────────────────────────────────── */
432
+
433
+ /* Container that replaces a claimed ```mermaid code block; the hidden <pre>
434
+ stays as the fallback source. Wide diagrams scroll inside the panel. */
435
+ .mermaidBlock {
436
+ margin: 10px 0;
437
+ padding: 12px 14px;
438
+ background: var(--aion-bg-2);
439
+ border: 1px solid var(--aion-bg-3);
440
+ border-radius: 6px;
441
+ overflow-x: auto;
442
+ text-align: center;
443
+ }
444
+
445
+ .mermaidBlock svg {
446
+ max-width: 100%;
447
+ height: auto;
448
+ }
449
+
450
+ /* Render-in-progress placeholder pulse before the SVG lands. */
451
+ .mermaidBlock[data-mermaid-state='pending'],
452
+ .mermaidBlock[data-mermaid-state='rendering'] {
453
+ min-height: 40px;
454
+ opacity: 0.6;
455
+ }
456
+
457
+ .mdViewer blockquote {
458
+ margin: 10px 0;
459
+ padding: 4px 14px;
460
+ border-left: 3px solid var(--aion-bg-3);
461
+ color: var(--aion-text-secondary);
462
+ }
463
+
464
+ .mdViewer blockquote p {
465
+ margin: 4px 0;
466
+ }
467
+
468
+ .mdViewer a {
469
+ color: var(--aion-primary);
470
+ text-decoration: none;
471
+ }
472
+
473
+ .mdViewer a:hover {
474
+ text-decoration: underline;
475
+ }
476
+
477
+ .mdViewer hr {
478
+ border: none;
479
+ border-top: 1px solid var(--aion-bg-3);
480
+ margin: 20px 0;
481
+ }
482
+
483
+ .mdViewer table {
484
+ border-collapse: collapse;
485
+ margin: 10px 0;
486
+ width: 100%;
487
+ font-size: 14px;
488
+ }
489
+
490
+ .mdViewer th,
491
+ .mdViewer td {
492
+ border: 1px solid var(--aion-bg-3);
493
+ padding: 6px 10px;
494
+ text-align: left;
495
+ }
496
+
497
+ .mdViewer th {
498
+ background: var(--aion-bg-2);
499
+ font-weight: 600;
500
+ }
501
+
502
+ .mdViewer img {
503
+ max-width: 100%;
504
+ border-radius: 4px;
505
+ }
506
+
507
+ /* The "添加到对话" floating action over a preview selection. */
508
+ .addToChat {
509
+ position: fixed;
510
+ z-index: 1000;
511
+ padding: 6px 12px;
512
+ background: var(--aion-primary);
513
+ color: #fff;
514
+ border-radius: 6px;
515
+ font-size: 13px;
516
+ font-weight: 500;
517
+ font-family: var(--aion-font-sans);
518
+ cursor: pointer;
519
+ box-shadow: var(--aion-overlay-shadow);
520
+ user-select: none;
521
+ white-space: nowrap;
522
+ }
523
+
524
+ .addToChat:hover {
525
+ filter: brightness(1.1);
526
+ }
527
+
528
+ /* Code viewer shell: line gutter + code body in one scroll container. */
529
+ .codeShell {
530
+ flex: 1;
531
+ min-height: 0;
532
+ display: flex;
533
+ overflow: auto;
534
+ align-items: stretch;
535
+ }
536
+
537
+ /* Line-number gutter: sticky so it survives horizontal scroll. */
538
+ .lineGutter {
539
+ flex: none;
540
+ position: sticky;
541
+ left: 0;
542
+ z-index: 2;
543
+ background: var(--aion-bg-1);
544
+ border-right: 1px solid var(--aion-border-base);
545
+ padding: 10px 10px 10px 12px;
546
+ text-align: right;
547
+ user-select: none;
548
+ font-family: var(--aion-font-mono);
549
+ font-size: 12px;
550
+ line-height: 1.6;
551
+ color: var(--aion-text-tertiary);
552
+ }
553
+
554
+ /* One gutter row; height must equal the code line height (1.6 x 12px). */
555
+ .lineNo {
556
+ height: 1.6em;
557
+ line-height: 1.6em;
558
+ }
559
+
560
+ /* Code body wraps CodeBlock; it owns horizontal space under the gutter. */
561
+ .codeBody {
562
+ flex: 1;
563
+ min-width: 0;
564
+ display: flex;
565
+ }
566
+
567
+ .codeBody .codeViewer {
568
+ flex: 1;
569
+ min-width: 0;
570
+ overflow: visible;
571
+ position: relative;
572
+ }
573
+
574
+ /* The CodeBlock language/copy banner occupies a full-width row above the
575
+ code, which pushes `pre` down and misaligns the gutter. Float it over the
576
+ top-right corner instead so the code starts at the container top and the
577
+ line numbers line up with the lines. */
578
+ .codeBody .codeViewer > div:first-child {
579
+ position: absolute;
580
+ top: 6px;
581
+ right: 8px;
582
+ z-index: 3;
583
+ }
584
+
585
+ /* Force the highlighted pre to share the gutter's metrics exactly so line
586
+ numbers never drift: same mono font, size, line-height and top padding.
587
+ `!important` overrides the primitives' scoped defaults. */
588
+ .codeBody :global(pre) {
589
+ font-family: var(--aion-font-mono) !important;
590
+ font-size: 12px !important;
591
+ line-height: 1.6 !important;
592
+ padding: 10px 12px !important;
593
+ margin: 0 !important;
594
+ border-radius: 0 !important;
595
+ background: transparent !important;
596
+ }
597
+
598
+ /* Code viewer (CodeBlock draws its own frame/padding). */
599
+ .codeViewer {
600
+ flex: 1;
601
+ min-height: 0;
602
+ overflow: auto;
603
+ padding: 0;
604
+ }
605
+
606
+ /* Diff viewer. */
607
+ .diffViewer {
608
+ flex: 1;
609
+ min-height: 0;
610
+ overflow: auto;
611
+ font-family: var(--aion-font-mono);
612
+ font-size: 12.5px;
613
+ line-height: 1.55;
614
+ padding: 4px 0 16px;
615
+ }
616
+
617
+ .diffLine {
618
+ display: flex;
619
+ white-space: pre;
620
+ padding: 0 12px;
621
+ min-height: 20px;
622
+ }
623
+
624
+ .diffLineAdd {
625
+ background: color-mix(in srgb, var(--aion-success) 12%, transparent);
626
+ color: var(--aion-text-primary);
627
+ }
628
+
629
+ .diffLineDel {
630
+ background: color-mix(in srgb, var(--aion-danger) 12%, transparent);
631
+ color: var(--aion-text-primary);
632
+ }
633
+
634
+ .diffLineHunk {
635
+ background: color-mix(in srgb, var(--aion-primary) 10%, transparent);
636
+ color: var(--aion-text-secondary);
637
+ }
638
+
639
+ .diffLineMeta {
640
+ color: var(--aion-text-tertiary);
641
+ }
642
+
643
+ /* CSV table. */
644
+ .csvViewer {
645
+ flex: 1;
646
+ min-height: 0;
647
+ overflow: auto;
648
+ padding: 12px;
649
+ }
650
+
651
+ .csvTable {
652
+ border-collapse: collapse;
653
+ font-size: 13px;
654
+ font-family: var(--aion-font-mono);
655
+ }
656
+
657
+ .csvTable th,
658
+ .csvTable td {
659
+ border: 1px solid var(--aion-bg-3);
660
+ padding: 4px 10px;
661
+ white-space: nowrap;
662
+ max-width: 480px;
663
+ overflow: hidden;
664
+ text-overflow: ellipsis;
665
+ }
666
+
667
+ .csvTable th {
668
+ background: var(--aion-bg-2);
669
+ font-weight: 600;
670
+ position: sticky;
671
+ top: 0;
672
+ }
673
+
674
+ /* Image viewer. */
675
+ .imageViewer {
676
+ flex: 1;
677
+ min-height: 0;
678
+ display: flex;
679
+ align-items: center;
680
+ justify-content: center;
681
+ overflow: auto;
682
+ padding: 16px;
683
+ background: var(--aion-bg-base);
684
+ }
685
+
686
+ .imageViewer img {
687
+ max-width: 100%;
688
+ max-height: 100%;
689
+ object-fit: contain;
690
+ border-radius: 2px;
691
+ }
692
+
693
+ .imageMeta {
694
+ position: absolute;
695
+ bottom: 12px;
696
+ left: 50%;
697
+ transform: translateX(-50%);
698
+ font-size: 11px;
699
+ color: var(--aion-text-tertiary);
700
+ background: var(--aion-bg-2);
701
+ border-radius: 9999px;
702
+ padding: 2px 10px;
703
+ }
704
+
705
+ /* PDF viewer. */
706
+ .pdfViewer {
707
+ flex: 1;
708
+ min-height: 0;
709
+ border: none;
710
+ background: var(--aion-bg-base);
711
+ }
712
+
713
+ /* URL viewer. */
714
+ .urlBar {
715
+ display: flex;
716
+ align-items: center;
717
+ gap: 6px;
718
+ height: 32px;
719
+ padding: 0 10px;
720
+ flex-shrink: 0;
721
+ background: var(--aion-bg-2);
722
+ border-bottom: 1px solid var(--aion-bg-3);
723
+ }
724
+
725
+ .urlInput {
726
+ flex: 1;
727
+ min-width: 0;
728
+ height: 24px;
729
+ border: none;
730
+ outline: none;
731
+ background: var(--aion-bg-base);
732
+ color: var(--aion-text-primary);
733
+ font-size: 12px;
734
+ border-radius: 4px;
735
+ padding: 0 8px;
736
+ font-family: var(--aion-font-sans);
737
+ }
738
+
739
+ .urlInput:focus-visible {
740
+ box-shadow: inset 0 0 0 2px var(--aion-primary);
741
+ }
742
+
743
+ .urlFrame {
744
+ flex: 1;
745
+ min-height: 0;
746
+ border: none;
747
+ background: var(--aion-bg-base);
748
+ width: 100%;
749
+ }
750
+
751
+ /* Unsupported / error placeholders. */
752
+ .placeholder {
753
+ flex: 1;
754
+ min-height: 0;
755
+ display: flex;
756
+ flex-direction: column;
757
+ align-items: center;
758
+ justify-content: center;
759
+ gap: 8px;
760
+ color: var(--aion-text-secondary);
761
+ font-size: 13px;
762
+ padding: 24px;
763
+ text-align: center;
764
+ }
765
+
766
+ .placeholderTitle {
767
+ font-size: 14px;
768
+ font-weight: 500;
769
+ color: var(--aion-text-primary);
770
+ }
771
+
772
+ .placeholderMeta {
773
+ font-size: 12px;
774
+ color: var(--aion-text-tertiary);
775
+ }
776
+
777
+ .placeholderError {
778
+ color: var(--aion-danger);
779
+ font-size: 12px;
780
+ }
781
+
782
+ /* Split screen: editor | preview. */
783
+ .splitPane {
784
+ flex: 1;
785
+ min-height: 0;
786
+ display: flex;
787
+ position: relative;
788
+ overflow: hidden;
789
+ }
790
+
791
+ .splitPaneLeft {
792
+ display: flex;
793
+ flex-direction: column;
794
+ min-width: 0;
795
+ height: 100%;
796
+ }
797
+
798
+ .splitPaneRight {
799
+ display: flex;
800
+ flex-direction: column;
801
+ min-width: 0;
802
+ height: 100%;
803
+ }
804
+
805
+ .splitHeader {
806
+ display: flex;
807
+ align-items: center;
808
+ height: 40px;
809
+ padding: 0 12px;
810
+ flex-shrink: 0;
811
+ background: var(--aion-bg-2);
812
+ font-size: 12px;
813
+ color: var(--aion-text-secondary);
814
+ border-bottom: 1px solid var(--aion-bg-3);
815
+ }
816
+
817
+ .splitBody {
818
+ flex: 1;
819
+ min-height: 0;
820
+ overflow: hidden;
821
+ }
822
+
823
+ /* The split drag handle (React-rendered). */
824
+ .splitHandle {
825
+ position: absolute;
826
+ top: 0;
827
+ bottom: 0;
828
+ width: 12px;
829
+ z-index: 20;
830
+ cursor: col-resize;
831
+ touch-action: none;
832
+ }
833
+
834
+ .splitHandle::after {
835
+ content: "";
836
+ position: absolute;
837
+ top: 0;
838
+ bottom: 0;
839
+ left: 50%;
840
+ transform: translateX(-50%);
841
+ width: 2px;
842
+ border-radius: 9999px;
843
+ background: var(--aion-bg-3);
844
+ opacity: 0.9;
845
+ transition: width 0.15s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
846
+ pointer-events: none;
847
+ }
848
+
849
+ .splitHandle:hover::after,
850
+ .splitHandle:active::after {
851
+ width: 6px;
852
+ background: var(--aion-brand);
853
+ }
854
+
855
+ /* Text editor (textarea-based, syntax-free but fast). */
856
+ .textEditor {
857
+ width: 100%;
858
+ height: 100%;
859
+ border: none;
860
+ outline: none;
861
+ resize: none;
862
+ background: var(--aion-bg-base);
863
+ color: var(--aion-text-primary);
864
+ font-family: var(--aion-font-mono);
865
+ font-size: 13px;
866
+ line-height: 1.6;
867
+ padding: 12px 14px;
868
+ tab-size: 2;
869
+ }
870
+
871
+ .textEditor:focus-visible {
872
+ box-shadow: inset 0 0 0 2px var(--aion-primary);
873
+ }
874
+
875
+ /* Save-state banner. */
876
+ .saveBanner {
877
+ position: absolute;
878
+ top: 8px;
879
+ right: 12px;
880
+ z-index: 5;
881
+ font-size: 12px;
882
+ padding: 4px 10px;
883
+ border-radius: 4px;
884
+ background: var(--aion-bg-2);
885
+ border: 1px solid var(--aion-bg-3);
886
+ color: var(--aion-text-secondary);
887
+ max-width: 60%;
888
+ overflow: hidden;
889
+ text-overflow: ellipsis;
890
+ white-space: nowrap;
891
+ }
892
+
893
+ .saveBannerError {
894
+ color: var(--aion-danger);
895
+ border-color: var(--aion-danger);
896
+ }
897
+
898
+ .truncatedNote {
899
+ font-size: 12px;
900
+ color: var(--aion-warning);
901
+ padding: 6px 20px;
902
+ background: color-mix(in srgb, var(--aion-warning) 10%, transparent);
903
+ flex-shrink: 0;
904
+ }