@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
|
@@ -53,7 +53,6 @@ export declare class PanelLayoutController {
|
|
|
53
53
|
private explorerCol;
|
|
54
54
|
private explorerHandle;
|
|
55
55
|
private previewHandle;
|
|
56
|
-
private floatingButton;
|
|
57
56
|
private styleObserver;
|
|
58
57
|
private sizeObserver;
|
|
59
58
|
private waitObserver;
|
|
@@ -82,9 +81,6 @@ export declare class PanelLayoutController {
|
|
|
82
81
|
* the shell has no header (standalone installs, desktop variants).
|
|
83
82
|
*/
|
|
84
83
|
private findHeaderBottom;
|
|
85
|
-
/** Position the floating button: docked at the top-right corner, just
|
|
86
|
-
* below the shell header's bottom divider (fallback: the chevron row). */
|
|
87
|
-
private positionFloatingButton;
|
|
88
84
|
/** Apply one store update with transitions disabled for exactly one frame. */
|
|
89
85
|
private instant;
|
|
90
86
|
/** Re-write the frame grid and reposition handles + floating button. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/client/layout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/client/layout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAcH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAK7C,iFAAiF;AACjF,wBAAgB,eAAe,IAAI,WAAW,GAAG,IAAI,CAEpD;AAgBD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAkBvD;AAED,yEAAyE;AACzE,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAG7C;AAED,oFAAoF;AACpF,eAAO,MAAM,qBAAqB,KAAK,CAAA;AACvC,eAAO,MAAM,oBAAoB,KAAK,CAAA;AAEtC;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,UAAU,GAAG,SAAS,EAC5B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,OAAO,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GAChF,MAAM,CAQR;AAED,+EAA+E;AAC/E,qBAAa,qBAAqB;IAiBpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAhBnC,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,UAAU,CAA8B;IAChD,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,cAAc,CAA8B;IACpD,OAAO,CAAC,aAAa,CAA8B;IAEnD,OAAO,CAAC,aAAa,CAAgC;IACrD,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,YAAY,CAAgC;IACpD,OAAO,CAAC,UAAU,CAAI;IACtB,4EAA4E;IAC5E,OAAO,CAAC,aAAa,CAA2B;IAChD,wFAAwF;IACxF,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,YAAY,CAA2C;IAC/D,OAAO,CAAC,SAAS,CAAwB;gBACZ,MAAM,EAAE,WAAW;IAEhD,+DAA+D;IAC/D,KAAK,IAAI,IAAI;IAYb,4EAA4E;IAC5E,OAAO,CAAC,MAAM;IA0Hd,8DAA8D;IAC9D,OAAO,CAAC,YAAY;IAkEpB,uEAAuE;IACvE,cAAc,IAAI,IAAI;IActB,uEAAuE;IACvE,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAOnC;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IAYxB,8EAA8E;IAC9E,OAAO,CAAC,OAAO;IAef,wEAAwE;IACxE,OAAO,CAAC,SAAS;IAiFjB;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IAkBtB,gEAAgE;IAChE,OAAO,CAAC,oBAAoB;IAK5B,yCAAyC;IACzC,OAAO,IAAI,IAAI;CAchB"}
|
|
@@ -109,6 +109,17 @@ declare const zh: {
|
|
|
109
109
|
readonly 'settings.unsaved': "未保存";
|
|
110
110
|
readonly 'settings.saveFailed': "部署未接受这些值,已保留供你修改。";
|
|
111
111
|
readonly 'settings.invalidNumber': "请输入数字,留空则使用默认值。";
|
|
112
|
+
readonly 'dock.filePanel.label': "文件面板";
|
|
113
|
+
readonly 'preview.addToChat': "添加到对话";
|
|
114
|
+
readonly 'picker.title': "引用项目文件";
|
|
115
|
+
readonly 'picker.searchPlaceholder': "搜索工作区文件…";
|
|
116
|
+
readonly 'picker.loading': "加载中…";
|
|
117
|
+
readonly 'picker.emptyDir': "(空目录)";
|
|
118
|
+
readonly 'picker.emptySelection': "选择文件或目录(可多选)";
|
|
119
|
+
readonly 'picker.insert': "插入";
|
|
120
|
+
readonly 'picker.removeAria': "移除";
|
|
121
|
+
readonly 'picker.clearAria': "清空";
|
|
122
|
+
readonly 'picker.closeAria': "关闭";
|
|
112
123
|
};
|
|
113
124
|
export type FileManagerPanelKey = keyof typeof zh;
|
|
114
125
|
/** The dictionary namespace this plugin owns. */
|
|
@@ -119,6 +130,16 @@ export declare function format(template: string, params: Record<string, string |
|
|
|
119
130
|
export declare const dictionaries: Record<'zh' | 'en', Record<FileManagerPanelKey, string>>;
|
|
120
131
|
/** Set the active language (the client mirrors the locale service). */
|
|
121
132
|
export declare function setLanguage(language: string): void;
|
|
133
|
+
/**
|
|
134
|
+
* Reactive translate function bound by the client entry via
|
|
135
|
+
* `ctx.locale.bind(NS)`. When set, `t` delegates to it so every call reads
|
|
136
|
+
* the active locale at call time (re-evaluated on each render). This is the
|
|
137
|
+
* same mechanism session-cleaner / im-gateway use; the legacy
|
|
138
|
+
* `currentLanguage` + `setLanguage` path remains as a fallback for any code
|
|
139
|
+
* path that runs before `bindT` is called.
|
|
140
|
+
*/
|
|
141
|
+
import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
|
|
142
|
+
export declare function bindT(t: TranslateNS<'filemgr'>): void;
|
|
122
143
|
/** Translate one key with optional params. */
|
|
123
144
|
export declare function t(key: FileManagerPanelKey, params?: Record<string, string | number>): string;
|
|
124
145
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,QAAA,MAAM,EAAE
|
|
1
|
+
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,QAAA,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0HE,CAAA;AAyHV,MAAM,MAAM,mBAAmB,GAAG,MAAM,OAAO,EAAE,CAAA;AAEjD,iDAAiD;AACjD,eAAO,MAAM,EAAE,YAAY,CAAA;AAE3B,uDAAuD;AACvD,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAExF;AAED,yEAAyE;AACzE,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,IAAI,GAAG,IAAI,EAAE,MAAM,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAc,CAAA;AAIhG,uEAAuE;AACvE,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAElD;AAED;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAInE,wBAAgB,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,GAAG,IAAI,CAErD;AAED,8CAA8C;AAC9C,wBAAgB,CAAC,CAAC,GAAG,EAAE,mBAAmB,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAK5F"}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* failure degrades the panels, never the GUI boot.
|
|
6
6
|
* @module dsh-filemgr/client/mount
|
|
7
7
|
*/
|
|
8
|
+
import type { LocaleFace } from '@deepseek-ai/dsh-client-ui-slots';
|
|
8
9
|
import type { PanelStores } from './store.ts';
|
|
9
10
|
import type { FileReferenceSelection } from './preview/selection.ts';
|
|
10
11
|
/**
|
|
@@ -18,5 +19,5 @@ import type { FileReferenceSelection } from './preview/selection.ts';
|
|
|
18
19
|
* a preview selection (path + start/end line).
|
|
19
20
|
* @returns a disposer unmounting both trees.
|
|
20
21
|
*/
|
|
21
|
-
export declare function mountPanels(stores: PanelStores, onToggleExplorer: () => void, onReference: (path: string, isDir: boolean) => void, onAddFileReference: (selection: FileReferenceSelection) => boolean): () => void;
|
|
22
|
+
export declare function mountPanels(stores: PanelStores, onToggleExplorer: () => void, onReference: (path: string, isDir: boolean) => void, onAddFileReference: (selection: FileReferenceSelection) => boolean, locale: LocaleFace): () => void;
|
|
22
23
|
//# sourceMappingURL=mount.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../../../src/client/mount.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../../../src/client/mount.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAG7C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAA;AAuCpE;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,WAAW,EACnB,gBAAgB,EAAE,MAAM,IAAI,EAC5B,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,EACnD,kBAAkB,EAAE,CAAC,SAAS,EAAE,sBAAsB,KAAK,OAAO,EAClE,MAAM,EAAE,UAAU,GACjB,MAAM,IAAI,CAmBZ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilePickerModal.d.ts","sourceRoot":"","sources":["../../../../src/client/picker/FilePickerModal.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAA;AAEhC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAE3E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"FilePickerModal.d.ts","sourceRoot":"","sources":["../../../../src/client/picker/FilePickerModal.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAA;AAEhC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAE3E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAqB7D,2EAA2E;AAC3E,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,OAAO,CAAA;CACf;AAED,kEAAkE;AAClE,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,GAAG,EACH,QAAQ,EACR,OAAO,GACR,EAAE;IACD,KAAK,EAAE,SAAS,CAAA;IAChB,GAAG,EAAE,QAAQ,CAAA;IACb,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,IAAI,CAAA;IACvC,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CAuQrB;AAoBD,wFAAwF;AACxF,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAOnG;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;IAAE,GAAG,EAAE,aAAa,CAAC;IAAC,GAAG,EAAE,QAAQ,CAAA;CAAE,GAAG,GAAG,CAAC,OAAO,CAmJ/F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/client/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAY,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACvG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/client/store.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lijian-ui/dsh-file-manager",
|
|
3
3
|
"description": "DSH web GUI right-panel system: a pixel-faithful re-implementation of FileManager's Explorer + Preview columns (file tree, filename search, git changes, multi-tab preview of 10+ formats) driven by real host-side fs/git services, hot-pluggable via a profile bundle without any dsh source changes",
|
|
4
|
-
"version": "0.1
|
|
4
|
+
"version": "0.2.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/types/index.d.ts",
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DockItem — a round dock button for the conversation session header.
|
|
3
|
+
* Each plugin owns its own DockItem copy (terminal in dsh-term, file-panel in
|
|
4
|
+
* dsh-file-manager). Hover scales the button up via pure CSS — no JS event
|
|
5
|
+
* coordination, no shared motion value.
|
|
6
|
+
* @module dsh-file-manager/client/DockItem
|
|
7
|
+
*/
|
|
8
|
+
import { type ReactElement, type ReactNode } from 'react'
|
|
9
|
+
|
|
10
|
+
const STYLE_ID = 'dsh-dock-item-style'
|
|
11
|
+
|
|
12
|
+
function ensureStyle(): void {
|
|
13
|
+
if (typeof document === 'undefined') return
|
|
14
|
+
if (document.getElementById(STYLE_ID) !== null) return
|
|
15
|
+
const tag = document.createElement('style')
|
|
16
|
+
tag.id = STYLE_ID
|
|
17
|
+
tag.textContent = '.dsh-dock-item{width:32px;height:32px;border:none;border-radius:9999px;background:#000;color:#fff;cursor:pointer;position:relative;transition:transform .15s ease,background .18s ease;display:inline-flex;align-items:center;justify-content:center}.dsh-dock-item:hover{transform:scale(1.15);background:#1a1a1a}.dsh-dock-item-active{background:var(--aion-primary,#6ea0ff)}.dsh-dock-tooltip{position:absolute;top:calc(100% + 6px);left:50%;transform:translateX(-50%);padding:2px 8px;font-size:12px;line-height:1.4;white-space:nowrap;color:#fff;background:rgba(20,20,30,.9);border:1px solid rgba(255,255,255,.12);border-radius:6px;opacity:0;pointer-events:none;transition:opacity .15s}.dsh-dock-item:hover .dsh-dock-tooltip{opacity:1}'
|
|
18
|
+
document.head.appendChild(tag)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
ensureStyle()
|
|
22
|
+
|
|
23
|
+
export function DockItem(props: {
|
|
24
|
+
active: boolean
|
|
25
|
+
label: string
|
|
26
|
+
onClick: () => void
|
|
27
|
+
children: ReactNode
|
|
28
|
+
}): ReactElement {
|
|
29
|
+
return (
|
|
30
|
+
<button
|
|
31
|
+
type="button"
|
|
32
|
+
className={`dsh-dock-item${props.active ? ' dsh-dock-item-active' : ''}`}
|
|
33
|
+
onClick={props.onClick}
|
|
34
|
+
aria-label={props.label}
|
|
35
|
+
aria-pressed={props.active}
|
|
36
|
+
title={props.label}
|
|
37
|
+
>
|
|
38
|
+
<span className="dsh-dock-tooltip">{props.label}</span>
|
|
39
|
+
{props.children}
|
|
40
|
+
</button>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FilePanelDockItem — the file-panel dock button rendered into the conversation
|
|
3
|
+
* session header (the `conversation.session.header.utilities` slot).
|
|
4
|
+
*
|
|
5
|
+
* This plugin owns its own dock button independently: dsh-term renders its own
|
|
6
|
+
* terminal button, dsh-file-manager renders this file-panel button. The two
|
|
7
|
+
* are fully decoupled — install either alone and you get just its button;
|
|
8
|
+
* install both and both buttons appear side by side with shared magnification.
|
|
9
|
+
*
|
|
10
|
+
* Clicking broadcasts `dsh-dock:toggle-filepanel` (handled in dsh-file-manager
|
|
11
|
+
* index); the open state is mirrored back through `dsh-dock:filepanel-state`.
|
|
12
|
+
* @module dsh-file-manager/client/FilePanelDockItem
|
|
13
|
+
*/
|
|
14
|
+
import { useEffect, useState, type ReactElement } from 'react'
|
|
15
|
+
import { DockItem } from './DockItem.tsx'
|
|
16
|
+
import { t } from './locales.ts'
|
|
17
|
+
|
|
18
|
+
const EV = {
|
|
19
|
+
toggleFile: 'dsh-dock:toggle-filepanel',
|
|
20
|
+
fileState: 'dsh-dock:filepanel-state',
|
|
21
|
+
} as const
|
|
22
|
+
|
|
23
|
+
export function FilePanelDockItem(): ReactElement {
|
|
24
|
+
const [active, setActive] = useState(false)
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
const onState = (e: Event): void => setActive(Boolean((e as CustomEvent).detail))
|
|
27
|
+
window.addEventListener(EV.fileState, onState)
|
|
28
|
+
return () => window.removeEventListener(EV.fileState, onState)
|
|
29
|
+
}, [])
|
|
30
|
+
return (
|
|
31
|
+
<DockItem
|
|
32
|
+
active={active}
|
|
33
|
+
label={t('dock.filePanel.label')}
|
|
34
|
+
onClick={() => window.dispatchEvent(new CustomEvent(EV.toggleFile))}
|
|
35
|
+
>
|
|
36
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
37
|
+
<path d="m6 14 1.45-2.9a2 2 0 0 1 1.79-1.1h11.76a2 2 0 0 1 1.94 1.5l1.55 6a2 2 0 0 1-1.94 2.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.5a2 2 0 0 1 1.59.79l.91 1.21a2 2 0 0 0 1.59.79H18a2 2 0 0 1 2 2v2" />
|
|
38
|
+
</svg>
|
|
39
|
+
</DockItem>
|
|
40
|
+
)
|
|
41
|
+
}
|
package/src/client/index.ts
CHANGED
|
@@ -27,7 +27,7 @@ import { FileManagerSettingsCard, FileManagerSettingsCardController, type FileMa
|
|
|
27
27
|
import { PanelLayoutController } from './layout.ts'
|
|
28
28
|
import { createPanelStores, layoutSetRoot } from './store.ts'
|
|
29
29
|
import { mountPanels } from './mount.tsx'
|
|
30
|
-
import { NS, dictionaries, setLanguage, type FileManagerPanelKey } from './locales.ts'
|
|
30
|
+
import { NS, dictionaries, setLanguage, bindT, type FileManagerPanelKey } from './locales.ts'
|
|
31
31
|
import { DragFileInlay, type DragFileInjected } from './drag/DragFileInlay.tsx'
|
|
32
32
|
import { insertPathIntoDraft } from './drag/file-drag.ts'
|
|
33
33
|
import { MermaidChatEnhancer } from './chat/mermaid-chat.tsx'
|
|
@@ -38,6 +38,7 @@ import { appendToDraft, appendFileReferenceChip } from './reference.ts'
|
|
|
38
38
|
import { registerFileReferenceSource } from './file-source.ts'
|
|
39
39
|
import type { FileReferenceSelection } from './preview/selection.ts'
|
|
40
40
|
import './styles/chip.module.css'
|
|
41
|
+
import { FilePanelDockItem } from './FilePanelDockItem.tsx'
|
|
41
42
|
|
|
42
43
|
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
43
44
|
interface LocaleNamespaceMap {
|
|
@@ -80,8 +81,28 @@ const panelApi = new PanelApi()
|
|
|
80
81
|
|
|
81
82
|
/** Apply the browser half. */
|
|
82
83
|
export function apply(ctx: ClientContext): void {
|
|
84
|
+
// Session header dock button (file-panel): each plugin owns its own button
|
|
85
|
+
// in conversation.session.header.utilities, so file-manager works standalone
|
|
86
|
+
// without dsh-term. Cross-button magnification is coordinated via window
|
|
87
|
+
// events (see DockItem.tsx).
|
|
88
|
+
ctx.inject(['slots'], (scope: ClientContext) => {
|
|
89
|
+
scope.slots.inject('conversation.session.header.utilities', () =>
|
|
90
|
+
scope.slots.register({
|
|
91
|
+
name: 'conversation.session.header.utilities',
|
|
92
|
+
id: 'filemgr-dock-item',
|
|
93
|
+
order: -2,
|
|
94
|
+
inject: () => ({}),
|
|
95
|
+
}, FilePanelDockItem))
|
|
96
|
+
})
|
|
97
|
+
|
|
83
98
|
ctx.effect(() => ctx.locale.register(NS, dictionaries), 'dsh-filemgr: dictionaries')
|
|
84
99
|
|
|
100
|
+
// Bind the reactive translate function from the locale service so every
|
|
101
|
+
// `t()` call reads the active locale at call time (same mechanism as
|
|
102
|
+
// session-cleaner / im-gateway). The legacy `currentLanguage` + `setLanguage`
|
|
103
|
+
// path in locales.ts remains as a fallback.
|
|
104
|
+
bindT(ctx.locale.bind(NS))
|
|
105
|
+
|
|
85
106
|
// The `file` reference source: registers the codec that serializes file
|
|
86
107
|
// chips on submit (`@path:lines`), which the shell requires before any
|
|
87
108
|
// `slash/input-insert-reference` chip can send. Inert as a menu
|
|
@@ -337,7 +358,7 @@ export function apply(ctx: ClientContext): void {
|
|
|
337
358
|
// Mount everything. DOM failures degrade the panels, never the GUI.
|
|
338
359
|
try {
|
|
339
360
|
layout.mount()
|
|
340
|
-
mountPanels(stores, () => layout.toggleExplorer(), onReference, onAddFileReference)
|
|
361
|
+
mountPanels(stores, () => layout.toggleExplorer(), onReference, onAddFileReference, ctx.locale)
|
|
341
362
|
} catch (error) {
|
|
342
363
|
console.error('[dsh-filemgr] mount failed:', error)
|
|
343
364
|
}
|
package/src/client/layout.ts
CHANGED
|
@@ -34,10 +34,7 @@ import {
|
|
|
34
34
|
} from './store.ts'
|
|
35
35
|
import { writeStoredNumber } from './persist.ts'
|
|
36
36
|
import { maximizedGridTracks, maximizedOverlay } from './maximize.ts'
|
|
37
|
-
|
|
38
|
-
FLOATING_BUTTON_HEIGHT_PX, FLOATING_HEADER_GAP_PX,
|
|
39
|
-
clampFloatingTop, titlebarAreaHeight, topAlignedFloatingTop,
|
|
40
|
-
} from './floating.ts'
|
|
37
|
+
|
|
41
38
|
import type { LayoutStore } from './store.ts'
|
|
42
39
|
|
|
43
40
|
/** The frame grid element (portals target it). */
|
|
@@ -123,7 +120,7 @@ export class PanelLayoutController {
|
|
|
123
120
|
private explorerCol: HTMLDivElement | null = null
|
|
124
121
|
private explorerHandle: HTMLDivElement | null = null
|
|
125
122
|
private previewHandle: HTMLDivElement | null = null
|
|
126
|
-
|
|
123
|
+
|
|
127
124
|
private styleObserver: MutationObserver | null = null
|
|
128
125
|
private sizeObserver: ResizeObserver | null = null
|
|
129
126
|
private waitObserver: MutationObserver | null = null
|
|
@@ -191,26 +188,6 @@ export class PanelLayoutController {
|
|
|
191
188
|
frame.appendChild(this.explorerHandle)
|
|
192
189
|
frame.appendChild(this.previewHandle)
|
|
193
190
|
|
|
194
|
-
// The floating expand button (fixed, top-right corner) — DOM-level,
|
|
195
|
-
// no React. Docked exactly where the explorer's collapse chevron sits,
|
|
196
|
-
// so collapsing and re-expanding toggle in place (issue #374 follow-up);
|
|
197
|
-
// a click toggles the explorer.
|
|
198
|
-
this.floatingButton = document.createElement('button')
|
|
199
|
-
this.floatingButton.type = 'button'
|
|
200
|
-
this.floatingButton.className = 'filemgr-floating-expand'
|
|
201
|
-
this.floatingButton.setAttribute('aria-label', 'Expand explorer')
|
|
202
|
-
this.floatingButton.innerHTML = '<svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3l5 5-5 5"/></svg>'
|
|
203
|
-
this.floatingButton.addEventListener('click', () => { this.toggleExplorer() })
|
|
204
|
-
document.body.appendChild(this.floatingButton)
|
|
205
|
-
|
|
206
|
-
// Window Controls Overlay (dsh-desktop, issue #292): re-position when
|
|
207
|
-
// the titlebar area changes (button must stay below the window buttons).
|
|
208
|
-
const overlay = (navigator as Navigator & { windowControlsOverlay?: EventTarget }).windowControlsOverlay
|
|
209
|
-
if (overlay !== undefined) {
|
|
210
|
-
const onGeometryChange = (): void => { this.positionFloatingButton() }
|
|
211
|
-
overlay.addEventListener('geometrychange', onGeometryChange)
|
|
212
|
-
this.disposers.push(() => overlay.removeEventListener('geometrychange', onGeometryChange))
|
|
213
|
-
}
|
|
214
191
|
|
|
215
192
|
// Esc restores a maximized panel (issue #315). Editing surfaces own Esc:
|
|
216
193
|
// while an input/textarea/contenteditable is focused, leave it alone.
|
|
@@ -240,6 +217,12 @@ export class PanelLayoutController {
|
|
|
240
217
|
// Our own write — keep it (the shell tracks are already mirrored).
|
|
241
218
|
return
|
|
242
219
|
}
|
|
220
|
+
// 6 tracks: dsh-term appended its track after our 5 — re-apply to
|
|
221
|
+
// update handle positions (they must offset left by dsh-term's width).
|
|
222
|
+
if (tracks.length === 6 && tracks.includes('[dsh-term]') && this.shellTracks.length === 3) {
|
|
223
|
+
this.applyGrid()
|
|
224
|
+
return
|
|
225
|
+
}
|
|
243
226
|
}
|
|
244
227
|
this.styleObserver = new MutationObserver(syncGrid)
|
|
245
228
|
this.styleObserver.observe(frame, { attributes: true, attributeFilter: ['style'] })
|
|
@@ -393,20 +376,6 @@ export class PanelLayoutController {
|
|
|
393
376
|
return Number.isFinite(bottom) ? bottom : null
|
|
394
377
|
}
|
|
395
378
|
|
|
396
|
-
/** Position the floating button: docked at the top-right corner, just
|
|
397
|
-
* below the shell header's bottom divider (fallback: the chevron row). */
|
|
398
|
-
private positionFloatingButton(): void {
|
|
399
|
-
const el = this.floatingButton
|
|
400
|
-
if (el === null) return
|
|
401
|
-
const height = window.innerHeight
|
|
402
|
-
const titlebar = titlebarAreaHeight()
|
|
403
|
-
const headerBottom = this.findHeaderBottom()
|
|
404
|
-
const top = headerBottom !== null
|
|
405
|
-
? clampFloatingTop(headerBottom + FLOATING_HEADER_GAP_PX, height, FLOATING_BUTTON_HEIGHT_PX, titlebar)
|
|
406
|
-
: topAlignedFloatingTop(height, FLOATING_BUTTON_HEIGHT_PX, titlebar)
|
|
407
|
-
el.style.top = `${Math.round(top)}px`
|
|
408
|
-
el.style.transform = 'none'
|
|
409
|
-
}
|
|
410
379
|
|
|
411
380
|
/** Apply one store update with transitions disabled for exactly one frame. */
|
|
412
381
|
private instant(fn: () => void): void {
|
|
@@ -445,9 +414,25 @@ export class PanelLayoutController {
|
|
|
445
414
|
const explorer = this.layout.explorerWidthPx(state)
|
|
446
415
|
const preview = this.layout.previewWidthPx(state)
|
|
447
416
|
|
|
417
|
+
// Detect dsh-term column (appended by the dsh-term plugin after our tracks).
|
|
418
|
+
// When present, preserve its track and offset handles left by its width.
|
|
419
|
+
// Check the grid tokens for [dsh-term] — the col element may exist but not
|
|
420
|
+
// have a track yet (initial mount), so display/width alone are unreliable.
|
|
421
|
+
const gridTokens = parseGridTracks(frame.style.gridTemplateColumns)
|
|
422
|
+
const hasDshTermTrack = gridTokens.includes('[dsh-term]')
|
|
423
|
+
const dshTermCol = hasDshTermTrack ? frame.querySelector<HTMLElement>('[data-dsh-term-col]') : null
|
|
424
|
+
const dshTermOpen = dshTermCol !== null
|
|
425
|
+
&& dshTermCol.style.display !== 'none'
|
|
426
|
+
&& dshTermCol.getBoundingClientRect().width > 0
|
|
427
|
+
const dshTermWidth = dshTermOpen ? Math.round(dshTermCol!.getBoundingClientRect().width) : 0
|
|
428
|
+
|
|
448
429
|
// Five tracks: shell sidebar, center, shell details, preview, explorer.
|
|
449
|
-
|
|
430
|
+
// (Six when dsh-term is open — preserve its track so we don't clobber it.)
|
|
431
|
+
const baseGrid =
|
|
450
432
|
`${this.shellTracks[0]} minmax(0, 1fr) ${this.shellTracks[2]} ${Math.round(preview)}px ${Math.round(explorer)}px`
|
|
433
|
+
frame.style.gridTemplateColumns = dshTermOpen
|
|
434
|
+
? `${baseGrid} [dsh-term] ${dshTermWidth}px`
|
|
435
|
+
: baseGrid
|
|
451
436
|
|
|
452
437
|
// Column contents follow the tracks (both columns always mounted).
|
|
453
438
|
if (this.explorerCol !== null) {
|
|
@@ -457,15 +442,15 @@ export class PanelLayoutController {
|
|
|
457
442
|
this.previewCol.style.visibility = preview > 0 ? 'visible' : 'hidden'
|
|
458
443
|
}
|
|
459
444
|
|
|
460
|
-
// Handles: at the left edge of each panel.
|
|
445
|
+
// Handles: at the left edge of each panel (offset left by dsh-term if open).
|
|
461
446
|
if (this.explorerHandle !== null) {
|
|
462
|
-
const left = Math.round(width - explorer)
|
|
447
|
+
const left = Math.round(width - explorer - dshTermWidth)
|
|
463
448
|
this.explorerHandle.style.left = `${left}px`
|
|
464
449
|
this.explorerHandle.style.marginLeft = `${-EXPLORER_HANDLE_WIDTH / 2}px`
|
|
465
450
|
this.explorerHandle.style.display = explorer > 0 && state.root !== '' ? 'block' : 'none'
|
|
466
451
|
}
|
|
467
452
|
if (this.previewHandle !== null) {
|
|
468
|
-
const left = Math.round(width - explorer - preview)
|
|
453
|
+
const left = Math.round(width - explorer - preview - dshTermWidth)
|
|
469
454
|
this.previewHandle.style.left = `${left}px`
|
|
470
455
|
this.previewHandle.style.display = preview > 0 && state.root !== '' ? 'block' : 'none'
|
|
471
456
|
}
|
|
@@ -485,15 +470,9 @@ export class PanelLayoutController {
|
|
|
485
470
|
this.detailsHandle = frame.querySelector<HTMLElement>('[data-side="details"]')
|
|
486
471
|
}
|
|
487
472
|
if (this.detailsHandle !== null) {
|
|
488
|
-
this.detailsHandle.style.left = `${Math.round(width - detailsTrack - preview - explorer)}px`
|
|
473
|
+
this.detailsHandle.style.left = `${Math.round(width - detailsTrack - preview - explorer - dshTermWidth)}px`
|
|
489
474
|
}
|
|
490
475
|
|
|
491
|
-
// Floating expand button: visible only when the explorer is collapsed.
|
|
492
|
-
if (this.floatingButton !== null) {
|
|
493
|
-
const show = state.root !== '' && state.explorerCollapsed
|
|
494
|
-
this.floatingButton.style.display = show ? 'flex' : 'none'
|
|
495
|
-
this.positionFloatingButton()
|
|
496
|
-
}
|
|
497
476
|
}
|
|
498
477
|
|
|
499
478
|
/**
|
|
@@ -515,11 +494,9 @@ export class PanelLayoutController {
|
|
|
515
494
|
this.previewCol.style.visibility = target === 'preview' ? 'visible' : 'hidden'
|
|
516
495
|
this.previewCol.classList.toggle('filemgr-maximized', target === 'preview' && overlay)
|
|
517
496
|
}
|
|
518
|
-
// No drag chrome while maximized: nothing to resize
|
|
519
|
-
// button only makes sense for the collapsed explorer.
|
|
497
|
+
// No drag chrome while maximized: nothing to resize.
|
|
520
498
|
if (this.explorerHandle !== null) this.explorerHandle.style.display = 'none'
|
|
521
499
|
if (this.previewHandle !== null) this.previewHandle.style.display = 'none'
|
|
522
|
-
if (this.floatingButton !== null) this.floatingButton.style.display = 'none'
|
|
523
500
|
}
|
|
524
501
|
|
|
525
502
|
/** Remove the narrow-screen overlay class from both columns. */
|
|
@@ -538,7 +515,7 @@ export class PanelLayoutController {
|
|
|
538
515
|
this.explorerCol?.remove()
|
|
539
516
|
this.explorerHandle?.remove()
|
|
540
517
|
this.previewHandle?.remove()
|
|
541
|
-
|
|
518
|
+
|
|
542
519
|
if (this.instantTimer !== undefined) clearTimeout(this.instantTimer)
|
|
543
520
|
if (frameElement === this.frame) frameElement = null
|
|
544
521
|
this.frame = null
|
package/src/client/locales.ts
CHANGED
|
@@ -110,6 +110,23 @@ const zh = {
|
|
|
110
110
|
'settings.unsaved': '未保存',
|
|
111
111
|
'settings.saveFailed': '部署未接受这些值,已保留供你修改。',
|
|
112
112
|
'settings.invalidNumber': '请输入数字,留空则使用默认值。',
|
|
113
|
+
|
|
114
|
+
// ── FilePanelDockItem.tsx ──
|
|
115
|
+
'dock.filePanel.label': '文件面板',
|
|
116
|
+
|
|
117
|
+
// ── PreviewPanel.tsx ──
|
|
118
|
+
'preview.addToChat': '添加到对话',
|
|
119
|
+
|
|
120
|
+
// ── FilePickerModal.tsx ──
|
|
121
|
+
'picker.title': '引用项目文件',
|
|
122
|
+
'picker.searchPlaceholder': '搜索工作区文件…',
|
|
123
|
+
'picker.loading': '加载中…',
|
|
124
|
+
'picker.emptyDir': '(空目录)',
|
|
125
|
+
'picker.emptySelection': '选择文件或目录(可多选)',
|
|
126
|
+
'picker.insert': '插入',
|
|
127
|
+
'picker.removeAria': '移除',
|
|
128
|
+
'picker.clearAria': '清空',
|
|
129
|
+
'picker.closeAria': '关闭',
|
|
113
130
|
} as const
|
|
114
131
|
|
|
115
132
|
const en: Record<keyof typeof zh, string> = {
|
|
@@ -217,6 +234,18 @@ const en: Record<keyof typeof zh, string> = {
|
|
|
217
234
|
'settings.unsaved': 'Unsaved',
|
|
218
235
|
'settings.saveFailed': 'The deployment rejected these values; your edits are kept.',
|
|
219
236
|
'settings.invalidNumber': 'Enter a number, or leave it empty to use the default.',
|
|
237
|
+
|
|
238
|
+
'dock.filePanel.label': 'File Panel',
|
|
239
|
+
'preview.addToChat': 'Add to Chat',
|
|
240
|
+
'picker.title': 'Reference Project Files',
|
|
241
|
+
'picker.searchPlaceholder': 'Search workspace files…',
|
|
242
|
+
'picker.loading': 'Loading…',
|
|
243
|
+
'picker.emptyDir': '(empty directory)',
|
|
244
|
+
'picker.emptySelection': 'Select files or directories (multi-select)',
|
|
245
|
+
'picker.insert': 'Insert',
|
|
246
|
+
'picker.removeAria': 'Remove',
|
|
247
|
+
'picker.clearAria': 'Clear',
|
|
248
|
+
'picker.closeAria': 'Close',
|
|
220
249
|
}
|
|
221
250
|
|
|
222
251
|
export type FileManagerPanelKey = keyof typeof zh
|
|
@@ -239,8 +268,25 @@ export function setLanguage(language: string): void {
|
|
|
239
268
|
currentLanguage = language === 'en' ? 'en' : 'zh'
|
|
240
269
|
}
|
|
241
270
|
|
|
271
|
+
/**
|
|
272
|
+
* Reactive translate function bound by the client entry via
|
|
273
|
+
* `ctx.locale.bind(NS)`. When set, `t` delegates to it so every call reads
|
|
274
|
+
* the active locale at call time (re-evaluated on each render). This is the
|
|
275
|
+
* same mechanism session-cleaner / im-gateway use; the legacy
|
|
276
|
+
* `currentLanguage` + `setLanguage` path remains as a fallback for any code
|
|
277
|
+
* path that runs before `bindT` is called.
|
|
278
|
+
*/
|
|
279
|
+
import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots'
|
|
280
|
+
|
|
281
|
+
let _boundT: TranslateNS<'filemgr'> | null = null
|
|
282
|
+
|
|
283
|
+
export function bindT(t: TranslateNS<'filemgr'>): void {
|
|
284
|
+
_boundT = t
|
|
285
|
+
}
|
|
286
|
+
|
|
242
287
|
/** Translate one key with optional params. */
|
|
243
288
|
export function t(key: FileManagerPanelKey, params?: Record<string, string | number>): string {
|
|
289
|
+
if (_boundT !== null) return _boundT(key, params)
|
|
244
290
|
const table = dictionaries[currentLanguage] ?? zh
|
|
245
291
|
const template = table[key] ?? zh[key]
|
|
246
292
|
return params === undefined ? template : format(template, params)
|
package/src/client/mount.tsx
CHANGED
|
@@ -6,12 +6,27 @@
|
|
|
6
6
|
* @module dsh-filemgr/client/mount
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { useSyncExternalStore, type ReactElement } from 'react'
|
|
9
10
|
import { createRoot, type Root } from 'react-dom/client'
|
|
11
|
+
import type { LocaleFace } from '@deepseek-ai/dsh-client-ui-slots'
|
|
10
12
|
import type { PanelStores } from './store.ts'
|
|
11
13
|
import { ExplorerPanel } from './components/ExplorerPanel.tsx'
|
|
12
14
|
import { PreviewPanel } from './preview/PreviewPanel.tsx'
|
|
13
15
|
import type { FileReferenceSelection } from './preview/selection.ts'
|
|
14
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Wrapper that subscribes to locale revision so createRoot-mounted panels
|
|
19
|
+
* re-render on language switch (slot outlets do this automatically via
|
|
20
|
+
* useLocaleRevision; createRoot trees must opt in explicitly).
|
|
21
|
+
*/
|
|
22
|
+
function LocaleAwareRoot({ children, locale }: { children: ReactElement; locale: LocaleFace }): ReactElement {
|
|
23
|
+
useSyncExternalStore(
|
|
24
|
+
(cb: () => void) => locale.subscribe(cb),
|
|
25
|
+
() => locale.getSnapshot().revision,
|
|
26
|
+
)
|
|
27
|
+
return children
|
|
28
|
+
}
|
|
29
|
+
|
|
15
30
|
const EXPLORER_COL_SELECTOR = '[data-filemgr-explorer-col]'
|
|
16
31
|
const PREVIEW_COL_SELECTOR = '[data-filemgr-preview-col]'
|
|
17
32
|
|
|
@@ -52,6 +67,7 @@ export function mountPanels(
|
|
|
52
67
|
onToggleExplorer: () => void,
|
|
53
68
|
onReference: (path: string, isDir: boolean) => void,
|
|
54
69
|
onAddFileReference: (selection: FileReferenceSelection) => boolean,
|
|
70
|
+
locale: LocaleFace,
|
|
55
71
|
): () => void {
|
|
56
72
|
let explorerRoot: Root | undefined
|
|
57
73
|
let previewRoot: Root | undefined
|
|
@@ -59,11 +75,11 @@ export function mountPanels(
|
|
|
59
75
|
|
|
60
76
|
disposers.push(waitForElement(EXPLORER_COL_SELECTOR, (el) => {
|
|
61
77
|
explorerRoot = createRoot(el)
|
|
62
|
-
explorerRoot.render(<ExplorerPanel stores={stores} onToggleCollapse={onToggleExplorer} onReference={onReference}
|
|
78
|
+
explorerRoot.render(<LocaleAwareRoot locale={locale}><ExplorerPanel stores={stores} onToggleCollapse={onToggleExplorer} onReference={onReference} /></LocaleAwareRoot>)
|
|
63
79
|
}))
|
|
64
80
|
disposers.push(waitForElement(PREVIEW_COL_SELECTOR, (el) => {
|
|
65
81
|
previewRoot = createRoot(el)
|
|
66
|
-
previewRoot.render(<PreviewPanel stores={stores} onAddFileReference={onAddFileReference}
|
|
82
|
+
previewRoot.render(<LocaleAwareRoot locale={locale}><PreviewPanel stores={stores} onAddFileReference={onAddFileReference} /></LocaleAwareRoot>)
|
|
67
83
|
}))
|
|
68
84
|
|
|
69
85
|
return () => {
|