dsh-subscriptions 0.1.5 → 0.2.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/README.md +212 -154
- package/lib/auth/claude-code-creds.js +31 -9
- package/lib/auth/device-flow.js +16 -9
- package/lib/auth/oauth-flow.js +13 -10
- package/lib/auth/rpc.d.ts +73 -2
- package/lib/auth/rpc.js +124 -23
- package/lib/auth/store.js +80 -31
- package/lib/client/CursorCard.d.ts +1 -1
- package/lib/client/CursorCard.js +50 -16
- package/lib/client/ExternalUsageCards.d.ts +1 -1
- package/lib/client/ExternalUsageCards.js +37 -16
- package/lib/client/ImageGallery.d.ts +2 -2
- package/lib/client/ImageGallery.js +92 -33
- package/lib/client/ImageGenerateToolview.js +50 -14
- package/lib/client/OllamaCard.d.ts +13 -0
- package/lib/client/OllamaCard.js +94 -0
- package/lib/client/OllamaSettingsManager.d.ts +24 -0
- package/lib/client/OllamaSettingsManager.js +329 -0
- package/lib/client/ProviderAccountManager.d.ts +1 -1
- package/lib/client/ProviderAccountManager.js +164 -49
- package/lib/client/ProviderModelEditor.js +109 -26
- package/lib/client/SpeedSelect.d.ts +62 -14
- package/lib/client/SpeedSelect.js +257 -46
- package/lib/client/SubscriptionUsageBadge.d.ts +5 -11
- package/lib/client/SubscriptionUsageBadge.js +301 -112
- package/lib/client/SubscriptionsSection.d.ts +2 -0
- package/lib/client/SubscriptionsSection.js +259 -85
- package/lib/client/UsageBadgeDisplaySetting.js +35 -12
- package/lib/client/UsageMeter.d.ts +1 -1
- package/lib/client/UsageMeter.js +69 -27
- package/lib/client/VideoGenerateToolview.js +69 -17
- package/lib/client/account-preferences.d.ts +8 -0
- package/lib/client/account-preferences.js +20 -5
- package/lib/client/host-contract.d.ts +11 -2
- package/lib/client/host-contract.js +20 -3
- package/lib/client/index.d.ts +5 -5
- package/lib/client/index.js +34 -12
- package/lib/client/locales.d.ts +78 -0
- package/lib/client/locales.js +121 -34
- package/lib/client/ollama-draft.d.ts +229 -0
- package/lib/client/ollama-draft.js +255 -0
- package/lib/client/reset-action.js +6 -4
- package/lib/client/reset-credits-view.d.ts +1 -1
- package/lib/client/reset-credits-view.js +66 -17
- package/lib/client/subscription-card-styles.js +94 -24
- package/lib/client/usage-color-preferences.js +4 -2
- package/lib/client/usage-pace.d.ts +7 -0
- package/lib/client/usage-pace.js +43 -10
- package/lib/client.js +1647 -266
- package/lib/client.js.map +1 -1
- package/lib/http.js +1 -1
- package/lib/index.d.ts +28 -3
- package/lib/index.js +9329 -8217
- package/lib/model-defaults.js +4 -2
- package/lib/provider-settings.d.ts +14 -1
- package/lib/provider-settings.js +64 -20
- package/lib/providers/account-preferences.js +51 -22
- package/lib/providers/accounts.js +15 -9
- package/lib/providers/antigravity-oauth-client.js +2 -2
- package/lib/providers/antigravity.js +141 -68
- package/lib/providers/catalog-store.js +120 -41
- package/lib/providers/claude-cli-version.js +3 -3
- package/lib/providers/claude.d.ts +23 -3
- package/lib/providers/claude.js +167 -92
- package/lib/providers/codex-client-version.js +3 -3
- package/lib/providers/codex-search.js +40 -13
- package/lib/providers/codex.js +196 -112
- package/lib/providers/common.d.ts +14 -0
- package/lib/providers/common.js +118 -38
- package/lib/providers/copilot.js +143 -82
- package/lib/providers/cursor-adapter.js +42 -18
- package/lib/providers/cursor-auth.d.ts +1 -1
- package/lib/providers/cursor-auth.js +69 -24
- package/lib/providers/cursor-model-settings.js +14 -5
- package/lib/providers/cursor-usage.js +27 -13
- package/lib/providers/external-usage-controller.d.ts +9 -2
- package/lib/providers/external-usage-controller.js +30 -7
- package/lib/providers/external-usage.d.ts +8 -0
- package/lib/providers/external-usage.js +140 -20
- package/lib/providers/grok.js +152 -89
- package/lib/providers/image-pool.js +29 -11
- package/lib/providers/minimax-usage.js +31 -11
- package/lib/providers/npm-cli-version.js +10 -3
- package/lib/providers/ollama-settings.d.ts +90 -0
- package/lib/providers/ollama-settings.js +213 -0
- package/lib/providers/ollama-web.d.ts +46 -0
- package/lib/providers/ollama-web.js +231 -0
- package/lib/providers/ollama.d.ts +107 -0
- package/lib/providers/ollama.js +608 -0
- package/lib/providers/pool-family.js +11 -3
- package/lib/providers/pool-health.js +28 -8
- package/lib/providers/pool-usage.js +16 -9
- package/lib/providers/pool.d.ts +8 -0
- package/lib/providers/pool.js +81 -42
- package/lib/providers/rate-limit.js +8 -2
- package/lib/providers/replay.js +40 -17
- package/lib/providers/reset-redemption.js +18 -6
- package/lib/tools/image-generate.js +123 -65
- package/lib/tools/registration.js +5 -2
- package/lib/tools/video-generate.js +51 -31
- package/lib/tools/x-search.js +50 -22
- package/lib/translate/anthropic.js +85 -37
- package/lib/translate/antigravity-schema.js +71 -28
- package/lib/translate/antigravity-thinking.js +22 -9
- package/lib/translate/antigravity.js +141 -50
- package/lib/translate/chat-completions.js +67 -23
- package/lib/translate/resolved.js +55 -21
- package/lib/translate/responses.js +69 -29
- package/lib/translate/sse.js +4 -1
- package/package.json +26 -4
|
@@ -27,13 +27,14 @@ import { useCallback, useEffect, useRef, useState } from 'react';
|
|
|
27
27
|
import { subscriptionChromeCss } from './provider-settings-styles.js';
|
|
28
28
|
import { createPortal } from 'react-dom';
|
|
29
29
|
import * as primitives from '@deepseek-ai/dsh-client-ui-primitives';
|
|
30
|
-
import { useAnchoredPosition, useDismissOnOutsidePointer } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
30
|
+
import { useAnchoredPosition, useDismissOnOutsidePointer, } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
31
31
|
import { callSubscriptionsAuth } from './SubscriptionsSection.js';
|
|
32
32
|
import { UsageMeter } from './UsageMeter.js';
|
|
33
33
|
import { displayUsedPercent } from './usage-pace.js';
|
|
34
34
|
import { en } from './locales.js';
|
|
35
35
|
import { hostIcon } from './host-icons.js';
|
|
36
|
-
import {
|
|
36
|
+
import { HOST_CONTRACT, markerSelector } from './host-contract.js';
|
|
37
|
+
import { USAGE_BADGE_REFRESH_EVENT, useUsageBadgeMode, } from './usage-badge-preferences.js';
|
|
37
38
|
/** DSH renamed the data icon in 0.1.7; retain older supported hosts too. */
|
|
38
39
|
export function usageBadgeIcon(icons) {
|
|
39
40
|
return hostIcon(icons, 'DataOutline');
|
|
@@ -51,7 +52,7 @@ const PANEL_GAP = 8;
|
|
|
51
52
|
const PANEL_MARGIN = 12;
|
|
52
53
|
/** The account the collapsed pill reads: the default one, else the first listed. */
|
|
53
54
|
export function pillAccountOf(d) {
|
|
54
|
-
return d.accounts.find(a => a.isDefault) ?? d.accounts[0];
|
|
55
|
+
return d.accounts.find((a) => a.isDefault) ?? d.accounts[0];
|
|
55
56
|
}
|
|
56
57
|
const PROVIDER_NAMES = {
|
|
57
58
|
codex: 'Codex',
|
|
@@ -62,8 +63,9 @@ const PROVIDER_NAMES = {
|
|
|
62
63
|
'cursor-subscription': 'Cursor',
|
|
63
64
|
'opencode-go': 'OpenCode Go',
|
|
64
65
|
'kimi-coding': 'Kimi Code',
|
|
65
|
-
|
|
66
|
+
minimax: 'MiniMax',
|
|
66
67
|
'minimax-cn': 'MiniMax CN',
|
|
68
|
+
'ollama-cloud': 'Ollama Cloud',
|
|
67
69
|
};
|
|
68
70
|
/** Key of one account's cached windows: `provider:accountKey`. */
|
|
69
71
|
function usageKeyOf(provider, account) {
|
|
@@ -90,13 +92,17 @@ export function groupUsageDisplays(roster, windowsOf, plans) {
|
|
|
90
92
|
const row = {
|
|
91
93
|
key: account.key,
|
|
92
94
|
isDefault: account.isDefault,
|
|
93
|
-
...account.account === undefined ? {} : { account: account.account },
|
|
94
|
-
...plan === undefined ? {} : { plan },
|
|
95
|
+
...(account.account === undefined ? {} : { account: account.account }),
|
|
96
|
+
...(plan === undefined ? {} : { plan }),
|
|
95
97
|
windows,
|
|
96
98
|
};
|
|
97
99
|
const display = byProvider.get(provider);
|
|
98
100
|
if (display === undefined)
|
|
99
|
-
byProvider.set(provider, {
|
|
101
|
+
byProvider.set(provider, {
|
|
102
|
+
provider,
|
|
103
|
+
name: PROVIDER_NAMES[provider],
|
|
104
|
+
accounts: [row],
|
|
105
|
+
});
|
|
100
106
|
else
|
|
101
107
|
display.accounts.push(row);
|
|
102
108
|
}
|
|
@@ -112,7 +118,13 @@ export async function loadBadgeRoster(rpc) {
|
|
|
112
118
|
const roster = [];
|
|
113
119
|
const refreshed = new Set();
|
|
114
120
|
if (subscriptions.status === 'fulfilled') {
|
|
115
|
-
for (const provider of [
|
|
121
|
+
for (const provider of [
|
|
122
|
+
'codex',
|
|
123
|
+
'claude',
|
|
124
|
+
'grok',
|
|
125
|
+
'copilot',
|
|
126
|
+
'antigravity',
|
|
127
|
+
]) {
|
|
116
128
|
refreshed.add(provider);
|
|
117
129
|
for (const account of accountsOf(subscriptions.value.providers[provider]))
|
|
118
130
|
roster.push({ provider, account });
|
|
@@ -122,17 +134,23 @@ export async function loadBadgeRoster(rpc) {
|
|
|
122
134
|
refreshed.add('cursor-subscription');
|
|
123
135
|
if (cursor.value.authenticated)
|
|
124
136
|
roster.push({
|
|
125
|
-
provider: 'cursor-subscription',
|
|
137
|
+
provider: 'cursor-subscription',
|
|
138
|
+
account: { key: 'cursor', isDefault: true },
|
|
126
139
|
});
|
|
127
140
|
}
|
|
128
141
|
if (external.status === 'fulfilled') {
|
|
129
142
|
for (const [source, provider] of [
|
|
130
|
-
['opencode-go', 'opencode-go'],
|
|
143
|
+
['opencode-go', 'opencode-go'],
|
|
144
|
+
['kimi-code', 'kimi-coding'],
|
|
145
|
+
['minimax', 'minimax'],
|
|
146
|
+
['minimax-cn', 'minimax-cn'],
|
|
147
|
+
['ollama-cloud', 'ollama-cloud'],
|
|
131
148
|
]) {
|
|
132
149
|
refreshed.add(provider);
|
|
133
150
|
if (external.value[source]?.configured)
|
|
134
151
|
roster.push({
|
|
135
|
-
provider,
|
|
152
|
+
provider,
|
|
153
|
+
account: { key: source, isDefault: true },
|
|
136
154
|
});
|
|
137
155
|
}
|
|
138
156
|
}
|
|
@@ -141,8 +159,14 @@ export async function loadBadgeRoster(rpc) {
|
|
|
141
159
|
export async function usageOf(rpc, { provider, account }) {
|
|
142
160
|
if (provider === 'cursor-subscription')
|
|
143
161
|
return callSubscriptionsAuth(rpc, 'cursorUsage', {});
|
|
144
|
-
if (provider === 'opencode-go' ||
|
|
145
|
-
|
|
162
|
+
if (provider === 'opencode-go' ||
|
|
163
|
+
provider === 'kimi-coding' ||
|
|
164
|
+
provider === 'minimax' ||
|
|
165
|
+
provider === 'minimax-cn' ||
|
|
166
|
+
provider === 'ollama-cloud') {
|
|
167
|
+
return callSubscriptionsAuth(rpc, 'externalUsage', {
|
|
168
|
+
source: provider === 'kimi-coding' ? 'kimi-code' : provider,
|
|
169
|
+
});
|
|
146
170
|
}
|
|
147
171
|
return callSubscriptionsAuth(rpc, 'usage', { provider, account: account.key });
|
|
148
172
|
}
|
|
@@ -172,9 +196,12 @@ export function windowLabel(w) {
|
|
|
172
196
|
if (w.scope !== undefined && w.scope !== '')
|
|
173
197
|
return w.scope;
|
|
174
198
|
switch (w.kind) {
|
|
175
|
-
case 'session':
|
|
176
|
-
|
|
177
|
-
|
|
199
|
+
case 'session':
|
|
200
|
+
return '5h';
|
|
201
|
+
case 'weekly':
|
|
202
|
+
return 'Wk';
|
|
203
|
+
default:
|
|
204
|
+
return 'W';
|
|
178
205
|
}
|
|
179
206
|
}
|
|
180
207
|
const ms = Math.max(0, w.resetsAt - Date.now());
|
|
@@ -197,10 +224,12 @@ function windowSegment(label, w) {
|
|
|
197
224
|
}
|
|
198
225
|
/** Keep model quotas separate: matching percentages do not imply a shared pool. */
|
|
199
226
|
export function prioritizeWindows(windows, model) {
|
|
200
|
-
return model === undefined
|
|
201
|
-
...windows
|
|
202
|
-
|
|
203
|
-
|
|
227
|
+
return model === undefined
|
|
228
|
+
? [...windows]
|
|
229
|
+
: [
|
|
230
|
+
...windows.filter((w) => w.scope === model),
|
|
231
|
+
...windows.filter((w) => w.scope !== model),
|
|
232
|
+
];
|
|
204
233
|
}
|
|
205
234
|
/** Small previews keep a live model catalog from taking over the dialog. */
|
|
206
235
|
export const WINDOW_PREVIEW_LIMIT = 4;
|
|
@@ -208,7 +237,9 @@ export function previewWindows(windows, model, provider) {
|
|
|
208
237
|
const ordered = prioritizeWindows(windows, model);
|
|
209
238
|
// Antigravity has many model-specific quotas: preview only the current model.
|
|
210
239
|
const limit = provider === 'antigravity'
|
|
211
|
-
? Math.min(2, model === undefined
|
|
240
|
+
? Math.min(2, model === undefined
|
|
241
|
+
? 0
|
|
242
|
+
: windows.filter((w) => w.scope === model).length)
|
|
212
243
|
: WINDOW_PREVIEW_LIMIT;
|
|
213
244
|
return { shown: ordered.slice(0, limit), hidden: ordered.slice(limit) };
|
|
214
245
|
}
|
|
@@ -216,27 +247,34 @@ export function previewWindows(windows, model, provider) {
|
|
|
216
247
|
export function compactSegment(d, model, t = fallbackTranslate) {
|
|
217
248
|
const windows = pillAccountOf(d).windows;
|
|
218
249
|
if (d.provider === 'antigravity') {
|
|
219
|
-
const matching = model === undefined ? [] : windows.filter(w => w.scope === model);
|
|
250
|
+
const matching = model === undefined ? [] : windows.filter((w) => w.scope === model);
|
|
220
251
|
if (matching.length === 0) {
|
|
221
|
-
return `${d.name} ${t(model === undefined
|
|
222
|
-
|
|
252
|
+
return `${d.name} ${t(model === undefined
|
|
253
|
+
? 'usageBadgeModelCount'
|
|
254
|
+
: 'usageBadgeModelUnavailable', {
|
|
255
|
+
count: new Set(windows.map((w) => w.scope).filter(Boolean)).size,
|
|
223
256
|
})}`;
|
|
224
257
|
}
|
|
225
|
-
const parts = matching
|
|
258
|
+
const parts = matching
|
|
259
|
+
.slice(0, 2)
|
|
260
|
+
.map((w) => windowSegment(w.kind === 'weekly' ? t('usageWeekly') : t('usageWindow'), w));
|
|
226
261
|
return `${d.name} ${parts.join(' · ')}`;
|
|
227
262
|
}
|
|
228
|
-
const parts = windows.slice(0, 2).map(w => windowSegment(windowLabel(w), w));
|
|
263
|
+
const parts = windows.slice(0, 2).map((w) => windowSegment(windowLabel(w), w));
|
|
229
264
|
if (windows.length > 2)
|
|
230
265
|
parts.push(`+${windows.length - 2}`);
|
|
231
266
|
return `${d.name} ${parts.join(' · ')}`;
|
|
232
267
|
}
|
|
233
268
|
/** Remember only the most recent subscription in this view, including its model scope. */
|
|
234
269
|
export function retainSubscriptionSelection(previous, current) {
|
|
235
|
-
return current !== undefined &&
|
|
270
|
+
return current !== undefined &&
|
|
271
|
+
Object.hasOwn(PROVIDER_NAMES, current.provider)
|
|
272
|
+
? current
|
|
273
|
+
: previous;
|
|
236
274
|
}
|
|
237
275
|
/** At most one provider; no known selection or no usage means no badge. */
|
|
238
276
|
export function collapsedDisplays(displays, current) {
|
|
239
|
-
const match = displays.find(d => d.provider === current);
|
|
277
|
+
const match = displays.find((d) => d.provider === current);
|
|
240
278
|
return match === undefined ? [] : [match];
|
|
241
279
|
}
|
|
242
280
|
/**
|
|
@@ -254,16 +292,20 @@ export function collapsedDisplays(displays, current) {
|
|
|
254
292
|
export function rotatingDisplay(displays, current, step) {
|
|
255
293
|
if (displays.length === 0)
|
|
256
294
|
return [];
|
|
257
|
-
const match = displays.find(d => d.provider === current);
|
|
295
|
+
const match = displays.find((d) => d.provider === current);
|
|
258
296
|
if (match !== undefined)
|
|
259
297
|
return [match];
|
|
260
298
|
const index = Number.isFinite(step) ? Math.floor(step) : 0;
|
|
261
|
-
return [
|
|
299
|
+
return [
|
|
300
|
+
displays[((index % displays.length) + displays.length) % displays.length],
|
|
301
|
+
];
|
|
262
302
|
}
|
|
263
303
|
/** Order for the expanded dialog: the current provider first, the rest in poll order. */
|
|
264
304
|
export function expandedDisplays(displays, current) {
|
|
265
|
-
const match = displays.find(d => d.provider === current);
|
|
266
|
-
return match === undefined
|
|
305
|
+
const match = displays.find((d) => d.provider === current);
|
|
306
|
+
return match === undefined
|
|
307
|
+
? displays
|
|
308
|
+
: [match, ...displays.filter((d) => d !== match)];
|
|
267
309
|
}
|
|
268
310
|
/**
|
|
269
311
|
* A provider's logged-in accounts, the effective default first. When no
|
|
@@ -273,9 +315,9 @@ export function expandedDisplays(displays, current) {
|
|
|
273
315
|
function accountsOf(status) {
|
|
274
316
|
if (status === undefined || status.accounts.length === 0)
|
|
275
317
|
return [];
|
|
276
|
-
const fallback = status.accounts.find(a => a.isDefault) ?? status.accounts[0];
|
|
318
|
+
const fallback = status.accounts.find((a) => a.isDefault) ?? status.accounts[0];
|
|
277
319
|
return status.accounts
|
|
278
|
-
.map(a => (a === fallback ? { ...a, isDefault: true } : a))
|
|
320
|
+
.map((a) => (a === fallback ? { ...a, isDefault: true } : a))
|
|
279
321
|
.sort((a, b) => Number(b.isDefault) - Number(a.isDefault));
|
|
280
322
|
}
|
|
281
323
|
/** English-dictionary fallback for a missing inject `t` (standalone renders). */
|
|
@@ -286,8 +328,12 @@ function fallbackTranslate(key, params) {
|
|
|
286
328
|
function usageWindowLabel(t, window) {
|
|
287
329
|
const base = window.kind === 'session'
|
|
288
330
|
? t('usageSession')
|
|
289
|
-
: window.kind === 'weekly'
|
|
290
|
-
|
|
331
|
+
: window.kind === 'weekly'
|
|
332
|
+
? t('usageWeekly')
|
|
333
|
+
: t('usageWindow');
|
|
334
|
+
return window.scope !== undefined && window.scope !== ''
|
|
335
|
+
? `${base} · ${window.scope}`
|
|
336
|
+
: base;
|
|
291
337
|
}
|
|
292
338
|
/**
|
|
293
339
|
* The composer subscription-usage badge: a pill reading e.g.
|
|
@@ -295,7 +341,9 @@ function usageWindowLabel(t, window) {
|
|
|
295
341
|
* every provider's accounts and their windows. Returns null when no data is
|
|
296
342
|
* available.
|
|
297
343
|
*/
|
|
298
|
-
|
|
344
|
+
const STATS_ROW_SELECTOR = markerSelector(HOST_CONTRACT.markers.composerStats.row);
|
|
345
|
+
const STATS_DOCK_SELECTOR = markerSelector(HOST_CONTRACT.markers.composerStats.dock);
|
|
346
|
+
export function SubscriptionUsageBadge({ rpc, currentModel, t, rotationMs, }) {
|
|
299
347
|
const translate = t ?? fallbackTranslate;
|
|
300
348
|
const [displays, setDisplays] = useState([]);
|
|
301
349
|
const [selection, setSelection] = useState(undefined);
|
|
@@ -342,7 +390,8 @@ export function SubscriptionUsageBadge({ rpc, currentModel, t, rotationMs }) {
|
|
|
342
390
|
// real signal, unlike a fetch failure.
|
|
343
391
|
const live = new Set(roster.map(({ provider, account }) => usageKeyOf(provider, account)));
|
|
344
392
|
for (const key of lastKnown.keys()) {
|
|
345
|
-
if (refreshed.has(key.split(':', 1)[0]) &&
|
|
393
|
+
if (refreshed.has(key.split(':', 1)[0]) &&
|
|
394
|
+
!live.has(key)) {
|
|
346
395
|
lastKnown.delete(key);
|
|
347
396
|
observationsRef.current.delete(key);
|
|
348
397
|
}
|
|
@@ -355,7 +404,10 @@ export function SubscriptionUsageBadge({ rpc, currentModel, t, rotationMs }) {
|
|
|
355
404
|
return;
|
|
356
405
|
for (const { provider, account } of roster) {
|
|
357
406
|
const key = usageKeyOf(provider, account);
|
|
358
|
-
observationsRef.current.set(key, {
|
|
407
|
+
observationsRef.current.set(key, {
|
|
408
|
+
...observationsRef.current.get(key),
|
|
409
|
+
stale: true,
|
|
410
|
+
});
|
|
359
411
|
}
|
|
360
412
|
const plans = new Map();
|
|
361
413
|
for (const r of results) {
|
|
@@ -371,24 +423,39 @@ export function SubscriptionUsageBadge({ rpc, currentModel, t, rotationMs }) {
|
|
|
371
423
|
continue;
|
|
372
424
|
}
|
|
373
425
|
lastKnown.set(key, usage.windows);
|
|
374
|
-
observationsRef.current.set(key, {
|
|
426
|
+
observationsRef.current.set(key, {
|
|
427
|
+
observedAt: usage.observedAt ?? Date.now(),
|
|
428
|
+
stale: usage.stale === true,
|
|
429
|
+
});
|
|
375
430
|
}
|
|
376
|
-
setDisplays(previous => [
|
|
377
|
-
...groupUsageDisplays(roster, lastKnown, plans).map(display => ({
|
|
378
|
-
|
|
431
|
+
setDisplays((previous) => [
|
|
432
|
+
...groupUsageDisplays(roster, lastKnown, plans).map((display) => ({
|
|
433
|
+
...display,
|
|
434
|
+
accounts: display.accounts.map((account) => ({
|
|
435
|
+
...account,
|
|
379
436
|
...observationsRef.current.get(`${display.provider}:${account.key}`),
|
|
380
437
|
})),
|
|
381
438
|
})),
|
|
382
|
-
...previous
|
|
383
|
-
|
|
439
|
+
...previous
|
|
440
|
+
.filter((display) => !refreshed.has(display.provider))
|
|
441
|
+
.map((display) => ({
|
|
442
|
+
...display,
|
|
443
|
+
accounts: display.accounts.map((account) => ({
|
|
444
|
+
...account,
|
|
445
|
+
stale: true,
|
|
446
|
+
})),
|
|
384
447
|
})),
|
|
385
448
|
]);
|
|
386
449
|
}
|
|
387
450
|
catch {
|
|
388
451
|
// Keep cached numbers, but never present failed observations as current.
|
|
389
452
|
if (mountedRef.current)
|
|
390
|
-
setDisplays(previous => previous.map(display => ({
|
|
391
|
-
|
|
453
|
+
setDisplays((previous) => previous.map((display) => ({
|
|
454
|
+
...display,
|
|
455
|
+
accounts: display.accounts.map((account) => ({
|
|
456
|
+
...account,
|
|
457
|
+
stale: true,
|
|
458
|
+
})),
|
|
392
459
|
})));
|
|
393
460
|
}
|
|
394
461
|
finally {
|
|
@@ -397,14 +464,18 @@ export function SubscriptionUsageBadge({ rpc, currentModel, t, rotationMs }) {
|
|
|
397
464
|
}, [rpc]);
|
|
398
465
|
useEffect(() => {
|
|
399
466
|
mountedRef.current = true;
|
|
400
|
-
return () => {
|
|
467
|
+
return () => {
|
|
468
|
+
mountedRef.current = false;
|
|
469
|
+
};
|
|
401
470
|
}, []);
|
|
402
471
|
// Hidden renders nothing, so it polls nothing; showing it again refreshes at once.
|
|
403
472
|
useEffect(() => {
|
|
404
473
|
if (displayMode === 'hidden')
|
|
405
474
|
return;
|
|
406
475
|
void refresh();
|
|
407
|
-
const timer = setInterval(() => {
|
|
476
|
+
const timer = setInterval(() => {
|
|
477
|
+
void refresh();
|
|
478
|
+
}, USAGE_POLL_INTERVAL_MS);
|
|
408
479
|
window.addEventListener(USAGE_BADGE_REFRESH_EVENT, refresh);
|
|
409
480
|
return () => {
|
|
410
481
|
clearInterval(timer);
|
|
@@ -421,12 +492,18 @@ export function SubscriptionUsageBadge({ rpc, currentModel, t, rotationMs }) {
|
|
|
421
492
|
if (read === undefined || inflight)
|
|
422
493
|
return;
|
|
423
494
|
inflight = true;
|
|
424
|
-
void read()
|
|
495
|
+
void read()
|
|
496
|
+
.then((model) => {
|
|
425
497
|
if (cancelled)
|
|
426
498
|
return;
|
|
427
|
-
setLastSubscription(previous => retainSubscriptionSelection(previous, model));
|
|
499
|
+
setLastSubscription((previous) => retainSubscriptionSelection(previous, model));
|
|
428
500
|
setSelection(model);
|
|
429
|
-
}, () => {
|
|
501
|
+
}, () => {
|
|
502
|
+
/* keep the last known provider; the next tick retries */
|
|
503
|
+
})
|
|
504
|
+
.finally(() => {
|
|
505
|
+
inflight = false;
|
|
506
|
+
});
|
|
430
507
|
};
|
|
431
508
|
reload();
|
|
432
509
|
const timer = setInterval(reload, MODEL_POLL_INTERVAL_MS);
|
|
@@ -435,7 +512,14 @@ export function SubscriptionUsageBadge({ rpc, currentModel, t, rotationMs }) {
|
|
|
435
512
|
clearInterval(timer);
|
|
436
513
|
};
|
|
437
514
|
}, []);
|
|
438
|
-
const pos = useAnchoredPosition({
|
|
515
|
+
const pos = useAnchoredPosition({
|
|
516
|
+
open,
|
|
517
|
+
anchorRef: rootRef,
|
|
518
|
+
panelRef,
|
|
519
|
+
side: 'top',
|
|
520
|
+
gap: PANEL_GAP,
|
|
521
|
+
margin: PANEL_MARGIN,
|
|
522
|
+
});
|
|
439
523
|
useDismissOnOutsidePointer(rootRef, open, setOpen, panelRef);
|
|
440
524
|
useEffect(() => {
|
|
441
525
|
if (!open)
|
|
@@ -445,15 +529,20 @@ export function SubscriptionUsageBadge({ rpc, currentModel, t, rotationMs }) {
|
|
|
445
529
|
setOpen(false);
|
|
446
530
|
};
|
|
447
531
|
document.addEventListener('keydown', onKeyDown);
|
|
448
|
-
return () => {
|
|
532
|
+
return () => {
|
|
533
|
+
document.removeEventListener('keydown', onKeyDown);
|
|
534
|
+
};
|
|
449
535
|
}, [open]);
|
|
450
|
-
// Sit on the host's stats row when there is one.
|
|
451
|
-
//
|
|
452
|
-
//
|
|
453
|
-
//
|
|
454
|
-
// on
|
|
455
|
-
// has steps or tokens, and unmounts
|
|
456
|
-
//
|
|
536
|
+
// Sit on the host's stats row when there is one. Hosts through 0.2.0 render
|
|
537
|
+
// their time/token pills in a row apart from the dock, marked
|
|
538
|
+
// `data-composer-stats`; every dock entry is its own row in the composer
|
|
539
|
+
// bar, so a badge rendered in place lands under those pills, and rendering
|
|
540
|
+
// into the row makes it a third pill on their line. The marker is watched
|
|
541
|
+
// (the row mounts only once the session has steps or tokens, and unmounts
|
|
542
|
+
// with them). From 0.2.1 the shipped pills are dock entries like this
|
|
543
|
+
// badge, each anchored `data-composer-stat`, so the in-place seat already
|
|
544
|
+
// shares their row; seeing a docked anchor ends the watch for a row that
|
|
545
|
+
// will not appear.
|
|
457
546
|
const [statsRow, setStatsRow] = useState(null);
|
|
458
547
|
useEffect(() => {
|
|
459
548
|
const seat = seatRef.current;
|
|
@@ -462,11 +551,19 @@ export function SubscriptionUsageBadge({ rpc, currentModel, t, rotationMs }) {
|
|
|
462
551
|
const scope = statsScopeOf(seat);
|
|
463
552
|
if (scope === null)
|
|
464
553
|
return;
|
|
465
|
-
const find = () => scope.querySelector(
|
|
466
|
-
|
|
467
|
-
|
|
554
|
+
const find = () => scope.querySelector(STATS_ROW_SELECTOR);
|
|
555
|
+
const settle = () => {
|
|
556
|
+
const row = find();
|
|
557
|
+
setStatsRow(row);
|
|
558
|
+
if (row === null && scope.querySelector(STATS_DOCK_SELECTOR) !== null)
|
|
559
|
+
observer.disconnect();
|
|
560
|
+
};
|
|
561
|
+
const observer = new MutationObserver(settle);
|
|
468
562
|
observer.observe(scope, { childList: true, subtree: true });
|
|
469
|
-
|
|
563
|
+
settle();
|
|
564
|
+
return () => {
|
|
565
|
+
observer.disconnect();
|
|
566
|
+
};
|
|
470
567
|
}, []);
|
|
471
568
|
useEffect(() => {
|
|
472
569
|
if (displayMode === 'hidden')
|
|
@@ -480,8 +577,12 @@ export function SubscriptionUsageBadge({ rpc, currentModel, t, rotationMs }) {
|
|
|
480
577
|
const interval = rotationMs !== undefined && Number.isFinite(rotationMs) && rotationMs > 0
|
|
481
578
|
? rotationMs
|
|
482
579
|
: BADGE_ROTATION_INTERVAL_MS;
|
|
483
|
-
const timer = setInterval(() => {
|
|
484
|
-
|
|
580
|
+
const timer = setInterval(() => {
|
|
581
|
+
setRotation((step) => step + 1);
|
|
582
|
+
}, interval);
|
|
583
|
+
return () => {
|
|
584
|
+
clearInterval(timer);
|
|
585
|
+
};
|
|
485
586
|
}, [displayMode, rotationMs]);
|
|
486
587
|
const seat = _jsx("span", { ref: seatRef, style: styles.seat, "aria-hidden": true });
|
|
487
588
|
// `always` follows the live model, not the retained subscription: the
|
|
@@ -494,7 +595,9 @@ export function SubscriptionUsageBadge({ rpc, currentModel, t, rotationMs }) {
|
|
|
494
595
|
// Model scope only while the pill shows the current model's provider;
|
|
495
596
|
// a rotated provider has no live model, so it reads at account level.
|
|
496
597
|
const pillModel = displayMode === 'always'
|
|
497
|
-
?
|
|
598
|
+
? current === collapsed[0]?.provider
|
|
599
|
+
? selection?.model
|
|
600
|
+
: undefined
|
|
498
601
|
: badgeSelection?.model;
|
|
499
602
|
const label = compactSegment(collapsed[0], pillModel, translate);
|
|
500
603
|
// The dialog opens from the badge, so it follows the provider and model the
|
|
@@ -503,7 +606,9 @@ export function SubscriptionUsageBadge({ rpc, currentModel, t, rotationMs }) {
|
|
|
503
606
|
// the provider that was showing when it opened instead of reordering live.
|
|
504
607
|
const dialogProvider = open && displayMode === 'always' ? dialogLead : badgeSelection?.provider;
|
|
505
608
|
const dialogModel = open && displayMode === 'always'
|
|
506
|
-
?
|
|
609
|
+
? dialogLead === current
|
|
610
|
+
? selection?.model
|
|
611
|
+
: undefined
|
|
507
612
|
: badgeSelection?.model;
|
|
508
613
|
const expanded = expandedDisplays(displays, dialogProvider);
|
|
509
614
|
const title = translate('usageBadgeTitle');
|
|
@@ -514,18 +619,29 @@ export function SubscriptionUsageBadge({ rpc, currentModel, t, rotationMs }) {
|
|
|
514
619
|
if (next)
|
|
515
620
|
void refresh();
|
|
516
621
|
};
|
|
517
|
-
const pill = (_jsxs("span", { ref: rootRef, style: styles.anchor, children: [_jsx("style", { children: subscriptionChromeCss }), _jsxs("button", { type: "button", className: "dsh-subscription-usage-pill", style: { ...styles.pill, ...(hover || open ? styles.pillActive : {}) }, "aria-haspopup": "dialog", "aria-expanded": open, "aria-label": `${title} · ${label}`, title: title, onMouseEnter: () => {
|
|
518
|
-
|
|
622
|
+
const pill = (_jsxs("span", { ref: rootRef, style: styles.anchor, children: [_jsx("style", { children: subscriptionChromeCss }), _jsxs("button", { type: "button", className: "dsh-subscription-usage-pill", style: { ...styles.pill, ...(hover || open ? styles.pillActive : {}) }, "aria-haspopup": "dialog", "aria-expanded": open, "aria-label": `${title} · ${label}`, title: title, onMouseEnter: () => {
|
|
623
|
+
setHover(true);
|
|
624
|
+
}, onMouseLeave: () => {
|
|
625
|
+
setHover(false);
|
|
626
|
+
}, onClick: toggle, children: [_jsx(UsageBadgeIcon, {}), _jsx("span", { style: styles.label, children: label })] }), open &&
|
|
627
|
+
createPortal(_jsxs("div", { ref: panelRef, role: "dialog", "aria-label": title, className: "dsh-subscription-usage-panel", style: { ...styles.panel, ...(pos ?? MEASURE_STYLE) }, children: [_jsx("div", { style: styles.title, children: _jsxs("span", { style: styles.titleLabel, children: [_jsx(UsageBadgeIcon, {}), title] }) }), _jsx("div", { style: styles.titleRule, "aria-hidden": true }), expanded.map((d, index) => (_jsxs("section", { style: index === 0 ? undefined : styles.section, children: [_jsxs("div", { style: styles.providerRow, children: [_jsxs("span", { style: styles.providerName, children: [d.name, d.provider === current && (_jsx("span", { style: styles.currentTag, children: translate('usageBadgeCurrent') }))] }), d.accounts.length === 1 && (_jsx(AccountMeta, { account: d.accounts[0], translate: translate }))] }), d.accounts.map((account, accountIndex) => (_jsxs("div", { style: accountIndex === 0 ? undefined : styles.accountBlock, children: [d.accounts.length > 1 && (_jsx("div", { style: styles.accountRow, children: _jsx(AccountMeta, { account: account, translate: translate }) })), _jsx(AccountWindows, { windows: account.windows, observedAt: account.observedAt, stale: account.stale, model: d.provider === dialogProvider ? dialogModel : undefined, provider: d.provider, translate: translate }, `${d.provider}:${dialogModel ?? ''}`)] }, account.key)))] }, d.provider)))] }), document.body)] }));
|
|
628
|
+
return (_jsxs(_Fragment, { children: [seat, statsRow !== null && statsRow.isConnected
|
|
629
|
+
? createPortal(pill, statsRow)
|
|
630
|
+
: pill] }));
|
|
519
631
|
}
|
|
632
|
+
/** How far statsScopeOf walks looking for `composerStats.row`. */
|
|
633
|
+
const LEGACY_STATS_SCOPE_DEPTH = 4;
|
|
520
634
|
/**
|
|
521
|
-
*
|
|
522
|
-
*
|
|
523
|
-
*
|
|
635
|
+
* Scope for the legacy stats row. The nearest ancestor within
|
|
636
|
+
* LEGACY_STATS_SCOPE_DEPTH that contains `composerStats.row`, so a badge
|
|
637
|
+
* does not adopt another composer's pills. When none does, the seat's
|
|
638
|
+
* parent: the slot outlet, which holds sibling `composerStats.dock` anchors
|
|
639
|
+
* on hosts whose pills are dock entries.
|
|
524
640
|
*/
|
|
525
641
|
function statsScopeOf(seat) {
|
|
526
642
|
let node = seat.parentElement;
|
|
527
|
-
for (let depth = 0; node !== null && depth <
|
|
528
|
-
if (node.querySelector(
|
|
643
|
+
for (let depth = 0; node !== null && depth < LEGACY_STATS_SCOPE_DEPTH; depth++) {
|
|
644
|
+
if (node.querySelector(STATS_ROW_SELECTOR) !== null)
|
|
529
645
|
return node;
|
|
530
646
|
node = node.parentElement;
|
|
531
647
|
}
|
|
@@ -536,21 +652,25 @@ function statsScopeOf(seat) {
|
|
|
536
652
|
* marks the default account (the one direct routes serve and the collapsed
|
|
537
653
|
* pill reads), the same glyph Settings → 订阅 uses.
|
|
538
654
|
*/
|
|
539
|
-
function AccountMeta({ account, translate }) {
|
|
540
|
-
const parts = [
|
|
541
|
-
.
|
|
542
|
-
|
|
655
|
+
function AccountMeta({ account, translate, }) {
|
|
656
|
+
const parts = [
|
|
657
|
+
account.account,
|
|
658
|
+
account.plan === undefined
|
|
659
|
+
? undefined
|
|
660
|
+
: translate('usagePlan', { plan: account.plan }),
|
|
661
|
+
].filter((part) => part !== undefined && part !== '');
|
|
662
|
+
return (_jsxs("span", { style: styles.providerMeta, title: account.account, children: [account.isDefault && (_jsxs("span", { style: styles.defaultStar, "aria-label": "default", children: ["\u2605", ' '] })), parts.join(' · ')] }));
|
|
543
663
|
}
|
|
544
664
|
/** Preview each account independently; all remaining quotas stay accessible. */
|
|
545
|
-
export function AccountWindows({ windows, model, provider, translate, observedAt, stale }) {
|
|
665
|
+
export function AccountWindows({ windows, model, provider, translate, observedAt, stale, }) {
|
|
546
666
|
const { shown, hidden } = previewWindows(windows, model, provider);
|
|
547
667
|
const rows = (items) => (_jsx("dl", { style: styles.details, children: items.map((w, i) => (_jsx(WindowRow, { label: `${usageWindowLabel(translate, w)}${model !== undefined && w.scope === model ? ` · ${translate('usageBadgeCurrent')}` : ''}`, window: w, t: translate, observedAt: observedAt, stale: stale }, i))) }));
|
|
548
|
-
return _jsxs(_Fragment, { children: [rows(shown), hidden.length > 0 && _jsxs("details", { style: styles.moreWindows, children: [_jsx("summary", { style: styles.moreSummary, children: translate('usageBadgeMoreWindows', { count: hidden.length }) }), rows(hidden)] })] });
|
|
668
|
+
return (_jsxs(_Fragment, { children: [rows(shown), hidden.length > 0 && (_jsxs("details", { style: styles.moreWindows, children: [_jsx("summary", { style: styles.moreSummary, children: translate('usageBadgeMoreWindows', { count: hidden.length }) }), rows(hidden)] }))] }));
|
|
549
669
|
}
|
|
550
670
|
/** One `dt`/`dd` pair: window name → `25% · 6d1h`, with the bar underneath. */
|
|
551
|
-
function WindowRow({ label, window: w, t, observedAt, stale }) {
|
|
671
|
+
function WindowRow({ label, window: w, t, observedAt, stale, }) {
|
|
552
672
|
const percent = displayUsedPercent(w.usedPercent);
|
|
553
|
-
return (_jsxs(_Fragment, { children: [_jsx("dt", { style: styles.dt, children: label }), _jsxs("dd", { style: styles.dd, children: [percent === undefined ? t('usageMeterInvalid') : `${percent}%`, w.resetsAt !== undefined && Number.isFinite(w.resetsAt) && _jsxs("span", { style: styles.reset, children: [" \u00B7 ", windowLabel(w)] })] }), _jsx(UsageMeter, { window: w, t: t, style: styles.bar, observedAt: observedAt, stale: stale })] }));
|
|
673
|
+
return (_jsxs(_Fragment, { children: [_jsx("dt", { style: styles.dt, children: label }), _jsxs("dd", { style: styles.dd, children: [percent === undefined ? t('usageMeterInvalid') : `${percent}%`, w.resetsAt !== undefined && Number.isFinite(w.resetsAt) && (_jsxs("span", { style: styles.reset, children: [" \u00B7 ", windowLabel(w)] }))] }), _jsx(UsageMeter, { window: w, t: t, style: styles.bar, observedAt: observedAt, stale: stale })] }));
|
|
554
674
|
}
|
|
555
675
|
/**
|
|
556
676
|
* Unplaced portal panel: hidden but laid out so the clamp measures real
|
|
@@ -563,12 +683,22 @@ const styles = {
|
|
|
563
683
|
// Mirrors the host StatsPills pill so the badge reads as a sibling of the
|
|
564
684
|
// shipped time/token pills.
|
|
565
685
|
pill: {
|
|
566
|
-
boxSizing: 'border-box',
|
|
686
|
+
boxSizing: 'border-box',
|
|
687
|
+
maxWidth: '100%',
|
|
567
688
|
color: 'var(--dsw-alias-label-tertiary)',
|
|
568
|
-
font: 'inherit',
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
689
|
+
font: 'inherit',
|
|
690
|
+
fontSize: 'calc(var(--dsh-content-font-size-secondary, 13px) - 1px)',
|
|
691
|
+
fontVariantNumeric: 'tabular-nums',
|
|
692
|
+
lineHeight: 'calc(20px + var(--dsh-content-font-delta-secondary, 0px))',
|
|
693
|
+
whiteSpace: 'nowrap',
|
|
694
|
+
background: 'transparent',
|
|
695
|
+
border: 'none',
|
|
696
|
+
borderRadius: 999,
|
|
697
|
+
alignItems: 'center',
|
|
698
|
+
gap: 6,
|
|
699
|
+
padding: '1px 8px',
|
|
700
|
+
display: 'inline-flex',
|
|
701
|
+
cursor: 'pointer',
|
|
572
702
|
},
|
|
573
703
|
pillActive: {
|
|
574
704
|
background: 'var(--dsw-alias-interactive-bg-hover)',
|
|
@@ -580,52 +710,111 @@ const styles = {
|
|
|
580
710
|
// without the blur the transcript behind the dialog stays sharp and shows
|
|
581
711
|
// through the fill.
|
|
582
712
|
panel: {
|
|
583
|
-
position: 'fixed',
|
|
713
|
+
position: 'fixed',
|
|
714
|
+
zIndex: 1100,
|
|
715
|
+
boxSizing: 'border-box',
|
|
584
716
|
background: 'var(--dsw-specific-menu)',
|
|
585
717
|
backdropFilter: 'var(--dsw-menu-backdrop-filter)',
|
|
586
|
-
width: 'max-content',
|
|
587
|
-
|
|
718
|
+
width: 'max-content',
|
|
719
|
+
minWidth: 'min(300px, 100vw - 24px)',
|
|
720
|
+
maxWidth: 'min(440px, 100vw - 24px)',
|
|
721
|
+
maxHeight: 'min(560px, 100dvh - 24px)',
|
|
722
|
+
overflowY: 'auto',
|
|
723
|
+
overscrollBehavior: 'contain',
|
|
588
724
|
boxShadow: 'var(--dsw-elevation-prominent)',
|
|
589
|
-
color: 'var(--dsw-alias-label-secondary)',
|
|
590
|
-
|
|
725
|
+
color: 'var(--dsw-alias-label-secondary)',
|
|
726
|
+
cursor: 'default',
|
|
727
|
+
border: 0,
|
|
728
|
+
borderRadius: 'var(--dsw-radius-lg, 16px)',
|
|
729
|
+
padding: 16,
|
|
730
|
+
fontSize: 12,
|
|
731
|
+
lineHeight: '18px',
|
|
591
732
|
},
|
|
592
733
|
title: {
|
|
593
|
-
color: 'var(--dsw-alias-label-primary)',
|
|
594
|
-
|
|
734
|
+
color: 'var(--dsw-alias-label-primary)',
|
|
735
|
+
display: 'flex',
|
|
736
|
+
justifyContent: 'space-between',
|
|
737
|
+
gap: 16,
|
|
738
|
+
marginBottom: 8,
|
|
739
|
+
fontWeight: 500,
|
|
740
|
+
},
|
|
741
|
+
titleLabel: {
|
|
742
|
+
alignItems: 'center',
|
|
743
|
+
gap: 6,
|
|
744
|
+
minWidth: 0,
|
|
745
|
+
display: 'inline-flex',
|
|
746
|
+
},
|
|
747
|
+
titleRule: {
|
|
748
|
+
borderTop: '0.5px solid var(--dsw-alias-border-l2)',
|
|
749
|
+
marginBottom: 10,
|
|
750
|
+
},
|
|
751
|
+
section: {
|
|
752
|
+
marginTop: 12,
|
|
753
|
+
paddingTop: 10,
|
|
754
|
+
borderTop: '0.5px solid var(--dsw-alias-border-l2)',
|
|
595
755
|
},
|
|
596
|
-
titleLabel: { alignItems: 'center', gap: 6, minWidth: 0, display: 'inline-flex' },
|
|
597
|
-
titleRule: { borderTop: '0.5px solid var(--dsw-alias-border-l2)', marginBottom: 10 },
|
|
598
|
-
section: { marginTop: 12, paddingTop: 10, borderTop: '0.5px solid var(--dsw-alias-border-l2)' },
|
|
599
756
|
providerRow: {
|
|
600
|
-
display: 'flex',
|
|
757
|
+
display: 'flex',
|
|
758
|
+
justifyContent: 'space-between',
|
|
759
|
+
alignItems: 'baseline',
|
|
760
|
+
gap: 16,
|
|
761
|
+
marginBottom: 6,
|
|
762
|
+
},
|
|
763
|
+
providerName: {
|
|
764
|
+
color: 'var(--dsw-alias-label-primary)',
|
|
765
|
+
fontWeight: 500,
|
|
766
|
+
display: 'inline-flex',
|
|
767
|
+
alignItems: 'center',
|
|
768
|
+
gap: 6,
|
|
601
769
|
},
|
|
602
|
-
providerName: { color: 'var(--dsw-alias-label-primary)', fontWeight: 500, display: 'inline-flex', alignItems: 'center', gap: 6 },
|
|
603
770
|
currentTag: {
|
|
604
|
-
fontSize: 10,
|
|
605
|
-
|
|
771
|
+
fontSize: 10,
|
|
772
|
+
lineHeight: '14px',
|
|
773
|
+
fontWeight: 400,
|
|
774
|
+
padding: '0 5px',
|
|
775
|
+
borderRadius: 7,
|
|
776
|
+
color: 'var(--dsw-alias-label-secondary)',
|
|
777
|
+
background: 'var(--dsw-alias-interactive-bg-hover)',
|
|
606
778
|
},
|
|
607
779
|
providerMeta: {
|
|
608
|
-
color: 'var(--dsw-alias-label-tertiary)',
|
|
609
|
-
|
|
780
|
+
color: 'var(--dsw-alias-label-tertiary)',
|
|
781
|
+
minWidth: 0,
|
|
782
|
+
overflow: 'hidden',
|
|
783
|
+
textOverflow: 'ellipsis',
|
|
784
|
+
whiteSpace: 'nowrap',
|
|
610
785
|
},
|
|
611
786
|
// Same star and color as the default-account marker in Settings → 订阅.
|
|
612
787
|
defaultStar: { color: 'var(--dsw-alias-state-warn-label)' },
|
|
613
788
|
accountBlock: { marginTop: 8 },
|
|
614
789
|
accountRow: { display: 'flex', marginBottom: 4 },
|
|
615
790
|
details: {
|
|
616
|
-
color: 'var(--dsw-alias-label-tertiary)',
|
|
617
|
-
|
|
791
|
+
color: 'var(--dsw-alias-label-tertiary)',
|
|
792
|
+
display: 'grid',
|
|
793
|
+
gridTemplateColumns: 'minmax(0, 1fr) max-content',
|
|
794
|
+
gap: '4px 16px',
|
|
795
|
+
margin: 0,
|
|
618
796
|
},
|
|
619
797
|
moreWindows: { marginTop: 8 },
|
|
620
|
-
moreSummary: {
|
|
798
|
+
moreSummary: {
|
|
799
|
+
cursor: 'pointer',
|
|
800
|
+
color: 'var(--dsw-alias-label-secondary)',
|
|
801
|
+
marginBottom: 8,
|
|
802
|
+
},
|
|
621
803
|
dt: { minWidth: 0, margin: 0, overflowWrap: 'anywhere' },
|
|
622
804
|
dd: {
|
|
623
|
-
minWidth: 0,
|
|
624
|
-
|
|
805
|
+
minWidth: 0,
|
|
806
|
+
margin: 0,
|
|
807
|
+
color: 'var(--dsw-alias-label-secondary)',
|
|
808
|
+
fontVariantNumeric: 'tabular-nums',
|
|
809
|
+
textAlign: 'right',
|
|
625
810
|
},
|
|
626
811
|
reset: { color: 'var(--dsw-alias-label-tertiary)' },
|
|
627
812
|
bar: {
|
|
628
|
-
gridColumn: '1 / -1',
|
|
629
|
-
|
|
813
|
+
gridColumn: '1 / -1',
|
|
814
|
+
height: 4,
|
|
815
|
+
borderRadius: 2,
|
|
816
|
+
overflow: 'hidden',
|
|
817
|
+
background: 'var(--dsw-alias-border-l2)',
|
|
818
|
+
marginBottom: 2,
|
|
630
819
|
},
|
|
631
820
|
};
|