@dsh-sparrow/dsh-file-manage 0.1.0-alpha.1 → 0.1.0-alpha.3

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/CHANGELOG.md CHANGED
@@ -2,9 +2,18 @@
2
2
 
3
3
  English | [简体中文](CHANGELOG.zh-CN.md)
4
4
 
5
+ ## 0.1.0-alpha.3 (2026-09-02 · pre-release)
6
+
7
+ - README screenshots now use absolute URLs and are no longer packed into the npm package (functionally identical to the previous release).
8
+
9
+ ## 0.1.0-alpha.2 (2026-09-01 · pre-release)
10
+
11
+ - Full-page loading: the list renders only once entries and totals are both ready (removes the open flicker).
12
+
5
13
  ## 0.1.0-alpha.1 (2026-09-01 · pre-release)
6
14
 
7
15
  - First pre-release, published to the `next` channel for validation; features match the planned `0.1.0` first release
8
16
  - Sidebar "Cloud Files" entry + panel (styled like the official Settings / Archive): list pages of 20, Load more cursor pagination, per-file delete (stronger notice for `dsh-` auto-uploaded files), one-click copy file_id
9
17
  - Total count + drive-style quota bar: used / 25 GiB, adaptive-precision percentage, striped empty area, "Loaded X / N" synced with pagination
10
18
  - Reuses the official DeepSeekFilesClient (connection facts from the llm-deepseek settings section + ctx.credentials); no local persistence
19
+
@@ -2,9 +2,18 @@
2
2
 
3
3
  简体中文 | [English](CHANGELOG.md)
4
4
 
5
+ ## 0.1.0-alpha.3 (2026-09-02 · pre-release)
6
+
7
+ - README 截图改为绝对 URL 引用,图片不再打包进 npm 包(功能与上版一致)。
8
+
9
+ ## 0.1.0-alpha.2 (2026-09-01 · pre-release)
10
+
11
+ - 面板整页 loading:列表与总数都就绪后再展示(消除打开闪动)。
12
+
5
13
  ## 0.1.0-alpha.1 (2026-09-01 · pre-release)
6
14
 
7
15
  - 首个预发布版本,先发 `next` 渠道验证;功能对齐计划中的 `0.1.0` 首版
8
16
  - 侧边栏「云端文件」入口 + 面板(样式对齐官方设置 / 归档面板):每页 20 条列表、Load more 游标翻页、单条删除(`dsh-` 自动上传文件给更强提示)、一键复制 file_id
9
17
  - 总数 + 网盘式配额条:已用 / 25 GiB、自适应精度百分比、条纹空白区、「已加载 X / N」随翻页同步
10
18
  - 复用官方 DeepSeekFilesClient(连接事实取自 llm-deepseek 设置节 + ctx.credentials);无本地持久化
19
+
package/README.md CHANGED
@@ -12,7 +12,7 @@ Large images pasted into DSH are auto-uploaded to the DeepSeek Files API, but th
12
12
  dsh plugin --profile web add @dsh-sparrow/dsh-file-manage
13
13
  ```
14
14
 
15
- Requires dsh ≥ 0.1.2-alpha.3 (verified baseline; earlier versions unverified) and a working `pnpm` (`dsh plugin` forwards installation to pnpm).
15
+ Requires dsh ≥ 0.1.2-alpha.4 and a working `pnpm` (`dsh plugin` forwards installation to pnpm).
16
16
 
17
17
  > Do **not** run `npm install @dsh-sparrow/dsh-file-manage` directly: that only downloads the package into some `node_modules` and does not register it with the DSH web profile. Use the `dsh plugin` command above, then restart DSH.
18
18
 
@@ -35,7 +35,7 @@ Requires dsh ≥ 0.1.2-alpha.3 (verified baseline; earlier versions unverified)
35
35
 
36
36
  ## Screenshot
37
37
 
38
- ![Cloud Files panel](docs/images/panel.png)
38
+ ![Cloud Files panel](https://raw.githubusercontent.com/peiyucn/dsh-sparrow/main/resources/dsh-file-manage.png)
39
39
 
40
40
  ## Uninstall & leftovers
41
41
 
package/README.zh-CN.md CHANGED
@@ -12,7 +12,7 @@ DSH 贴图的大图会自动上传到 DeepSeek Files API(云端文件库),
12
12
  dsh plugin --profile web add @dsh-sparrow/dsh-file-manage
13
13
  ```
14
14
 
