@lijian-ui/dsh-file-manager 0.1.21 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +611 -542
- package/lib/client.js.map +1 -1
- package/lib/tsconfig.client.tsbuildinfo +1 -1
- package/lib/types/client/DockItem.d.ts +15 -0
- package/lib/types/client/DockItem.d.ts.map +1 -0
- package/lib/types/client/FilePanelDockItem.d.ts +16 -0
- package/lib/types/client/FilePanelDockItem.d.ts.map +1 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/layout.d.ts +0 -4
- package/lib/types/client/layout.d.ts.map +1 -1
- package/lib/types/client/locales.d.ts +21 -0
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/mount.d.ts +2 -1
- package/lib/types/client/mount.d.ts.map +1 -1
- package/lib/types/client/picker/FilePickerModal.d.ts.map +1 -1
- package/lib/types/client/store.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/client/DockItem.tsx +42 -0
- package/src/client/FilePanelDockItem.tsx +41 -0
- package/src/client/index.ts +23 -2
- package/src/client/layout.ts +31 -54
- package/src/client/locales.ts +46 -0
- package/src/client/mount.tsx +18 -2
- package/src/client/picker/FilePickerModal.tsx +15 -14
- package/src/client/preview/PreviewPanel.tsx +1 -1
- package/src/client/store.ts +2 -1
- package/src/client/styles/tokens.module.css +2 -74
- package/lib/assets/mermaid.min.js +0 -3587
- package/src/client/floating.ts +0 -63
|
@@ -23,6 +23,7 @@ import type { PanelApi } from '../api.ts'
|
|
|
23
23
|
import { filePicker, type PickState } from './file-picker.ts'
|
|
24
24
|
import { ChevronDownIcon, ChevronRightIcon, CloseIcon, FileIcon, FolderIcon, FolderOpenIcon, SearchIcon } from '../components/icons.tsx'
|
|
25
25
|
import { appendToDraft, insertFileReference, type RefSpan } from '../reference.ts'
|
|
26
|
+
import { t } from '../locales.ts'
|
|
26
27
|
import pickerCss from '../styles/picker.module.css'
|
|
27
28
|
|
|
28
29
|
/** Debounce for the workspace search box. */
|
|
@@ -194,9 +195,9 @@ export function FilePickerModal({
|
|
|
194
195
|
{isDir && isOpen && (
|
|
195
196
|
<div>
|
|
196
197
|
{isLoading ? (
|
|
197
|
-
<div className={pickerCss.note} style={{ paddingLeft: 8 + (depth + 1) * 16 }}
|
|
198
|
+
<div className={pickerCss.note} style={{ paddingLeft: 8 + (depth + 1) * 16 }}>{t('picker.loading')}</div>
|
|
198
199
|
) : children.length === 0 ? (
|
|
199
|
-
<div className={pickerCss.note} style={{ paddingLeft: 8 + (depth + 1) * 16 }}
|
|
200
|
+
<div className={pickerCss.note} style={{ paddingLeft: 8 + (depth + 1) * 16 }}>{t('picker.emptyDir')}</div>
|
|
200
201
|
) : (
|
|
201
202
|
children.map((child) => renderNode(child, depth + 1))
|
|
202
203
|
)}
|
|
@@ -218,8 +219,8 @@ export function FilePickerModal({
|
|
|
218
219
|
<div className={pickerCss.modal} onClick={(e) => e.stopPropagation()}>
|
|
219
220
|
<div className={pickerCss.header}>
|
|
220
221
|
<div className={pickerCss.titleRow}>
|
|
221
|
-
<span className={pickerCss.title}
|
|
222
|
-
<button type="button" className={pickerCss.closeBtn} onClick={onClose} aria-label=
|
|
222
|
+
<span className={pickerCss.title}>{t('picker.title')}</span>
|
|
223
|
+
<button type="button" className={pickerCss.closeBtn} onClick={onClose} aria-label={t('picker.closeAria')}>
|
|
223
224
|
<CloseIcon size={16} />
|
|
224
225
|
</button>
|
|
225
226
|
</div>
|
|
@@ -227,13 +228,13 @@ export function FilePickerModal({
|
|
|
227
228
|
<span className={pickerCss.searchIcon}><SearchIcon size={14} /></span>
|
|
228
229
|
<input
|
|
229
230
|
className={pickerCss.searchInput}
|
|
230
|
-
placeholder=
|
|
231
|
+
placeholder={t('picker.searchPlaceholder')}
|
|
231
232
|
value={search}
|
|
232
233
|
onChange={(e) => setSearch(e.target.value)}
|
|
233
234
|
autoFocus
|
|
234
235
|
/>
|
|
235
236
|
{search !== '' && (
|
|
236
|
-
<button type="button" className={pickerCss.searchClear} onClick={() => setSearch('')} aria-label=
|
|
237
|
+
<button type="button" className={pickerCss.searchClear} onClick={() => setSearch('')} aria-label={t('picker.clearAria')}>
|
|
237
238
|
<CloseIcon size={13} />
|
|
238
239
|
</button>
|
|
239
240
|
)}
|
|
@@ -244,9 +245,9 @@ export function FilePickerModal({
|
|
|
244
245
|
<div className={pickerCss.body}>
|
|
245
246
|
{searchResults !== null ? (
|
|
246
247
|
searching ? (
|
|
247
|
-
<div className={pickerCss.note}
|
|
248
|
+
<div className={pickerCss.note}>{t('explorer.search.searching')}</div>
|
|
248
249
|
) : searchResults.length === 0 ? (
|
|
249
|
-
<div className={pickerCss.note}
|
|
250
|
+
<div className={pickerCss.note}>{t('explorer.search.empty')}</div>
|
|
250
251
|
) : (
|
|
251
252
|
searchResults.map((hit) => {
|
|
252
253
|
const isSel = selected.has(hit.path)
|
|
@@ -276,9 +277,9 @@ export function FilePickerModal({
|
|
|
276
277
|
})
|
|
277
278
|
)
|
|
278
279
|
) : rootLoading ? (
|
|
279
|
-
<div className={pickerCss.note}
|
|
280
|
+
<div className={pickerCss.note}>{t('picker.loading')}</div>
|
|
280
281
|
) : rootEntries.length === 0 ? (
|
|
281
|
-
<div className={pickerCss.note}
|
|
282
|
+
<div className={pickerCss.note}>{t('picker.emptyDir')}</div>
|
|
282
283
|
) : (
|
|
283
284
|
rootEntries.map((entry) => tree(entry, 0))
|
|
284
285
|
)}
|
|
@@ -287,7 +288,7 @@ export function FilePickerModal({
|
|
|
287
288
|
<div className={pickerCss.footer}>
|
|
288
289
|
<div className={pickerCss.chips}>
|
|
289
290
|
{selectedList.length === 0 ? (
|
|
290
|
-
<span className={pickerCss.chipsEmpty}
|
|
291
|
+
<span className={pickerCss.chipsEmpty}>{t('picker.emptySelection')}</span>
|
|
291
292
|
) : (
|
|
292
293
|
selectedList.map((pick) => (
|
|
293
294
|
<span key={pick.path} className={pickerCss.chip}>
|
|
@@ -296,7 +297,7 @@ export function FilePickerModal({
|
|
|
296
297
|
type="button"
|
|
297
298
|
className={pickerCss.chipX}
|
|
298
299
|
onClick={() => toggleSelect(pick.path, pick.isDir)}
|
|
299
|
-
aria-label=
|
|
300
|
+
aria-label={t('picker.removeAria')}
|
|
300
301
|
>
|
|
301
302
|
<CloseIcon size={11} />
|
|
302
303
|
</button>
|
|
@@ -305,14 +306,14 @@ export function FilePickerModal({
|
|
|
305
306
|
)}
|
|
306
307
|
</div>
|
|
307
308
|
<div className={pickerCss.footerActions}>
|
|
308
|
-
<button type="button" className={pickerCss.cancelBtn} onClick={onClose}
|
|
309
|
+
<button type="button" className={pickerCss.cancelBtn} onClick={onClose}>{t('common.cancel')}</button>
|
|
309
310
|
<button
|
|
310
311
|
type="button"
|
|
311
312
|
className={pickerCss.insertBtn}
|
|
312
313
|
disabled={selectedList.length === 0}
|
|
313
314
|
onClick={() => onInsert(selectedList)}
|
|
314
315
|
>
|
|
315
|
-
|
|
316
|
+
{t('picker.insert')}{selectedList.length > 0 ? ` (${selectedList.length})` : ''}
|
|
316
317
|
</button>
|
|
317
318
|
</div>
|
|
318
319
|
</div>
|
package/src/client/store.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import type { FileRead, FsEntry, GitStatusView, PreviewContentType, SearchHit } from '../core/types.ts'
|
|
14
14
|
import type { PanelApi } from './api.ts'
|
|
15
15
|
import { detectContentType, isTextType, pdfPreviewUrl, tabIdOf } from './fileType.ts'
|
|
16
|
+
import { t } from './locales.ts'
|
|
16
17
|
import {
|
|
17
18
|
createDebounced, evictPreviewScopes, readJson, readStoredNumber, writeJson, writeStoredNumber,
|
|
18
19
|
} from './persist.ts'
|
|
@@ -1133,7 +1134,7 @@ export function createPreviewStore(api: PanelApi): PreviewStore {
|
|
|
1133
1134
|
...item,
|
|
1134
1135
|
loading: false,
|
|
1135
1136
|
error: result.error.code === 'write-conflict'
|
|
1136
|
-
? '
|
|
1137
|
+
? t('preview.saveConflict')
|
|
1137
1138
|
: result.error.message,
|
|
1138
1139
|
}
|
|
1139
1140
|
}
|
|
@@ -188,85 +188,13 @@
|
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
-
/* Drag handles:
|
|
191
|
+
/* Drag handles: invisible, col-resize cursor only (like DSH native sidebar). */
|
|
192
192
|
:global(.filemgr-explorer-handle),
|
|
193
193
|
:global(.filemgr-preview-handle) {
|
|
194
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;
|
|
195
|
+
cursor: col-resize;
|
|
228
196
|
}
|
|
229
197
|
|
|
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
198
|
|
|
271
199
|
/* The collapse chevron inside the explorer tab bar (top-right). It rides
|
|
272
200
|
the explorer column's stacking context (the column stacks at z 30), so
|