dsh-smooth-stream 0.3.3 → 0.4.0
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/README.en.md +23 -18
- package/README.md +23 -18
- package/lib/client.js +2343 -175
- package/lib/client.js.map +1 -1
- package/lib/index.js +123 -6
- package/package.json +15 -10
- package/src/client/DebugPanel.module.css +370 -0
- package/src/client/DebugPanel.tsx +248 -0
- package/src/client/SmoothStreamCard.module.css +8 -0
- package/src/client/SmoothStreamCard.tsx +42 -3
- package/src/client/TypewriterAssistantNodeView.tsx +226 -49
- package/src/client/auto-collapse-controller.ts +977 -0
- package/src/client/debugRuntime.ts +355 -0
- package/src/client/index.ts +121 -30
- package/src/client/locales.ts +122 -0
- package/src/client/smooth-stream-card-controller.ts +97 -14
- package/src/client/smooth-stream-settings-api.ts +53 -3
- package/src/client/teleprompterGlide.ts +160 -31
- package/src/client/useFpsGuard.ts +7 -0
- package/src/client/useProgressiveDomText.ts +99 -17
- package/src/client/useSmoothStreamContent.ts +20 -4
- package/src/plugin.ts +137 -7
- package/src/settings-api.ts +12 -0
- package/src/settings.ts +55 -0
package/lib/index.js
CHANGED
|
@@ -145,6 +145,8 @@ const STREAM_SETTINGS_RPC_CHANNEL = "/smooth-stream";
|
|
|
145
145
|
const STREAM_SETTINGS_RPC = {
|
|
146
146
|
read: "settings.read",
|
|
147
147
|
write: "settings.write",
|
|
148
|
+
debugRead: "debug.read",
|
|
149
|
+
debugWrite: "debug.write",
|
|
148
150
|
upgrade: "plugin.upgrade"
|
|
149
151
|
};
|
|
150
152
|
//#endregion
|
|
@@ -160,7 +162,23 @@ const STREAM_SETTINGS_RPC = {
|
|
|
160
162
|
/** Settings namespace registered by the Host and served through the plugin RPC. */
|
|
161
163
|
const STREAM_SETTINGS_NS = "smooth-stream";
|
|
162
164
|
/** Defaults shared by the Host schema and the client-side fallback. */
|
|
163
|
-
const DEFAULT_STREAM_SETTINGS = {
|
|
165
|
+
const DEFAULT_STREAM_SETTINGS = {
|
|
166
|
+
enabled: true,
|
|
167
|
+
thinkAutoExpand: true,
|
|
168
|
+
autoCollapse: true,
|
|
169
|
+
debugEnabled: false,
|
|
170
|
+
debugTuning: {
|
|
171
|
+
revealScale: 1,
|
|
172
|
+
queuePressure: .85,
|
|
173
|
+
maxRevealCps: 600,
|
|
174
|
+
springStiffness: 130,
|
|
175
|
+
springDamping: 24,
|
|
176
|
+
springMass: 1,
|
|
177
|
+
runwayPx: 48,
|
|
178
|
+
reserveResponseMs: 180,
|
|
179
|
+
backpressureMinScale: .55
|
|
180
|
+
}
|
|
181
|
+
};
|
|
164
182
|
//#endregion
|
|
165
183
|
//#region src/plugin.ts
|
|
166
184
|
/** Display name shown by the Host loader while the plugin is mounted. */
|
|
@@ -180,7 +198,23 @@ const Config = Schema.object({
|
|
|
180
198
|
* Schema of the user-owned settings section. The Host keeps it in the durable
|
|
181
199
|
* settings provider while the browser edits it through the plugin RPC below.
|
|
182
200
|
*/
|
|
183
|
-
const StreamSettingsSchema = Schema.object({
|
|
201
|
+
const StreamSettingsSchema = Schema.object({
|
|
202
|
+
enabled: Schema.boolean().default(DEFAULT_STREAM_SETTINGS.enabled),
|
|
203
|
+
thinkAutoExpand: Schema.boolean().default(DEFAULT_STREAM_SETTINGS.thinkAutoExpand),
|
|
204
|
+
autoCollapse: Schema.boolean().default(DEFAULT_STREAM_SETTINGS.autoCollapse),
|
|
205
|
+
debugEnabled: Schema.boolean().default(DEFAULT_STREAM_SETTINGS.debugEnabled),
|
|
206
|
+
debugTuning: Schema.object({
|
|
207
|
+
revealScale: Schema.number().min(.25).max(2).default(DEFAULT_STREAM_SETTINGS.debugTuning.revealScale),
|
|
208
|
+
queuePressure: Schema.number().min(0).max(2).default(DEFAULT_STREAM_SETTINGS.debugTuning.queuePressure),
|
|
209
|
+
maxRevealCps: Schema.number().min(120).max(1e3).default(DEFAULT_STREAM_SETTINGS.debugTuning.maxRevealCps),
|
|
210
|
+
springStiffness: Schema.number().min(40).max(320).default(DEFAULT_STREAM_SETTINGS.debugTuning.springStiffness),
|
|
211
|
+
springDamping: Schema.number().min(8).max(80).default(DEFAULT_STREAM_SETTINGS.debugTuning.springDamping),
|
|
212
|
+
springMass: Schema.number().min(.5).max(3).default(DEFAULT_STREAM_SETTINGS.debugTuning.springMass),
|
|
213
|
+
runwayPx: Schema.number().min(0).max(120).default(DEFAULT_STREAM_SETTINGS.debugTuning.runwayPx),
|
|
214
|
+
reserveResponseMs: Schema.number().min(60).max(600).default(DEFAULT_STREAM_SETTINGS.debugTuning.reserveResponseMs),
|
|
215
|
+
backpressureMinScale: Schema.number().min(.25).max(1).default(DEFAULT_STREAM_SETTINGS.debugTuning.backpressureMinScale)
|
|
216
|
+
})
|
|
217
|
+
});
|
|
184
218
|
/**
|
|
185
219
|
* Host half: log the resolved configuration and bridge it to the browser
|
|
186
220
|
* half. The web boot graph carries no per-entry config, so the validated
|
|
@@ -200,25 +234,40 @@ function apply(ctx, config) {
|
|
|
200
234
|
let upgrade;
|
|
201
235
|
const view = () => {
|
|
202
236
|
const installation = inspectProfileInstallation(connectionCtx.baseUrl, STREAM_PACKAGE_NAME);
|
|
237
|
+
const settings = scope.get();
|
|
203
238
|
return {
|
|
204
239
|
version: STREAM_PACKAGE_VERSION,
|
|
205
240
|
installation: installation.kind,
|
|
206
241
|
writable: connectionCtx.settings.writable,
|
|
207
|
-
|
|
242
|
+
enabled: settings.enabled,
|
|
243
|
+
thinkAutoExpand: settings.thinkAutoExpand,
|
|
244
|
+
autoCollapse: settings.autoCollapse,
|
|
208
245
|
canUpgrade: installation.kind === "npm"
|
|
209
246
|
};
|
|
210
247
|
};
|
|
248
|
+
const debugView = () => {
|
|
249
|
+
const settings = scope.get();
|
|
250
|
+
return {
|
|
251
|
+
debugEnabled: settings.debugEnabled,
|
|
252
|
+
tuning: { ...settings.debugTuning }
|
|
253
|
+
};
|
|
254
|
+
};
|
|
255
|
+
const validDebugTuning = (value) => {
|
|
256
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
257
|
+
const tuning = value;
|
|
258
|
+
return typeof tuning.revealScale === "number" && tuning.revealScale >= .25 && tuning.revealScale <= 2 && typeof tuning.queuePressure === "number" && tuning.queuePressure >= 0 && tuning.queuePressure <= 2 && typeof tuning.maxRevealCps === "number" && tuning.maxRevealCps >= 120 && tuning.maxRevealCps <= 1e3 && typeof tuning.springStiffness === "number" && tuning.springStiffness >= 40 && tuning.springStiffness <= 320 && typeof tuning.springDamping === "number" && tuning.springDamping >= 8 && tuning.springDamping <= 80 && typeof tuning.springMass === "number" && tuning.springMass >= .5 && tuning.springMass <= 3 && typeof tuning.runwayPx === "number" && tuning.runwayPx >= 0 && tuning.runwayPx <= 120 && typeof tuning.reserveResponseMs === "number" && tuning.reserveResponseMs >= 60 && tuning.reserveResponseMs <= 600 && typeof tuning.backpressureMinScale === "number" && tuning.backpressureMinScale >= .25 && tuning.backpressureMinScale <= 1;
|
|
259
|
+
};
|
|
211
260
|
const handle = async (endpoint, payload) => {
|
|
212
261
|
if (endpoint === STREAM_SETTINGS_RPC.read) return {
|
|
213
262
|
ok: true,
|
|
214
263
|
value: view()
|
|
215
264
|
};
|
|
216
265
|
if (endpoint === STREAM_SETTINGS_RPC.write) {
|
|
217
|
-
if (typeof payload !== "object" || payload === null || typeof payload.thinkAutoExpand !== "boolean") return {
|
|
266
|
+
if (typeof payload !== "object" || payload === null || Array.isArray(payload) || typeof payload.enabled !== "boolean" || typeof payload.thinkAutoExpand !== "boolean" || typeof payload.autoCollapse !== "boolean") return {
|
|
218
267
|
ok: false,
|
|
219
268
|
error: {
|
|
220
269
|
code: "settings-rejected",
|
|
221
|
-
message: "thinkAutoExpand must be
|
|
270
|
+
message: "enabled, thinkAutoExpand and autoCollapse must be booleans",
|
|
222
271
|
details: { ns: STREAM_SETTINGS_NS }
|
|
223
272
|
}
|
|
224
273
|
};
|
|
@@ -231,7 +280,25 @@ function apply(ctx, config) {
|
|
|
231
280
|
}
|
|
232
281
|
};
|
|
233
282
|
try {
|
|
234
|
-
|
|
283
|
+
const next = payload;
|
|
284
|
+
const hasDebug = next.debugEnabled !== void 0 || next.debugTuning !== void 0;
|
|
285
|
+
if (hasDebug && (typeof next.debugEnabled !== "boolean" || !validDebugTuning(next.debugTuning))) return {
|
|
286
|
+
ok: false,
|
|
287
|
+
error: {
|
|
288
|
+
code: "settings-rejected",
|
|
289
|
+
message: "debugEnabled and debugTuning must be provided together and be valid",
|
|
290
|
+
details: { ns: STREAM_SETTINGS_NS }
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
await scope.update({
|
|
294
|
+
enabled: next.enabled,
|
|
295
|
+
thinkAutoExpand: next.thinkAutoExpand,
|
|
296
|
+
autoCollapse: next.autoCollapse,
|
|
297
|
+
...hasDebug ? {
|
|
298
|
+
debugEnabled: next.debugEnabled,
|
|
299
|
+
debugTuning: next.debugTuning
|
|
300
|
+
} : {}
|
|
301
|
+
});
|
|
235
302
|
} catch {
|
|
236
303
|
return {
|
|
237
304
|
ok: false,
|
|
@@ -247,6 +314,56 @@ function apply(ctx, config) {
|
|
|
247
314
|
value: view()
|
|
248
315
|
};
|
|
249
316
|
}
|
|
317
|
+
if (endpoint === STREAM_SETTINGS_RPC.debugRead) return {
|
|
318
|
+
ok: true,
|
|
319
|
+
value: debugView()
|
|
320
|
+
};
|
|
321
|
+
if (endpoint === STREAM_SETTINGS_RPC.debugWrite) {
|
|
322
|
+
if (typeof payload !== "object" || payload === null || Array.isArray(payload)) return {
|
|
323
|
+
ok: false,
|
|
324
|
+
error: {
|
|
325
|
+
code: "settings-rejected",
|
|
326
|
+
message: "debug settings must be an object",
|
|
327
|
+
details: { ns: STREAM_SETTINGS_NS }
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
const next = payload;
|
|
331
|
+
if (typeof next.debugEnabled !== "boolean" || !validDebugTuning(next.tuning)) return {
|
|
332
|
+
ok: false,
|
|
333
|
+
error: {
|
|
334
|
+
code: "settings-rejected",
|
|
335
|
+
message: "debugEnabled and tuning are malformed",
|
|
336
|
+
details: { ns: STREAM_SETTINGS_NS }
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
if (!connectionCtx.settings.writable) return {
|
|
340
|
+
ok: false,
|
|
341
|
+
error: {
|
|
342
|
+
code: "settings-rejected",
|
|
343
|
+
message: "smooth-stream debug settings are read-only",
|
|
344
|
+
details: { ns: STREAM_SETTINGS_NS }
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
try {
|
|
348
|
+
await scope.update({
|
|
349
|
+
debugEnabled: next.debugEnabled,
|
|
350
|
+
debugTuning: next.tuning
|
|
351
|
+
});
|
|
352
|
+
} catch {
|
|
353
|
+
return {
|
|
354
|
+
ok: false,
|
|
355
|
+
error: {
|
|
356
|
+
code: "settings-rejected",
|
|
357
|
+
message: "smooth-stream debug settings update failed",
|
|
358
|
+
details: { ns: STREAM_SETTINGS_NS }
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
return {
|
|
363
|
+
ok: true,
|
|
364
|
+
value: debugView()
|
|
365
|
+
};
|
|
366
|
+
}
|
|
250
367
|
if (endpoint === STREAM_SETTINGS_RPC.upgrade) {
|
|
251
368
|
const installation = inspectProfileInstallation(connectionCtx.baseUrl, STREAM_PACKAGE_NAME);
|
|
252
369
|
if (installation.kind !== "npm") return {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-smooth-stream",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "DeepSeek Harness
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Fluid streaming rendering and silky scrolling for DeepSeek Harness replies, including Markdown, code blocks, tables, and tool results.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"engines": {
|
|
@@ -23,6 +23,11 @@
|
|
|
23
23
|
"cordis",
|
|
24
24
|
"streaming",
|
|
25
25
|
"smooth-streaming",
|
|
26
|
+
"fluid-streaming",
|
|
27
|
+
"streaming-renderer",
|
|
28
|
+
"markdown-streaming",
|
|
29
|
+
"smooth-scrolling",
|
|
30
|
+
"smooth-scroll",
|
|
26
31
|
"smooth-stream",
|
|
27
32
|
"typewriter",
|
|
28
33
|
"typewriter-effect",
|
|
@@ -72,13 +77,6 @@
|
|
|
72
77
|
]
|
|
73
78
|
}
|
|
74
79
|
},
|
|
75
|
-
"scripts": {
|
|
76
|
-
"build": "tsdown",
|
|
77
|
-
"build:repro": "esbuild repro/main.tsx --bundle --format=esm --platform=browser --loader:.css=local-css --outfile=repro/bundle.js",
|
|
78
|
-
"prepare": "tsdown",
|
|
79
|
-
"test": "vitest run",
|
|
80
|
-
"typecheck": "tsc -p tsconfig.json --pretty false"
|
|
81
|
-
},
|
|
82
80
|
"dependencies": {
|
|
83
81
|
"@deepseek-ai/dsh-settings": "0.1.0-rc.6"
|
|
84
82
|
},
|
|
@@ -155,5 +153,12 @@
|
|
|
155
153
|
"tsdown": "^0.22.2",
|
|
156
154
|
"typescript": "^5.9.2",
|
|
157
155
|
"vitest": "^4.1.8"
|
|
156
|
+
},
|
|
157
|
+
"scripts": {
|
|
158
|
+
"benchmark": "node scripts/run-stream-benchmark.mjs",
|
|
159
|
+
"build": "tsdown",
|
|
160
|
+
"build:repro": "esbuild repro/main.tsx --bundle --format=esm --platform=browser --loader:.css=local-css --outfile=repro/bundle.js",
|
|
161
|
+
"test": "vitest run",
|
|
162
|
+
"typecheck": "tsc -p tsconfig.json --pretty false"
|
|
158
163
|
}
|
|
159
|
-
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
.trigger,
|
|
2
|
+
.iconButton {
|
|
3
|
+
appearance: none;
|
|
4
|
+
display: inline-flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
justify-content: center;
|
|
7
|
+
width: 32px;
|
|
8
|
+
height: 32px;
|
|
9
|
+
padding: 0;
|
|
10
|
+
border: 1px solid transparent;
|
|
11
|
+
border-radius: 6px;
|
|
12
|
+
background: transparent;
|
|
13
|
+
color: var(--dsw-alias-label-tertiary);
|
|
14
|
+
cursor: pointer;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.trigger:hover,
|
|
18
|
+
.iconButton:hover:not(:disabled) {
|
|
19
|
+
background: var(--dsw-alias-interactive-bg-hover);
|
|
20
|
+
color: var(--dsw-alias-label-primary);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.iconButton:disabled {
|
|
24
|
+
opacity: 0.45;
|
|
25
|
+
cursor: not-allowed;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.triggerActive {
|
|
29
|
+
border-color: var(--dsw-alias-border-l2);
|
|
30
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
31
|
+
color: var(--dsw-alias-state-business-primary);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.trigger:focus-visible,
|
|
35
|
+
.iconButton:focus-visible,
|
|
36
|
+
.secondaryButton:focus-visible,
|
|
37
|
+
.primaryButton:focus-visible,
|
|
38
|
+
.number:focus-visible,
|
|
39
|
+
.range:focus-visible {
|
|
40
|
+
outline: 2px solid var(--dsw-alias-brand-primary);
|
|
41
|
+
outline-offset: 1px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.panel {
|
|
45
|
+
position: fixed;
|
|
46
|
+
top: 88px;
|
|
47
|
+
right: 16px;
|
|
48
|
+
bottom: 16px;
|
|
49
|
+
z-index: 30;
|
|
50
|
+
display: flex;
|
|
51
|
+
flex-direction: column;
|
|
52
|
+
width: min(328px, calc(100vw - 32px));
|
|
53
|
+
min-height: 280px;
|
|
54
|
+
overflow: hidden;
|
|
55
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
56
|
+
border-radius: 8px;
|
|
57
|
+
background: var(--dsw-alias-bg-layer-3);
|
|
58
|
+
box-shadow: 0 12px 32px color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent);
|
|
59
|
+
color: var(--dsw-alias-label-primary);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.panelHeader {
|
|
63
|
+
display: flex;
|
|
64
|
+
flex: none;
|
|
65
|
+
align-items: center;
|
|
66
|
+
gap: 8px;
|
|
67
|
+
min-height: 48px;
|
|
68
|
+
padding: 0 8px 0 14px;
|
|
69
|
+
border-bottom: 1px solid var(--dsw-alias-border-l2);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.statusDot {
|
|
73
|
+
flex: none;
|
|
74
|
+
width: 7px;
|
|
75
|
+
height: 7px;
|
|
76
|
+
border-radius: 50%;
|
|
77
|
+
background: var(--dsw-alias-label-caption);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.statusLive {
|
|
81
|
+
background: var(--dsw-alias-state-success-primary);
|
|
82
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--dsw-alias-state-success-primary) 15%, transparent);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.title {
|
|
86
|
+
min-width: 0;
|
|
87
|
+
overflow: hidden;
|
|
88
|
+
flex: 1;
|
|
89
|
+
font-size: 14px;
|
|
90
|
+
font-weight: 600;
|
|
91
|
+
line-height: 20px;
|
|
92
|
+
text-overflow: ellipsis;
|
|
93
|
+
white-space: nowrap;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.state,
|
|
97
|
+
.unsaved {
|
|
98
|
+
flex: none;
|
|
99
|
+
font-size: 10px;
|
|
100
|
+
line-height: 16px;
|
|
101
|
+
color: var(--dsw-alias-label-tertiary);
|
|
102
|
+
white-space: nowrap;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.unsaved {
|
|
106
|
+
color: var(--dsw-alias-state-warn-primary);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.scrollArea {
|
|
110
|
+
min-height: 0;
|
|
111
|
+
overflow-y: auto;
|
|
112
|
+
overscroll-behavior: contain;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.section {
|
|
116
|
+
padding: 14px;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.guide {
|
|
120
|
+
margin: 0;
|
|
121
|
+
padding: 12px 14px;
|
|
122
|
+
border-bottom: 1px solid var(--dsw-alias-border-l2);
|
|
123
|
+
color: var(--dsw-alias-label-tertiary);
|
|
124
|
+
font-size: 11px;
|
|
125
|
+
line-height: 1.55;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.section + .section {
|
|
129
|
+
border-top: 1px solid var(--dsw-alias-border-l2);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.section h2 {
|
|
133
|
+
margin: 0 0 10px;
|
|
134
|
+
font-size: 12px;
|
|
135
|
+
font-weight: 600;
|
|
136
|
+
line-height: 18px;
|
|
137
|
+
color: var(--dsw-alias-label-secondary);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.metrics {
|
|
141
|
+
display: grid;
|
|
142
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
143
|
+
gap: 0 16px;
|
|
144
|
+
margin: 0;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.metric {
|
|
148
|
+
display: flex;
|
|
149
|
+
align-items: baseline;
|
|
150
|
+
justify-content: space-between;
|
|
151
|
+
gap: 8px;
|
|
152
|
+
min-width: 0;
|
|
153
|
+
padding: 5px 0;
|
|
154
|
+
border-bottom: 1px solid color-mix(in srgb, var(--dsw-alias-border-l2) 65%, transparent);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.metric dt {
|
|
158
|
+
min-width: 0;
|
|
159
|
+
overflow: hidden;
|
|
160
|
+
font-size: 11px;
|
|
161
|
+
line-height: 16px;
|
|
162
|
+
color: var(--dsw-alias-label-tertiary);
|
|
163
|
+
text-overflow: ellipsis;
|
|
164
|
+
white-space: nowrap;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.metric dd {
|
|
168
|
+
min-width: 0;
|
|
169
|
+
margin: 0;
|
|
170
|
+
overflow: hidden;
|
|
171
|
+
color: var(--dsw-alias-label-primary);
|
|
172
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
173
|
+
font-size: 11px;
|
|
174
|
+
font-variant-numeric: tabular-nums;
|
|
175
|
+
line-height: 16px;
|
|
176
|
+
text-overflow: ellipsis;
|
|
177
|
+
white-space: nowrap;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.metric dd[data-tone='good'] {
|
|
181
|
+
color: var(--dsw-alias-state-success-primary);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.metric dd[data-tone='warn'] {
|
|
185
|
+
color: var(--dsw-alias-state-warn-primary);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.control {
|
|
189
|
+
display: flex;
|
|
190
|
+
flex-direction: column;
|
|
191
|
+
gap: 5px;
|
|
192
|
+
padding: 6px 0;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.controlHead {
|
|
196
|
+
display: flex;
|
|
197
|
+
align-items: center;
|
|
198
|
+
justify-content: space-between;
|
|
199
|
+
gap: 10px;
|
|
200
|
+
font-size: 11px;
|
|
201
|
+
line-height: 18px;
|
|
202
|
+
color: var(--dsw-alias-label-secondary);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.controlLabel {
|
|
206
|
+
display: inline-flex;
|
|
207
|
+
align-items: center;
|
|
208
|
+
min-width: 0;
|
|
209
|
+
gap: 4px;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.infoButton {
|
|
213
|
+
appearance: none;
|
|
214
|
+
display: inline-flex;
|
|
215
|
+
align-items: center;
|
|
216
|
+
justify-content: center;
|
|
217
|
+
width: 20px;
|
|
218
|
+
height: 20px;
|
|
219
|
+
padding: 0;
|
|
220
|
+
border: 0;
|
|
221
|
+
border-radius: 50%;
|
|
222
|
+
background: transparent;
|
|
223
|
+
color: var(--dsw-alias-label-tertiary);
|
|
224
|
+
cursor: help;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.infoButton:hover {
|
|
228
|
+
color: var(--dsw-alias-label-primary);
|
|
229
|
+
background: var(--dsw-alias-interactive-bg-hover);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.infoButton:focus-visible {
|
|
233
|
+
outline: 2px solid var(--dsw-alias-brand-primary);
|
|
234
|
+
outline-offset: 1px;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.numberWrap {
|
|
238
|
+
display: inline-flex;
|
|
239
|
+
align-items: center;
|
|
240
|
+
flex: none;
|
|
241
|
+
gap: 4px;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.number {
|
|
245
|
+
box-sizing: border-box;
|
|
246
|
+
width: 68px;
|
|
247
|
+
height: 26px;
|
|
248
|
+
padding: 2px 6px;
|
|
249
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
250
|
+
border-radius: 5px;
|
|
251
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
252
|
+
color: var(--dsw-alias-label-primary);
|
|
253
|
+
font: inherit;
|
|
254
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
255
|
+
font-variant-numeric: tabular-nums;
|
|
256
|
+
text-align: right;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.unit {
|
|
260
|
+
width: 30px;
|
|
261
|
+
color: var(--dsw-alias-label-tertiary);
|
|
262
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
263
|
+
font-size: 10px;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.range {
|
|
267
|
+
width: 100%;
|
|
268
|
+
height: 18px;
|
|
269
|
+
margin: 0;
|
|
270
|
+
accent-color: var(--dsw-alias-state-business-primary);
|
|
271
|
+
cursor: pointer;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.range:disabled,
|
|
275
|
+
.number:disabled {
|
|
276
|
+
opacity: 0.5;
|
|
277
|
+
cursor: default;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.footer {
|
|
281
|
+
display: flex;
|
|
282
|
+
flex: none;
|
|
283
|
+
align-items: center;
|
|
284
|
+
gap: 6px;
|
|
285
|
+
min-height: 50px;
|
|
286
|
+
padding: 8px 10px;
|
|
287
|
+
border-top: 1px solid var(--dsw-alias-border-l2);
|
|
288
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.footerSpacer {
|
|
292
|
+
flex: 1;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.secondaryButton,
|
|
296
|
+
.primaryButton {
|
|
297
|
+
appearance: none;
|
|
298
|
+
display: inline-flex;
|
|
299
|
+
align-items: center;
|
|
300
|
+
justify-content: center;
|
|
301
|
+
gap: 5px;
|
|
302
|
+
min-height: 30px;
|
|
303
|
+
padding: 4px 9px;
|
|
304
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
305
|
+
border-radius: 6px;
|
|
306
|
+
background: transparent;
|
|
307
|
+
color: var(--dsw-alias-label-secondary);
|
|
308
|
+
font: inherit;
|
|
309
|
+
font-size: 11px;
|
|
310
|
+
line-height: 18px;
|
|
311
|
+
cursor: pointer;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.primaryButton {
|
|
315
|
+
border-color: transparent;
|
|
316
|
+
background: var(--dsw-alias-label-primary);
|
|
317
|
+
color: var(--dsw-alias-bg-layer-3);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.secondaryButton:hover:not(:disabled) {
|
|
321
|
+
color: var(--dsw-alias-label-primary);
|
|
322
|
+
border-color: var(--dsw-alias-label-dimmed);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.secondaryButton:disabled,
|
|
326
|
+
.primaryButton:disabled {
|
|
327
|
+
opacity: 0.4;
|
|
328
|
+
cursor: default;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.visuallyHidden {
|
|
332
|
+
position: absolute;
|
|
333
|
+
overflow: hidden;
|
|
334
|
+
width: 1px;
|
|
335
|
+
height: 1px;
|
|
336
|
+
padding: 0;
|
|
337
|
+
border: 0;
|
|
338
|
+
margin: -1px;
|
|
339
|
+
clip: rect(0 0 0 0);
|
|
340
|
+
clip-path: inset(50%);
|
|
341
|
+
white-space: nowrap;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
@media (max-width: 900px) {
|
|
345
|
+
.trigger,
|
|
346
|
+
.iconButton {
|
|
347
|
+
width: 44px;
|
|
348
|
+
height: 44px;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.panel {
|
|
352
|
+
top: auto;
|
|
353
|
+
right: 12px;
|
|
354
|
+
bottom: max(12px, env(safe-area-inset-bottom));
|
|
355
|
+
left: 12px;
|
|
356
|
+
width: auto;
|
|
357
|
+
max-height: min(70dvh, 640px);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.secondaryButton,
|
|
361
|
+
.primaryButton {
|
|
362
|
+
min-height: 44px;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
@media (prefers-reduced-motion: reduce) {
|
|
367
|
+
.statusLive {
|
|
368
|
+
box-shadow: none;
|
|
369
|
+
}
|
|
370
|
+
}
|