dsh-router-core 0.3.0 → 0.3.2
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/LICENSE +21 -0
- package/README.md +91 -57
- package/docs/screenshot.png +0 -0
- package/docs/suppliers.md +302 -0
- package/lib/client-registry.js +472 -205
- package/lib/client.js +472 -205
- package/lib/types/shared.d.ts +17 -1
- package/package.json +21 -4
- package/src/client/CheckinCard.tsx +180 -0
- package/src/client/RouterView.tsx +40 -28
- package/src/client/StatsTab.tsx +11 -1
- package/src/client/SupplierDetail.tsx +9 -1
- package/src/client/index.tsx +61 -11
- package/src/client/router.css +294 -38
- package/src/client/settings-nav-icon.ts +55 -0
- package/src/client/settings-section.tsx +21 -0
- package/src/shared.ts +13 -1
- package/src/suppliers/nvidia/plugin.ts +8 -2
package/src/client/router.css
CHANGED
|
@@ -64,17 +64,176 @@
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
/* ============================================================
|
|
67
|
-
dsh-router —
|
|
67
|
+
dsh-router — 主题变量(设置页 .dshr-settings / 老中心栏 .dshr-shell 共用)
|
|
68
68
|
============================================================ */
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
.dshr-settings,
|
|
71
|
+
.dshr-shell {
|
|
72
|
+
--rs-bg: var(--dsw-alias-bg-overlay, var(--dsw-alias-bg-base));
|
|
73
|
+
--rs-layer-1: var(--dsw-alias-bg-layer-1);
|
|
74
|
+
--rs-layer-2: var(--dsw-alias-bg-layer-2);
|
|
75
|
+
--rs-input: var(--dsw-specific-input-major, var(--dsw-alias-bg-layer-2));
|
|
76
|
+
--rs-text: var(--dsw-alias-label-primary);
|
|
77
|
+
--rs-muted: var(--dsw-alias-label-secondary);
|
|
78
|
+
--rs-faint: var(--dsw-alias-label-tertiary);
|
|
79
|
+
--rs-line: var(--dsw-alias-border-l1);
|
|
80
|
+
--rs-line-strong: var(--dsw-alias-border-l2);
|
|
81
|
+
--rs-accent: var(--dsw-alias-state-business-primary);
|
|
82
|
+
--rs-hover: var(--dsw-alias-interactive-bg-hover);
|
|
83
|
+
--rs-danger: var(--dsw-alias-state-error-primary);
|
|
84
|
+
--rs-success: var(--dsw-alias-state-success-primary);
|
|
85
|
+
--rs-ok: var(--rs-success);
|
|
86
|
+
--rs-warn: #9a6a18;
|
|
87
|
+
--rs-mono: var(--ds-font-family-code, 'SFMono-Regular', Consolas, monospace);
|
|
88
|
+
--rs-sans: var(--dsw-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif);
|
|
89
|
+
box-sizing: border-box;
|
|
90
|
+
min-width: 0;
|
|
91
|
+
color: var(--rs-text);
|
|
92
|
+
font: 13px/1.55 var(--rs-sans);
|
|
93
|
+
-webkit-tap-highlight-color: transparent;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* ============================================================
|
|
97
|
+
dsh-router — 设置页容器(settings.section 座位)
|
|
98
|
+
============================================================ */
|
|
99
|
+
|
|
100
|
+
/* 容器几何(浏览器实测,改之前先量别凭感觉):
|
|
101
|
+
- 内容宽 564px(面板 612 − 左右 padding 24)
|
|
102
|
+
- 外壳 .VOzbGW_options 是 `overflow-y:auto` + `flex:1 1 0%`,高度确定
|
|
103
|
+
(视口 813 时可视高 703~746)
|
|
104
|
+
- 根节点外面套了一层 display:contents(宿主 slot renderer 给的),**没有
|
|
105
|
+
盒子** —— 但实测 `height:100%` 仍能穿过它解析到外壳高度
|
|
106
|
+
(验过:root 从 1332px 溢出态变成 722px,正好填满容器)
|
|
107
|
+
|
|
108
|
+
布局规则:**tab 条固定,只有下面的内容区滚**。
|
|
109
|
+
所以根节点必须限高(不限高内容会把外壳撑开,变成整页滚),内容区再
|
|
110
|
+
min-height:0 + overflow-y:auto 自己滚。
|
|
111
|
+
关键字是 min-height:0 —— flex 子项默认 min-height:auto,不给 0 的话
|
|
112
|
+
子项缩不小,overflow 永远不触发。 */
|
|
113
|
+
.dshr-settings {
|
|
114
|
+
display: flex;
|
|
115
|
+
height: 100%;
|
|
116
|
+
min-height: 0;
|
|
117
|
+
flex-direction: column;
|
|
118
|
+
gap: 14px;
|
|
72
119
|
}
|
|
73
120
|
|
|
74
|
-
.
|
|
121
|
+
.dshr-settings *,
|
|
122
|
+
.dshr-settings *::before,
|
|
123
|
+
.dshr-settings *::after { box-sizing: border-box; }
|
|
124
|
+
|
|
125
|
+
/* 主导航 = tab 条。照 DSH 原生的内容区 tab(插件页那套 pbvGtq_tab):
|
|
126
|
+
容器一条 1px 底部分隔线,激活项用 ::after 画 2px 下划线压在线上。
|
|
127
|
+
刻意**不用**填充色块——那会跟下面的周期按钮组撞成同一种控件,
|
|
128
|
+
层级也反了(导航是页面级,周期是筛选级)。 */
|
|
129
|
+
.dshr-tabs {
|
|
130
|
+
display: flex;
|
|
131
|
+
flex: none; /* 固定:内容区滚,tab 条不动 */
|
|
132
|
+
align-items: center;
|
|
133
|
+
gap: 4px;
|
|
134
|
+
border-bottom: 1px solid var(--rs-line);
|
|
135
|
+
/* 右端跟卡片对齐(实测数字,别凭感觉调):
|
|
136
|
+
root = 564;内容区因 padding-right 8px → 内容可视宽 556;
|
|
137
|
+
卡片再贴着可视区排 → 548。
|
|
138
|
+
tab 条是 .dshr-settings 的直接子项,起点是 root(564),
|
|
139
|
+
要落到 548 就得让掉 8(padding) + 8(滚动条) = 16px。
|
|
140
|
+
写成 margin 而不用 padding,是为了不把分隔线画到 padding 区域外。 */
|
|
141
|
+
margin-right: 16px;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.dshr-tab {
|
|
75
145
|
position: relative;
|
|
146
|
+
min-width: 0;
|
|
147
|
+
height: 36px;
|
|
148
|
+
padding: 0 12px;
|
|
149
|
+
border: none;
|
|
150
|
+
border-radius: 0;
|
|
151
|
+
color: var(--rs-muted);
|
|
152
|
+
background: transparent;
|
|
153
|
+
font-size: 13px;
|
|
154
|
+
font-weight: 400;
|
|
155
|
+
white-space: nowrap;
|
|
156
|
+
cursor: pointer;
|
|
157
|
+
transition: color .12s ease;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.dshr-tab:hover { color: var(--rs-text); }
|
|
161
|
+
|
|
162
|
+
/* 激活:主文字色 + 2px 下划线(bottom:-1px 压在容器的分隔线上)。
|
|
163
|
+
双类是因为上面有 `.dshr-settings button { color: inherit; font: inherit }` (1,1),
|
|
164
|
+
单类的 .dshr-tab-on 只有 (1,0),颜色和字号会被吃掉。 */
|
|
165
|
+
.dshr-settings .dshr-tab-on {
|
|
166
|
+
color: var(--rs-text);
|
|
167
|
+
font-size: 13px;
|
|
168
|
+
font-weight: 500;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.dshr-settings .dshr-tab-on::after {
|
|
172
|
+
position: absolute;
|
|
173
|
+
right: 0;
|
|
174
|
+
bottom: -1px;
|
|
175
|
+
left: 0;
|
|
176
|
+
height: 2px;
|
|
177
|
+
border-radius: 2px 2px 0 0;
|
|
178
|
+
content: '';
|
|
179
|
+
background: var(--rs-text);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.dshr-tabBack {
|
|
183
|
+
height: 26px;
|
|
184
|
+
padding: 0 10px;
|
|
185
|
+
border: 1px solid var(--rs-line);
|
|
186
|
+
border-radius: 6px;
|
|
187
|
+
color: var(--rs-muted);
|
|
188
|
+
background: transparent;
|
|
189
|
+
font-size: 12px;
|
|
190
|
+
white-space: nowrap;
|
|
191
|
+
cursor: pointer;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.dshr-tabBack:hover { color: var(--rs-text); background: var(--rs-hover); }
|
|
195
|
+
|
|
196
|
+
/* 内容区:吃掉剩余高度并**自己滚**,这样 tab 条永远留在顶部。
|
|
197
|
+
flex:1 + min-height:0 是必须的(见 .dshr-settings 的注释)。 */
|
|
198
|
+
.dshr-settingsBody {
|
|
199
|
+
display: flex;
|
|
200
|
+
min-width: 0;
|
|
201
|
+
min-height: 0;
|
|
202
|
+
flex: 1 1 auto;
|
|
203
|
+
flex-direction: column;
|
|
204
|
+
overflow-y: auto;
|
|
205
|
+
/* 恒定预留滚动条槽位。
|
|
206
|
+
实测不设它时 clientWidth 在 564(内容短、无滚动条)和 556(内容长、有滚动条)
|
|
207
|
+
之间跳,卡片宽也跟着 556/548 跳 —— 切 tab 时内容会横向抖一下。
|
|
208
|
+
不支持 scrollbar-gutter 的浏览器只是退化成「照样占宽」,不会坏。 */
|
|
209
|
+
scrollbar-gutter: stable;
|
|
210
|
+
/* 右内边距:内容别贴到滚动条上。滚动条宽 8px 且占布局宽度
|
|
211
|
+
(offsetWidth 564 vs clientWidth 556),不撑开的话内容右边缘正好压在它上面。 */
|
|
212
|
+
padding-right: 8px;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/* 细滚动条:跟 .dshr-content / .dshr-modalBody 一个套路 */
|
|
216
|
+
.dshr-settingsBody::-webkit-scrollbar {
|
|
217
|
+
width: 8px;
|
|
218
|
+
height: 8px;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.dshr-settingsBody::-webkit-scrollbar-thumb {
|
|
222
|
+
border-radius: 4px;
|
|
223
|
+
background: var(--rs-line-strong);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.dshr-settingsBody::-webkit-scrollbar-track {
|
|
227
|
+
background: transparent;
|
|
76
228
|
}
|
|
77
229
|
|
|
230
|
+
/* ============================================================
|
|
231
|
+
dsh-router — 老的中心栏劫持骨架(settings 不可用时的回退,非主路径)
|
|
232
|
+
============================================================ */
|
|
233
|
+
|
|
234
|
+
[data-pane='conversation'] { position: relative; }
|
|
235
|
+
.dshDesktopConversationSurface { position: relative; }
|
|
236
|
+
|
|
78
237
|
[data-dsh-router-view] {
|
|
79
238
|
position: absolute;
|
|
80
239
|
z-index: 60;
|
|
@@ -86,9 +245,7 @@
|
|
|
86
245
|
background: var(--dsw-alias-bg-overlay, var(--dsw-alias-bg-base));
|
|
87
246
|
}
|
|
88
247
|
|
|
89
|
-
.dshr-panelView {
|
|
90
|
-
isolation: isolate;
|
|
91
|
-
}
|
|
248
|
+
.dshr-panelView { isolation: isolate; }
|
|
92
249
|
|
|
93
250
|
html[data-dsh-router-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]):not([data-dsh-mnemon-active]) [data-dsh-router-view] {
|
|
94
251
|
display: block;
|
|
@@ -100,50 +257,37 @@ html[data-dsh-router-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-
|
|
|
100
257
|
display: none !important;
|
|
101
258
|
}
|
|
102
259
|
|
|
103
|
-
/* ============================================================
|
|
104
|
-
dsh-router — panel shell
|
|
105
|
-
============================================================ */
|
|
106
|
-
|
|
107
260
|
.dshr-shell {
|
|
108
|
-
--rs-bg: var(--dsw-alias-bg-overlay, var(--dsw-alias-bg-base));
|
|
109
|
-
--rs-layer-1: var(--dsw-alias-bg-layer-1);
|
|
110
|
-
--rs-layer-2: var(--dsw-alias-bg-layer-2);
|
|
111
|
-
--rs-input: var(--dsw-specific-input-major, var(--dsw-alias-bg-layer-2));
|
|
112
|
-
--rs-text: var(--dsw-alias-label-primary);
|
|
113
|
-
--rs-muted: var(--dsw-alias-label-secondary);
|
|
114
|
-
--rs-faint: var(--dsw-alias-label-tertiary);
|
|
115
|
-
--rs-line: var(--dsw-alias-border-l1);
|
|
116
|
-
--rs-line-strong: var(--dsw-alias-border-l2);
|
|
117
|
-
--rs-accent: var(--dsw-alias-state-business-primary);
|
|
118
|
-
--rs-hover: var(--dsw-alias-interactive-bg-hover);
|
|
119
|
-
--rs-danger: var(--dsw-alias-state-error-primary);
|
|
120
|
-
--rs-success: var(--dsw-alias-state-success-primary);
|
|
121
|
-
--rs-ok: var(--rs-success);
|
|
122
|
-
--rs-warn: #9a6a18;
|
|
123
|
-
--rs-mono: var(--ds-font-family-code, 'SFMono-Regular', Consolas, monospace);
|
|
124
|
-
--rs-sans: var(--dsw-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif);
|
|
125
|
-
box-sizing: border-box;
|
|
126
261
|
display: flex;
|
|
127
262
|
height: 100%;
|
|
128
|
-
min-width: 0;
|
|
129
263
|
min-height: 0;
|
|
130
264
|
flex-direction: column;
|
|
131
265
|
overflow: hidden;
|
|
132
|
-
color: var(--rs-text);
|
|
133
266
|
background: var(--rs-bg);
|
|
134
|
-
font: 13px/1.55 var(--rs-sans);
|
|
135
|
-
-webkit-tap-highlight-color: transparent;
|
|
136
267
|
}
|
|
137
268
|
|
|
269
|
+
.dshr-settings *,
|
|
270
|
+
.dshr-settings *::before,
|
|
271
|
+
.dshr-settings *::after,
|
|
138
272
|
.dshr-shell *,
|
|
139
273
|
.dshr-shell *::before,
|
|
140
274
|
.dshr-shell *::after { box-sizing: border-box; }
|
|
141
275
|
|
|
276
|
+
/* 按钮/表单重置 + 聚焦环:两个挂载容器都要覆盖。
|
|
277
|
+
只写 .dshr-shell 的话设置页整套控件样式全掉(踩过:周期按钮变裸文字)。 */
|
|
278
|
+
.dshr-settings button,
|
|
279
|
+
.dshr-settings input,
|
|
280
|
+
.dshr-settings select,
|
|
281
|
+
.dshr-settings textarea,
|
|
142
282
|
.dshr-shell button,
|
|
143
283
|
.dshr-shell input,
|
|
144
284
|
.dshr-shell select,
|
|
145
285
|
.dshr-shell textarea { color: inherit; font: inherit; }
|
|
146
286
|
|
|
287
|
+
.dshr-settings button:focus-visible,
|
|
288
|
+
.dshr-settings input:focus-visible,
|
|
289
|
+
.dshr-settings select:focus-visible,
|
|
290
|
+
.dshr-settings textarea:focus-visible,
|
|
147
291
|
.dshr-shell button:focus-visible,
|
|
148
292
|
.dshr-shell input:focus-visible,
|
|
149
293
|
.dshr-shell select:focus-visible,
|
|
@@ -396,6 +540,14 @@ html[data-dsh-router-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-
|
|
|
396
540
|
padding: 14px 18px;
|
|
397
541
|
}
|
|
398
542
|
|
|
543
|
+
/* 设置页里横向 padding 归零:内容区已经贴着容器边,再加 18px 会把卡片挤成
|
|
544
|
+
1 列、图表也跟着变窄。上下 padding 保留。 */
|
|
545
|
+
.dshr-settings .dshr-modelGrid,
|
|
546
|
+
.dshr-settings .dshr-tableWrap {
|
|
547
|
+
padding-right: 0;
|
|
548
|
+
padding-left: 0;
|
|
549
|
+
}
|
|
550
|
+
|
|
399
551
|
.dshr-modelCard {
|
|
400
552
|
display: flex;
|
|
401
553
|
min-width: 0;
|
|
@@ -428,13 +580,20 @@ html[data-dsh-router-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-
|
|
|
428
580
|
dsh-router — 9router 风格 tab 内容(供应商 / 组合 / 端点与密钥)
|
|
429
581
|
============================================================ */
|
|
430
582
|
|
|
583
|
+
/* tab 内容:设置页里**不自己滚** —— 滚动交给 .dshr-settingsBody(tab 条下方
|
|
584
|
+
那一块)。这里再给 overflow 就会出现嵌套滚动条(内容区一个、tabBody 一个)。
|
|
585
|
+
老的 .dshr-shell 中心栏挂载方式没有 settingsBody 那层,滚动由它自己承担。 */
|
|
431
586
|
.dshr-tabBody {
|
|
432
587
|
display: flex;
|
|
433
|
-
flex: 1 1 auto; /* 填满 content;自身滚动 */
|
|
434
588
|
min-width: 0;
|
|
435
|
-
min-height: 0;
|
|
436
589
|
flex-direction: column;
|
|
437
590
|
gap: 14px;
|
|
591
|
+
padding: 0;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
.dshr-shell .dshr-tabBody {
|
|
595
|
+
flex: 1 1 auto;
|
|
596
|
+
min-height: 0;
|
|
438
597
|
padding: 14px 18px;
|
|
439
598
|
overflow-y: auto;
|
|
440
599
|
}
|
|
@@ -845,6 +1004,7 @@ html[data-dsh-router-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-
|
|
|
845
1004
|
@keyframes dshrModalIn { from { opacity: 0; transform: translateY(8px) scale(.98); } to { opacity: 1; transform: none; } }
|
|
846
1005
|
|
|
847
1006
|
/* 按钮 */
|
|
1007
|
+
.dshr-settings .dshr-primaryButton,
|
|
848
1008
|
.dshr-shell .dshr-primaryButton {
|
|
849
1009
|
display: inline-flex;
|
|
850
1010
|
height: 30px;
|
|
@@ -862,9 +1022,12 @@ html[data-dsh-router-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-
|
|
|
862
1022
|
transition: filter .12s ease;
|
|
863
1023
|
}
|
|
864
1024
|
|
|
1025
|
+
.dshr-settings .dshr-primaryButton:hover,
|
|
865
1026
|
.dshr-shell .dshr-primaryButton:hover { filter: brightness(1.08); }
|
|
1027
|
+
.dshr-settings .dshr-primaryButton:disabled,
|
|
866
1028
|
.dshr-shell .dshr-primaryButton:disabled { opacity: .55; cursor: default; }
|
|
867
1029
|
|
|
1030
|
+
.dshr-settings .dshr-dangerButton,
|
|
868
1031
|
.dshr-shell .dshr-dangerButton {
|
|
869
1032
|
display: inline-flex;
|
|
870
1033
|
height: 30px;
|
|
@@ -882,6 +1045,7 @@ html[data-dsh-router-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-
|
|
|
882
1045
|
transition: filter .12s ease;
|
|
883
1046
|
}
|
|
884
1047
|
|
|
1048
|
+
.dshr-settings .dshr-dangerButton:hover,
|
|
885
1049
|
.dshr-shell .dshr-dangerButton:hover { filter: brightness(1.1); }
|
|
886
1050
|
|
|
887
1051
|
/* 登录步骤 */
|
|
@@ -2126,11 +2290,15 @@ html[data-dsh-router-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-
|
|
|
2126
2290
|
background: var(--rs-layer-2);
|
|
2127
2291
|
}
|
|
2128
2292
|
|
|
2129
|
-
/*
|
|
2130
|
-
|
|
2293
|
+
/* 周期按钮三态(按钮组:一组互斥的筛选按钮,不是导航 tab)。
|
|
2294
|
+
特异性阶梯(类/伪类数 , 元素数):
|
|
2295
|
+
文件顶部有 `.dshr-settings button { color: inherit; font: inherit }` = (1,1),
|
|
2131
2296
|
单类的 .dshr-period (1,0) 会被它打死(白字、600 字重全丢),所以下面每条
|
|
2132
|
-
|
|
2297
|
+
都必须带挂载容器(.dshr-settings / .dshr-shell)抬到 (2,0) 以上。
|
|
2298
|
+
**两个容器都要写**:只写 .dshr-shell 的话设置页里这套样式全掉
|
|
2299
|
+
(踩过:周期按钮退化成浏览器默认按钮)。
|
|
2133
2300
|
两种 hover 用 :not() 做成互斥,谁赢跟源码顺序无关(免得以后有人挪块就翻车)。 */
|
|
2301
|
+
.dshr-settings .dshr-period,
|
|
2134
2302
|
.dshr-shell .dshr-period {
|
|
2135
2303
|
min-width: 46px;
|
|
2136
2304
|
height: 26px;
|
|
@@ -2146,12 +2314,14 @@ html[data-dsh-router-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-
|
|
|
2146
2314
|
}
|
|
2147
2315
|
|
|
2148
2316
|
/* 未激活悬停:跟 .dshr-miniButton / .dshr-iconButton 一个套路(主文字色 + --rs-hover 底) */
|
|
2317
|
+
.dshr-settings .dshr-period:not(.dshr-period-on):hover,
|
|
2149
2318
|
.dshr-shell .dshr-period:not(.dshr-period-on):hover {
|
|
2150
2319
|
color: var(--rs-text);
|
|
2151
2320
|
background: var(--rs-hover);
|
|
2152
2321
|
}
|
|
2153
2322
|
|
|
2154
2323
|
/* 激活:强调色块 + 白字。底色用 layer-1 时跟卡片同色,根本看不出选中了哪个 */
|
|
2324
|
+
.dshr-settings .dshr-period-on,
|
|
2155
2325
|
.dshr-shell .dshr-period-on {
|
|
2156
2326
|
color: #fff;
|
|
2157
2327
|
background: var(--rs-accent);
|
|
@@ -2160,6 +2330,7 @@ html[data-dsh-router-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-
|
|
|
2160
2330
|
}
|
|
2161
2331
|
|
|
2162
2332
|
/* 激活态被悬停:跟 .dshr-primaryButton 一样提亮,表示「它还是能点的」 */
|
|
2333
|
+
.dshr-settings .dshr-period-on:hover,
|
|
2163
2334
|
.dshr-shell .dshr-period-on:hover {
|
|
2164
2335
|
color: #fff;
|
|
2165
2336
|
background: var(--rs-accent);
|
|
@@ -2228,6 +2399,68 @@ html[data-dsh-router-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-
|
|
|
2228
2399
|
.dshr-statCard-warn .dshr-statValue { color: var(--rs-warn); }
|
|
2229
2400
|
.dshr-statCard-danger .dshr-statValue { color: var(--rs-danger); }
|
|
2230
2401
|
|
|
2402
|
+
/* 签到卡:跟统计卡同宽同高,但里面是按钮不是数字。
|
|
2403
|
+
gap 沿用卡片的 3px(不覆写)—— 之前改成 6px 让这一行比别的高 6px,
|
|
2404
|
+
两行卡片因此不齐(92 vs 98px)。
|
|
2405
|
+
今日已点过 → 边框转成功色,一眼看出「今天点过了」 */
|
|
2406
|
+
.dshr-statCard-checkin { gap: 3px; }
|
|
2407
|
+
|
|
2408
|
+
.dshr-statCard-done {
|
|
2409
|
+
border-color: color-mix(in srgb, var(--rs-success) 45%, transparent);
|
|
2410
|
+
}
|
|
2411
|
+
|
|
2412
|
+
/* 按钮撑满卡片宽度:卡片本来就窄,居左的小按钮看着像没对齐 */
|
|
2413
|
+
.dshr-checkinButton {
|
|
2414
|
+
display: inline-flex;
|
|
2415
|
+
width: 100%;
|
|
2416
|
+
/* 26px ≈ .dshr-statValue 的行高(22px × 1.2),让按钮那一行跟数字的
|
|
2417
|
+
那一行一样高,卡片整体高度才跟邻卡一致 */
|
|
2418
|
+
height: 26px;
|
|
2419
|
+
align-items: center;
|
|
2420
|
+
justify-content: center;
|
|
2421
|
+
gap: 5px;
|
|
2422
|
+
border: 1px solid var(--rs-line);
|
|
2423
|
+
border-radius: 6px;
|
|
2424
|
+
color: var(--rs-text);
|
|
2425
|
+
background: var(--rs-layer-2);
|
|
2426
|
+
font-size: 12px;
|
|
2427
|
+
font-weight: 500;
|
|
2428
|
+
white-space: nowrap;
|
|
2429
|
+
cursor: pointer;
|
|
2430
|
+
transition: color .12s ease, background .12s ease, border-color .12s ease;
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2433
|
+
.dshr-checkinButton:hover:not(:disabled) {
|
|
2434
|
+
border-color: var(--rs-accent);
|
|
2435
|
+
color: var(--rs-accent);
|
|
2436
|
+
background: color-mix(in srgb, var(--rs-accent) 8%, transparent);
|
|
2437
|
+
}
|
|
2438
|
+
|
|
2439
|
+
.dshr-checkinButton:disabled { opacity: .6; cursor: default; }
|
|
2440
|
+
|
|
2441
|
+
/* 已点过:按钮转成成功色柔和态(仍可再点) */
|
|
2442
|
+
.dshr-statCard-done .dshr-checkinButton {
|
|
2443
|
+
border-color: color-mix(in srgb, var(--rs-success) 40%, transparent);
|
|
2444
|
+
color: var(--rs-success);
|
|
2445
|
+
background: color-mix(in srgb, var(--rs-success) 8%, transparent);
|
|
2446
|
+
}
|
|
2447
|
+
|
|
2448
|
+
/* 结果/失败都压在 hint 那一行里(卡片行数必须跟邻卡一致):
|
|
2449
|
+
失败时才转红,其余沿用 hint 的弱色,不成功后多出一行 */
|
|
2450
|
+
.dshr-statHint-err {
|
|
2451
|
+
overflow: hidden;
|
|
2452
|
+
color: var(--rs-danger);
|
|
2453
|
+
text-overflow: ellipsis;
|
|
2454
|
+
white-space: nowrap;
|
|
2455
|
+
}
|
|
2456
|
+
|
|
2457
|
+
/* 忙碌态:按钮转成弱色,跟「已点过」的成功色区分开 */
|
|
2458
|
+
.dshr-checkinButton-busy {
|
|
2459
|
+
color: var(--rs-faint);
|
|
2460
|
+
background: var(--rs-layer-2);
|
|
2461
|
+
border-color: var(--rs-line);
|
|
2462
|
+
}
|
|
2463
|
+
|
|
2231
2464
|
.dshr-estimateNote {
|
|
2232
2465
|
margin: 0;
|
|
2233
2466
|
color: var(--rs-faint);
|
|
@@ -2500,3 +2733,26 @@ html[data-dsh-router-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-
|
|
|
2500
2733
|
|
|
2501
2734
|
.dshr-dot-ok { background: var(--rs-success); }
|
|
2502
2735
|
.dshr-dot-fail { background: var(--rs-danger); }
|
|
2736
|
+
|
|
2737
|
+
/* ============================================================
|
|
2738
|
+
dsh-router — 设置导航图标(换掉宿主的默认齿轮)
|
|
2739
|
+
============================================================ */
|
|
2740
|
+
|
|
2741
|
+
/* DSH 0.1.x 的 settings.section 注册只认 id / order / label,图标是宿主按
|
|
2742
|
+
「内置 id 白名单」选的,插件传不了 —— 外部 section 一律拿到通用齿轮。
|
|
2743
|
+
settings-nav-icon.ts 给本插件那一行打上标记,这里用 currentColor mask
|
|
2744
|
+
渲染路由字形:跟随宿主导航的 hover/active 配色,也保持 16px 图标节奏。
|
|
2745
|
+
升级路径:等契约长出 icon 字段,删掉 settings-nav-icon.ts 和这一整块。 */
|
|
2746
|
+
[data-dsh-router-settings-nav] > svg:first-child {
|
|
2747
|
+
display: none;
|
|
2748
|
+
}
|
|
2749
|
+
|
|
2750
|
+
[data-dsh-router-settings-nav]::before {
|
|
2751
|
+
content: '';
|
|
2752
|
+
flex: none;
|
|
2753
|
+
width: 16px;
|
|
2754
|
+
height: 16px;
|
|
2755
|
+
background: currentColor;
|
|
2756
|
+
-webkit-mask: url("data:image/svg+xml,<svg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'><circle%20cx='5'%20cy='5'%20r='2.4'/><circle%20cx='19'%20cy='5'%20r='2.4'/><circle%20cx='12'%20cy='19'%20r='2.4'/><path%20d='M7.4%205h9.2'/><path%20d='M5%207.4v6.2c0%202.6%203%203.4%204.6%203.8'/><path%20d='M19%207.4v6.2c0%202.6-3%203.4-4.6%203.8'/></svg>") center / contain no-repeat;
|
|
2757
|
+
mask: url("data:image/svg+xml,<svg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'><circle%20cx='5'%20cy='5'%20r='2.4'/><circle%20cx='19'%20cy='5'%20r='2.4'/><circle%20cx='12'%20cy='19'%20r='2.4'/><path%20d='M7.4%205h9.2'/><path%20d='M5%207.4v6.2c0%202.6%203%203.4%204.6%203.8'/><path%20d='M19%207.4v6.2c0%202.6-3%203.4-4.6%203.8'/></svg>") center / contain no-repeat;
|
|
2758
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 给设置导航里「路由」这一行换掉宿主的默认齿轮。
|
|
3
|
+
*
|
|
4
|
+
* 为什么需要这个:DSH 0.1.x 的 `settings.section` 注册**只认 id / order / label
|
|
5
|
+
* 三个字段**,图标是宿主内部按「内置 id 白名单」选的,插件传不了。所以外部
|
|
6
|
+
* section 一律拿到通用齿轮(跟「通用设置」「远程访问」同一个)。
|
|
7
|
+
* 在契约长出 icon 字段之前,只能注册后认领自己的那一行。
|
|
8
|
+
*
|
|
9
|
+
* 做法跟 dsh-better-sidebar 的 settings-nav-icon.ts 一致:给自己的行打一个
|
|
10
|
+
* 属性标记,再由 CSS 用 mask 渲染图标(见 router.css 的
|
|
11
|
+
* `[data-dsh-router-settings-nav]`)。用 mask + currentColor 是为了跟随
|
|
12
|
+
* 宿主导航的 hover/active 配色,也保持 16px 的图标节奏。
|
|
13
|
+
*
|
|
14
|
+
* 匹配方式:按行的**可见文案**认领(label 可能本地化),且只认 `nav button`,
|
|
15
|
+
* 碰到同名的别人家 section 不会误伤(我们同时校验它确实在设置面板里)。
|
|
16
|
+
* 卸载时断开观察并摘掉标记,HMR / 插件热卸载安全。
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** 打在设置导航按钮上的标记属性。 */
|
|
20
|
+
export const SETTINGS_NAV_MARKER = 'data-dsh-router-settings-nav'
|
|
21
|
+
|
|
22
|
+
/** 设置面板的导航按钮选择器(宿主结构:dialog 里的 nav)。 */
|
|
23
|
+
const NAV_BUTTON_SELECTOR = '[role="dialog"] nav button'
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 持续把标记打在文案等于 `label` 的那一行的身上。
|
|
27
|
+
* @param label 当前本地化的 section 标题(跟注册时的 label 一致)
|
|
28
|
+
* @returns 清理函数:断开观察 + 摘掉所有本插件打的标记
|
|
29
|
+
*/
|
|
30
|
+
export function registerSettingsNavIcon(label: string): () => void {
|
|
31
|
+
let disposed = false
|
|
32
|
+
const wanted = label.trim()
|
|
33
|
+
|
|
34
|
+
const sync = (): void => {
|
|
35
|
+
if (disposed || wanted === '') return
|
|
36
|
+
for (const button of document.querySelectorAll<HTMLElement>(NAV_BUTTON_SELECTOR)) {
|
|
37
|
+
const matches = button.textContent?.trim() === wanted
|
|
38
|
+
if (matches) button.setAttribute(SETTINGS_NAV_MARKER, '')
|
|
39
|
+
else button.removeAttribute(SETTINGS_NAV_MARKER)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
sync()
|
|
44
|
+
// 设置面板是按需挂载的:body 子树变动时重新认领
|
|
45
|
+
const observer = new MutationObserver(sync)
|
|
46
|
+
observer.observe(document.body, { childList: true, subtree: true, characterData: true })
|
|
47
|
+
|
|
48
|
+
return () => {
|
|
49
|
+
disposed = true
|
|
50
|
+
observer.disconnect()
|
|
51
|
+
for (const el of document.querySelectorAll(`[${SETTINGS_NAV_MARKER}]`)) {
|
|
52
|
+
el.removeAttribute(SETTINGS_NAV_MARKER)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 「设置 → 路由」页 —— 走 DSH 官方 `settings.section` 座位。
|
|
3
|
+
*
|
|
4
|
+
* 容器几何(浏览器实测,不是估的)决定了这里的写法:
|
|
5
|
+
* - 内容宽 564px(面板 612 − 左右 padding 24)
|
|
6
|
+
* - 外壳 `.VOzbGW_options` 是 `overflow-y:auto` 且高度确定,所以**根节点
|
|
7
|
+
* 限高**(`height:100%`)+ 内容区自己滚,才能做到「tab 条固定、只有
|
|
8
|
+
* 内容区滚」。不限高就会退化成整页滚,tab 条跟着滚上去
|
|
9
|
+
* - 根节点外面套了一层 `display: contents`(宿主 slot renderer 给的),
|
|
10
|
+
* 但实测 `height:100%` 能穿过它解析到外壳高度
|
|
11
|
+
* - 横向会溢出:老布局是按整个中心栏宽做的,卡片 grid 必须按 564px 排
|
|
12
|
+
*
|
|
13
|
+
* 组件本身无状态、无 props:数据全在 RouterView 里自己 fetch。
|
|
14
|
+
*/
|
|
15
|
+
import { RouterView } from './RouterView.tsx'
|
|
16
|
+
|
|
17
|
+
/** 设置页入口组件。 */
|
|
18
|
+
export function RouterSettingsSection(): JSX.Element {
|
|
19
|
+
// 不传 onBack:设置面板自带关闭,不需要「返回会话」
|
|
20
|
+
return <RouterView />
|
|
21
|
+
}
|
package/src/shared.ts
CHANGED
|
@@ -15,7 +15,7 @@ export const ROUTER_VIEW_SELECTOR = '[data-dsh-router-view]'
|
|
|
15
15
|
export const ROUTER_ACTIVE_ATTR = 'data-dsh-router-active'
|
|
16
16
|
|
|
17
17
|
/** The panel's visible title (also the sidebar entry label). */
|
|
18
|
-
export const ROUTER_TITLE = '
|
|
18
|
+
export const ROUTER_TITLE = '路由'
|
|
19
19
|
|
|
20
20
|
/** Same-origin API base the client panel fetches (host half serves it). */
|
|
21
21
|
export const ROUTER_API_BASE = '/router/api'
|
|
@@ -51,6 +51,18 @@ export interface RouterModelsResponse {
|
|
|
51
51
|
models?: Array<{ id: string; context_length?: number }>
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
/** 一键签到:单个供应商的汇总结果(`/suppliers/:id/checkin` 的响应体)。 */
|
|
55
|
+
export interface RouterCheckinResponse {
|
|
56
|
+
ok: boolean
|
|
57
|
+
error?: string
|
|
58
|
+
total: number
|
|
59
|
+
/** 真正 claim 成功的链接数。 */
|
|
60
|
+
succeeded: number
|
|
61
|
+
/** 今日已签到的链接数(幂等成功)。 */
|
|
62
|
+
already: number
|
|
63
|
+
results?: Array<{ uid: string; ok: boolean; status?: string; message?: string }>
|
|
64
|
+
}
|
|
65
|
+
|
|
54
66
|
/** `/router/api/health` response. */
|
|
55
67
|
export interface RouterHealthResponse {
|
|
56
68
|
ok: boolean
|
|
@@ -22,8 +22,14 @@ import type { SupplierEnv, SupplierModule } from '../contract.ts'
|
|
|
22
22
|
export const id = 'nvidia'
|
|
23
23
|
export const name = 'NVIDIA NIM'
|
|
24
24
|
export const priority = 20 // 同 9Router:免费直连(opencode=0)之后
|
|
25
|
-
/**
|
|
26
|
-
|
|
25
|
+
/**
|
|
26
|
+
* 面板图标(NVIDIA 官方 logo,128×128 PNG,base64 内联)。
|
|
27
|
+
*
|
|
28
|
+
* **必须内联,不能放网络 URL**:之前是 `http://localhost:20128/...`(9router
|
|
29
|
+
* 的端口),9router 没跑时就是一张坏图 —— 面板图标不该依赖另一个服务活着,
|
|
30
|
+
* 更不该依赖特定端口。跟 opencode / openrouter / traework 的做法保持一致。
|
|
31
|
+
*/
|
|
32
|
+
export const icon = 'data:image/png;base64,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'
|
|
27
33
|
|
|
28
34
|
const BASE = 'https://integrate.api.nvidia.com/v1'
|
|
29
35
|
const MODELS_URL = `${BASE}/models`
|