dsh-token-gauge 0.1.8 → 0.1.9
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.mjs +82 -22
- package/package.json +6 -2
- package/src/client.ts +71 -32
package/lib/client.mjs
CHANGED
|
@@ -966,34 +966,94 @@ function GaugePanel() {
|
|
|
966
966
|
}
|
|
967
967
|
});
|
|
968
968
|
}
|
|
969
|
+
function GaugeTab() {
|
|
970
|
+
return import_react.default.createElement("div", {
|
|
971
|
+
ref: gaugeRef,
|
|
972
|
+
className: "tg-panel-root",
|
|
973
|
+
style: {
|
|
974
|
+
width: "100%",
|
|
975
|
+
height: "100%",
|
|
976
|
+
boxSizing: "border-box",
|
|
977
|
+
overflow: "hidden",
|
|
978
|
+
background: "var(--dsw-alias-bg-base)",
|
|
979
|
+
color: "var(--dsw-alias-label-primary)"
|
|
980
|
+
}
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
var GaugeIcon = (size) => {
|
|
984
|
+
const s = typeof size === "number" && size > 0 ? size : 16;
|
|
985
|
+
const svgProps = {
|
|
986
|
+
width: s,
|
|
987
|
+
height: s,
|
|
988
|
+
viewBox: "0 0 16 16",
|
|
989
|
+
fill: "none",
|
|
990
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
991
|
+
"aria-hidden": "true"
|
|
992
|
+
};
|
|
993
|
+
const arc = import_react.default.createElement("path", {
|
|
994
|
+
d: "M2.6 11.6a5.6 5.6 0 1 1 10.8 0",
|
|
995
|
+
stroke: "currentColor",
|
|
996
|
+
strokeWidth: 1.5,
|
|
997
|
+
strokeLinecap: "round"
|
|
998
|
+
});
|
|
999
|
+
const needle = import_react.default.createElement("path", {
|
|
1000
|
+
d: "M8 11.6 10.4 7.2",
|
|
1001
|
+
stroke: "currentColor",
|
|
1002
|
+
strokeWidth: 1.5,
|
|
1003
|
+
strokeLinecap: "round"
|
|
1004
|
+
});
|
|
1005
|
+
return import_react.default.createElement("svg", svgProps, arc, needle);
|
|
1006
|
+
};
|
|
1007
|
+
var TAB_ORDER = 90;
|
|
969
1008
|
var name = PLUGIN_ID;
|
|
970
1009
|
var inject = ["slots"];
|
|
971
1010
|
function apply(ctx) {
|
|
972
|
-
let
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
1011
|
+
let unregisterTab = null;
|
|
1012
|
+
let overlayDispose = void 0;
|
|
1013
|
+
let registeredViaBetter = false;
|
|
1014
|
+
let fallbackTimer = void 0;
|
|
1015
|
+
const tryMountOverlay = (reason) => {
|
|
1016
|
+
if (registeredViaBetter || overlayDispose !== void 0) return;
|
|
1017
|
+
console.warn(`[dsh-token-gauge] ${reason}\uFF0C\u4EEA\u8868\u76D8\u6539\u4E3A\u53F3\u4E0B\u89D2\u6D6E\u5C42\u663E\u793A\uFF08\u4ECD\u53EF\u7528\uFF09\u3002`);
|
|
1018
|
+
try {
|
|
1019
|
+
overlayDispose = ctx.slots.register(
|
|
1020
|
+
{ name: "shell.overlay", id: PLUGIN_ID, order: 100, label: "Token \u4EEA\u8868\u76D8" },
|
|
1021
|
+
() => import_react.default.createElement(GaugePanel)
|
|
1022
|
+
);
|
|
1023
|
+
} catch (e) {
|
|
1024
|
+
console.error("[dsh-token-gauge] \u6D6E\u5C42\u515C\u5E95\u4E5F\u5931\u8D25", e);
|
|
1025
|
+
}
|
|
983
1026
|
};
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
if (typeof
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
1027
|
+
const disposeSidebar = ctx.inject(["betterSidebar"], (sidebarCtx) => {
|
|
1028
|
+
const sidebar = sidebarCtx.betterSidebar;
|
|
1029
|
+
if (!sidebar || typeof sidebar.registerTab !== "function") return;
|
|
1030
|
+
unregisterTab = sidebar.registerTab({
|
|
1031
|
+
id: PLUGIN_ID,
|
|
1032
|
+
title: "Token \u4EEA\u8868\u76D8",
|
|
1033
|
+
single: true,
|
|
1034
|
+
order: TAB_ORDER,
|
|
1035
|
+
icon: GaugeIcon,
|
|
1036
|
+
component: () => import_react.default.createElement(GaugeTab)
|
|
1037
|
+
});
|
|
1038
|
+
registeredViaBetter = true;
|
|
1039
|
+
if (typeof fallbackTimer !== "undefined") clearTimeout(fallbackTimer);
|
|
1040
|
+
try {
|
|
1041
|
+
if (typeof sidebar.openTab === "function") sidebar.openTab({ type: PLUGIN_ID, single: true });
|
|
1042
|
+
} catch (e) {
|
|
990
1043
|
}
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1044
|
+
return () => {
|
|
1045
|
+
if (unregisterTab) unregisterTab();
|
|
1046
|
+
};
|
|
1047
|
+
});
|
|
1048
|
+
fallbackTimer = setTimeout(() => {
|
|
1049
|
+
if (!registeredViaBetter) {
|
|
1050
|
+
tryMountOverlay("\u672A\u53D6\u5F97 dsh-better-sidebar \u670D\u52A1\uFF08\u8BF7\u786E\u8BA4\u5176\u5DF2\u5B89\u88C5\u5E76\u542F\u7528\uFF09");
|
|
1051
|
+
}
|
|
1052
|
+
}, 3e4);
|
|
994
1053
|
return () => {
|
|
995
|
-
if (typeof
|
|
996
|
-
if (typeof
|
|
1054
|
+
if (typeof fallbackTimer !== "undefined") clearTimeout(fallbackTimer);
|
|
1055
|
+
if (typeof disposeSidebar === "function") disposeSidebar();
|
|
1056
|
+
if (typeof overlayDispose === "function") overlayDispose();
|
|
997
1057
|
};
|
|
998
1058
|
}
|
|
999
1059
|
; return module.exports; } });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-token-gauge",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "DSH 机车风格 Token 用量/费用仪表盘侧边栏插件(稳定版 0.1.1-rc.x 兼容)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.mjs",
|
|
@@ -60,7 +60,8 @@
|
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
62
|
"@deepseek-ai/cordis": "*",
|
|
63
|
-
"@deepseek-ai/dsh-host-webserver": "*"
|
|
63
|
+
"@deepseek-ai/dsh-host-webserver": "*",
|
|
64
|
+
"dsh-better-sidebar": ">=0.15.2"
|
|
64
65
|
},
|
|
65
66
|
"peerDependenciesMeta": {
|
|
66
67
|
"@deepseek-ai/cordis": {
|
|
@@ -68,6 +69,9 @@
|
|
|
68
69
|
},
|
|
69
70
|
"@deepseek-ai/dsh-host-webserver": {
|
|
70
71
|
"optional": true
|
|
72
|
+
},
|
|
73
|
+
"dsh-better-sidebar": {
|
|
74
|
+
"optional": true
|
|
71
75
|
}
|
|
72
76
|
},
|
|
73
77
|
"devDependencies": {
|
package/src/client.ts
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
// 通过同域 HTTP 与 Host 半边通信:
|
|
5
5
|
// GET /plugins/dsh-token-gauge/state -> 完整 State(JSON)
|
|
6
6
|
// POST /plugins/dsh-token-gauge/cmd -> {type,payload} -> 更新后 State
|
|
7
|
-
//
|
|
7
|
+
// 优先把仪表盘注册到 dsh-better-sidebar 的右侧工作台 Tab(停靠侧边栏);若 better-sidebar
|
|
8
|
+
// 未就绪,回退到官方 shell.overlay 浮层(双模式,保证仪表盘永远可见)。
|
|
8
9
|
// 为避免与运行时 React 产生双实例 hook 冲突,本组件不调用任何 hook,
|
|
9
10
|
// 仅在 ref 回调里挂载一次原生 DOM 仪表盘,并自行轮询刷新。
|
|
10
11
|
// ============================================================================
|
|
@@ -223,6 +224,22 @@ function GaugePanel(): React.ReactElement {
|
|
|
223
224
|
})
|
|
224
225
|
}
|
|
225
226
|
|
|
227
|
+
// 停靠在 better-sidebar 工作台 Tab 内的面板:填满容器(非固定定位),同样零 hook、ref 挂原生 DOM。
|
|
228
|
+
function GaugeTab(): React.ReactElement {
|
|
229
|
+
return React.createElement('div', {
|
|
230
|
+
ref: gaugeRef,
|
|
231
|
+
className: 'tg-panel-root',
|
|
232
|
+
style: {
|
|
233
|
+
width: '100%',
|
|
234
|
+
height: '100%',
|
|
235
|
+
boxSizing: 'border-box',
|
|
236
|
+
overflow: 'hidden',
|
|
237
|
+
background: 'var(--dsw-alias-bg-base)',
|
|
238
|
+
color: 'var(--dsw-alias-label-primary)',
|
|
239
|
+
} as any,
|
|
240
|
+
})
|
|
241
|
+
}
|
|
242
|
+
|
|
226
243
|
// 侧边栏图标:better-sidebar 以 `icon(size)` 形式调用(见其内置 tab:
|
|
227
244
|
// `icon: (size) => jsx(Icon, { size })`),故这里接收数字尺寸。用 currentColor
|
|
228
245
|
// 着色以自适应明暗主题,纯 SVG 零依赖。
|
|
@@ -258,45 +275,67 @@ const TAB_ORDER = 90
|
|
|
258
275
|
|
|
259
276
|
export const name = PLUGIN_ID
|
|
260
277
|
|
|
261
|
-
//
|
|
262
|
-
//
|
|
263
|
-
//
|
|
264
|
-
// 问题——这正是脱离 better-sidebar 的核心收益。
|
|
278
|
+
// slots 是 layout 提供的框架级服务(root 早期即就绪),用于浮层兜底,可安全声明顶层 inject。
|
|
279
|
+
// 注意:betterSidebar 是兄弟 bundle 提供的服务,不用顶层 inject(会触发 pending),改用
|
|
280
|
+
// apply 内的 ctx.inject 软注入回调。
|
|
265
281
|
export const inject = ['slots']
|
|
266
282
|
|
|
267
283
|
export function apply(ctx: any): (() => void) | void {
|
|
268
|
-
let
|
|
284
|
+
let unregisterTab: (() => void) | null = null
|
|
285
|
+
let overlayDispose: unknown = void 0
|
|
286
|
+
let registeredViaBetter = false
|
|
287
|
+
let fallbackTimer: any = void 0
|
|
269
288
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
id: PLUGIN_ID,
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
(
|
|
282
|
-
|
|
289
|
+
// 浮层兜底:把仪表盘挂到官方 shell.overlay(全程右下角 33vh),保证即使 better-sidebar
|
|
290
|
+
// 缺失/未启用,仪表盘也始终可见。
|
|
291
|
+
const tryMountOverlay = (reason: string): void => {
|
|
292
|
+
if (registeredViaBetter || overlayDispose !== void 0) return
|
|
293
|
+
console.warn(`[dsh-token-gauge] ${reason},仪表盘改为右下角浮层显示(仍可用)。`)
|
|
294
|
+
try {
|
|
295
|
+
overlayDispose = ctx.slots.register(
|
|
296
|
+
{ name: 'shell.overlay', id: PLUGIN_ID, order: 100, label: 'Token 仪表盘' },
|
|
297
|
+
() => React.createElement(GaugePanel),
|
|
298
|
+
)
|
|
299
|
+
} catch (e) {
|
|
300
|
+
console.error('[dsh-token-gauge] 浮层兜底也失败', e)
|
|
301
|
+
}
|
|
283
302
|
}
|
|
284
303
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
304
|
+
// 主路径:注册到 better-sidebar 右侧工作台 Tab(停靠侧边栏,带图标、靠前排序)
|
|
305
|
+
const disposeSidebar = ctx.inject(['betterSidebar'], (sidebarCtx: any) => {
|
|
306
|
+
const sidebar = sidebarCtx.betterSidebar
|
|
307
|
+
if (!sidebar || typeof sidebar.registerTab !== 'function') return
|
|
308
|
+
unregisterTab = sidebar.registerTab({
|
|
309
|
+
id: PLUGIN_ID,
|
|
310
|
+
title: 'Token 仪表盘',
|
|
311
|
+
single: true,
|
|
312
|
+
order: TAB_ORDER,
|
|
313
|
+
icon: GaugeIcon,
|
|
314
|
+
component: () => React.createElement(GaugeTab),
|
|
315
|
+
})
|
|
316
|
+
registeredViaBetter = true
|
|
317
|
+
if (typeof fallbackTimer !== 'undefined') clearTimeout(fallbackTimer)
|
|
318
|
+
// 会话就绪时尝试自动打开 Tab(未就绪会静默 no-op,用户也可从「+ 新建 Tab」菜单手动打开)
|
|
319
|
+
try {
|
|
320
|
+
if (typeof sidebar.openTab === 'function') sidebar.openTab({ type: PLUGIN_ID, single: true })
|
|
321
|
+
} catch (e) {
|
|
322
|
+
/* ignore */
|
|
293
323
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
324
|
+
return () => {
|
|
325
|
+
if (unregisterTab) unregisterTab()
|
|
326
|
+
}
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
// 兜底:30s 内 better-sidebar 仍未就绪 → 浮层
|
|
330
|
+
fallbackTimer = setTimeout(() => {
|
|
331
|
+
if (!registeredViaBetter) {
|
|
332
|
+
tryMountOverlay('未取得 dsh-better-sidebar 服务(请确认其已安装并启用)')
|
|
333
|
+
}
|
|
334
|
+
}, 30000)
|
|
297
335
|
|
|
298
336
|
return () => {
|
|
299
|
-
if (typeof
|
|
300
|
-
if (typeof
|
|
337
|
+
if (typeof fallbackTimer !== 'undefined') clearTimeout(fallbackTimer)
|
|
338
|
+
if (typeof disposeSidebar === 'function') (disposeSidebar as () => void)()
|
|
339
|
+
if (typeof overlayDispose === 'function') (overlayDispose as () => void)()
|
|
301
340
|
}
|
|
302
341
|
}
|