dsh-ds-balance 2.1.0 → 2.1.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/lib/client.js CHANGED
@@ -56,7 +56,10 @@ var zh = {
56
56
  "popover.cooldown": "{value} \u79D2\u540E\u53EF\u518D\u6B21\u5237\u65B0",
57
57
  "popover.mismatch": "\u672A\u627E\u5230 {wanted} \u4F59\u989D\uFF0C\u5F53\u524D\u663E\u793A {shown}",
58
58
  "popover.action.useShown": "\u6539\u7528 {shown}",
59
+ // 右上角图标的两档措辞。落点由**宿主能力**决定(跨插件深链服务在不在),
60
+ // 措辞就跟着落点分档:一句含糊的话盖不住两种落点。见 BalancePopover 的 PluginsAction。
59
61
  "popover.action.openPlugins": "\u6253\u5F00\u63D2\u4EF6\u9875",
62
+ "popover.action.openPluginConfig": "\u6253\u5F00\u63D2\u4EF6\u914D\u7F6E\u9875",
60
63
  "state.unavailable": "\u8D26\u6237\u4E0D\u53EF\u7528",
61
64
  "state.stale": "\u6570\u636E\u5DF2\u8FC7\u671F",
62
65
  "state.error": "\u8BFB\u53D6\u5931\u8D25",
@@ -137,6 +140,7 @@ var en = {
137
140
  "popover.mismatch": "No {wanted} balance found; showing {shown}",
138
141
  "popover.action.useShown": "Use {shown}",
139
142
  "popover.action.openPlugins": "Open the Plugins page",
143
+ "popover.action.openPluginConfig": "Open the plugin configuration page",
140
144
  "state.unavailable": "Account unavailable",
141
145
  "state.stale": "Data is stale",
142
146
  "state.error": "Failed to load",
@@ -194,7 +198,10 @@ var en = {
194
198
  "dev.hint": "UI development only; does not affect real configuration."
195
199
  };
196
200
  function interpolate(template, params) {
197
- return template.replace(/\{(\w+)\}/g, (whole, name) => Object.prototype.hasOwnProperty.call(params, name) ? params[name] : whole);
201
+ return template.replace(
202
+ /\{(\w+)\}/g,
203
+ (whole, name) => Object.prototype.hasOwnProperty.call(params, name) ? params[name] : whole
204
+ );
198
205
  }
199
206
 
200
207
  // src/client/settings/fields.tsx
@@ -226,7 +233,6 @@ var fields_default = {
226
233
  groupNote: "fields_groupNote",
227
234
  fields: "fields_fields",
228
235
  details: "fields_details",
229
- detailsSummary: "fields_detailsSummary",
230
236
  detailsBody: "fields_detailsBody",
231
237
  field: "fields_field",
232
238
  row: "fields_row",
@@ -237,10 +243,10 @@ var fields_default = {
237
243
  label: "fields_label",
238
244
  badges: "fields_badges",
239
245
  reset: "fields_reset",
240
- input: "fields_input",
241
246
  inputStatic: "fields_inputStatic",
242
247
  inputInvalid: "fields_inputInvalid",
243
248
  inputWithAction: "fields_inputWithAction",
249
+ input: "fields_input",
244
250
  reveal: "fields_reveal",
245
251
  revealOn: "fields_revealOn",
246
252
  selectorAnchor: "fields_selectorAnchor",
@@ -250,7 +256,6 @@ var fields_default = {
250
256
  pairNote: "fields_pairNote",
251
257
  invalid: "fields_invalid",
252
258
  actions: "fields_actions",
253
- actionButton: "fields_actionButton",
254
259
  resultOk: "fields_resultOk",
255
260
  resultFail: "fields_resultFail"
256
261
  };
@@ -318,10 +323,10 @@ function FieldFrame(props) {
318
323
  }
319
324
  function TextControl(props) {
320
325
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
321
- "input",
326
+ import_dsh_client_ui_primitives.Input,
322
327
  {
323
328
  id: props.id,
324
- className: props.invalid ? fields_default.inputInvalid : fields_default.input,
329
+ className: props.invalid ? fields_default.inputInvalid : void 0,
325
330
  type: "text",
326
331
  ...props.numeric ? { inputMode: "numeric" } : {},
327
332
  ...props.invalid ? { "aria-invalid": true } : {},
@@ -336,10 +341,10 @@ function TextControl(props) {
336
341
  }
337
342
  function ReadOnlyControl(props) {
338
343
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
339
- "input",
344
+ import_dsh_client_ui_primitives.Input,
340
345
  {
341
346
  id: props.id,
342
- className: clsx_default(fields_default.input, fields_default.inputStatic),
347
+ className: fields_default.inputStatic,
343
348
  type: "text",
344
349
  value: "",
345
350
  readOnly: true
@@ -348,20 +353,20 @@ function ReadOnlyControl(props) {
348
353
  }
349
354
  function DetailsGroup(props) {
350
355
  const [open, setOpen] = (0, import_react.useState)(props.defaultOpen === true);
351
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
352
- "details",
356
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: fields_default.details, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
357
+ import_dsh_client_ui_primitives.DisclosureRow,
353
358
  {
354
- className: fields_default.details,
359
+ icon: null,
360
+ title: props.title,
355
361
  open,
356
- onToggle: (event) => {
357
- setOpen(event.currentTarget.open);
362
+ expandable: true,
363
+ expandOnRowClick: true,
364
+ onToggle: () => {
365
+ setOpen((value) => !value);
358
366
  },
359
- children: [
360
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { className: fields_default.detailsSummary, children: props.title }),
361
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: fields_default.detailsBody, children: props.children })
362
- ]
367
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: fields_default.detailsBody, children: props.children })
363
368
  }
364
- );
369
+ ) });
365
370
  }
