dsh-ds-balance 2.1.2 → 2.2.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.md +78 -19
- package/README_en.md +81 -19
- package/lib/adapters/domain-core-store.d.ts +2 -2
- package/lib/adapters/domain-core-store.js +3 -1
- package/lib/adapters/host-account.d.ts +66 -0
- package/lib/adapters/host-account.js +68 -0
- package/lib/client.js +473 -114
- package/lib/domain/account.d.ts +40 -0
- package/lib/domain/account.js +74 -0
- package/lib/domain/balance.d.ts +20 -1
- package/lib/domain/normalize.d.ts +3 -2
- package/lib/domain/normalize.js +3 -2
- package/lib/domain/severity.d.ts +8 -2
- package/lib/domain/severity.js +11 -4
- package/lib/domain/situation.d.ts +104 -0
- package/lib/domain/situation.js +93 -0
- package/lib/http/handlers.d.ts +1 -1
- package/lib/http/handlers.js +29 -5
- package/lib/http/wire.d.ts +11 -1
- package/lib/http/wire.js +2 -0
- package/lib/index.js +122 -6
- package/lib/ports/account.d.ts +27 -0
- package/lib/ports/account.js +9 -0
- package/lib/services/balance-service.d.ts +66 -85
- package/lib/services/balance-service.js +132 -181
- package/lib/services/balance-source.d.ts +174 -0
- package/lib/services/balance-source.js +294 -0
- package/lib/services/scheduler.d.ts +31 -2
- package/lib/services/scheduler.js +29 -2
- package/lib/services/source-readers.d.ts +26 -0
- package/lib/services/source-readers.js +73 -0
- package/lib/services/source-selector.d.ts +50 -0
- package/lib/services/source-selector.js +64 -0
- package/lib/types/client/api-types.d.ts +16 -0
- package/lib/types/client/data.d.ts +12 -3
- package/lib/types/client/index.d.ts +6 -0
- package/lib/types/client/locales.d.ts +10 -18
- package/lib/types/client/mock/index.d.ts +12 -11
- package/lib/types/client/mock/scenarios.d.ts +13 -5
- package/lib/types/client/model.d.ts +49 -25
- package/lib/types/client/route-hint.d.ts +61 -0
- package/lib/types/client/sidebar/BalancePopover.d.ts +7 -0
- package/lib/types/client/sidebar/PercentRing.d.ts +13 -5
- package/lib/types/client/sidebar/SidebarBalance.d.ts +9 -1
- package/lib/types/client/situation.d.ts +164 -0
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +25 -23
package/lib/client.js
CHANGED
|
@@ -42,11 +42,14 @@ var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primi
|
|
|
42
42
|
var NS = "ds-balance";
|
|
43
43
|
var zh = {
|
|
44
44
|
"sidebar.label": "DeepSeek \u4F59\u989D",
|
|
45
|
-
"sidebar.aria.balance": "DeepSeek \u4F59\u989D",
|
|
46
45
|
"sidebar.aria.ring": "DeepSeek \u4F59\u989D\u72B6\u6001",
|
|
47
46
|
"sidebar.aria.refresh": "\u5237\u65B0\u4F59\u989D",
|
|
48
47
|
"sidebar.aria.mismatch": "\u663E\u793A\u7684\u5E01\u79CD\u4E0E\u4F60\u9009\u62E9\u7684\u4E0D\u4E00\u81F4",
|
|
49
48
|
"popover.title": "\u8D26\u6237\u4F59\u989D",
|
|
49
|
+
// 来源标签:跟着数据来源走。**括号属于词典** —— 中文全角、英文半角带前置空格,
|
|
50
|
+
// 代码里只做拼接,绝不写死括号字符。
|
|
51
|
+
"popover.source.key": "\uFF08API Key\uFF09",
|
|
52
|
+
"popover.source.account": "\uFF08\u8D26\u53F7\u767B\u5F55\uFF09",
|
|
50
53
|
"popover.total": "\u4F59\u989D",
|
|
51
54
|
"popover.granted": "\u8D60\u9001",
|
|
52
55
|
"popover.toppedUp": "\u5145\u503C",
|
|
@@ -60,12 +63,33 @@ var zh = {
|
|
|
60
63
|
// 措辞就跟着落点分档:一句含糊的话盖不住两种落点。见 BalancePopover 的 PluginsAction。
|
|
61
64
|
"popover.action.openPlugins": "\u6253\u5F00\u63D2\u4EF6\u9875",
|
|
62
65
|
"popover.action.openPluginConfig": "\u6253\u5F00\u63D2\u4EF6\u914D\u7F6E\u9875",
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
// 处境文案:**一个处境一句**,环 / 悬停 / 浮层都从这里取。
|
|
67
|
+
// 键名前缀是 situation 而不是 state:后者是契约字段名,而「处境」是界面概念
|
|
68
|
+
// (一个处境可能吃掉多个 state + severity + error 的组合)。
|
|
69
|
+
//
|
|
70
|
+
// **措辞是给用户看的,不是给开发者看的**。这七句会出现在两处,都必须能**单独读懂**:
|
|
71
|
+
// - **悬停气泡**(收起态与展开态同一份,见 `client/situation.ts` 的 `hoverTextOf`):
|
|
72
|
+
// 数字**可信**时气泡显示金额本身(只有 `ok` / `low` / `critical` 三个处境,
|
|
73
|
+
// 它们的 `textKey` 是 `null`);其余八个处境显示下面这些句子 —— 包括
|
|
74
|
+
// `stale` 与 `account-unavailable`,它们**手里有数字也显文案**;
|
|
75
|
+
// - 浮层与读屏的 `aria-label`。
|
|
76
|
+
//
|
|
77
|
+
// 所以每一句都要能单独回答「**这一格现在怎么了**」:
|
|
78
|
+
//
|
|
79
|
+
// - 不写「插件内部错误」:用户不知道也不关心是哪个组件坏了,他要的是「现在拿不到」。
|
|
80
|
+
// 改「服务异常」—— 说的是同一件事,但主语是这个功能,不是我们的代码。
|
|
81
|
+
// - `unavailable` 刻意**不带「暂时」**。它接住的是 `fetch-failed` 那一整片错误码,
|
|
82
|
+
// 里面既有等一等就好的(网络 / 超时 / 429 / 5xx),也有**等不好的**:
|
|
83
|
+
// `UPSTREAM_401`(key 失效)与 `UPSTREAM_402`(欠费)。对后者说「暂时」是假话,
|
|
84
|
+
// 而且是有害的假话 —— 用户该去改凭据、去充值,不是在原地等。
|
|
85
|
+
// 宁可少说一层时间性,也不能说反。
|
|
86
|
+
"situation.checking": "\u6B63\u5728\u83B7\u53D6",
|
|
87
|
+
"situation.unavailable": "\u8BFB\u4E0D\u5230\u4F59\u989D",
|
|
88
|
+
"situation.internalError": "\u670D\u52A1\u5F02\u5E38",
|
|
89
|
+
"situation.noCredential": "\u5C1A\u672A\u914D\u7F6E\u51ED\u636E",
|
|
90
|
+
"situation.accountUnavailable": "\u8D26\u6237\u4E0D\u53EF\u7528",
|
|
91
|
+
"situation.stale": "\u6570\u636E\u5DF2\u8FC7\u671F",
|
|
92
|
+
"situation.emptyWallet": "\u6682\u65E0\u4F59\u989D",
|
|
69
93
|
"settings.group.connection": "\u8FDE\u63A5",
|
|
70
94
|
"settings.group.refresh": "\u5237\u65B0",
|
|
71
95
|
"settings.group.display": "\u5C55\u793A",
|
|
@@ -81,15 +105,13 @@ var zh = {
|
|
|
81
105
|
"settings.field.cnyCritical": "CNY \u544A\u6025",
|
|
82
106
|
"settings.field.usdWarn": "USD \u9884\u8B66",
|
|
83
107
|
"settings.field.usdCritical": "USD \u544A\u6025",
|
|
84
|
-
"settings.hint.apiKey": "\u7559\u7A7A\u5219\u6539\u7528\u5F15\u7528\u540D\u4ECE\u51ED\u636E\u5B58\u50A8\u8BFB\u53D6\u3002",
|
|
85
108
|
"settings.hint.apiKeyRef": "\u51ED\u636E\u5B58\u50A8\u91CC\u7684\u6761\u76EE\u540D\uFF1B\u975E\u7A7A\u65F6\u4F18\u5148\u4E8E API Key\u3002",
|
|
86
109
|
"settings.hint.baseUrl": "\u7559\u7A7A\u5219\u4F7F\u7528\u63D0\u4F9B\u65B9\u9ED8\u8BA4\u5730\u5740\u3002",
|
|
87
110
|
"settings.hint.displayCurrency": "\u6240\u9009\u5E01\u79CD\u4E0D\u5B58\u5728\u65F6\uFF0C\u56DE\u843D\u5230\u8D26\u6237\u5B9E\u9645\u6301\u6709\u7684\u5E01\u79CD\u3002",
|
|
88
|
-
"settings.hint.number": "\u8BF7\u586B\u6570\u5B57\uFF1B\u7559\u7A7A\u8868\u793A\u4F7F\u7528\u9ED8\u8BA4\u503C\u3002",
|
|
89
111
|
"settings.hint.threshold": "\u540E\u7AEF\u5224\u5B9A\uFF1B\u754C\u9762\u989C\u8272\u8DDF\u968F\u8FD4\u56DE\u7684\u4E25\u91CD\u5EA6\u3002",
|
|
90
112
|
"settings.hint.thresholdPair": "\u544A\u6025\u503C\u5FC5\u987B\u4F4E\u4E8E\u9884\u8B66\u503C",
|
|
91
113
|
"settings.hint.serverRefreshSeconds": "\u8BBF\u95EE\u5B98\u65B9\u63A5\u53E3\u7684\u95F4\u9694\u3002",
|
|
92
|
-
"settings.hint.clientPollSeconds": "\u5237\u65B0\u663E\u793A\u7684\u95F4\u9694\uFF1B\u53EA\u8BFB\
|
|
114
|
+
"settings.hint.clientPollSeconds": "\u5237\u65B0\u663E\u793A\u7684\u95F4\u9694\uFF1B\u6B63\u5E38\u65F6\u53EA\u8BFB\u7F13\u5B58\uFF0C\u8BFB\u4E0D\u5230\u65F6\u624D\u8BBF\u95EE\u4E0A\u6E38\u3002",
|
|
93
115
|
"settings.hint.manualRefreshCooldownSeconds": "\u4E24\u6B21\u624B\u52A8\u5237\u65B0\u4E4B\u95F4\u7684\u6700\u77ED\u95F4\u9694\u3002",
|
|
94
116
|
"settings.currency.auto": "\u81EA\u52A8\uFF08\u8DDF\u968F\u8D26\u6237\uFF09",
|
|
95
117
|
// 凭据行的**状态徽章**:两条逐字用官方措辞 —— 取自 ui-settings-plugins 的
|
|
@@ -115,21 +137,24 @@ var zh = {
|
|
|
115
137
|
"settings.overridden": "\u5DF2\u8986\u76D6",
|
|
116
138
|
"settings.reset": "\u91CD\u7F6E",
|
|
117
139
|
"settings.invalidNumber": "\u8BF7\u586B\u6570\u5B57\uFF1B\u7559\u7A7A\u8868\u793A\u4F7F\u7528\u9ED8\u8BA4\u503C\u3002",
|
|
118
|
-
"settings.hint.refreshAdvanced": "\u4E0D\u5E38\u6539\uFF1A\u9ED8\u8BA4\u503C\u9002\u7528\u4E8E\u5927\u591A\u6570\u60C5\u51B5\u3002"
|
|
119
|
-
"settings.currencyMismatch": "\u5F53\u524D\u8D26\u6237\u65E0 {wanted} \u4F59\u989D\uFF0C\u5B9E\u9645\u663E\u793A {shown}",
|
|
140
|
+
"settings.hint.refreshAdvanced": "\u4E0D\u5E38\u6539\uFF1A\u9ED8\u8BA4\u503C\u9002\u7528\u4E8E\u5927\u591A\u6570\u60C5\u51B5\u3002"
|
|
120
141
|
// 这里曾有一条 'settings.summary'(该行 Configure 子页的说明行)。回退到
|
|
121
142
|
// plugins.bundle.config 之后没有任何渲染路径会问 summary 档,于是连同它一起删了 ——
|
|
122
143
|
// 详见 src/client/index.tsx 的 SettingsSeat。
|
|
123
|
-
|
|
124
|
-
|
|
144
|
+
// 本轮又删掉四条**孤儿键**(词典里有、全仓没人引用):`sidebar.aria.balance`
|
|
145
|
+
// (与 sidebar.label 逐字相同,rail 的 aria 走 aria.ring)、`settings.hint.apiKey`
|
|
146
|
+
// (那一行用的是 settings.hint.credential)、`settings.hint.number`
|
|
147
|
+
// (真正用的是 settings.invalidNumber,两者文案原本就重复)、
|
|
148
|
+
// `settings.currencyMismatch`(出到屏幕的是 popover.mismatch)。
|
|
125
149
|
};
|
|
126
150
|
var en = {
|
|
127
151
|
"sidebar.label": "DeepSeek balance",
|
|
128
|
-
"sidebar.aria.balance": "DeepSeek balance",
|
|
129
152
|
"sidebar.aria.ring": "DeepSeek balance status",
|
|
130
153
|
"sidebar.aria.refresh": "Refresh balance",
|
|
131
154
|
"sidebar.aria.mismatch": "Shown currency differs from your selection",
|
|
132
155
|
"popover.title": "Account balance",
|
|
156
|
+
"popover.source.key": " (API key)",
|
|
157
|
+
"popover.source.account": " (account sign-in)",
|
|
133
158
|
"popover.total": "Balance",
|
|
134
159
|
"popover.granted": "Granted",
|
|
135
160
|
"popover.toppedUp": "Topped up",
|
|
@@ -141,12 +166,16 @@ var en = {
|
|
|
141
166
|
"popover.action.useShown": "Use {shown}",
|
|
142
167
|
"popover.action.openPlugins": "Open the Plugins page",
|
|
143
168
|
"popover.action.openPluginConfig": "Open the plugin configuration page",
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"
|
|
169
|
+
// 与 zh 逐条对应,理由写在 zh 那一段。
|
|
170
|
+
// `unavailable` 同样**不带 Temporarily**:它接住 401(key 失效)/ 402(欠费)这类
|
|
171
|
+
// 「等不好」的错误,说「暂时」会把人劝去干等。
|
|
172
|
+
"situation.checking": "Loading",
|
|
173
|
+
"situation.unavailable": "Balance unavailable",
|
|
174
|
+
"situation.internalError": "Service error",
|
|
175
|
+
"situation.noCredential": "No credential configured",
|
|
176
|
+
"situation.accountUnavailable": "Account unavailable",
|
|
177
|
+
"situation.stale": "Data is stale",
|
|
178
|
+
"situation.emptyWallet": "No balance",
|
|
150
179
|
"settings.group.connection": "Connection",
|
|
151
180
|
"settings.group.refresh": "Refresh",
|
|
152
181
|
"settings.group.display": "Display",
|
|
@@ -162,15 +191,13 @@ var en = {
|
|
|
162
191
|
"settings.field.cnyCritical": "CNY critical",
|
|
163
192
|
"settings.field.usdWarn": "USD warning",
|
|
164
193
|
"settings.field.usdCritical": "USD critical",
|
|
165
|
-
"settings.hint.apiKey": "Leave empty to resolve from the credential reference instead.",
|
|
166
194
|
"settings.hint.apiKeyRef": "Credential store entry name; takes precedence over the API key.",
|
|
167
195
|
"settings.hint.baseUrl": "Leave blank to use the provider default.",
|
|
168
196
|
"settings.hint.displayCurrency": "Falls back to a currency the account actually holds.",
|
|
169
|
-
"settings.hint.number": "Enter a number; leave empty to use the default.",
|
|
170
197
|
"settings.hint.threshold": "Decided on the server; the UI colour follows the returned severity.",
|
|
171
198
|
"settings.hint.thresholdPair": "Critical must be lower than warning",
|
|
172
199
|
"settings.hint.serverRefreshSeconds": "How often the official API is called.",
|
|
173
|
-
"settings.hint.clientPollSeconds": "How often the display refreshes;
|
|
200
|
+
"settings.hint.clientPollSeconds": "How often the display refreshes; cache-only while healthy.",
|
|
174
201
|
"settings.hint.manualRefreshCooldownSeconds": "Minimum gap between two manual refreshes.",
|
|
175
202
|
"settings.currency.auto": "Automatic (follow account)",
|
|
176
203
|
"settings.credential.configured": "A key is configured.",
|
|
@@ -192,10 +219,8 @@ var en = {
|
|
|
192
219
|
"settings.overridden": "Overridden",
|
|
193
220
|
"settings.reset": "Reset",
|
|
194
221
|
"settings.invalidNumber": "Enter a number; leave empty to use the default.",
|
|
195
|
-
"settings.hint.refreshAdvanced": "Rarely changed: the defaults suit most setups."
|
|
196
|
-
|
|
197
|
-
"dev.title": "Dev scenario",
|
|
198
|
-
"dev.hint": "UI development only; does not affect real configuration."
|
|
222
|
+
"settings.hint.refreshAdvanced": "Rarely changed: the defaults suit most setups."
|
|
223
|
+
// 与 zh 同批删掉四条孤儿键,以及 `dev.*`(见 zh 那段末尾的说明)。
|
|
199
224
|
};
|
|
200
225
|
function interpolate(template, params) {
|
|
201
226
|
return template.replace(
|
|
@@ -411,16 +436,7 @@ function SelectorControl(props) {
|
|
|
411
436
|
}
|
|
412
437
|
function ActionRow(props) {
|
|
413
438
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
414
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: fields_default.actions, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
415
|
-
import_dsh_client_ui_primitives.Button,
|
|
416
|
-
{
|
|
417
|
-
type: "button",
|
|
418
|
-
variant: "outline",
|
|
419
|
-
disabled: props.disabled,
|
|
420
|
-
onClick: props.onClick,
|
|
421
|
-
children: props.label
|
|
422
|
-
}
|
|
423
|
-
) }),
|
|
439
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: fields_default.actions, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { type: "button", variant: "outline", disabled: props.disabled, onClick: props.onClick, children: props.label }) }),
|
|
424
440
|
props.result === null ? null : (
|
|
425
441
|
// 成功只是通报,用 polite 的 status;失败需要用户处理,按 06 §6.7 的「行内错误」用 alert。
|
|
426
442
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -862,6 +878,9 @@ function pendingView() {
|
|
|
862
878
|
return {
|
|
863
879
|
requestId: "",
|
|
864
880
|
schemaVersion: 1,
|
|
881
|
+
// 占位视图没有取数路可言;处境为 checking / offline 时界面都不渲染来源标签。
|
|
882
|
+
source: "deepseek-http",
|
|
883
|
+
situation: "checking",
|
|
865
884
|
state: "empty",
|
|
866
885
|
stale: false,
|
|
867
886
|
fetchedAt: 0,
|
|
@@ -879,6 +898,7 @@ function pendingView() {
|
|
|
879
898
|
function unreachableView(message) {
|
|
880
899
|
return {
|
|
881
900
|
...pendingView(),
|
|
901
|
+
situation: "offline",
|
|
882
902
|
state: "error",
|
|
883
903
|
error: { code: UNREACHABLE_CODE, message }
|
|
884
904
|
};
|
|
@@ -893,7 +913,11 @@ async function readJson(response, path) {
|
|
|
893
913
|
}
|
|
894
914
|
async function requestBalance(options) {
|
|
895
915
|
const fetchImpl = options.fetchImpl ?? ((input, init) => fetch(input, init));
|
|
896
|
-
const
|
|
916
|
+
const query = new URLSearchParams({ currency: options.currency });
|
|
917
|
+
if (options.provider !== void 0 && options.provider !== "") {
|
|
918
|
+
query.set("provider", options.provider);
|
|
919
|
+
}
|
|
920
|
+
const url = `${BALANCE_PATH}?${query.toString()}`;
|
|
897
921
|
const response = await fetchImpl(url, {
|
|
898
922
|
headers: { accept: "application/json" },
|
|
899
923
|
...options.signal === void 0 ? {} : { signal: options.signal }
|
|
@@ -922,7 +946,10 @@ async function requestRefresh(options = {}) {
|
|
|
922
946
|
const response = await fetchImpl(REFRESH_PATH, {
|
|
923
947
|
method: "POST",
|
|
924
948
|
headers: { "content-type": "application/json", accept: "application/json" },
|
|
925
|
-
body: JSON.stringify({
|
|
949
|
+
body: JSON.stringify({
|
|
950
|
+
reason: options.reason ?? "manual",
|
|
951
|
+
...options.provider === void 0 || options.provider === "" ? {} : { provider: options.provider }
|
|
952
|
+
})
|
|
926
953
|
});
|
|
927
954
|
return await readJson(response, REFRESH_PATH);
|
|
928
955
|
}
|
|
@@ -1292,12 +1319,6 @@ function dotStateOf(severity) {
|
|
|
1292
1319
|
return "idle";
|
|
1293
1320
|
}
|
|
1294
1321
|
}
|
|
1295
|
-
function ringSpecOf(severity) {
|
|
1296
|
-
return {
|
|
1297
|
-
state: dotStateOf(severity),
|
|
1298
|
-
marker: severity === "unavailable" ? "cross" : null
|
|
1299
|
-
};
|
|
1300
|
-
}
|
|
1301
1322
|
var DECIMAL_SCALE = 100000000n;
|
|
1302
1323
|
var ARC_STEPS = 10000n;
|
|
1303
1324
|
var DECIMAL_PATTERN = /^(-?)(\d+)(?:\.(\d*))?$/;
|
|
@@ -1377,6 +1398,166 @@ function currentAgeMs(seenAt, seenAgeMs, now) {
|
|
|
1377
1398
|
const base = Number.isFinite(seenAgeMs) ? Math.max(0, seenAgeMs) : 0;
|
|
1378
1399
|
return Math.max(0, base + (now - seenAt));
|
|
1379
1400
|
}
|
|
1401
|
+
var MS_PER_SECOND = 1e3;
|
|
1402
|
+
function sourceLabelKeyOf(source) {
|
|
1403
|
+
if (source === "deepseek-http") return "popover.source.key";
|
|
1404
|
+
if (source === "deepseek-account") return "popover.source.account";
|
|
1405
|
+
return null;
|
|
1406
|
+
}
|
|
1407
|
+
function cooldownUntilOf(now, configuredSeconds, rejectedRemainingMs) {
|
|
1408
|
+
const span = rejectedRemainingMs === null ? Math.max(0, configuredSeconds) * MS_PER_SECOND : Math.max(0, rejectedRemainingMs);
|
|
1409
|
+
return now + span;
|
|
1410
|
+
}
|
|
1411
|
+
function cooldownSecondsOf(until, now) {
|
|
1412
|
+
return Math.max(0, Math.ceil((until - now) / MS_PER_SECOND));
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
// src/client/situation.ts
|
|
1416
|
+
var SITUATIONS = [
|
|
1417
|
+
"checking",
|
|
1418
|
+
"offline",
|
|
1419
|
+
"internal-error",
|
|
1420
|
+
"no-credential",
|
|
1421
|
+
"fetch-failed",
|
|
1422
|
+
"account-unavailable",
|
|
1423
|
+
"stale",
|
|
1424
|
+
"empty-wallet",
|
|
1425
|
+
"ok",
|
|
1426
|
+
"low",
|
|
1427
|
+
"critical"
|
|
1428
|
+
];
|
|
1429
|
+
var SHAPES = {
|
|
1430
|
+
// —— 客户端本地事实(宿主不可能知道这两件事)——
|
|
1431
|
+
checking: {
|
|
1432
|
+
family: "pending",
|
|
1433
|
+
ring: "ongoing",
|
|
1434
|
+
marker: null,
|
|
1435
|
+
arc: "none",
|
|
1436
|
+
textKey: "situation.checking",
|
|
1437
|
+
severityColoured: false
|
|
1438
|
+
},
|
|
1439
|
+
offline: {
|
|
1440
|
+
family: "unreadable",
|
|
1441
|
+
ring: "error",
|
|
1442
|
+
marker: "cross",
|
|
1443
|
+
arc: "none",
|
|
1444
|
+
textKey: "situation.unavailable",
|
|
1445
|
+
severityColoured: false
|
|
1446
|
+
},
|
|
1447
|
+
// —— 宿主判定 ——
|
|
1448
|
+
"internal-error": {
|
|
1449
|
+
family: "unreadable",
|
|
1450
|
+
ring: "error",
|
|
1451
|
+
marker: "cross",
|
|
1452
|
+
arc: "none",
|
|
1453
|
+
textKey: "situation.internalError",
|
|
1454
|
+
severityColoured: false
|
|
1455
|
+
},
|
|
1456
|
+
"no-credential": {
|
|
1457
|
+
family: "needs-credential",
|
|
1458
|
+
ring: "idle",
|
|
1459
|
+
marker: "plus",
|
|
1460
|
+
arc: "none",
|
|
1461
|
+
textKey: "situation.noCredential",
|
|
1462
|
+
severityColoured: false
|
|
1463
|
+
},
|
|
1464
|
+
"fetch-failed": {
|
|
1465
|
+
family: "unreadable",
|
|
1466
|
+
ring: "error",
|
|
1467
|
+
marker: "cross",
|
|
1468
|
+
arc: "none",
|
|
1469
|
+
textKey: "situation.unavailable",
|
|
1470
|
+
severityColoured: false
|
|
1471
|
+
},
|
|
1472
|
+
"account-unavailable": {
|
|
1473
|
+
family: "unreadable",
|
|
1474
|
+
// **颜色定死为红,不吃 severity。**
|
|
1475
|
+
// 它是「账户停用」—— 这个事实本身就决定了红,与余额多少无关;
|
|
1476
|
+
// 而上游对欠费账户可能给空的余额列表(selected=null → severity=unknown → 灰环),
|
|
1477
|
+
// 那会把「停用」画成「没信息」。定死红环是**结构保证**,不依赖另一处的判定顺序。
|
|
1478
|
+
ring: "error",
|
|
1479
|
+
// **叉:与「余额告急」分开的唯一办法。**
|
|
1480
|
+
// 从前它靠「红环无叉」与 critical 区分,但余额恰好为 0 的 critical 也是红环无叉无弧 ——
|
|
1481
|
+
// 两者在屏幕上逐像素相同(见 test/render-matrix.test.ts 的「两枚红环」一组)。
|
|
1482
|
+
// 叉的语义从「读不到」扩到「读不到**或用不了**」:两者同属「这里没有可用的数字」。
|
|
1483
|
+
marker: "cross",
|
|
1484
|
+
arc: "none",
|
|
1485
|
+
textKey: "situation.accountUnavailable",
|
|
1486
|
+
severityColoured: false
|
|
1487
|
+
},
|
|
1488
|
+
stale: {
|
|
1489
|
+
family: "gauge",
|
|
1490
|
+
ring: "done",
|
|
1491
|
+
marker: null,
|
|
1492
|
+
arc: "gauge",
|
|
1493
|
+
textKey: "situation.stale",
|
|
1494
|
+
severityColoured: true
|
|
1495
|
+
},
|
|
1496
|
+
"empty-wallet": {
|
|
1497
|
+
family: "empty",
|
|
1498
|
+
ring: "idle",
|
|
1499
|
+
marker: null,
|
|
1500
|
+
arc: "none",
|
|
1501
|
+
textKey: "situation.emptyWallet",
|
|
1502
|
+
severityColoured: false
|
|
1503
|
+
},
|
|
1504
|
+
ok: {
|
|
1505
|
+
family: "gauge",
|
|
1506
|
+
ring: "done",
|
|
1507
|
+
marker: null,
|
|
1508
|
+
arc: "gauge",
|
|
1509
|
+
textKey: null,
|
|
1510
|
+
severityColoured: true
|
|
1511
|
+
},
|
|
1512
|
+
low: {
|
|
1513
|
+
family: "gauge",
|
|
1514
|
+
ring: "warning",
|
|
1515
|
+
marker: null,
|
|
1516
|
+
arc: "gauge",
|
|
1517
|
+
textKey: null,
|
|
1518
|
+
severityColoured: true
|
|
1519
|
+
},
|
|
1520
|
+
critical: {
|
|
1521
|
+
family: "gauge",
|
|
1522
|
+
ring: "error",
|
|
1523
|
+
marker: null,
|
|
1524
|
+
arc: "gauge",
|
|
1525
|
+
textKey: null,
|
|
1526
|
+
severityColoured: true
|
|
1527
|
+
}
|
|
1528
|
+
};
|
|
1529
|
+
function presentationOf(situation, severity) {
|
|
1530
|
+
const shape = SHAPES[situation];
|
|
1531
|
+
if (!shape.severityColoured) return shape;
|
|
1532
|
+
return { ...shape, ring: dotStateOf(severity) };
|
|
1533
|
+
}
|
|
1534
|
+
function hoverTextOf(shown, stateText) {
|
|
1535
|
+
if (stateText !== null) return stateText;
|
|
1536
|
+
return shown === null ? null : formatMoney(shown.total, shown.currency);
|
|
1537
|
+
}
|
|
1538
|
+
function isSituation(value) {
|
|
1539
|
+
return typeof value === "string" && SITUATIONS.includes(value);
|
|
1540
|
+
}
|
|
1541
|
+
function legacySituationOf(response) {
|
|
1542
|
+
const hasSnapshot = response.fetchedAt > 0 || response.selected !== null;
|
|
1543
|
+
const code = response.error?.code;
|
|
1544
|
+
if (!hasSnapshot) {
|
|
1545
|
+
if (code === "NO_KEY") return "no-credential";
|
|
1546
|
+
if (code === "PLUGIN_UNREACHABLE") return "offline";
|
|
1547
|
+
return response.state === "empty" && code === void 0 ? "checking" : "fetch-failed";
|
|
1548
|
+
}
|
|
1549
|
+
if (!response.isAvailable) return "account-unavailable";
|
|
1550
|
+
if (response.selected === null)
|
|
1551
|
+
return response.state === "stale" ? "fetch-failed" : "empty-wallet";
|
|
1552
|
+
if (response.state === "stale") return "stale";
|
|
1553
|
+
if (response.severity === "critical") return "critical";
|
|
1554
|
+
if (response.severity === "warn") return "low";
|
|
1555
|
+
if (response.severity === "unavailable" || response.severity === "unknown") return "fetch-failed";
|
|
1556
|
+
return "ok";
|
|
1557
|
+
}
|
|
1558
|
+
function situationOfResponse(response) {
|
|
1559
|
+
return isSituation(response.situation) ? response.situation : legacySituationOf(response);
|
|
1560
|
+
}
|
|
1380
1561
|
|
|
1381
1562
|
// src/client/mock/scenarios.ts
|
|
1382
1563
|
var T0 = 176e10;
|
|
@@ -1390,6 +1571,8 @@ function make(patch) {
|
|
|
1390
1571
|
return {
|
|
1391
1572
|
requestId: "req_mock",
|
|
1392
1573
|
schemaVersion: 1,
|
|
1574
|
+
source: "deepseek-http",
|
|
1575
|
+
situation: "ok",
|
|
1393
1576
|
state: "ok",
|
|
1394
1577
|
stale: false,
|
|
1395
1578
|
fetchedAt: T0,
|
|
@@ -1408,27 +1591,33 @@ function make(patch) {
|
|
|
1408
1591
|
var scenarios = {
|
|
1409
1592
|
/** 正常。 */
|
|
1410
1593
|
ok: make({}),
|
|
1594
|
+
/** 正常,但数字来自账号登录那条路(用来眼看「来源标签」)。 */
|
|
1595
|
+
account: make({ source: "deepseek-account" }),
|
|
1411
1596
|
/** 余额偏低但可用。 */
|
|
1412
1597
|
warn: make({
|
|
1598
|
+
situation: "low",
|
|
1413
1599
|
severity: "warn",
|
|
1414
1600
|
balances: [cny("8.00000000", "0.00000000", "8.00000000")],
|
|
1415
1601
|
selected: { currency: "CNY", total: "8.00000000" }
|
|
1416
1602
|
}),
|
|
1417
1603
|
/** 余额告急。 */
|
|
1418
1604
|
critical: make({
|
|
1605
|
+
situation: "critical",
|
|
1419
1606
|
severity: "critical",
|
|
1420
1607
|
balances: [cny("3.00000000", "0.00000000", "3.00000000")],
|
|
1421
1608
|
selected: { currency: "CNY", total: "3.00000000" }
|
|
1422
1609
|
}),
|
|
1423
|
-
/** 账户不可用(余额耗尽 /
|
|
1610
|
+
/** 账户不可用(余额耗尽 / 欠费)。读到了,但上游说这个账户停用。 */
|
|
1424
1611
|
unavailable: make({
|
|
1612
|
+
situation: "account-unavailable",
|
|
1425
1613
|
severity: "unavailable",
|
|
1426
1614
|
isAvailable: false,
|
|
1427
1615
|
balances: [cny("0.00000000", "0.00000000", "0.00000000")],
|
|
1428
1616
|
selected: { currency: "CNY", total: "0.00000000" }
|
|
1429
1617
|
}),
|
|
1430
|
-
/**
|
|
1618
|
+
/** 有旧值但本次刷新失败:数字照常显示,文案说它旧。 */
|
|
1431
1619
|
stale: make({
|
|
1620
|
+
situation: "stale",
|
|
1432
1621
|
state: "stale",
|
|
1433
1622
|
stale: true,
|
|
1434
1623
|
severity: "unknown",
|
|
@@ -1436,8 +1625,9 @@ var scenarios = {
|
|
|
1436
1625
|
fetchedAt: T0 - 36e5,
|
|
1437
1626
|
error: { code: "NO_NETWORK", message: "fetch failed" }
|
|
1438
1627
|
}),
|
|
1439
|
-
/**
|
|
1628
|
+
/** 无值失败:接入了却读不到(没有旧快照)。环是叉。 */
|
|
1440
1629
|
error: make({
|
|
1630
|
+
situation: "fetch-failed",
|
|
1441
1631
|
state: "error",
|
|
1442
1632
|
stale: false,
|
|
1443
1633
|
severity: "unknown",
|
|
@@ -1447,8 +1637,33 @@ var scenarios = {
|
|
|
1447
1637
|
ageMs: 0,
|
|
1448
1638
|
error: { code: "UPSTREAM_5XX", message: "upstream returned 500" }
|
|
1449
1639
|
}),
|
|
1450
|
-
/**
|
|
1640
|
+
/** 插件自己的端点不可达(旧契约里没有这个信号,靠客户端本地合成)。 */
|
|
1641
|
+
offline: make({
|
|
1642
|
+
situation: "offline",
|
|
1643
|
+
state: "error",
|
|
1644
|
+
stale: false,
|
|
1645
|
+
severity: "unknown",
|
|
1646
|
+
isAvailable: false,
|
|
1647
|
+
balances: [],
|
|
1648
|
+
selected: null,
|
|
1649
|
+
ageMs: 0,
|
|
1650
|
+
error: { code: UNREACHABLE_CODE, message: "balance endpoint responded 502" }
|
|
1651
|
+
}),
|
|
1652
|
+
/** 插件自己出错了(装配错误之类):与「上游坏了」分开说。 */
|
|
1653
|
+
internalError: make({
|
|
1654
|
+
situation: "internal-error",
|
|
1655
|
+
state: "error",
|
|
1656
|
+
stale: false,
|
|
1657
|
+
severity: "unknown",
|
|
1658
|
+
isAvailable: false,
|
|
1659
|
+
balances: [],
|
|
1660
|
+
selected: null,
|
|
1661
|
+
ageMs: 0,
|
|
1662
|
+
error: { code: "STORAGE_ERROR", message: "no ledger for source deepseek-account" }
|
|
1663
|
+
}),
|
|
1664
|
+
/** 未配置:尚无任何解释。 */
|
|
1451
1665
|
empty: make({
|
|
1666
|
+
situation: "empty-wallet",
|
|
1452
1667
|
state: "empty",
|
|
1453
1668
|
severity: "unknown",
|
|
1454
1669
|
isAvailable: false,
|
|
@@ -1456,8 +1671,9 @@ var scenarios = {
|
|
|
1456
1671
|
selected: null,
|
|
1457
1672
|
ageMs: 0
|
|
1458
1673
|
}),
|
|
1459
|
-
/** 未配置且带 NO_KEY
|
|
1674
|
+
/** 未配置且带 NO_KEY 错误 —— 需要用户去配置的那一族。 */
|
|
1460
1675
|
noKey: make({
|
|
1676
|
+
situation: "no-credential",
|
|
1461
1677
|
state: "empty",
|
|
1462
1678
|
severity: "unknown",
|
|
1463
1679
|
isAvailable: false,
|
|
@@ -1466,6 +1682,16 @@ var scenarios = {
|
|
|
1466
1682
|
ageMs: 0,
|
|
1467
1683
|
error: { code: "NO_KEY", message: "no API key configured" }
|
|
1468
1684
|
}),
|
|
1685
|
+
/** 首帧:还没问到后端。 */
|
|
1686
|
+
checking: make({
|
|
1687
|
+
situation: "checking",
|
|
1688
|
+
state: "empty",
|
|
1689
|
+
severity: "unknown",
|
|
1690
|
+
isAvailable: false,
|
|
1691
|
+
balances: [],
|
|
1692
|
+
selected: null,
|
|
1693
|
+
ageMs: 0
|
|
1694
|
+
}),
|
|
1469
1695
|
/** 多币种。`selected` 显式写出,不靠 `make()` 的默认值兜。 */
|
|
1470
1696
|
multiCurrency: make({
|
|
1471
1697
|
balances: [
|
|
@@ -1490,6 +1716,7 @@ var scenarios = {
|
|
|
1490
1716
|
}),
|
|
1491
1717
|
/** 账户完全没有余额。 */
|
|
1492
1718
|
noBalanceAtAll: make({
|
|
1719
|
+
situation: "empty-wallet",
|
|
1493
1720
|
severity: "unknown",
|
|
1494
1721
|
isAvailable: true,
|
|
1495
1722
|
balances: [],
|
|
@@ -1627,7 +1854,9 @@ var import_dsh_client_ui_primitives3 = require("@deepseek-ai/dsh-client-ui-primi
|
|
|
1627
1854
|
var BalancePopover_default = {
|
|
1628
1855
|
panel: "BalancePopover_panel",
|
|
1629
1856
|
title: "BalancePopover_title",
|
|
1857
|
+
titleMain: "BalancePopover_titleMain",
|
|
1630
1858
|
titleLabel: "BalancePopover_titleLabel",
|
|
1859
|
+
sourceLabel: "BalancePopover_sourceLabel",
|
|
1631
1860
|
iconButton: "BalancePopover_iconButton",
|
|
1632
1861
|
titleRule: "BalancePopover_titleRule",
|
|
1633
1862
|
details: "BalancePopover_details",
|
|
@@ -1670,6 +1899,7 @@ function BalancePopover(props) {
|
|
|
1670
1899
|
selection,
|
|
1671
1900
|
displayCurrency,
|
|
1672
1901
|
ageMs,
|
|
1902
|
+
sourceLabel,
|
|
1673
1903
|
refreshing,
|
|
1674
1904
|
cooldownSeconds,
|
|
1675
1905
|
configSlotWarning,
|
|
@@ -1707,19 +1937,22 @@ function BalancePopover(props) {
|
|
|
1707
1937
|
"aria-label": t("popover.title"),
|
|
1708
1938
|
children: [
|
|
1709
1939
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: BalancePopover_default.title, children: [
|
|
1710
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1940
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: BalancePopover_default.titleMain, children: [
|
|
1941
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1942
|
+
"a",
|
|
1943
|
+
{
|
|
1944
|
+
className: BalancePopover_default.titleLabel,
|
|
1945
|
+
href: "https://platform.deepseek.com/usage",
|
|
1946
|
+
target: "_blank",
|
|
1947
|
+
rel: "noopener noreferrer",
|
|
1948
|
+
children: [
|
|
1949
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.FishLogo, { size: 14 }),
|
|
1950
|
+
t("popover.title")
|
|
1951
|
+
]
|
|
1952
|
+
}
|
|
1953
|
+
),
|
|
1954
|
+
sourceLabel === null ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: BalancePopover_default.sourceLabel, children: sourceLabel })
|
|
1955
|
+
] }),
|
|
1723
1956
|
pluginsAction === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.Tooltip, { label: pluginsLabel, side: "top", delayMs: 500, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1724
1957
|
"button",
|
|
1725
1958
|
{
|
|
@@ -1781,7 +2014,9 @@ var PercentRing_default = {
|
|
|
1781
2014
|
ring: "PercentRing_ring",
|
|
1782
2015
|
track: "PercentRing_track",
|
|
1783
2016
|
fill: "PercentRing_fill",
|
|
1784
|
-
|
|
2017
|
+
marker: "PercentRing_marker",
|
|
2018
|
+
spin: "PercentRing_spin",
|
|
2019
|
+
"dsb-ring-spin": "PercentRing_dsb-ring-spin"
|
|
1785
2020
|
};
|
|
1786
2021
|
|
|
1787
2022
|
// src/client/sidebar/PercentRing.tsx
|
|
@@ -1792,10 +2027,13 @@ var RING_INSET = 1;
|
|
|
1792
2027
|
var RADIUS = VIEW / 2 - RING_INSET - STROKE / 2;
|
|
1793
2028
|
var CENTER = VIEW / 2;
|
|
1794
2029
|
var CIRCUMFERENCE = 2 * Math.PI * RADIUS;
|
|
1795
|
-
var
|
|
2030
|
+
var INNER_RADIUS = RADIUS - STROKE / 2;
|
|
2031
|
+
var MARK_ARM = INNER_RADIUS / 2 / Math.SQRT2;
|
|
1796
2032
|
function round3(value) {
|
|
1797
2033
|
return Math.round(value * 1e3) / 1e3;
|
|
1798
2034
|
}
|
|
2035
|
+
var SPIN_ARC_RATIO = 12 / (2 * Math.PI * 9.5);
|
|
2036
|
+
var SPIN_ARC = round3(CIRCUMFERENCE * SPIN_ARC_RATIO);
|
|
1799
2037
|
function PercentRing({
|
|
1800
2038
|
state,
|
|
1801
2039
|
marker = null,
|
|
@@ -1817,37 +2055,55 @@ function PercentRing({
|
|
|
1817
2055
|
children: [
|
|
1818
2056
|
title === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("title", { children: title }),
|
|
1819
2057
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { className: PercentRing_default.track, cx: CENTER, cy: CENTER, r: RADIUS }),
|
|
1820
|
-
|
|
2058
|
+
state === "ongoing" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("g", { className: PercentRing_default.spin, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1821
2059
|
"circle",
|
|
1822
2060
|
{
|
|
1823
2061
|
className: PercentRing_default.fill,
|
|
1824
2062
|
cx: CENTER,
|
|
1825
2063
|
cy: CENTER,
|
|
1826
2064
|
r: RADIUS,
|
|
1827
|
-
strokeDasharray: `${
|
|
2065
|
+
strokeDasharray: `${SPIN_ARC} ${round3(CIRCUMFERENCE)}`,
|
|
1828
2066
|
transform: `rotate(-90 ${CENTER} ${CENTER})`
|
|
1829
2067
|
}
|
|
2068
|
+
) }) : (
|
|
2069
|
+
/* dash 取弧长、gap 取整周长,于是只画出一条弧;rotate 让接缝落在 12 点而不是 3 点
|
|
2070
|
+
(中心跟着 VIEW 走,16 格时是 rotate(-90 8 8))。
|
|
2071
|
+
比例为 0 时整条弧不画:dash 长度为 0 配上圆头线帽会在 12 点留下一个点。 */
|
|
2072
|
+
clamped === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2073
|
+
"circle",
|
|
2074
|
+
{
|
|
2075
|
+
className: PercentRing_default.fill,
|
|
2076
|
+
cx: CENTER,
|
|
2077
|
+
cy: CENTER,
|
|
2078
|
+
r: RADIUS,
|
|
2079
|
+
strokeDasharray: `${round3(CIRCUMFERENCE * clamped)} ${round3(CIRCUMFERENCE)}`,
|
|
2080
|
+
transform: `rotate(-90 ${CENTER} ${CENTER})`
|
|
2081
|
+
}
|
|
2082
|
+
)
|
|
1830
2083
|
),
|
|
1831
|
-
marker ===
|
|
2084
|
+
marker === null ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("g", { className: PercentRing_default.marker, children: marker === "cross" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
1832
2085
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1833
2086
|
"line",
|
|
1834
2087
|
{
|
|
1835
|
-
x1: CENTER -
|
|
1836
|
-
y1: CENTER -
|
|
1837
|
-
x2: CENTER +
|
|
1838
|
-
y2: CENTER +
|
|
2088
|
+
x1: CENTER - MARK_ARM,
|
|
2089
|
+
y1: CENTER - MARK_ARM,
|
|
2090
|
+
x2: CENTER + MARK_ARM,
|
|
2091
|
+
y2: CENTER + MARK_ARM
|
|
1839
2092
|
}
|
|
1840
2093
|
),
|
|
1841
2094
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1842
2095
|
"line",
|
|
1843
2096
|
{
|
|
1844
|
-
x1: CENTER +
|
|
1845
|
-
y1: CENTER -
|
|
1846
|
-
x2: CENTER -
|
|
1847
|
-
y2: CENTER +
|
|
2097
|
+
x1: CENTER + MARK_ARM,
|
|
2098
|
+
y1: CENTER - MARK_ARM,
|
|
2099
|
+
x2: CENTER - MARK_ARM,
|
|
2100
|
+
y2: CENTER + MARK_ARM
|
|
1848
2101
|
}
|
|
1849
2102
|
)
|
|
1850
|
-
] }) :
|
|
2103
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
2104
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: CENTER, y1: CENTER - MARK_ARM, x2: CENTER, y2: CENTER + MARK_ARM }),
|
|
2105
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: CENTER - MARK_ARM, y1: CENTER, x2: CENTER + MARK_ARM, y2: CENTER })
|
|
2106
|
+
] }) })
|
|
1851
2107
|
]
|
|
1852
2108
|
}
|
|
1853
2109
|
);
|
|
@@ -1868,8 +2124,8 @@ var REFRESH_SIMULATION_MS = 600;
|
|
|
1868
2124
|
var PANEL_GAP = 8;
|
|
1869
2125
|
var PANEL_MARGIN = 12;
|
|
1870
2126
|
var MEASURE_STYLE = { visibility: "hidden", left: 0, top: 0 };
|
|
1871
|
-
var
|
|
1872
|
-
var TICK_MS =
|
|
2127
|
+
var MS_PER_SECOND2 = 1e3;
|
|
2128
|
+
var TICK_MS = MS_PER_SECOND2;
|
|
1873
2129
|
function useConfigSlotState(probe) {
|
|
1874
2130
|
const [state, setState] = (0, import_react5.useState)(() => probe.getSnapshot());
|
|
1875
2131
|
(0, import_react5.useEffect)(() => {
|
|
@@ -1894,19 +2150,22 @@ function usePluginsNavigation(navigation) {
|
|
|
1894
2150
|
}, [navigation]);
|
|
1895
2151
|
return action;
|
|
1896
2152
|
}
|
|
1897
|
-
function
|
|
1898
|
-
|
|
1899
|
-
return response.error?.code === "NO_KEY" ? "state.noKey" : "state.error";
|
|
1900
|
-
if (response.state === "empty")
|
|
1901
|
-
return response.error?.code === "NO_KEY" ? "state.noKey" : "state.empty";
|
|
1902
|
-
if (response.state === "stale") return "state.stale";
|
|
1903
|
-
if (!response.isAvailable) return "state.unavailable";
|
|
1904
|
-
if (selection.shown === null) return "state.noBalance";
|
|
1905
|
-
return null;
|
|
2153
|
+
function ringSpecFor(presentation) {
|
|
2154
|
+
return { state: presentation.ring, marker: presentation.marker };
|
|
1906
2155
|
}
|
|
1907
|
-
function
|
|
1908
|
-
const
|
|
1909
|
-
|
|
2156
|
+
function useRouteProvider(hint) {
|
|
2157
|
+
const [provider, setProvider] = (0, import_react5.useState)(() => hint?.getSnapshot());
|
|
2158
|
+
(0, import_react5.useEffect)(() => {
|
|
2159
|
+
if (hint === void 0) {
|
|
2160
|
+
setProvider(void 0);
|
|
2161
|
+
return;
|
|
2162
|
+
}
|
|
2163
|
+
setProvider(hint.getSnapshot());
|
|
2164
|
+
return hint.subscribe(() => {
|
|
2165
|
+
setProvider(hint.getSnapshot());
|
|
2166
|
+
});
|
|
2167
|
+
}, [hint]);
|
|
2168
|
+
return provider;
|
|
1910
2169
|
}
|
|
1911
2170
|
function SidebarBalance({
|
|
1912
2171
|
wide,
|
|
@@ -1914,7 +2173,8 @@ function SidebarBalance({
|
|
|
1914
2173
|
config,
|
|
1915
2174
|
configSlotProbe,
|
|
1916
2175
|
onSelectCurrency,
|
|
1917
|
-
pluginsNavigation
|
|
2176
|
+
pluginsNavigation,
|
|
2177
|
+
routeHint
|
|
1918
2178
|
}) {
|
|
1919
2179
|
const [view, setView] = (0, import_react5.useState)(() => {
|
|
1920
2180
|
const response2 = resolveScenario() === null ? pendingView() : currentBalance();
|
|
@@ -1927,6 +2187,7 @@ function SidebarBalance({
|
|
|
1927
2187
|
const [refreshing, setRefreshing] = (0, import_react5.useState)(false);
|
|
1928
2188
|
const [cooldownUntil, setCooldownUntil] = (0, import_react5.useState)(0);
|
|
1929
2189
|
const [now, setNow] = (0, import_react5.useState)(() => Date.now());
|
|
2190
|
+
const provider = useRouteProvider(routeHint);
|
|
1930
2191
|
const rootRef = (0, import_react5.useRef)(null);
|
|
1931
2192
|
const panelRef = (0, import_react5.useRef)(null);
|
|
1932
2193
|
const refreshTimer = (0, import_react5.useRef)(void 0);
|
|
@@ -1961,7 +2222,7 @@ function SidebarBalance({
|
|
|
1961
2222
|
let cancelled = false;
|
|
1962
2223
|
const load = async () => {
|
|
1963
2224
|
try {
|
|
1964
|
-
const next = await requestBalance({ currency: preference });
|
|
2225
|
+
const next = await requestBalance({ currency: preference, provider });
|
|
1965
2226
|
if (cancelled) return;
|
|
1966
2227
|
loadedRef.current = true;
|
|
1967
2228
|
acceptBalance(next);
|
|
@@ -1975,7 +2236,7 @@ function SidebarBalance({
|
|
|
1975
2236
|
() => {
|
|
1976
2237
|
void load();
|
|
1977
2238
|
},
|
|
1978
|
-
Math.max(5, config.clientPollSeconds) *
|
|
2239
|
+
Math.max(5, config.clientPollSeconds) * MS_PER_SECOND2
|
|
1979
2240
|
);
|
|
1980
2241
|
return () => {
|
|
1981
2242
|
cancelled = true;
|
|
@@ -1984,6 +2245,7 @@ function SidebarBalance({
|
|
|
1984
2245
|
}, [
|
|
1985
2246
|
mock,
|
|
1986
2247
|
preference,
|
|
2248
|
+
provider,
|
|
1987
2249
|
config.clientPollSeconds,
|
|
1988
2250
|
config.configSignature,
|
|
1989
2251
|
acceptBalance,
|
|
@@ -2009,9 +2271,12 @@ function SidebarBalance({
|
|
|
2009
2271
|
gap: PANEL_GAP,
|
|
2010
2272
|
margin: PANEL_MARGIN
|
|
2011
2273
|
});
|
|
2012
|
-
(0, import_react5.
|
|
2274
|
+
(0, import_react5.useLayoutEffect)(() => {
|
|
2013
2275
|
if (!open) return;
|
|
2014
2276
|
setNow(Date.now());
|
|
2277
|
+
}, [open]);
|
|
2278
|
+
(0, import_react5.useEffect)(() => {
|
|
2279
|
+
if (!open) return;
|
|
2015
2280
|
const id = window.setInterval(() => {
|
|
2016
2281
|
setNow(Date.now());
|
|
2017
2282
|
}, TICK_MS);
|
|
@@ -2019,6 +2284,17 @@ function SidebarBalance({
|
|
|
2019
2284
|
window.clearInterval(id);
|
|
2020
2285
|
};
|
|
2021
2286
|
}, [open]);
|
|
2287
|
+
(0, import_react5.useEffect)(() => {
|
|
2288
|
+
if (cooldownUntil === 0) return;
|
|
2289
|
+
const remaining = cooldownUntil - Date.now();
|
|
2290
|
+
if (remaining <= 0) return;
|
|
2291
|
+
const id = window.setTimeout(() => {
|
|
2292
|
+
setNow(Date.now());
|
|
2293
|
+
}, remaining);
|
|
2294
|
+
return () => {
|
|
2295
|
+
window.clearTimeout(id);
|
|
2296
|
+
};
|
|
2297
|
+
}, [cooldownUntil]);
|
|
2022
2298
|
(0, import_react5.useEffect)(() => {
|
|
2023
2299
|
if (!open) return;
|
|
2024
2300
|
const onKeyDown = (event) => {
|
|
@@ -2034,30 +2310,34 @@ function SidebarBalance({
|
|
|
2034
2310
|
if (refreshing) return;
|
|
2035
2311
|
if (Date.now() < cooldownUntil) return;
|
|
2036
2312
|
setRefreshing(true);
|
|
2037
|
-
const finish = () => {
|
|
2313
|
+
const finish = (rejectedRemainingMs) => {
|
|
2314
|
+
const at = Date.now();
|
|
2038
2315
|
setRefreshing(false);
|
|
2039
2316
|
setCooldownUntil(
|
|
2040
|
-
|
|
2317
|
+
cooldownUntilOf(at, config.manualRefreshCooldownSeconds, rejectedRemainingMs)
|
|
2041
2318
|
);
|
|
2319
|
+
setNow(at);
|
|
2042
2320
|
};
|
|
2043
2321
|
if (mock) {
|
|
2044
2322
|
refreshTimer.current = window.setTimeout(() => {
|
|
2045
2323
|
refreshTimer.current = void 0;
|
|
2046
2324
|
markFresh();
|
|
2047
|
-
finish();
|
|
2325
|
+
finish(null);
|
|
2048
2326
|
}, REFRESH_SIMULATION_MS);
|
|
2049
2327
|
return;
|
|
2050
2328
|
}
|
|
2051
2329
|
void (async () => {
|
|
2330
|
+
let rejectedRemainingMs = null;
|
|
2052
2331
|
try {
|
|
2053
|
-
await requestRefresh({ reason: "manual" });
|
|
2054
|
-
|
|
2332
|
+
const result = await requestRefresh({ reason: "manual", provider });
|
|
2333
|
+
if (!result.triggered) rejectedRemainingMs = Math.max(0, result.cooldownMs);
|
|
2334
|
+
const next = await requestBalance({ currency: preference, provider });
|
|
2055
2335
|
loadedRef.current = true;
|
|
2056
2336
|
acceptBalance(next);
|
|
2057
2337
|
} catch (error) {
|
|
2058
2338
|
if (!loadedRef.current) showUnreachable(error);
|
|
2059
2339
|
} finally {
|
|
2060
|
-
finish();
|
|
2340
|
+
finish(rejectedRemainingMs);
|
|
2061
2341
|
}
|
|
2062
2342
|
})();
|
|
2063
2343
|
}, [
|
|
@@ -2065,6 +2345,7 @@ function SidebarBalance({
|
|
|
2065
2345
|
config.manualRefreshCooldownSeconds,
|
|
2066
2346
|
mock,
|
|
2067
2347
|
preference,
|
|
2348
|
+
provider,
|
|
2068
2349
|
refreshing,
|
|
2069
2350
|
acceptBalance,
|
|
2070
2351
|
showUnreachable,
|
|
@@ -2088,18 +2369,20 @@ function SidebarBalance({
|
|
|
2088
2369
|
);
|
|
2089
2370
|
const configSlotState = useConfigSlotState(configSlotProbe);
|
|
2090
2371
|
const shown = selection.shown;
|
|
2091
|
-
const
|
|
2092
|
-
const
|
|
2372
|
+
const situation = situationOfResponse(response);
|
|
2373
|
+
const presentation = presentationOf(situation, response.severity);
|
|
2374
|
+
const ring = ringSpecFor(presentation);
|
|
2375
|
+
const ringRatio = presentation.arc === "gauge" ? ringRatioOf(
|
|
2093
2376
|
shown === null ? null : shown.total,
|
|
2094
2377
|
shown === null ? void 0 : config.warnThresholdOf(shown.currency),
|
|
2095
2378
|
response.severity
|
|
2096
|
-
);
|
|
2097
|
-
const stateKey =
|
|
2379
|
+
) : 0;
|
|
2380
|
+
const stateKey = presentation.textKey;
|
|
2098
2381
|
const stateText = stateKey === null ? null : t(stateKey);
|
|
2099
2382
|
let markerLabel = null;
|
|
2100
2383
|
let markerHint = "";
|
|
2101
2384
|
if (shown === null) {
|
|
2102
|
-
markerLabel = t(stateKey ?? "
|
|
2385
|
+
markerLabel = t(stateKey ?? "situation.emptyWallet");
|
|
2103
2386
|
markerHint = markerLabel;
|
|
2104
2387
|
} else if (!selection.matchesPreference) {
|
|
2105
2388
|
markerLabel = t("sidebar.aria.mismatch");
|
|
@@ -2110,10 +2393,11 @@ function SidebarBalance({
|
|
|
2110
2393
|
if (stateText !== null && stateText !== markerLabel) ariaParts.push(stateText);
|
|
2111
2394
|
if (markerLabel !== null) ariaParts.push(markerLabel);
|
|
2112
2395
|
const ariaLabel = ariaParts.join(" ");
|
|
2113
|
-
const cooldownSeconds =
|
|
2396
|
+
const cooldownSeconds = cooldownSecondsOf(cooldownUntil, now);
|
|
2397
|
+
const sourceKey = shown === null ? null : sourceLabelKeyOf(response.source);
|
|
2398
|
+
const sourceLabel = sourceKey === null ? null : t(sourceKey);
|
|
2114
2399
|
const ageMs = currentAgeMs(view.seenAt, view.seenAgeMs, now);
|
|
2115
|
-
const
|
|
2116
|
-
const hoverLabel = shown === null ? stateText : formatMoney(shown.total, shown.currency);
|
|
2400
|
+
const hoverText = hoverTextOf(shown, stateText);
|
|
2117
2401
|
const trigger = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2118
2402
|
"button",
|
|
2119
2403
|
{
|
|
@@ -2133,13 +2417,13 @@ function SidebarBalance({
|
|
|
2133
2417
|
marker: ring.marker,
|
|
2134
2418
|
ratio: ringRatio,
|
|
2135
2419
|
size: 18,
|
|
2136
|
-
title:
|
|
2420
|
+
title: hoverText ?? void 0
|
|
2137
2421
|
}
|
|
2138
2422
|
)
|
|
2139
2423
|
}
|
|
2140
2424
|
);
|
|
2141
2425
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: rootRef, className: SidebarBalance_default.root, "data-mode": wide ? "wide" : "rail", tabIndex: -1, children: [
|
|
2142
|
-
wide &&
|
|
2426
|
+
wide && hoverText !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.Tooltip, { label: hoverText, side: "right", delayMs: 500, disabled: open, children: trigger }) : trigger,
|
|
2143
2427
|
open ? (0, import_react_dom.createPortal)(
|
|
2144
2428
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2145
2429
|
BalancePopover,
|
|
@@ -2148,6 +2432,7 @@ function SidebarBalance({
|
|
|
2148
2432
|
selection,
|
|
2149
2433
|
displayCurrency: preference,
|
|
2150
2434
|
ageMs,
|
|
2435
|
+
sourceLabel,
|
|
2151
2436
|
refreshing,
|
|
2152
2437
|
cooldownSeconds,
|
|
2153
2438
|
configSlotWarning: configSlotState === "missing" ? CONFIG_SLOT_WARNING : null,
|
|
@@ -2164,6 +2449,66 @@ function SidebarBalance({
|
|
|
2164
2449
|
] });
|
|
2165
2450
|
}
|
|
2166
2451
|
|
|
2452
|
+
// src/client/route-hint.ts
|
|
2453
|
+
function safely(read) {
|
|
2454
|
+
try {
|
|
2455
|
+
return read();
|
|
2456
|
+
} catch {
|
|
2457
|
+
return void 0;
|
|
2458
|
+
}
|
|
2459
|
+
}
|
|
2460
|
+
function projectionOf(ctx) {
|
|
2461
|
+
return safely(() => {
|
|
2462
|
+
const current = ctx.uiSession?.adapter?.current?.getSnapshot?.();
|
|
2463
|
+
const key = current?.key;
|
|
2464
|
+
if (key === void 0) return void 0;
|
|
2465
|
+
return ctx.sessions?.binding?.(key)?.session?.projections?.faceOf?.("modelSelection");
|
|
2466
|
+
});
|
|
2467
|
+
}
|
|
2468
|
+
function createRouteHint(services) {
|
|
2469
|
+
const listeners2 = /* @__PURE__ */ new Set();
|
|
2470
|
+
let stopCurrent;
|
|
2471
|
+
let stopProjection;
|
|
2472
|
+
const notify = () => {
|
|
2473
|
+
for (const listener of [...listeners2]) listener();
|
|
2474
|
+
};
|
|
2475
|
+
const bindProjection = () => {
|
|
2476
|
+
stopProjection?.();
|
|
2477
|
+
stopProjection = safely(() => projectionOf(services())?.subscribe?.(notify));
|
|
2478
|
+
};
|
|
2479
|
+
const start = () => {
|
|
2480
|
+
stopCurrent = safely(
|
|
2481
|
+
() => services().uiSession?.adapter?.current?.subscribe?.(() => {
|
|
2482
|
+
bindProjection();
|
|
2483
|
+
notify();
|
|
2484
|
+
})
|
|
2485
|
+
);
|
|
2486
|
+
bindProjection();
|
|
2487
|
+
};
|
|
2488
|
+
const stop = () => {
|
|
2489
|
+
stopCurrent?.();
|
|
2490
|
+
stopProjection?.();
|
|
2491
|
+
stopCurrent = void 0;
|
|
2492
|
+
stopProjection = void 0;
|
|
2493
|
+
};
|
|
2494
|
+
return {
|
|
2495
|
+
getSnapshot() {
|
|
2496
|
+
const value = safely(
|
|
2497
|
+
() => projectionOf(services())?.getSnapshot?.()?.next?.provider
|
|
2498
|
+
);
|
|
2499
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
2500
|
+
},
|
|
2501
|
+
subscribe(listener) {
|
|
2502
|
+
listeners2.add(listener);
|
|
2503
|
+
if (listeners2.size === 1) start();
|
|
2504
|
+
return () => {
|
|
2505
|
+
listeners2.delete(listener);
|
|
2506
|
+
if (listeners2.size === 0) stop();
|
|
2507
|
+
};
|
|
2508
|
+
}
|
|
2509
|
+
};
|
|
2510
|
+
}
|
|
2511
|
+
|
|
2167
2512
|
// src/client/index.tsx
|
|
2168
2513
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
2169
2514
|
var ENTRY_ID = "dsh-ds-balance";
|
|
@@ -2233,6 +2578,7 @@ function SidebarSeatComponent(props) {
|
|
|
2233
2578
|
t: translateOf(props.seat.t),
|
|
2234
2579
|
configSlotProbe: props.configSlotProbe,
|
|
2235
2580
|
pluginsNavigation: props.pluginsNavigation,
|
|
2581
|
+
routeHint: props.routeHint,
|
|
2236
2582
|
onSelectCurrency: selectCurrency,
|
|
2237
2583
|
config: {
|
|
2238
2584
|
displayCurrency: readDisplayCurrency(value),
|
|
@@ -2312,6 +2658,18 @@ function apply(ctx) {
|
|
|
2312
2658
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }), "ds-balance: dictionaries");
|
|
2313
2659
|
const configSlotProbe = createConfigSlotProbe();
|
|
2314
2660
|
ctx.effect(() => () => configSlotProbe.dispose(), "ds-balance: config slot probe");
|
|
2661
|
+
const routeServices = {};
|
|
2662
|
+
for (const name of ["uiSession", "sessions"]) {
|
|
2663
|
+
ctx.inject([name], (serviceCtx) => {
|
|
2664
|
+
serviceCtx.effect(() => {
|
|
2665
|
+
routeServices[name] = serviceCtx[name];
|
|
2666
|
+
return () => {
|
|
2667
|
+
delete routeServices[name];
|
|
2668
|
+
};
|
|
2669
|
+
}, `ds-balance: route hint (${name})`);
|
|
2670
|
+
});
|
|
2671
|
+
}
|
|
2672
|
+
const routeHint = createRouteHint(() => routeServices);
|
|
2315
2673
|
const pluginsNavigation = createPluginsNavigation();
|
|
2316
2674
|
ctx.inject(["pluginNavigation"], (navCtx) => {
|
|
2317
2675
|
const face = navCtx["pluginNavigation"];
|
|
@@ -2357,14 +2715,15 @@ function apply(ctx) {
|
|
|
2357
2715
|
seat,
|
|
2358
2716
|
form,
|
|
2359
2717
|
configSlotProbe,
|
|
2360
|
-
pluginsNavigation
|
|
2718
|
+
pluginsNavigation,
|
|
2719
|
+
routeHint
|
|
2361
2720
|
}
|
|
2362
2721
|
)
|
|
2363
2722
|
)
|
|
2364
2723
|
);
|
|
2365
2724
|
});
|
|
2366
2725
|
}
|
|
2367
|
-
var __dsbCss = "/* src/client/settings/fields.module.css */\n.fields_group {\n padding: 12px 0 0;\n}\n.fields_groupLast {\n padding-bottom: 12px;\n}\n.fields_groupNote {\n margin: 4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.fields_fields {\n display: flex;\n flex-direction: column;\n}\n.fields_fields > * + * {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n.fields_details {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n margin-top: 12px;\n padding-top: 12px;\n}\n.fields_detailsBody {\n padding-top: 10px;\n}\n.fields_field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px 0;\n}\n.fields_row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 0;\n}\n.fields_rowText {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding-right: 48px;\n}\n.fields_rowTitleLine {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_rowTitle {\n flex: 1;\n min-width: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_head {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_label {\n flex: 1;\n min-width: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_badges {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n.fields_reset {\n border: none;\n background: none;\n padding: 0;\n font: inherit;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n.fields_reset:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}\n.fields_reset:disabled {\n cursor: default;\n}\n.fields_inputStatic,\n.fields_inputStatic:hover {\n pointer-events: none;\n}\n.fields_inputStatic input,\n.fields_inputStatic input:hover,\n.fields_inputStatic input:focus,\n.fields_inputStatic input:focus-visible,\n.fields_inputStatic input:active {\n border-color: var(--dsw-alias-border-l4);\n background: var(--dsw-alias-bg-layer-3);\n outline: none;\n box-shadow: none;\n cursor: default;\n}\n.fields_inputInvalid input {\n border: 1px solid var(--dsw-alias-state-error-primary);\n}\n.fields_inputInvalid input:focus-visible {\n border-color: var(--dsw-alias-brand-primary);\n}\n.fields_inputWithAction {\n position: relative;\n display: flex;\n align-items: center;\n}\n.fields_inputWithAction .fields_input,\n.fields_inputWithAction .fields_inputInvalid {\n padding-right: 38px;\n}\n.fields_reveal {\n position: absolute;\n right: 4px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n padding: 0;\n border: none;\n border-radius: 999px;\n corner-shape: round;\n background: transparent;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n.fields_reveal:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n.fields_revealOn {\n color: var(--dsw-alias-label-primary);\n}\n.fields_reveal:disabled {\n cursor: default;\n opacity: 0.4;\n}\n.fields_selectorAnchor {\n flex: none;\n}\n.fields_selector {\n display: inline-flex;\n align-items: center;\n gap: 12px;\n flex: none;\n max-width: 100%;\n height: 36px;\n padding: 0 14px;\n border: none;\n border-radius: 18px;\n background: var(--dsw-alias-bg-module-platform);\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n text-align: left;\n cursor: pointer;\n}\n.fields_selector:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.fields_selector:disabled {\n color: var(--dsw-alias-label-tertiary);\n cursor: default;\n}\n.fields_selectorChevron {\n flex: none;\n}\n.fields_hint {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.fields_pairNote {\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-warn-primary);\n}\n.fields_pairNote::before {\n content: \"\";\n flex: none;\n width: 5px;\n height: 5px;\n border-radius: 999px;\n corner-shape: round;\n background: currentColor;\n}\n.fields_invalid {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n.fields_actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_resultOk {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-success-primary);\n}\n.fields_resultFail {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n\n/* src/client/settings/BalanceSettingsCard.module.css */\n.BalanceSettingsCard_form {\n display: flex;\n flex-direction: column;\n}\n.BalanceSettingsCard_readOnly {\n margin: 0 0 12px;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalanceSettingsCard_footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding-top: 16px;\n}\n.BalanceSettingsCard_failed {\n flex: 1;\n min-width: 0;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n.BalanceSettingsCard_notice {\n flex: 1;\n min-width: 0;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n\n/* src/client/sidebar/BalancePopover.module.css */\n.BalancePopover_panel {\n position: fixed;\n isolation: isolate;\n z-index: 1100;\n box-sizing: border-box;\n width: max-content;\n min-width: min(300px, calc(100vw - 24px));\n max-width: min(440px, calc(100vw - 24px));\n padding: 16px;\n border: 0;\n border-radius: 12px;\n --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);\n box-shadow: var(--dsw-elevation-prominent);\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n cursor: default;\n}\n.BalancePopover_panel::before {\n position: absolute;\n z-index: -1;\n inset: 0;\n border-radius: inherit;\n background: var(--dsw-specific-menu);\n backdrop-filter: var(--dsw-menu-backdrop-filter);\n content: \"\";\n pointer-events: none;\n}\n.BalancePopover_title {\n display: flex;\n justify-content: space-between;\n gap: 16px;\n margin-bottom: 8px;\n color: var(--dsw-alias-label-primary);\n font-weight: 500;\n}\n.BalancePopover_titleLabel {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n cursor: pointer;\n color: inherit;\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n.BalancePopover_titleLabel:hover,\n.BalancePopover_titleLabel:visited {\n color: inherit;\n}\n.BalancePopover_titleLabel svg {\n flex: none;\n width: 14px;\n height: auto;\n}\n.BalancePopover_iconButton {\n position: relative;\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n border-radius: 50%;\n corner-shape: round;\n padding: 0;\n background: transparent;\n cursor: pointer;\n color: var(--dsw-alias-label-secondary);\n}\n.BalancePopover_iconButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.BalancePopover_iconButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n.BalancePopover_titleRule {\n margin-bottom: 10px;\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n.BalancePopover_details {\n display: grid;\n grid-template-columns: minmax(76px, auto) minmax(0, 1fr);\n gap: 6px 16px;\n margin: 0;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_details dt,\n.BalancePopover_details dd {\n min-width: 0;\n margin: 0;\n}\n.BalancePopover_details dd {\n color: var(--dsw-alias-label-secondary);\n font-variant-numeric: tabular-nums;\n text-align: right;\n}\n.BalancePopover_notice {\n margin-top: 12px;\n}\n.BalancePopover_noticeText {\n margin: 0 0 8px;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_noticeActions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n}\n.BalancePopover_footer {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 12px;\n}\n.BalancePopover_updated {\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_status {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: right;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_refresh {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: none;\n border-radius: 999px;\n corner-shape: round;\n background: transparent;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n.BalancePopover_refresh:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n.BalancePopover_refresh:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n.BalancePopover_refresh:disabled {\n opacity: 0.4;\n cursor: default;\n}\n.BalancePopover_refresh[data-cooling] {\n color: var(--dsw-alias-label-caption);\n}\n.BalancePopover_refresh[data-refreshing] svg {\n animation: BalancePopover_balance-refresh-spin 900ms linear infinite;\n}\n@keyframes BalancePopover_balance-refresh-spin {\n to {\n transform: rotate(360deg);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .BalancePopover_refresh[data-refreshing] svg {\n animation-duration: 2400ms;\n }\n}\n\n/* src/client/sidebar/PercentRing.module.css */\n.PercentRing_ring {\n display: block;\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n}\n.PercentRing_ring[data-state=done] {\n color: var(--dsw-alias-state-success-primary);\n}\n.PercentRing_ring[data-state=warning] {\n color: var(--dsw-alias-state-warn-primary);\n}\n.PercentRing_ring[data-state=error] {\n color: var(--dsw-alias-state-error-primary);\n}\n.PercentRing_ring[data-state=idle] {\n color: var(--dsw-alias-state-idle-primary);\n}\n.PercentRing_track {\n fill: none;\n stroke: var(--dsw-alias-border-l3);\n stroke-width: 1;\n}\n.PercentRing_fill {\n fill: none;\n stroke: currentColor;\n stroke-width: 1;\n stroke-linecap: round;\n}\n.PercentRing_cross {\n fill: none;\n stroke: currentColor;\n stroke-width: 1;\n stroke-linecap: round;\n}\n\n/* src/client/sidebar/SidebarBalance.module.css */\n.SidebarBalance_root {\n position: relative;\n display: flex;\n min-width: 0;\n}\n.SidebarBalance_root[data-mode=wide] {\n flex: none;\n width: calc(100% + 4px);\n margin: 4px -2px 0;\n}\n.SidebarBalance_root[data-mode=rail] {\n flex: none;\n margin: 8px 0 0;\n}\n.SidebarBalance_trigger {\n display: flex;\n align-items: center;\n box-sizing: border-box;\n border: none;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font-family: inherit;\n font-size: 14px;\n line-height: 22px;\n cursor: pointer;\n overflow: hidden;\n}\n.SidebarBalance_trigger:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.SidebarBalance_trigger:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n.SidebarBalance_root[data-mode=wide] .SidebarBalance_trigger {\n flex: none;\n gap: 8px;\n width: 100%;\n height: 42px;\n padding: 0 10px 0 8px;\n border-radius: 12px;\n}\n.SidebarBalance_root[data-mode=rail] .SidebarBalance_trigger {\n flex: none;\n justify-content: center;\n width: 36px;\n height: 36px;\n padding: 0;\n border-radius: 12px;\n}\n.SidebarBalance_icon {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n}\n.SidebarBalance_label {\n flex: 0 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.SidebarBalance_marker {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n color: var(--dsw-alias-label-tertiary);\n position: relative;\n top: 1.63px;\n}\n\n/* src/client/sidebar/footer-stack.module.css */\ndiv:has(> [data-slot=\"sidebar.footer.action\"]) {\n flex-direction: column;\n}\n";
|
|
2726
|
+
var __dsbCss = "/* src/client/settings/fields.module.css */\n.fields_group {\n padding: 12px 0 0;\n}\n.fields_groupLast {\n padding-bottom: 12px;\n}\n.fields_groupNote {\n margin: 4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.fields_fields {\n display: flex;\n flex-direction: column;\n}\n.fields_fields > * + * {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n.fields_details {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n margin-top: 12px;\n padding-top: 12px;\n}\n.fields_detailsBody {\n padding-top: 10px;\n}\n.fields_field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px 0;\n}\n.fields_row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 0;\n}\n.fields_rowText {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding-right: 48px;\n}\n.fields_rowTitleLine {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_rowTitle {\n flex: 1;\n min-width: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_head {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_label {\n flex: 1;\n min-width: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_badges {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n.fields_reset {\n border: none;\n background: none;\n padding: 0;\n font: inherit;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n.fields_reset:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}\n.fields_reset:disabled {\n cursor: default;\n}\n.fields_inputStatic,\n.fields_inputStatic:hover {\n pointer-events: none;\n}\n.fields_inputStatic input,\n.fields_inputStatic input:hover,\n.fields_inputStatic input:focus,\n.fields_inputStatic input:focus-visible,\n.fields_inputStatic input:active {\n border-color: var(--dsw-alias-border-l4);\n background: var(--dsw-alias-bg-layer-3);\n outline: none;\n box-shadow: none;\n cursor: default;\n}\n.fields_inputInvalid input {\n border: 1px solid var(--dsw-alias-state-error-primary);\n}\n.fields_inputInvalid input:focus-visible {\n border-color: var(--dsw-alias-brand-primary);\n}\n.fields_inputWithAction {\n position: relative;\n display: flex;\n align-items: center;\n}\n.fields_inputWithAction .fields_input,\n.fields_inputWithAction .fields_inputInvalid {\n padding-right: 38px;\n}\n.fields_reveal {\n position: absolute;\n right: 4px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n padding: 0;\n border: none;\n border-radius: 50%;\n corner-shape: round;\n background: transparent;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n.fields_reveal:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n.fields_revealOn {\n color: var(--dsw-alias-label-primary);\n}\n.fields_reveal:disabled {\n cursor: default;\n opacity: 0.4;\n}\n.fields_selectorAnchor {\n flex: none;\n}\n.fields_selector {\n display: inline-flex;\n align-items: center;\n gap: 12px;\n flex: none;\n max-width: 100%;\n height: 36px;\n padding: 0 14px;\n border: none;\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-module-platform);\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n text-align: left;\n cursor: pointer;\n}\n.fields_selector:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.fields_selector:disabled {\n color: var(--dsw-alias-label-tertiary);\n cursor: default;\n}\n.fields_selectorChevron {\n flex: none;\n}\n.fields_hint {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.fields_pairNote {\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-warn-primary);\n}\n.fields_pairNote::before {\n content: \"\";\n flex: none;\n width: 5px;\n height: 5px;\n border-radius: 50%;\n corner-shape: round;\n background: currentColor;\n}\n.fields_invalid {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n.fields_actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_resultOk {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-success-primary);\n}\n.fields_resultFail {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n\n/* src/client/settings/BalanceSettingsCard.module.css */\n.BalanceSettingsCard_form {\n display: flex;\n flex-direction: column;\n}\n.BalanceSettingsCard_readOnly {\n margin: 0 0 12px;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalanceSettingsCard_footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding-top: 16px;\n}\n.BalanceSettingsCard_failed {\n flex: 1;\n min-width: 0;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n.BalanceSettingsCard_notice {\n flex: 1;\n min-width: 0;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n\n/* src/client/sidebar/BalancePopover.module.css */\n.BalancePopover_panel {\n position: fixed;\n isolation: isolate;\n z-index: 1100;\n box-sizing: border-box;\n width: max-content;\n min-width: min(300px, calc(100vw - 24px));\n max-width: min(440px, calc(100vw - 24px));\n padding: 16px;\n border: 0;\n border-radius: var(--dsw-radius-lg);\n --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);\n box-shadow: var(--dsw-elevation-prominent);\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n cursor: default;\n}\n.BalancePopover_panel::before {\n position: absolute;\n z-index: -1;\n inset: 0;\n border-radius: inherit;\n background: var(--dsw-specific-menu);\n backdrop-filter: var(--dsw-menu-backdrop-filter);\n content: \"\";\n pointer-events: none;\n}\n.BalancePopover_title {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n margin-bottom: 8px;\n color: var(--dsw-alias-label-primary);\n font-weight: 500;\n}\n.BalancePopover_titleMain {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n}\n.BalancePopover_titleLabel {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n cursor: pointer;\n color: inherit;\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n.BalancePopover_titleLabel:hover,\n.BalancePopover_titleLabel:visited {\n color: inherit;\n}\n.BalancePopover_sourceLabel {\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n font-weight: 400;\n}\n.BalancePopover_titleLabel svg {\n flex: none;\n width: 14px;\n height: auto;\n}\n.BalancePopover_iconButton {\n position: relative;\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n margin-block: -5px;\n border: none;\n border-radius: var(--dsw-radius-sm);\n padding: 0;\n background: transparent;\n cursor: pointer;\n color: var(--dsw-alias-label-secondary);\n}\n.BalancePopover_iconButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.BalancePopover_iconButton:focus-visible {\n outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color);\n outline-offset: -2px;\n}\n.BalancePopover_titleRule {\n margin-bottom: 10px;\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n.BalancePopover_details {\n display: grid;\n grid-template-columns: minmax(76px, auto) minmax(0, 1fr);\n gap: 6px 16px;\n margin: 0;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_details dt,\n.BalancePopover_details dd {\n min-width: 0;\n margin: 0;\n}\n.BalancePopover_details dd {\n color: var(--dsw-alias-label-secondary);\n font-variant-numeric: tabular-nums;\n text-align: right;\n}\n.BalancePopover_notice {\n margin-top: 12px;\n}\n.BalancePopover_noticeText {\n margin: 0 0 8px;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_noticeActions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n}\n.BalancePopover_footer {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 12px;\n}\n.BalancePopover_updated {\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_status {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: right;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_refresh {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: none;\n border-radius: var(--dsw-radius-sm);\n background: transparent;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n.BalancePopover_refresh:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n.BalancePopover_refresh:focus-visible {\n outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color);\n outline-offset: -2px;\n}\n.BalancePopover_refresh:disabled {\n opacity: 0.4;\n cursor: default;\n}\n.BalancePopover_refresh[data-cooling] {\n color: var(--dsw-alias-label-caption);\n}\n.BalancePopover_refresh[data-refreshing] svg {\n animation: BalancePopover_balance-refresh-spin 900ms linear infinite;\n}\n@keyframes BalancePopover_balance-refresh-spin {\n to {\n transform: rotate(360deg);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .BalancePopover_refresh[data-refreshing] svg {\n animation-duration: 2400ms;\n }\n}\n\n/* src/client/sidebar/PercentRing.module.css */\n.PercentRing_ring {\n display: block;\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n}\n.PercentRing_ring[data-state=done] {\n color: var(--dsw-alias-state-success-primary);\n}\n.PercentRing_ring[data-state=warning] {\n color: var(--dsw-alias-state-warn-primary);\n}\n.PercentRing_ring[data-state=error] {\n color: var(--dsw-alias-state-error-primary);\n}\n.PercentRing_ring[data-state=idle] {\n color: var(--dsw-alias-state-idle-primary);\n}\n.PercentRing_track {\n fill: none;\n stroke: var(--dsw-alias-border-l3);\n stroke-width: 1;\n}\n.PercentRing_fill {\n fill: none;\n stroke: currentColor;\n stroke-width: 1;\n stroke-linecap: round;\n}\n.PercentRing_marker {\n fill: none;\n stroke: currentColor;\n stroke-width: 1;\n stroke-linecap: round;\n}\n.PercentRing_spin {\n transform-origin: center;\n animation: PercentRing_dsb-ring-spin 1.5s linear infinite;\n}\n@keyframes PercentRing_dsb-ring-spin {\n to {\n transform: rotate(360deg);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .PercentRing_spin {\n animation: none;\n }\n}\n\n/* src/client/sidebar/SidebarBalance.module.css */\n.SidebarBalance_root {\n position: relative;\n display: flex;\n min-width: 0;\n}\n.SidebarBalance_root[data-mode=wide] {\n flex: none;\n width: calc(100% + 4px);\n margin: 4px -2px 0;\n}\n.SidebarBalance_root[data-mode=rail] {\n flex: none;\n margin: 8px 0 0;\n}\n.SidebarBalance_trigger {\n display: flex;\n align-items: center;\n box-sizing: border-box;\n border: none;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font-family: inherit;\n font-size: 14px;\n line-height: 22px;\n cursor: pointer;\n overflow: hidden;\n}\n.SidebarBalance_trigger:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.SidebarBalance_trigger:focus-visible {\n outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color);\n outline-offset: -2px;\n}\n.SidebarBalance_root[data-mode=wide] .SidebarBalance_trigger {\n flex: none;\n gap: 8px;\n width: 100%;\n height: 42px;\n padding: 0 10px 0 8px;\n border-radius: var(--dsw-radius-md);\n}\n.SidebarBalance_root[data-mode=rail] .SidebarBalance_trigger {\n flex: none;\n justify-content: center;\n width: 36px;\n height: 36px;\n padding: 0;\n border-radius: var(--dsw-radius-md);\n}\n.SidebarBalance_icon {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n}\n.SidebarBalance_label {\n flex: 0 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.SidebarBalance_marker {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n color: var(--dsw-alias-label-tertiary);\n position: relative;\n top: 1.63px;\n}\n\n/* src/client/sidebar/footer-stack.module.css */\ndiv:has(> [data-slot=\"sidebar.footer.action\"]) {\n flex-direction: column;\n}\n";
|
|
2368
2727
|
var __dsbTagId = "dsh-ds-balance/client.css";
|
|
2369
2728
|
if (typeof document !== 'undefined' && document.querySelector('style[data-plugin-css="' + __dsbTagId + '"]') === null) {
|
|
2370
2729
|
var __dsbTag = document.createElement('style');
|