15
- 适配 dsh ≥ 0.1.2-alpha.3(本机验证基线;更早版本未验证),并需要可用的 `pnpm`(`dsh plugin` 会把安装操作转发给 pnpm)。
15
+ 适配 dsh ≥ 0.1.2-alpha.4,并需要可用的 `pnpm`(`dsh plugin` 会把安装操作转发给 pnpm)。
16
16
 
17
17
  > **不要**直接执行 `npm install @dsh-sparrow/dsh-file-manage`:那只会把包下载到某个 `node_modules`,不会注册进 DSH 的 web profile。请使用上面的 `dsh plugin` 命令安装,并在安装后重启 DSH。
18
18
 
@@ -35,7 +35,7 @@ dsh plugin --profile web add @dsh-sparrow/dsh-file-manage
35
35
 
36
36
  ## 截图
37
37
 
38
- ![云端文件面板](docs/images/panel.png)
38
+ ![云端文件面板](https://raw.githubusercontent.com/peiyucn/dsh-sparrow/main/resources/dsh-file-manage.png)
39
39
 
40
40
  ## 卸载与残留
41
41
 
@@ -17,14 +17,19 @@ export function FileManageDock({ wide, listFiles, deleteFile, countFiles, t }) {
17
17
  const [busyDelete, setBusyDelete] = useState(false);
18
18
  const [copied, setCopied] = useState(null);
19
19
  const [summary, setSummary] = useState(null);
20
+ /** 总数统计请求尚未落定:与 loading 一起构成首屏 ready 门(2026-09-01 整页 loading)。 */
21
+ const [summaryPending, setSummaryPending] = useState(false);
20
22
  const closeButtonRef = useRef(null);
21
23
  /** 刷新代际:快速关/开面板产生并发请求时,只让最新一次的结果落地(陈旧响应竞态,archive 同款)。 */
22
24
  const refreshSeqRef = useRef(0);
23
25
  /** 「已复制」反馈 2s 复位(archive 同款)。 */
24
26
  const copiedTimerRef = useRef(null);
25
- const loadFirst = useCallback(() => {
27
+ /** 首屏 / 重试共用:列表与总数统计并发拉取,两者都落定才揭开内容(整页 loading 防闪动,2026-09-01)。 */
28
+ const reload = useCallback(() => {
26
29
  const seq = ++refreshSeqRef.current;
27
30
  setLoading(true);
31
+ setSummaryPending(true);
32
+ setSummary(null);
28
33
  setError(null);
29
34
  listFiles()
30
35
  .then(page => {
@@ -43,7 +48,18 @@ export function FileManageDock({ wide, listFiles, deleteFile, countFiles, t }) {
43
48
  if (seq === refreshSeqRef.current)
44
49
  setLoading(false);
45
50
  });
46
- }, [listFiles]);
51
+ // 总数统计为 best-effort:接口失败只隐藏统计行,不影响列表;同样受刷新代际约束。
52
+ void countFiles()
53
+ .then(next => {
54
+ if (seq === refreshSeqRef.current)
55
+ setSummary(next);
56
+ })
57
+ .catch(() => { })
58
+ .finally(() => {
59
+ if (seq === refreshSeqRef.current)
60
+ setSummaryPending(false);
61
+ });
62
+ }, [listFiles, countFiles]);
47
63
  // 官方弹窗行为:打开时聚焦关闭按钮,Esc 关闭。
48
64
  useEffect(() => {
49
65
  if (!open)
@@ -61,16 +77,11 @@ export function FileManageDock({ wide, listFiles, deleteFile, countFiles, t }) {
61
77
  return;
62
78
  setConfirming(null);
63
79
  setSummary(null);
64
- loadFirst();
65
- // 总数统计为 best-effort:接口失败只隐藏统计行,不影响列表;同样受刷新代际约束。
66
- const seq = refreshSeqRef.current;
67
- void countFiles()
68
- .then(next => {
69
- if (seq === refreshSeqRef.current)
70
- setSummary(next);
71
- })
72
- .catch(() => { });
73
- }, [open, loadFirst, countFiles]);
80
+ setRows([]);
81
+ setHasMore(false);
82
+ setLastId(undefined);
83
+ reload();
84
+ }, [open, reload]);
74
85
  useEffect(() => () => {
75
86
  if (copiedTimerRef.current !== null)
76
87
  window.clearTimeout(copiedTimerRef.current);
@@ -101,6 +112,8 @@ export function FileManageDock({ wide, listFiles, deleteFile, countFiles, t }) {
101
112
  setError(t('copyFailed'));
102
113
  }
103
114
  }, [t]);
115
+ /** 首屏 ready 门:列表 + 总数都落定前展示整页 loading(2026-09-01)。 */
116
+ const initialLoading = loading || summaryPending;
104
117
  const quotaRatio = summary === null ? 0 : storageUsageRatio(summary.totalBytes, summary.quotaBytes);
105
118
  const submitDelete = useCallback(() => {
106
119
  if (confirming === null || busyDelete)
@@ -126,7 +139,7 @@ export function FileManageDock({ wide, listFiles, deleteFile, countFiles, t }) {
126
139
  ? _jsx("div", { className: "dsh-file-manage-quota-fill", style: { width: `${Math.round(quotaRatio * 100)}%` } })
127
140
  : null] }), _jsx("p", { className: "dsh-file-manage-count", children: rows.length < summary.count
128
141
  ? t('summary.loaded', { loaded: rows.length, count: summary.count })
129
- : t('summary.count', { count: summary.count }) })] })) : null, _jsxs("div", { style: { ...styles.body, padding: summary !== null ? '0 24px 24px' : '12px 24px 24px' }, className: "dsh-file-manage-body", children: [error !== null ? (_jsxs("p", { role: "alert", style: { ...styles.secondarySmall, margin: '0 0 12px', color: 'var(--dsw-alias-state-error-primary, #c62828)' }, children: [error, ' ', _jsx("button", { type: "button", className: "dsh-file-manage-btn", onClick: loadFirst, children: t('retry') })] })) : null, loading ? _jsx("p", { style: styles.secondarySmall, children: t('loading') }) : null, !loading && error === null && rows.length === 0 ? _jsx("p", { style: styles.secondarySmall, children: t('empty') }) : null, rows.length > 0 ? (_jsx("div", { className: "dsh-file-manage-card", children: rows.map(row => (_jsxs("div", { style: styles.row, children: [_jsxs("div", { style: { minWidth: 0 }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 6, minWidth: 0 }, children: [_jsx("span", { style: styles.title, title: row.filename, children: row.filename }), row.dshOwned ? _jsx("span", { className: "dsh-file-manage-badge", children: t('dshBadge') }) : null] }), _jsxs("div", { style: styles.secondarySmall, children: [row.sizeLabel, " \u00B7 ", row.createdAtLabel, row.expiresAtLabel !== undefined ? ` · ${t('expires', { time: row.expiresAtLabel })}` : ''] })] }), _jsxs("div", { style: styles.actions, children: [_jsx("button", { type: "button", className: "dsh-file-manage-btn", onClick: () => { void copyId(row); }, children: copied === row.id ? t('copied') : t('copy') }), _jsx("button", { type: "button", className: "dsh-file-manage-btn dsh-file-manage-btn-danger", onClick: () => { setConfirming(row); }, children: t('delete') })] })] }, row.id))) })) : null] }), hasMore && !loading ? (_jsx("div", { style: styles.footerBar, children: _jsx("button", { type: "button", className: "dsh-file-manage-btn", disabled: loadingMore, onClick: () => { void loadMore(); }, children: loadingMore ? t('loading') : t('loadMore') }) })) : null] }) })) : null, confirming !== null ? (_jsx("div", { className: "dsh-file-manage-confirm-overlay", role: "presentation", onMouseDown: (event) => {
142
+ : t('summary.count', { count: summary.count }) })] })) : null, _jsx("div", { style: { ...styles.body, padding: summary !== null ? '0 24px 24px' : '12px 24px 24px' }, className: "dsh-file-manage-body", children: initialLoading ? (_jsxs("div", { className: "dsh-file-manage-loading", role: "status", children: [_jsx("span", { className: "dsh-file-manage-spinner", "aria-hidden": true }), _jsx("span", { children: t('loading') })] })) : (_jsxs(_Fragment, { children: [error !== null ? (_jsxs("p", { role: "alert", style: { ...styles.secondarySmall, margin: '0 0 12px', color: 'var(--dsw-alias-state-error-primary, #c62828)' }, children: [error, ' ', _jsx("button", { type: "button", className: "dsh-file-manage-btn", onClick: () => { reload(); }, children: t('retry') })] })) : null, error === null && rows.length === 0 ? _jsx("p", { style: styles.secondarySmall, children: t('empty') }) : null, rows.length > 0 ? (_jsx("div", { className: "dsh-file-manage-card", children: rows.map(row => (_jsxs("div", { style: styles.row, children: [_jsxs("div", { style: { minWidth: 0 }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 6, minWidth: 0 }, children: [_jsx("span", { style: styles.title, title: row.filename, children: row.filename }), row.dshOwned ? _jsx("span", { className: "dsh-file-manage-badge", children: t('dshBadge') }) : null] }), _jsxs("div", { style: styles.secondarySmall, children: [row.sizeLabel, " \u00B7 ", row.createdAtLabel, row.expiresAtLabel !== undefined ? ` · ${t('expires', { time: row.expiresAtLabel })}` : ''] })] }), _jsxs("div", { style: styles.actions, children: [_jsx("button", { type: "button", className: "dsh-file-manage-btn", onClick: () => { void copyId(row); }, children: copied === row.id ? t('copied') : t('copy') }), _jsx("button", { type: "button", className: "dsh-file-manage-btn dsh-file-manage-btn-danger", onClick: () => { setConfirming(row); }, children: t('delete') })] })] }, row.id))) })) : null] })) }), hasMore && !initialLoading ? (_jsx("div", { style: styles.footerBar, children: _jsx("button", { type: "button", className: "dsh-file-manage-btn", disabled: loadingMore, onClick: () => { void loadMore(); }, children: loadingMore ? t('loading') : t('loadMore') }) })) : null] }) })) : null, confirming !== null ? (_jsx("div", { className: "dsh-file-manage-confirm-overlay", role: "presentation", onMouseDown: (event) => {
130
143
  if (event.target === event.currentTarget && !busyDelete)
131
144
  setConfirming(null);
132
145
  }, children: _jsxs("div", { className: "dsh-file-manage-confirm-card", role: "alertdialog", "aria-modal": "true", "aria-label": t('delete'), onKeyDown: (event) => {
@@ -45,6 +45,7 @@ export function ensureFileManageStyles() {
45
45
  gap: 0;
46
46
  padding: 0;
47
47
  border-radius: 50%;
48
+ corner-shape: round;
48
49
  }
49
50
  .dsh-file-manage-trigger-icon {
50
51
  flex: none;
@@ -54,6 +55,32 @@ export function ensureFileManageStyles() {
54
55
  text-overflow: ellipsis;
55
56
  white-space: nowrap;
56
57
  }
58
+ /* 整页 loading:首屏数据(列表 + 总数)落定前占满内容区,避免「打开后加载闪动」(2026-09-01)。 */
59
+ .dsh-file-manage-loading {
60
+ display: flex;
61
+ align-items: center;
62
+ justify-content: center;
63
+ gap: 10px;
64
+ min-height: 240px;
65
+ color: var(--dsw-alias-label-secondary, #6b7280);
66
+ font-size: 14px;
67
+ line-height: 22px;
68
+ }
69
+ .dsh-file-manage-spinner {
70
+ width: 16px;
71
+ height: 16px;
72
+ border: 2px solid var(--dsw-alias-border-l1, #d4d8e0);
73
+ border-top-color: var(--dsw-alias-button-info-fill, #4d6bfe);
74
+ border-radius: 50%;
75
+ corner-shape: round;
76
+ animation: dsh-file-manage-spin 0.8s linear infinite;
77
+ }
78
+ @keyframes dsh-file-manage-spin {
79
+ to { transform: rotate(360deg); }
80
+ }
81
+ @media (prefers-reduced-motion: reduce) {
82
+ .dsh-file-manage-spinner { animation: none; }
83
+ }
57
84
  /* 面板滚动区:官方 settings 同款——elevated surface 重绑 l2 滚动条 token(base 默认 l1,浮层上对比度不对)。 */
58
85
  .dsh-file-manage-body {
59
86
  --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);
@@ -84,7 +111,7 @@ export function ensureFileManageStyles() {
84
111
  height: 28px;
85
112
  padding: 0;
86
113
  border: none;
87
- border-radius: 28px;
114
+ border-radius: 8px;
88
115
  outline: none;
89
116
  background: transparent;
90
117
  cursor: pointer;
@@ -98,20 +125,22 @@ export function ensureFileManageStyles() {
98
125
  padding: 1px 6px;
99
126
  border: 1px solid var(--dsw-alias-border-l2, #e2e5ea);
100
127
  border-radius: 999px;
128
+ corner-shape: round;
101
129
  color: var(--dsw-alias-label-caption, #8a919f);
102
130
  font-size: 11px;
103
131
  line-height: 16px;
104
132
  }
105
133
  .dsh-file-manage-btn {
134
+ /* 官方 Button.sm 同款几何:h28 + r14 胶囊(超椭圆角随官方全局规则自动生效)。 */
106
135
  height: 28px;
107
- padding: 0 12px;
108
- border: 1px solid var(--dsw-alias-border-l1, #d4d8e0);
109
- border-radius: 999px;
136
+ padding: 0 10px;
137
+ border: 0.5px solid var(--dsw-alias-border-l3, #d4d8e0);
138
+ border-radius: 14px;
110
139
  outline: none;
111
140
  background: transparent;
112
141
  color: var(--dsw-alias-label-primary, #1f2329);
113
- font-size: 13px;
114
- line-height: 20px;
142
+ font-size: 12px;
143
+ line-height: 18px;
115
144
  white-space: nowrap;
116
145
  cursor: pointer;
117
146
  }
@@ -145,7 +174,7 @@ export function ensureFileManageStyles() {
145
174
  border-radius: 16px;
146
175
  background: var(--dsw-alias-bg-layer-2, #f6f7f9);
147
176
  color: var(--dsw-alias-label-primary, #1f2329);
148
- box-shadow: var(--dsw-shadow-lv3, 0 12px 40px rgba(0,0,0,0.22));
177
+ box-shadow: var(--dsw-elevation-prominent, 0 12px 40px rgba(0,0,0,0.22));
149
178
  }
150
179
  .dsh-file-manage-confirm-title {
151
180
  margin: 0;
@@ -184,8 +213,8 @@ export function ensureFileManageStyles() {
184
213
  flex-direction: column;
185
214
  margin: 0 0 12px;
186
215
  padding: 8px 12px 12px;
187
- border: 1px solid var(--dsw-alias-border-l2, #e2e5ea);
188
- border-radius: 12px;
216
+ border: 0.5px solid var(--dsw-alias-border-l4, #e2e5ea);
217
+ border-radius: 16px;
189
218
  }
190
219
  /* 配额容量条:加厚 + 未使用区斜纹(repeating-linear-gradient),与分割线区分;填充盖住斜纹。
191
220
  容量文字绝对定位居中叠加在条上。 */
@@ -253,7 +282,7 @@ export const styles = {
253
282
  padding: 0,
254
283
  background: 'var(--dsw-alias-bg-layer-2, #f6f7f9)',
255
284
  color: 'var(--dsw-alias-label-primary, #1f2329)',
256
- boxShadow: 'var(--dsw-shadow-lv3, 0 12px 40px rgba(0,0,0,0.22))',
285
+ boxShadow: 'var(--dsw-elevation-prominent, 0 12px 40px rgba(0,0,0,0.22))',
257
286
  },
258
287
  body: {
259
288
  flex: 1,
package/lib/client.js CHANGED
@@ -142,6 +142,7 @@ function ensureFileManageStyles() {
142
142
  gap: 0;
143
143
  padding: 0;
144
144
  border-radius: 50%;
145
+ corner-shape: round;
145
146
  }
146
147
  .dsh-file-manage-trigger-icon {
147
148
  flex: none;
@@ -151,6 +152,32 @@ function ensureFileManageStyles() {
151
152
  text-overflow: ellipsis;
152
153
  white-space: nowrap;
153
154
  }
155
+ /* \u6574\u9875 loading\uFF1A\u9996\u5C4F\u6570\u636E\uFF08\u5217\u8868 + \u603B\u6570\uFF09\u843D\u5B9A\u524D\u5360\u6EE1\u5185\u5BB9\u533A\uFF0C\u907F\u514D\u300C\u6253\u5F00\u540E\u52A0\u8F7D\u95EA\u52A8\u300D\uFF082026-09-01\uFF09\u3002 */
156
+ .dsh-file-manage-loading {
157
+ display: flex;
158
+ align-items: center;
159
+ justify-content: center;
160
+ gap: 10px;
161
+ min-height: 240px;
162
+ color: var(--dsw-alias-label-secondary, #6b7280);
163
+ font-size: 14px;
164
+ line-height: 22px;
165
+ }
166
+ .dsh-file-manage-spinner {
167
+ width: 16px;
168
+ height: 16px;
169
+ border: 2px solid var(--dsw-alias-border-l1, #d4d8e0);
170
+ border-top-color: var(--dsw-alias-button-info-fill, #4d6bfe);
171
+ border-radius: 50%;
172
+ corner-shape: round;
173
+ animation: dsh-file-manage-spin 0.8s linear infinite;
174
+ }
175
+ @keyframes dsh-file-manage-spin {
176
+ to { transform: rotate(360deg); }
177
+ }
178
+ @media (prefers-reduced-motion: reduce) {
179
+ .dsh-file-manage-spinner { animation: none; }
180
+ }
154
181
  /* \u9762\u677F\u6EDA\u52A8\u533A\uFF1A\u5B98\u65B9 settings \u540C\u6B3E\u2014\u2014elevated surface \u91CD\u7ED1 l2 \u6EDA\u52A8\u6761 token\uFF08base \u9ED8\u8BA4 l1\uFF0C\u6D6E\u5C42\u4E0A\u5BF9\u6BD4\u5EA6\u4E0D\u5BF9\uFF09\u3002 */
155
182
  .dsh-file-manage-body {
156
183
  --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);
@@ -181,7 +208,7 @@ function ensureFileManageStyles() {
181
208
  height: 28px;
182
209
  padding: 0;
183
210
  border: none;
184
- border-radius: 28px;
211
+ border-radius: 8px;
185
212
  outline: none;
186
213
  background: transparent;
187
214
  cursor: pointer;
@@ -195,20 +222,22 @@ function ensureFileManageStyles() {
195
222
  padding: 1px 6px;
196
223
  border: 1px solid var(--dsw-alias-border-l2, #e2e5ea);
197
224
  border-radius: 999px;
225
+ corner-shape: round;
198
226
  color: var(--dsw-alias-label-caption, #8a919f);
199
227
  font-size: 11px;
200
228
  line-height: 16px;
201
229
  }
202
230
  .dsh-file-manage-btn {
231
+ /* \u5B98\u65B9 Button.sm \u540C\u6B3E\u51E0\u4F55\uFF1Ah28 + r14 \u80F6\u56CA\uFF08\u8D85\u692D\u5706\u89D2\u968F\u5B98\u65B9\u5168\u5C40\u89C4\u5219\u81EA\u52A8\u751F\u6548\uFF09\u3002 */
203
232
  height: 28px;
204
- padding: 0 12px;
205
- border: 1px solid var(--dsw-alias-border-l1, #d4d8e0);
206
- border-radius: 999px;
233
+ padding: 0 10px;
234
+ border: 0.5px solid var(--dsw-alias-border-l3, #d4d8e0);
235
+ border-radius: 14px;
207
236
  outline: none;
208
237
  background: transparent;
209
238
  color: var(--dsw-alias-label-primary, #1f2329);
210
- font-size: 13px;
211
- line-height: 20px;
239
+ font-size: 12px;
240
+ line-height: 18px;
212
241
  white-space: nowrap;
213
242
  cursor: pointer;
214
243
  }
@@ -242,7 +271,7 @@ function ensureFileManageStyles() {
242
271
  border-radius: 16px;
243
272
  background: var(--dsw-alias-bg-layer-2, #f6f7f9);
244
273
  color: var(--dsw-alias-label-primary, #1f2329);
245
- box-shadow: var(--dsw-shadow-lv3, 0 12px 40px rgba(0,0,0,0.22));
274
+ box-shadow: var(--dsw-elevation-prominent, 0 12px 40px rgba(0,0,0,0.22));
246
275
  }
247
276
  .dsh-file-manage-confirm-title {
248
277
  margin: 0;
@@ -281,8 +310,8 @@ function ensureFileManageStyles() {
281
310
  flex-direction: column;
282
311
  margin: 0 0 12px;
283
312
  padding: 8px 12px 12px;
284
- border: 1px solid var(--dsw-alias-border-l2, #e2e5ea);
285
- border-radius: 12px;
313
+ border: 0.5px solid var(--dsw-alias-border-l4, #e2e5ea);
314
+ border-radius: 16px;
286
315
  }
287
316
  /* \u914D\u989D\u5BB9\u91CF\u6761\uFF1A\u52A0\u539A + \u672A\u4F7F\u7528\u533A\u659C\u7EB9\uFF08repeating-linear-gradient\uFF09\uFF0C\u4E0E\u5206\u5272\u7EBF\u533A\u5206\uFF1B\u586B\u5145\u76D6\u4F4F\u659C\u7EB9\u3002
288
317
  \u5BB9\u91CF\u6587\u5B57\u7EDD\u5BF9\u5B9A\u4F4D\u5C45\u4E2D\u53E0\u52A0\u5728\u6761\u4E0A\u3002 */
@@ -349,7 +378,7 @@ var styles = {
349
378
  padding: 0,
350
379
  background: "var(--dsw-alias-bg-layer-2, #f6f7f9)",
351
380
  color: "var(--dsw-alias-label-primary, #1f2329)",
352
- boxShadow: "var(--dsw-shadow-lv3, 0 12px 40px rgba(0,0,0,0.22))"
381
+ boxShadow: "var(--dsw-elevation-prominent, 0 12px 40px rgba(0,0,0,0.22))"
353
382
  },
354
383
  body: {
355
384
  flex: 1,
@@ -405,12 +434,15 @@ function FileManageDock({ wide, listFiles, deleteFile, countFiles, t }) {
405
434
  const [busyDelete, setBusyDelete] = (0, import_react.useState)(false);
406
435
  const [copied, setCopied] = (0, import_react.useState)(null);
407
436
  const [summary, setSummary] = (0, import_react.useState)(null);
437
+ const [summaryPending, setSummaryPending] = (0, import_react.useState)(false);
408
438
  const closeButtonRef = (0, import_react.useRef)(null);
409
439
  const refreshSeqRef = (0, import_react.useRef)(0);
410
440
  const copiedTimerRef = (0, import_react.useRef)(null);
411
- const loadFirst = (0, import_react.useCallback)(() => {
441
+ const reload = (0, import_react.useCallback)(() => {
412
442
  const seq = ++refreshSeqRef.current;
413
443
  setLoading(true);
444
+ setSummaryPending(true);
445
+ setSummary(null);
414
446
  setError(null);
415
447
  listFiles().then((page) => {
416
448
  if (seq !== refreshSeqRef.current) return;
@@ -423,7 +455,13 @@ function FileManageDock({ wide, listFiles, deleteFile, countFiles, t }) {
423
455
  }).finally(() => {
424
456
  if (seq === refreshSeqRef.current) setLoading(false);
425
457
  });
426
- }, [listFiles]);
458
+ void countFiles().then((next) => {
459
+ if (seq === refreshSeqRef.current) setSummary(next);
460
+ }).catch(() => {
461
+ }).finally(() => {
462
+ if (seq === refreshSeqRef.current) setSummaryPending(false);
463
+ });
464
+ }, [listFiles, countFiles]);
427
465
  (0, import_react.useEffect)(() => {
428
466
  if (!open) return;
429
467
  closeButtonRef.current?.focus();
@@ -439,13 +477,11 @@ function FileManageDock({ wide, listFiles, deleteFile, countFiles, t }) {
439
477
  if (!open) return;
440
478
  setConfirming(null);
441
479
  setSummary(null);
442
- loadFirst();
443
- const seq = refreshSeqRef.current;
444
- void countFiles().then((next) => {
445
- if (seq === refreshSeqRef.current) setSummary(next);
446
- }).catch(() => {
447
- });
448
- }, [open, loadFirst, countFiles]);
480
+ setRows([]);
481
+ setHasMore(false);
482
+ setLastId(void 0);
483
+ reload();
484
+ }, [open, reload]);
449
485
  (0, import_react.useEffect)(() => () => {
450
486
  if (copiedTimerRef.current !== null) window.clearTimeout(copiedTimerRef.current);
451
487
  }, []);
@@ -475,6 +511,7 @@ function FileManageDock({ wide, listFiles, deleteFile, countFiles, t }) {
475
511
  setError(t("copyFailed"));
476
512
  }
477
513
  }, [t]);
514
+ const initialLoading = loading || summaryPending;
478
515
  const quotaRatio = summary === null ? 0 : storageUsageRatio(summary.totalBytes, summary.quotaBytes);
479
516
  const submitDelete = (0, import_react.useCallback)(() => {
480
517
  if (confirming === null || busyDelete) return;
@@ -525,14 +562,18 @@ function FileManageDock({ wide, listFiles, deleteFile, countFiles, t }) {
525
562
  ] }),
526
563
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dsh-file-manage-count", children: rows.length < summary.count ? t("summary.loaded", { loaded: rows.length, count: summary.count }) : t("summary.count", { count: summary.count }) })
527
564
  ] }) : null,
528
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { ...styles.body, padding: summary !== null ? "0 24px 24px" : "12px 24px 24px" }, className: "dsh-file-manage-body", children: [
565
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...styles.body, padding: summary !== null ? "0 24px 24px" : "12px 24px 24px" }, className: "dsh-file-manage-body", children: initialLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dsh-file-manage-loading", role: "status", children: [
566
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dsh-file-manage-spinner", "aria-hidden": true }),
567
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: t("loading") })
568
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
529
569
  error !== null ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { role: "alert", style: { ...styles.secondarySmall, margin: "0 0 12px", color: "var(--dsw-alias-state-error-primary, #c62828)" }, children: [
530
570
  error,
531
571
  " ",
532
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "dsh-file-manage-btn", onClick: loadFirst, children: t("retry") })
572
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "dsh-file-manage-btn", onClick: () => {
573
+ reload();
574
+ }, children: t("retry") })
533
575
  ] }) : null,
534
- loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.secondarySmall, children: t("loading") }) : null,
535
- !loading && error === null && rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.secondarySmall, children: t("empty") }) : null,
576
+ error === null && rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.secondarySmall, children: t("empty") }) : null,
536
577
  rows.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dsh-file-manage-card", children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.row, children: [
537
578
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { minWidth: 0 }, children: [
538
579
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6, minWidth: 0 }, children: [
@@ -571,8 +612,8 @@ function FileManageDock({ wide, listFiles, deleteFile, countFiles, t }) {
571
612
  )
572
613
  ] })
573
614
  ] }, row.id)) }) : null
574
- ] }),
575
- hasMore && !loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.footerBar, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
615
+ ] }) }),
616
+ hasMore && !initialLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.footerBar, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
576
617
  "button",
577
618
  {
578
619
  type: "button",
@@ -24,7 +24,7 @@ export declare const styles: {
24
24
  padding: number;
25
25
  background: string;
26
26
  color: "var(--dsw-alias-label-primary, #1f2329)";
27
- boxShadow: "var(--dsw-shadow-lv3, 0 12px 40px rgba(0,0,0,0.22))";
27
+ boxShadow: "var(--dsw-elevation-prominent, 0 12px 40px rgba(0,0,0,0.22))";
28
28
  };
29
29
  readonly body: {
30
30
  flex: number;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dsh-sparrow/dsh-file-manage",
3
3
  "description": "DSH web plugin: manage DeepSeek Files API cloud files from the sidebar — list with cursor pagination, delete, and copy file_id (reuses the official DeepSeekFilesClient, no extra credentials)",
4
- "version": "0.1.0-alpha.1",
4
+ "version": "0.1.0-alpha.3",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -26,7 +26,6 @@
26
26
  "lib/**/*.js",
27
27
  "lib/types/**/*.d.ts",
28
28
  "cordis.patch.yml",
29
- "docs/images/**",
30
29
  "README.md",
31
30
  "README.zh-CN.md",
32
31
  "CHANGELOG.md", "CHANGELOG.zh-CN.md"
@@ -49,11 +48,11 @@
49
48
  },
50
49
  "peerDependencies": {
51
50
  "@deepseek-ai/cordis": "^0.1.1-rc.2 || ^4.0.1",
52
- "@deepseek-ai/dsh-credentials": "^0.1.1-rc.2",
53
- "@deepseek-ai/dsh-host-webserver": "^0.1.1-rc.2",
54
- "@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
55
- "@deepseek-ai/dsh-llm-deepseek": "^0.1.1-rc.2",
56
- "@deepseek-ai/dsh-settings": "^0.1.1-rc.2"
51
+ "@deepseek-ai/dsh-credentials": "^0.1.2-alpha.4",
52
+ "@deepseek-ai/dsh-host-webserver": "^0.1.2-alpha.4",
53
+ "@deepseek-ai/dsh-llm": "^0.1.2-alpha.4",
54
+ "@deepseek-ai/dsh-llm-deepseek": "^0.1.2-alpha.4",
55
+ "@deepseek-ai/dsh-settings": "^0.1.2-alpha.4"
57
56
  },
58
57
  "devDependencies": {
59
58
  "@deepseek-ai/cordis": "0.1.1-rc.2",
@@ -62,14 +61,14 @@
62
61
  "@deepseek-ai/dsh-client-ui-primitives": "0.1.1-rc.2",
63
62
  "@deepseek-ai/dsh-client-ui-sidebar": "0.1.1-rc.2",
64
63
  "@deepseek-ai/dsh-client-ui-slots": "0.1.1-rc.2",
65
- "@deepseek-ai/dsh-credentials": "0.1.1-rc.2",
66
- "@deepseek-ai/dsh-host-webserver": "0.1.1-rc.2",
67
- "@deepseek-ai/dsh-llm": "0.1.1-rc.2",
68
- "@deepseek-ai/dsh-llm-deepseek": "0.1.1-rc.2",
69
- "@deepseek-ai/dsh-settings": "0.1.1-rc.2",
64
+ "@deepseek-ai/dsh-credentials": "0.1.2-alpha.4",
65
+ "@deepseek-ai/dsh-host-webserver": "0.1.2-alpha.4",
66
+ "@deepseek-ai/dsh-llm": "0.1.2-alpha.4",
67
+ "@deepseek-ai/dsh-llm-deepseek": "0.1.2-alpha.4",
68
+ "@deepseek-ai/dsh-settings": "0.1.2-alpha.4",
70
69
  "@types/node": "^22.20.0",
71
70
  "@types/react": "~18.3.1",
72
71
  "@types/react-dom": "~18.3.1",
73
72
  "react": "^18.2.0"
74
73
  }
75
- }
74
+ }
Binary file