366
371
  function SelectorControl(props) {
367
372
  const [open, setOpen] = (0, import_react.useState)(false);
@@ -407,10 +412,10 @@ function SelectorControl(props) {
407
412
  function ActionRow(props) {
408
413
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
409
414
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: fields_default.actions, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
410
- "button",
415
+ import_dsh_client_ui_primitives.Button,
411
416
  {
412
417
  type: "button",
413
- className: fields_default.actionButton,
418
+ variant: "outline",
414
419
  disabled: props.disabled,
415
420
  onClick: props.onClick,
416
421
  children: props.label
@@ -465,7 +470,13 @@ function selectField(field) {
465
470
  var AUTO_CURRENCY = "auto";
466
471
  var KNOWN_CURRENCIES = ["CNY", "USD"];
467
472
  var THRESHOLD_PAIRS = [
468
- { currency: "CNY", warn: "cnyWarn", critical: "cnyCritical", defaultWarn: 10, defaultCritical: 5 },
473
+ {
474
+ currency: "CNY",
475
+ warn: "cnyWarn",
476
+ critical: "cnyCritical",
477
+ defaultWarn: 10,
478
+ defaultCritical: 5
479
+ },
469
480
  { currency: "USD", warn: "usdWarn", critical: "usdCritical", defaultWarn: 2, defaultCritical: 1 }
470
481
  ];
471
482
  function pairNumber(state, fallback) {
@@ -508,8 +519,10 @@ var SPEC_BY_FIELD = new Map(
508
519
  var TEST_LATENCY_MS = 800;
509
520
  function probeFailure(baseUrl, apiKey, apiKeyRef) {
510
521
  const url = baseUrl.trim();
511
- if (url !== "" && !/^https?:\/\//i.test(url)) return "base URL must start with http:// or https://";
512
- if (apiKey.trim() === "" && apiKeyRef.trim() === "") return "no API key or credential reference configured";
522
+ if (url !== "" && !/^https?:\/\//i.test(url))
523
+ return "base URL must start with http:// or https://";
524
+ if (apiKey.trim() === "" && apiKeyRef.trim() === "")
525
+ return "no API key or credential reference configured";
513
526
  return null;
514
527
  }
515
528
  function isRecord(input) {
@@ -560,16 +573,72 @@ function fieldStateOf(snapshot, spec, edit) {
560
573
  const effective = snapshot.value[spec.field];
561
574
  const stored = Object.hasOwn(snapshot.user, spec.field);
562
575
  if (edit === void 0) {
563
- return isTextSpec(spec) ? { text: spec.format(effective), value: void 0, effective, stored, overridden: stored, dirty: false, invalid: false } : { text: "", value: effective, effective, stored, overridden: stored, dirty: false, invalid: false };
576
+ return isTextSpec(spec) ? {
577
+ text: spec.format(effective),
578
+ value: void 0,
579
+ effective,
580
+ stored,
581
+ overridden: stored,
582
+ dirty: false,
583
+ invalid: false
584
+ } : {
585
+ text: "",
586
+ value: effective,
587
+ effective,
588
+ stored,
589
+ overridden: stored,
590
+ dirty: false,
591
+ invalid: false
592
+ };
564
593
  }
565
594
  if (edit.kind === "clear") {
566
- return isTextSpec(spec) ? { text: "", value: void 0, effective, stored, overridden: false, dirty: stored, invalid: false } : { text: "", value: effective, effective, stored, overridden: false, dirty: stored, invalid: false };
595
+ return isTextSpec(spec) ? {
596
+ text: "",
597
+ value: void 0,
598
+ effective,
599
+ stored,
600
+ overridden: false,
601
+ dirty: stored,
602
+ invalid: false
603
+ } : {
604
+ text: "",
605
+ value: effective,
606
+ effective,
607
+ stored,
608
+ overridden: false,
609
+ dirty: stored,
610
+ invalid: false
611
+ };
567
612
  }
568
613
  if (!isTextSpec(spec)) {
569
- return edit.kind === "value" ? { text: "", value: edit.value, effective, stored, overridden: true, dirty: edit.value !== effective, invalid: false } : { text: "", value: effective, effective, stored, overridden: stored, dirty: false, invalid: false };
614
+ return edit.kind === "value" ? {
615
+ text: "",
616
+ value: edit.value,
617
+ effective,
618
+ stored,
619
+ overridden: true,
620
+ dirty: edit.value !== effective,
621
+ invalid: false
622
+ } : {
623
+ text: "",
624
+ value: effective,
625
+ effective,
626
+ stored,
627
+ overridden: stored,
628
+ dirty: false,
629
+ invalid: false
630
+ };
570
631
  }
571
632
  if (edit.kind !== "text") {
572
- return { text: "", value: void 0, effective, stored, overridden: stored, dirty: false, invalid: false };
633
+ return {
634
+ text: "",
635
+ value: void 0,
636
+ effective,
637
+ stored,
638
+ overridden: stored,
639
+ dirty: false,
640
+ invalid: false
641
+ };
573
642
  }
574
643
  const write = spec.parse(edit.text);
575
644
  const dirty = write === void 0 ? true : write.kind === "clear" ? stored : edit.text !== spec.format(effective);
@@ -614,10 +683,7 @@ function useConfigForm(form) {
614
683
  cacheRef.current = { value, user, writable, available, snapshot: snapshot2 };
615
684
  return snapshot2;
616
685
  }, [form]);
617
- const subscribe = (0, import_react2.useCallback)(
618
- (listener) => form.subscribe(listener),
619
- [form]
620
- );
686
+ const subscribe = (0, import_react2.useCallback)((listener) => form.subscribe(listener), [form]);
621
687
  const snapshot = (0, import_react2.useSyncExternalStore)(subscribe, readSnapshot);
622
688
  const [staged, setStaged] = (0, import_react2.useState)(() => /* @__PURE__ */ new Map());
623
689
  const [saving, setSaving] = (0, import_react2.useState)(false);
@@ -627,18 +693,23 @@ function useConfigForm(form) {
627
693
  const [test, setTest] = (0, import_react2.useState)({ running: false, ok: null, message: "" });
628
694
  const testTimerRef = (0, import_react2.useRef)(null);
629
695
  const testRunningRef = (0, import_react2.useRef)(false);
630
- (0, import_react2.useEffect)(() => () => {
631
- if (testTimerRef.current !== null) clearTimeout(testTimerRef.current);
632
- testTimerRef.current = null;
633
- testRunningRef.current = false;
634
- }, []);
696
+ (0, import_react2.useEffect)(
697
+ () => () => {
698
+ if (testTimerRef.current !== null) clearTimeout(testTimerRef.current);
699
+ testTimerRef.current = null;
700
+ testRunningRef.current = false;
701
+ },
702
+ []
703
+ );
635
704
  const plan = (0, import_react2.useMemo)(() => planWrites(snapshot, staged), [snapshot, staged]);
636
705
  const pairsInvalid = (0, import_react2.useMemo)(
637
- () => THRESHOLD_PAIRS.some((pair) => !thresholdsOk(
638
- pair,
639
- fieldOf(snapshot, pair.warn, staged.get(pair.warn)),
640
- fieldOf(snapshot, pair.critical, staged.get(pair.critical))
641
- )),
706
+ () => THRESHOLD_PAIRS.some(
707
+ (pair) => !thresholdsOk(
708
+ pair,
709
+ fieldOf(snapshot, pair.warn, staged.get(pair.warn)),
710
+ fieldOf(snapshot, pair.critical, staged.get(pair.critical))
711
+ )
712
+ ),
642
713
  [snapshot, staged]
643
714
  );
644
715
  const invalid = plan.some((item) => item.write === void 0) || pairsInvalid;
@@ -655,17 +726,28 @@ function useConfigForm(form) {
655
726
  testTimerRef.current = null;
656
727
  }
657
728
  testRunningRef.current = false;
658
- setTest((current) => current.running || current.ok !== null ? { running: false, ok: null, message: "" } : current);
729
+ setTest(
730
+ (current) => current.running || current.ok !== null ? { running: false, ok: null, message: "" } : current
731
+ );
659
732
  }, []);
660
- const edit = (0, import_react2.useCallback)((field2, text) => {
661
- stage(field2, { kind: "text", text });
662
- }, [stage]);
663
- const setValue = (0, import_react2.useCallback)((field2, value) => {
664
- stage(field2, { kind: "value", value });
665
- }, [stage]);
666
- const resetField = (0, import_react2.useCallback)((field2) => {
667
- stage(field2, { kind: "clear" });
668
- }, [stage]);
733
+ const edit = (0, import_react2.useCallback)(
734
+ (field2, text) => {
735
+ stage(field2, { kind: "text", text });
736
+ },
737
+ [stage]
738
+ );
739
+ const setValue = (0, import_react2.useCallback)(
740
+ (field2, value) => {
741
+ stage(field2, { kind: "value", value });
742
+ },
743
+ [stage]
744
+ );
745
+ const resetField = (0, import_react2.useCallback)(
746
+ (field2) => {
747
+ stage(field2, { kind: "clear" });
748
+ },
749
+ [stage]
750
+ );
669
751
  const discard = (0, import_react2.useCallback)(() => {
670
752
  setStaged((current) => current.size === 0 ? current : /* @__PURE__ */ new Map());
671
753
  setFailed(false);
@@ -674,7 +756,9 @@ function useConfigForm(form) {
674
756
  testTimerRef.current = null;
675
757
  }
676
758
  testRunningRef.current = false;
677
- setTest((current) => current.running || current.ok !== null ? { running: false, ok: null, message: "" } : current);
759
+ setTest(
760
+ (current) => current.running || current.ok !== null ? { running: false, ok: null, message: "" } : current
761
+ );
678
762
  }, []);
679
763
  const save = (0, import_react2.useCallback)(async () => {
680
764
  if (savingRef.current) return;
@@ -688,9 +772,11 @@ function useConfigForm(form) {
688
772
  for (const item of writes) {
689
773
  const write = item.write;
690
774
  if (write === void 0) continue;
691
- ops.push(write.kind === "clear" ? { op: "unset", path: [item.field] } : { op: "set", path: [item.field], value: write.value });
775
+ ops.push(
776
+ write.kind === "clear" ? { op: "unset", path: [item.field] } : { op: "set", path: [item.field], value: write.value }
777
+ );
692
778
  }
693
- let landed = false;
779
+ let landed;
694
780
  try {
695
781
  landed = await form.mutate(ops, form.getSnapshot().revision);
696
782
  } catch {
@@ -716,7 +802,9 @@ function useConfigForm(form) {
716
802
  testTimerRef.current = setTimeout(() => {
717
803
  testTimerRef.current = null;
718
804
  testRunningRef.current = false;
719
- setTest(failure === null ? { running: false, ok: true, message: "" } : { running: false, ok: false, message: failure });
805
+ setTest(
806
+ failure === null ? { running: false, ok: true, message: "" } : { running: false, ok: false, message: failure }
807
+ );
720
808
  }, TEST_LATENCY_MS);
721
809
  }, [readSnapshot, staged]);
722
810
  const field = (0, import_react2.useCallback)(
@@ -867,8 +955,7 @@ var BalanceSettingsCard_default = {
867
955
  readOnly: "BalanceSettingsCard_readOnly",
868
956
  footer: "BalanceSettingsCard_footer",
869
957
  failed: "BalanceSettingsCard_failed",
870
- notice: "BalanceSettingsCard_notice",
871
- save: "BalanceSettingsCard_save"
958
+ notice: "BalanceSettingsCard_notice"
872
959
  };
873
960
 
874
961
  // src/client/settings/BalanceSettingsCard.tsx
@@ -918,7 +1005,8 @@ function BalanceSettingsCard({ t, form: scopedForm }) {
918
1005
  const toggleGroup = (key) => {
919
1006
  setGroupOpen((current) => ({ ...current, [key]: !current[key] }));
920
1007
  };
921
- const groupOpenNow = (key) => groupOpen[key] || GROUP_FIELDS[key].some((name) => form.field(name).invalid) || key === "thresholds" && THRESHOLD_PAIRS.some((pair) => !form.thresholdPairOk(pair.currency));
1008
+ const groupOpenNow = (key) => groupOpen[key] || GROUP_FIELDS[key].some((name) => form.field(name).invalid) || // 成对校验不是字段级 invalid,得单独问一次:否则收起的阈值组会挡住「保存为什么是灰的」。
1009
+ key === "thresholds" && THRESHOLD_PAIRS.some((pair) => !form.thresholdPairOk(pair.currency));
922
1010
  const { available, writable, dirty, invalid, saving, failed } = form.state;
923
1011
  const disabled = !writable || saving;
924
1012
  const credentialStatus = (name) => {
@@ -1075,7 +1163,10 @@ function BalanceSettingsCard({ t, form: scopedForm }) {
1075
1163
  {
1076
1164
  id: FIELD_IDS.apiKeyState ?? "apiKeyState",
1077
1165
  label: t("settings.field.apiKey"),
1078
- status: { label: t(CREDENTIAL_BADGE[credentialView]), tone: credentialView === "notConfigured" ? "quiet" : "neutral" },
1166
+ status: {
1167
+ label: t(CREDENTIAL_BADGE[credentialView]),
1168
+ tone: credentialView === "notConfigured" ? "quiet" : "neutral"
1169
+ },
1079
1170
  pending: false,
1080
1171
  resettable: false,
1081
1172
  pendingLabel: t("settings.unsaved"),
@@ -1085,12 +1176,7 @@ function BalanceSettingsCard({ t, form: scopedForm }) {
1085
1176
  disabled: true,
1086
1177
  onReset: () => {
1087
1178
  },
1088
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1089
- ReadOnlyControl,
1090
- {
1091
- id: FIELD_IDS.apiKeyState ?? "apiKeyState"
1092
- }
1093
- )
1179
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ReadOnlyControl, { id: FIELD_IDS.apiKeyState ?? "apiKeyState" })
1094
1180
  }
1095
1181
  ),
1096
1182
  textRow("baseUrl", "settings.field.baseUrl", "settings.hint.baseUrl", false),
@@ -1149,19 +1235,31 @@ function BalanceSettingsCard({ t, form: scopedForm }) {
1149
1235
  },
1150
1236
  last: true,
1151
1237
  children: [
1152
- numberRow("serverRefreshSeconds", "settings.field.serverRefreshSeconds", "settings.hint.serverRefreshSeconds"),
1153
- numberRow("clientPollSeconds", "settings.field.clientPollSeconds", "settings.hint.clientPollSeconds"),
1154
- numberRow("manualRefreshCooldownSeconds", "settings.field.manualRefreshCooldownSeconds", "settings.hint.manualRefreshCooldownSeconds")
1238
+ numberRow(
1239
+ "serverRefreshSeconds",
1240
+ "settings.field.serverRefreshSeconds",
1241
+ "settings.hint.serverRefreshSeconds"
1242
+ ),
1243
+ numberRow(
1244
+ "clientPollSeconds",
1245
+ "settings.field.clientPollSeconds",
1246
+ "settings.hint.clientPollSeconds"
1247
+ ),
1248
+ numberRow(
1249
+ "manualRefreshCooldownSeconds",
1250
+ "settings.field.manualRefreshCooldownSeconds",
1251
+ "settings.hint.manualRefreshCooldownSeconds"
1252
+ )
1155
1253
  ]
1156
1254
  }
1157
1255
  ),
1158
1256
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: BalanceSettingsCard_default.footer, children: [
1159
1257
  footerNote === null ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: footerNote.className, role: "status", children: footerNote.text }),
1160
1258
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1161
- "button",
1259
+ import_dsh_client_ui_primitives2.Button,
1162
1260
  {
1163
1261
  type: "button",
1164
- className: BalanceSettingsCard_default.save,
1262
+ variant: "primary",
1165
1263
  disabled: !dirty || invalid || saving || !writable,
1166
1264
  onClick: () => {
1167
1265
  void form.save();
@@ -1311,9 +1409,17 @@ var scenarios = {
1311
1409
  /** 正常。 */
1312
1410
  ok: make({}),
1313
1411
  /** 余额偏低但可用。 */
1314
- warn: make({ severity: "warn", balances: [cny("8.00000000", "0.00000000", "8.00000000")], selected: { currency: "CNY", total: "8.00000000" } }),
1412
+ warn: make({
1413
+ severity: "warn",
1414
+ balances: [cny("8.00000000", "0.00000000", "8.00000000")],
1415
+ selected: { currency: "CNY", total: "8.00000000" }
1416
+ }),
1315
1417
  /** 余额告急。 */
1316
- critical: make({ severity: "critical", balances: [cny("3.00000000", "0.00000000", "3.00000000")], selected: { currency: "CNY", total: "3.00000000" } }),
1418
+ critical: make({
1419
+ severity: "critical",
1420
+ balances: [cny("3.00000000", "0.00000000", "3.00000000")],
1421
+ selected: { currency: "CNY", total: "3.00000000" }
1422
+ }),
1317
1423
  /** 账户不可用(余额耗尽 / 欠费)。 */
1318
1424
  unavailable: make({
1319
1425
  severity: "unavailable",
@@ -1322,7 +1428,14 @@ var scenarios = {
1322
1428
  selected: { currency: "CNY", total: "0.00000000" }
1323
1429
  }),
1324
1430
  /** 有旧值但本次刷新失败。 */
1325
- stale: make({ state: "stale", stale: true, severity: "unknown", ageMs: 36e5, fetchedAt: T0 - 36e5, error: { code: "NO_NETWORK", message: "fetch failed" } }),
1431
+ stale: make({
1432
+ state: "stale",
1433
+ stale: true,
1434
+ severity: "unknown",
1435
+ ageMs: 36e5,
1436
+ fetchedAt: T0 - 36e5,
1437
+ error: { code: "NO_NETWORK", message: "fetch failed" }
1438
+ }),
1326
1439
  /** 无值失败。 */
1327
1440
  error: make({
1328
1441
  state: "error",
@@ -1335,14 +1448,35 @@ var scenarios = {
1335
1448
  error: { code: "UPSTREAM_5XX", message: "upstream returned 500" }
1336
1449
  }),
1337
1450
  /** 未配置。 */
1338
- empty: make({ state: "empty", severity: "unknown", isAvailable: false, balances: [], selected: null, ageMs: 0 }),
1451
+ empty: make({
1452
+ state: "empty",
1453
+ severity: "unknown",
1454
+ isAvailable: false,
1455
+ balances: [],
1456
+ selected: null,
1457
+ ageMs: 0
1458
+ }),
1339
1459
  /** 未配置且带 NO_KEY 错误。 */
1340
- noKey: make({ state: "empty", severity: "unknown", isAvailable: false, balances: [], selected: null, ageMs: 0, error: { code: "NO_KEY", message: "no API key configured" } }),
1460
+ noKey: make({
1461
+ state: "empty",
1462
+ severity: "unknown",
1463
+ isAvailable: false,
1464
+ balances: [],
1465
+ selected: null,
1466
+ ageMs: 0,
1467
+ error: { code: "NO_KEY", message: "no API key configured" }
1468
+ }),
1341
1469
  /** 多币种。`selected` 显式写出,不靠 `make()` 的默认值兜。 */
1342
1470
  multiCurrency: make({
1343
- balances: [cny("110.00000000", "10.00000000", "100.00000000"), { currency: "USD", total: "20.00000000", granted: "0.00000000", toppedUp: "20.00000000" }],
1471
+ balances: [
1472
+ cny("110.00000000", "10.00000000", "100.00000000"),
1473
+ { currency: "USD", total: "20.00000000", granted: "0.00000000", toppedUp: "20.00000000" }
1474
+ ],
1344
1475
  selected: { currency: "CNY", total: "110.00000000" },
1345
- thresholds: { CNY: { warn: "10.00000000", critical: "5.00000000" }, USD: { warn: "2.00000000", critical: "1.00000000" } }
1476
+ thresholds: {
1477
+ CNY: { warn: "10.00000000", critical: "5.00000000" },
1478
+ USD: { warn: "2.00000000", critical: "1.00000000" }
1479
+ }
1346
1480
  }),
1347
1481
  /**
1348
1482
  * 选定了账户里没有的币种(USD),账户只有 CNY。
@@ -1544,7 +1678,7 @@ function BalancePopover(props) {
1544
1678
  onRefresh,
1545
1679
  onUseShown,
1546
1680
  useShownDisabled,
1547
- onOpenPlugins
1681
+ pluginsAction
1548
1682
  } = props;
1549
1683
  const shown = selection.shown;
1550
1684
  const totalText = shown === null ? BALANCE_PLACEHOLDER : formatMoney(shown.total, shown.currency);
@@ -1557,8 +1691,12 @@ function BalancePopover(props) {
1557
1691
  const cooling = cooldownSeconds > 0;
1558
1692
  let statusText = "";
1559
1693
  if (refreshing) statusText = t("popover.refreshing");
1560
- else if (cooling) statusText = interpolate(t("popover.cooldown"), { value: String(cooldownSeconds) });
1694
+ else if (cooling)
1695
+ statusText = interpolate(t("popover.cooldown"), { value: String(cooldownSeconds) });
1561
1696
  const refreshLabel = t("sidebar.aria.refresh");
1697
+ const pluginsLabel = t(
1698
+ pluginsAction?.reachesConfig === true ? "popover.action.openPluginConfig" : "popover.action.openPlugins"
1699
+ );
1562
1700
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1563
1701
  "section",
1564
1702
  {
@@ -1582,13 +1720,13 @@ function BalancePopover(props) {
1582
1720
  ]
1583
1721
  }
1584
1722
  ),
1585
- onOpenPlugins === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.Tooltip, { label: t("popover.action.openPlugins"), side: "top", delayMs: 500, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1723
+ 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)(
1586
1724
  "button",
1587
1725
  {
1588
1726
  type: "button",
1589
1727
  className: BalancePopover_default.iconButton,
1590
- "aria-label": t("popover.action.openPlugins"),
1591
- onClick: onOpenPlugins,
1728
+ "aria-label": pluginsLabel,
1729
+ onClick: pluginsAction.open,
1592
1730
  children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.IconPluginPinwheelOutlineRegular, { size: 16 })
1593
1731
  }
1594
1732
  ) })
@@ -1604,7 +1742,16 @@ function BalancePopover(props) {
1604
1742
  ] }),
1605
1743
  shown !== null && !selection.matchesPreference ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: BalancePopover_default.notice, children: [
1606
1744
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: BalancePopover_default.noticeText, children: interpolate(t("popover.mismatch"), { wanted: displayCurrency, shown: shown.currency }) }),
1607
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: BalancePopover_default.noticeActions, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.Button, { size: "sm", variant: "outline", disabled: useShownDisabled === true, onClick: onUseShown, children: interpolate(t("popover.action.useShown"), { shown: shown.currency }) }) })
1745
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: BalancePopover_default.noticeActions, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1746
+ import_dsh_client_ui_primitives3.Button,
1747
+ {
1748
+ size: "sm",
1749
+ variant: "outline",
1750
+ disabled: useShownDisabled === true,
1751
+ onClick: onUseShown,
1752
+ children: interpolate(t("popover.action.useShown"), { shown: shown.currency })
1753
+ }
1754
+ ) })
1608
1755
  ] }) : null,
1609
1756
  configSlotWarning === null ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: BalancePopover_default.notice, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: BalancePopover_default.noticeText, children: configSlotWarning }) }),
1610
1757
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: BalancePopover_default.footer, children: [
@@ -1649,7 +1796,13 @@ var CROSS_ARM = (2 * RADIUS - STROKE) / 2 / Math.SQRT2;
1649
1796
  function round3(value) {
1650
1797
  return Math.round(value * 1e3) / 1e3;
1651
1798
  }
1652
- function PercentRing({ state, marker = null, ratio = 1, size = 18, title }) {
1799
+ function PercentRing({
1800
+ state,
1801
+ marker = null,
1802
+ ratio = 1,
1803
+ size = 18,
1804
+ title
1805
+ }) {
1653
1806
  const clamped = Number.isFinite(ratio) ? Math.min(1, Math.max(0, ratio)) : 1;
1654
1807
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1655
1808
  "svg",
@@ -1728,22 +1881,24 @@ function useConfigSlotState(probe) {
1728
1881
  return state;
1729
1882
  }
1730
1883
  function usePluginsNavigation(navigation) {
1731
- const [openPlugins, setOpenPlugins] = (0, import_react5.useState)(() => navigation?.getSnapshot());
1884
+ const [action, setAction] = (0, import_react5.useState)(() => navigation?.getSnapshot());
1732
1885
  (0, import_react5.useEffect)(() => {
1733
1886
  if (navigation === void 0) {
1734
- setOpenPlugins(void 0);
1887
+ setAction(void 0);
1735
1888
  return;
1736
1889
  }
1737
- setOpenPlugins(() => navigation.getSnapshot());
1890
+ setAction(navigation.getSnapshot());
1738
1891
  return navigation.subscribe(() => {
1739
- setOpenPlugins(() => navigation.getSnapshot());
1892
+ setAction(navigation.getSnapshot());
1740
1893
  });
1741
1894
  }, [navigation]);
1742
- return openPlugins;
1895
+ return action;
1743
1896
  }
1744
1897
  function stateLabelKey(response, selection) {
1745
- if (response.state === "error") return response.error?.code === "NO_KEY" ? "state.noKey" : "state.error";
1746
- if (response.state === "empty") return response.error?.code === "NO_KEY" ? "state.noKey" : "state.empty";
1898
+ if (response.state === "error")
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";
1747
1902
  if (response.state === "stale") return "state.stale";
1748
1903
  if (!response.isAvailable) return "state.unavailable";
1749
1904
  if (selection.shown === null) return "state.noBalance";
@@ -1788,16 +1943,19 @@ function SidebarBalance({
1788
1943
  }, []);
1789
1944
  const preference = config.displayCurrency;
1790
1945
  const selection = (0, import_react5.useMemo)(() => selectionOf(response, preference), [response, preference]);
1791
- (0, import_react5.useEffect)(() => subscribeScenario((key) => {
1792
- const active = resolveScenario() !== null;
1793
- setMock(active);
1794
- if (!active || lastScenario.current === key) return;
1795
- lastScenario.current = key;
1796
- acceptBalance(currentBalance());
1797
- setRefreshing(false);
1798
- setCooldownUntil(0);
1799
- setOpen(false);
1800
- }), [acceptBalance]);
1946
+ (0, import_react5.useEffect)(
1947
+ () => subscribeScenario((key) => {
1948
+ const active = resolveScenario() !== null;
1949
+ setMock(active);
1950
+ if (!active || lastScenario.current === key) return;
1951
+ lastScenario.current = key;
1952
+ acceptBalance(currentBalance());
1953
+ setRefreshing(false);
1954
+ setCooldownUntil(0);
1955
+ setOpen(false);
1956
+ }),
1957
+ [acceptBalance]
1958
+ );
1801
1959
  (0, import_react5.useEffect)(() => {
1802
1960
  if (mock) return;
1803
1961
  let cancelled = false;
@@ -1813,17 +1971,30 @@ function SidebarBalance({
1813
1971
  }
1814
1972
  };
1815
1973
  void load();
1816
- const id = window.setInterval(() => {
1817
- void load();
1818
- }, Math.max(5, config.clientPollSeconds) * MS_PER_SECOND);
1974
+ const id = window.setInterval(
1975
+ () => {
1976
+ void load();
1977
+ },
1978
+ Math.max(5, config.clientPollSeconds) * MS_PER_SECOND
1979
+ );
1819
1980
  return () => {
1820
1981
  cancelled = true;
1821
1982
  window.clearInterval(id);
1822
1983
  };
1823
- }, [mock, preference, config.clientPollSeconds, config.configSignature, acceptBalance, showUnreachable]);
1824
- (0, import_react5.useEffect)(() => () => {
1825
- if (refreshTimer.current !== void 0) window.clearTimeout(refreshTimer.current);
1826
- }, []);
1984
+ }, [
1985
+ mock,
1986
+ preference,
1987
+ config.clientPollSeconds,
1988
+ config.configSignature,
1989
+ acceptBalance,
1990
+ showUnreachable
1991
+ ]);
1992
+ (0, import_react5.useEffect)(
1993
+ () => () => {
1994
+ if (refreshTimer.current !== void 0) window.clearTimeout(refreshTimer.current);
1995
+ },
1996
+ []
1997
+ );
1827
1998
  const closeNow = (0, import_react5.useCallback)(() => {
1828
1999
  setOpen(false);
1829
2000
  }, []);
@@ -1865,7 +2036,9 @@ function SidebarBalance({
1865
2036
  setRefreshing(true);
1866
2037
  const finish = () => {
1867
2038
  setRefreshing(false);
1868
- setCooldownUntil(Date.now() + Math.max(0, config.manualRefreshCooldownSeconds) * MS_PER_SECOND);
2039
+ setCooldownUntil(
2040
+ Date.now() + Math.max(0, config.manualRefreshCooldownSeconds) * MS_PER_SECOND
2041
+ );
1869
2042
  };
1870
2043
  if (mock) {
1871
2044
  refreshTimer.current = window.setTimeout(() => {
@@ -1887,17 +2060,32 @@ function SidebarBalance({
1887
2060
  finish();
1888
2061
  }
1889
2062
  })();
1890
- }, [cooldownUntil, config.manualRefreshCooldownSeconds, mock, preference, refreshing, acceptBalance, showUnreachable, markFresh]);
2063
+ }, [
2064
+ cooldownUntil,
2065
+ config.manualRefreshCooldownSeconds,
2066
+ mock,
2067
+ preference,
2068
+ refreshing,
2069
+ acceptBalance,
2070
+ showUnreachable,
2071
+ markFresh
2072
+ ]);
1891
2073
  const handleUseShown = (0, import_react5.useCallback)(() => {
1892
2074
  const current = selection.shown;
1893
2075
  if (current === null) return;
1894
2076
  void onSelectCurrency(current.currency);
1895
2077
  }, [selection, onSelectCurrency]);
1896
- const openPlugins = usePluginsNavigation(pluginsNavigation);
1897
- const handleOpenPlugins = (0, import_react5.useCallback)(() => {
1898
- closeNow();
1899
- openPlugins?.();
1900
- }, [closeNow, openPlugins]);
2078
+ const pluginsAction = usePluginsNavigation(pluginsNavigation);
2079
+ const popoverPluginsAction = (0, import_react5.useMemo)(
2080
+ () => pluginsAction === void 0 ? void 0 : {
2081
+ reachesConfig: pluginsAction.reachesConfig,
2082
+ open: () => {
2083
+ closeNow();
2084
+ pluginsAction.open();
2085
+ }
2086
+ },
2087
+ [closeNow, pluginsAction]
2088
+ );
1901
2089
  const configSlotState = useConfigSlotState(configSlotProbe);
1902
2090
  const shown = selection.shown;
1903
2091
  const ring = ringSpecFor(response.severity);
@@ -1938,42 +2126,42 @@ function SidebarBalance({
1938
2126
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: SidebarBalance_default.icon, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PercentRing, { state: ring.state, marker: ring.marker, ratio: ringRatio, size: 16 }) }),
1939
2127
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: SidebarBalance_default.label, children: t("sidebar.label") }),
1940
2128
  markerLabel === null ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.Tooltip, { label: markerHint, side: "bottom", delayMs: 500, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: SidebarBalance_default.marker, role: "img", "aria-label": markerLabel, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.IconWarningOutlineRegular, { size: 12 }) }) })
1941
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PercentRing, { state: ring.state, marker: ring.marker, ratio: ringRatio, size: 18, title: ringTitle })
1942
- }
1943
- );
1944
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1945
- "div",
1946
- {
1947
- ref: rootRef,
1948
- className: SidebarBalance_default.root,
1949
- "data-mode": wide ? "wide" : "rail",
1950
- tabIndex: -1,
1951
- children: [
1952
- wide && hoverLabel !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.Tooltip, { label: hoverLabel, side: "right", delayMs: 500, disabled: open, children: trigger }) : trigger,
1953
- open ? (0, import_react_dom.createPortal)(
1954
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1955
- BalancePopover,
1956
- {
1957
- t,
1958
- selection,
1959
- displayCurrency: preference,
1960
- ageMs,
1961
- refreshing,
1962
- cooldownSeconds,
1963
- configSlotWarning: configSlotState === "missing" ? CONFIG_SLOT_WARNING : null,
1964
- panelRef,
1965
- style: pos ?? MEASURE_STYLE,
1966
- onRefresh: handleRefresh,
1967
- onUseShown: handleUseShown,
1968
- useShownDisabled: !config.writable,
1969
- onOpenPlugins: openPlugins === void 0 ? void 0 : handleOpenPlugins
1970
- }
1971
- ),
1972
- document.body
1973
- ) : null
1974
- ]
2129
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2130
+ PercentRing,
2131
+ {
2132
+ state: ring.state,
2133
+ marker: ring.marker,
2134
+ ratio: ringRatio,
2135
+ size: 18,
2136
+ title: ringTitle
2137
+ }
2138
+ )
1975
2139
  }
1976
2140
  );
2141
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: rootRef, className: SidebarBalance_default.root, "data-mode": wide ? "wide" : "rail", tabIndex: -1, children: [
2142
+ wide && hoverLabel !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.Tooltip, { label: hoverLabel, side: "right", delayMs: 500, disabled: open, children: trigger }) : trigger,
2143
+ open ? (0, import_react_dom.createPortal)(
2144
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2145
+ BalancePopover,
2146
+ {
2147
+ t,
2148
+ selection,
2149
+ displayCurrency: preference,
2150
+ ageMs,
2151
+ refreshing,
2152
+ cooldownSeconds,
2153
+ configSlotWarning: configSlotState === "missing" ? CONFIG_SLOT_WARNING : null,
2154
+ panelRef,
2155
+ style: pos ?? MEASURE_STYLE,
2156
+ onRefresh: handleRefresh,
2157
+ onUseShown: handleUseShown,
2158
+ useShownDisabled: !config.writable,
2159
+ pluginsAction: popoverPluginsAction
2160
+ }
2161
+ ),
2162
+ document.body
2163
+ ) : null
2164
+ ] });
1977
2165
  }
1978
2166
 
1979
2167
  // src/client/index.tsx
@@ -2063,25 +2251,59 @@ function SettingsSeatComponent(props) {
2063
2251
  }
2064
2252
  var PLUGINS_PANEL_ID = "plugins";
2065
2253
  function createPluginsNavigation() {
2066
- let open;
2254
+ let selectPanel;
2255
+ let openBundle;
2256
+ let snapshot;
2067
2257
  const listeners2 = /* @__PURE__ */ new Set();
2068
- const publish = (next) => {
2069
- if (next === open) return;
2070
- open = next;
2258
+ const open = () => {
2259
+ if (openBundle !== void 0) {
2260
+ try {
2261
+ openBundle(BUNDLE_CONFIG_KEY);
2262
+ return;
2263
+ } catch (error) {
2264
+ console.warn("[WARN] ds-balance: cannot open the bundle config page", error);
2265
+ }
2266
+ }
2267
+ try {
2268
+ selectPanel?.();
2269
+ } catch (error) {
2270
+ console.warn("[WARN] ds-balance: cannot switch to the plugins panel", error);
2271
+ }
2272
+ };
2273
+ const publish = () => {
2274
+ const reachesConfig = openBundle !== void 0;
2275
+ const next = selectPanel === void 0 ? void 0 : { open, reachesConfig };
2276
+ const unchanged = next === void 0 ? snapshot === void 0 : snapshot !== void 0 && snapshot.reachesConfig === reachesConfig;
2277
+ if (unchanged) return;
2278
+ snapshot = next;
2071
2279
  for (const listener of [...listeners2]) listener();
2072
2280
  };
2073
2281
  return {
2074
- getSnapshot: () => open,
2282
+ getSnapshot: () => snapshot,
2075
2283
  subscribe: (listener) => {
2076
2284
  listeners2.add(listener);
2077
2285
  return () => {
2078
2286
  listeners2.delete(listener);
2079
2287
  };
2080
2288
  },
2081
- attach: (callback) => {
2082
- publish(callback);
2289
+ attachPanel: (callback) => {
2290
+ selectPanel = callback;
2291
+ publish();
2083
2292
  return () => {
2084
- if (open === callback) publish(void 0);
2293
+ if (selectPanel === callback) {
2294
+ selectPanel = void 0;
2295
+ publish();
2296
+ }
2297
+ };
2298
+ },
2299
+ attachDeepLink: (callback) => {
2300
+ openBundle = callback;
2301
+ publish();
2302
+ return () => {
2303
+ if (openBundle === callback) {
2304
+ openBundle = void 0;
2305
+ publish();
2306
+ }
2085
2307
  };
2086
2308
  }
2087
2309
  };
@@ -2091,21 +2313,16 @@ function apply(ctx) {
2091
2313
  const configSlotProbe = createConfigSlotProbe();
2092
2314
  ctx.effect(() => () => configSlotProbe.dispose(), "ds-balance: config slot probe");
2093
2315
  const pluginsNavigation = createPluginsNavigation();
2094
- let openBundlePanel;
2095
2316
  ctx.inject(["pluginNavigation"], (navCtx) => {
2096
2317
  const face = navCtx["pluginNavigation"];
2097
2318
  if (typeof face !== "object" || face === null) return;
2098
2319
  const candidate = face["openBundle"];
2099
2320
  if (typeof candidate !== "function") return;
2100
2321
  const openBundle = candidate.bind(face);
2101
- navCtx.effect(() => {
2102
- openBundlePanel = (packageName) => {
2103
- openBundle(packageName);
2104
- };
2105
- return () => {
2106
- openBundlePanel = void 0;
2107
- };
2108
- }, "ds-balance: bundle config deep link");
2322
+ navCtx.effect(
2323
+ () => pluginsNavigation.attachDeepLink(openBundle),
2324
+ "ds-balance: bundle config deep link"
2325
+ );
2109
2326
  });
2110
2327
  ctx.inject(["layout"], (layoutCtx) => {
2111
2328
  if (!("layout" in layoutCtx)) return;
@@ -2113,44 +2330,41 @@ function apply(ctx) {
2113
2330
  if (typeof face !== "object" || face === null) return;
2114
2331
  if (!("selectPanel" in face) || typeof face.selectPanel !== "function") return;
2115
2332
  const selectPanel = face.selectPanel.bind(face);
2116
- layoutCtx.effect(() => pluginsNavigation.attach(() => {
2117
- if (openBundlePanel !== void 0) {
2118
- try {
2119
- openBundlePanel(BUNDLE_CONFIG_KEY);
2120
- return;
2121
- } catch (error) {
2122
- console.warn("[WARN] ds-balance: cannot open the bundle config page", error);
2123
- }
2124
- }
2125
- try {
2333
+ layoutCtx.effect(
2334
+ () => pluginsNavigation.attachPanel(() => {
2126
2335
  selectPanel(PLUGINS_PANEL_ID);
2127
- } catch (error) {
2128
- console.warn("[WARN] ds-balance: cannot switch to the plugins panel", error);
2129
- }
2130
- }), "ds-balance: plugins panel navigation");
2336
+ }),
2337
+ "ds-balance: plugins panel navigation"
2338
+ );
2131
2339
  });
2132
2340
  ctx.inject(["configForms"], (configCtx) => {
2133
2341
  configSlotProbe.markDeclared();
2134
2342
  const form = configCtx.configForms.get(ENTRY_ID);
2135
- ctx.slots.inject(CONFIG_SLOT, () => ctx.slots.register(
2136
- { name: CONFIG_SLOT, key: BUNDLE_CONFIG_KEY, locale: NS },
2137
- (seat) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SettingsSeatComponent, { seat, form })
2138
- ));
2139
- ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register(
2140
- { name: "sidebar.footer.action", id: SIDEBAR_ENTRY_ID, order: 0, locale: NS },
2141
- (seat) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2142
- SidebarSeatComponent,
2143
- {
2144
- seat,
2145
- form,
2146
- configSlotProbe,
2147
- pluginsNavigation
2148
- }
2343
+ ctx.slots.inject(
2344
+ CONFIG_SLOT,
2345
+ () => ctx.slots.register(
2346
+ { name: CONFIG_SLOT, key: BUNDLE_CONFIG_KEY, locale: NS },
2347
+ (seat) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SettingsSeatComponent, { seat, form })
2149
2348
  )
2150
- ));
2349
+ );
2350
+ ctx.slots.inject(
2351
+ "sidebar.footer.action",
2352
+ () => ctx.slots.register(
2353
+ { name: "sidebar.footer.action", id: SIDEBAR_ENTRY_ID, order: 0, locale: NS },
2354
+ (seat) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2355
+ SidebarSeatComponent,
2356
+ {
2357
+ seat,
2358
+ form,
2359
+ configSlotProbe,
2360
+ pluginsNavigation
2361
+ }
2362
+ )
2363
+ )
2364
+ );
2151
2365
  });
2152
2366
  }
2153
- 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_detailsSummary {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 500;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n list-style: none;\n}\n.fields_detailsSummary::-webkit-details-marker {\n display: none;\n}\n.fields_detailsSummary::before {\n content: \"\";\n flex: none;\n width: 5px;\n height: 5px;\n border-right: 1.5px solid currentColor;\n border-bottom: 1.5px solid currentColor;\n transform: translate(-0.5px, -1px) rotate(-45deg);\n transition: transform 120ms ease;\n}\n.fields_details[open] > .fields_detailsSummary::before {\n transform: translate(-0.5px, -1px) rotate(45deg);\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_input {\n box-sizing: border-box;\n width: 100%;\n height: 34px;\n padding: 0 12px;\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-3);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_input:focus-visible {\n outline: none;\n border-color: var(--dsw-alias-brand-primary);\n}\n.fields_input:disabled {\n color: var(--dsw-alias-label-tertiary);\n opacity: 0.6;\n cursor: default;\n}\ninput.fields_inputStatic,\ninput.fields_inputStatic:hover,\ninput.fields_inputStatic:focus,\ninput.fields_inputStatic:focus-visible,\ninput.fields_inputStatic: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 pointer-events: none;\n}\n.fields_inputInvalid {\n box-sizing: border-box;\n width: 100%;\n height: 34px;\n padding: 0 12px;\n border: 1px solid var(--dsw-alias-state-error-primary);\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-3);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_inputInvalid:focus-visible {\n outline: none;\n border-color: var(--dsw-alias-brand-primary);\n}\n.fields_inputInvalid:disabled {\n color: var(--dsw-alias-label-tertiary);\n cursor: default;\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_actionButton {\n appearance: none;\n border: 0.5px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 5px 14px;\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n cursor: pointer;\n background: none;\n color: var(--dsw-alias-label-secondary);\n}\n.fields_actionButton:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n border-color: var(--dsw-alias-label-dimmed);\n}\n.fields_actionButton:disabled {\n opacity: 0.4;\n cursor: default;\n}\n.fields_actionButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\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.BalanceSettingsCard_save {\n appearance: none;\n border: 0.5px solid transparent;\n border-radius: 8px;\n padding: 5px 14px;\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n cursor: pointer;\n background: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-bg-layer-3);\n}\n.BalanceSettingsCard_save:disabled {\n opacity: 0.4;\n cursor: default;\n}\n.BalanceSettingsCard_save:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\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";
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";
2154
2368
  var __dsbTagId = "dsh-ds-balance/client.css";
2155
2369
  if (typeof document !== 'undefined' && document.querySelector('style[data-plugin-css="' + __dsbTagId + '"]') === null) {
2156
2370
  var __dsbTag = document.createElement('style');