@jxgame2020/dsh-token-quota 0.1.31 → 0.1.33

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
@@ -37,6 +37,9 @@ window.__ModuleLoader__.load({
37
37
  onFull: "stop",
38
38
  checkUpdates: true,
39
39
  dimWhenIdle: false,
40
+ order: [],
41
+ notes: [],
42
+ notesLoaded: false,
40
43
  musicEnabled: false,
41
44
  musicVolume: .5,
42
45
  musicStyle: "pentatonic",
@@ -82,6 +85,13 @@ window.__ModuleLoader__.load({
82
85
  setDimWhenIdle: (d, dimWhenIdle) => {
83
86
  d.dimWhenIdle = dimWhenIdle;
84
87
  },
88
+ setOrder: (d, order) => {
89
+ d.order = order;
90
+ },
91
+ setNotes: (d, notes) => {
92
+ d.notes = notes;
93
+ d.notesLoaded = true;
94
+ },
85
95
  setMusicEnabled: (d, enabled) => {
86
96
  d.musicEnabled = enabled;
87
97
  },
@@ -95,7 +105,7 @@ window.__ModuleLoader__.load({
95
105
  d.musicOnlyCurrentSession = only;
96
106
  },
97
107
  setUpgrade: (d, upgrade) => {
98
- const normalized = upgrade !== null && upgrade.latestVersion !== "" && upgrade.latestVersion !== "0.1.31" ? upgrade : null;
108
+ const normalized = upgrade !== null && upgrade.latestVersion !== "" && upgrade.latestVersion !== "0.1.33" ? upgrade : null;
99
109
  if (d.upgrade === null || d.upgrade.latestVersion !== normalized?.latestVersion) d.upgradeDismissed = false;
100
110
  d.upgrade = normalized;
101
111
  },
@@ -157,9 +167,11 @@ window.__ModuleLoader__.load({
157
167
  * @param groups - advisory provider groups of the current session.
158
168
  * @param snapshot - latest quota snapshot, or null before the first one.
159
169
  * @param current - current model selection reported by the Host.
160
- * @returns rows sorted by key.
170
+ * @param order - user's drag-to-reorder preference (model keys); listed keys
171
+ * come first in that exact order, the rest follow in catalog order.
172
+ * @returns rows in display order.
161
173
  */
162
- function mergeModelRows(groups, snapshot, current) {
174
+ function mergeModelRows(groups, snapshot, current, order = []) {
163
175
  const entryByKey = new Map((snapshot?.entries ?? []).map((entry) => [entry.key, entry]));
164
176
  const rows = /* @__PURE__ */ new Map();
165
177
  for (const group of groups) for (const model of group.models) {
@@ -187,11 +199,33 @@ window.__ModuleLoader__.load({
187
199
  current: current !== null && current.provider === entry.provider && current.model === entry.model
188
200
  });
189
201
  }
190
- return [...rows.values()].sort((left, right) => left.key.localeCompare(right.key));
202
+ const rank = new Map(order.map((key, index) => [key, index]));
203
+ return [...rows.values()].sort((left, right) => {
204
+ const leftRank = rank.get(left.key);
205
+ const rightRank = rank.get(right.key);
206
+ if (leftRank !== void 0 && rightRank !== void 0) return leftRank - rightRank;
207
+ if (leftRank !== void 0) return -1;
208
+ if (rightRank !== void 0) return 1;
209
+ return left.key.localeCompare(right.key);
210
+ });
211
+ }
212
+ /**
213
+ * Move one key to another key's position, returning the full reordered key
214
+ * list (the shape persisted in the settings document's `order`).
215
+ */
216
+ function reorderKeys(keys, from, to) {
217
+ const next = [...keys];
218
+ const fromIndex = next.indexOf(from);
219
+ const toIndex = next.indexOf(to);
220
+ if (fromIndex < 0 || toIndex < 0 || fromIndex === toIndex) return next;
221
+ const [moved] = next.splice(fromIndex, 1);
222
+ if (moved === void 0) return next;
223
+ next.splice(toIndex, 0, moved);
224
+ return next;
191
225
  }
192
226
  //#endregion
193
227
  //#region \0dsh-css:/Users/jxgame/Desktop/works/deepseek-harness-package/dsh-token-quota/packages/token-quota/src/client/TokenQuotaPanel.module.css.mjs
194
- const css = ".NPLLIq_panel{box-sizing:border-box;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);pointer-events:auto;z-index:40;opacity:1;border-radius:12px;flex-direction:column;width:320px;max-height:min(72vh,560px);transition:opacity .18s;display:flex;position:fixed;top:56px;right:12px;overflow:hidden;box-shadow:0 8px 28px #0000002e}.NPLLIq_panelDim{opacity:.55}.NPLLIq_panelDimStrong{opacity:.3}.NPLLIq_header{border-bottom:1px solid var(--dsw-alias-border-l1);cursor:grab;user-select:none;touch-action:none;justify-content:space-between;align-items:flex-start;gap:8px;padding:10px 12px;display:flex}.NPLLIq_header:active{cursor:grabbing}.NPLLIq_headerText{flex-direction:column;gap:2px;min-width:0;display:flex}.NPLLIq_title{color:var(--dsw-alias-label-primary);align-items:baseline;gap:6px;font-size:13px;font-weight:600;display:flex}.NPLLIq_version{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:10px;font-weight:500}.NPLLIq_versionNew{color:var(--dsw-alias-status-warning-foreground,#b56900);background:var(--dsw-alias-status-warning-background,#fff6d7);cursor:default;border-radius:4px;padding:1px 6px}.NPLLIq_subtitle{color:var(--dsw-alias-label-secondary);font-size:11px}.NPLLIq_collapse{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;flex:none;padding:2px 6px;font-size:11px}.NPLLIq_collapse:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_body{padding:4px 0;overflow-y:auto}.NPLLIq_row{border-bottom:1px solid var(--dsw-alias-border-l1);flex-direction:column;gap:6px;padding:8px 12px;display:flex}.NPLLIq_rowHeader{justify-content:space-between;align-items:center;gap:8px;display:flex}.NPLLIq_rowName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;align-items:center;gap:6px;font-size:12px;font-weight:500;display:inline-flex;overflow:hidden}.NPLLIq_currentBadge{color:var(--dsw-alias-state-success-primary);border:1px solid var(--dsw-alias-state-success-primary);border-radius:8px;flex:none;padding:1px 6px;font-size:10px}.NPLLIq_rowMeta{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:11px}.NPLLIq_bar{background:var(--dsw-alias-bg-layer-1);border-radius:3px;height:6px;overflow:hidden}.NPLLIq_fillIdle{background:var(--dsw-alias-brand-primary);height:100%;transition:width .2s}.NPLLIq_fillWarn{background:var(--dsw-alias-state-warn-primary);height:100%;transition:width .2s}.NPLLIq_fillOver{background:var(--dsw-alias-state-error-primary);height:100%;transition:width .2s}.NPLLIq_controls{align-items:center;gap:6px;display:flex}.NPLLIq_input{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);min-width:0;color:var(--dsw-alias-label-primary);border-radius:6px;flex:1;padding:4px 8px;font-size:11px}.NPLLIq_input::placeholder{color:var(--dsw-alias-label-secondary)}.NPLLIq_save,.NPLLIq_switch{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;flex:none;padding:4px 10px;font-size:11px}.NPLLIq_save:hover,.NPLLIq_switch:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2)}.NPLLIq_switch:disabled{opacity:.5;cursor:default}.NPLLIq_notice,.NPLLIq_noticeError{color:var(--dsw-alias-label-secondary);padding:10px 12px;font-size:12px}.NPLLIq_noticeError{color:var(--dsw-alias-state-error-primary)}.NPLLIq_tab{background:var(--dsw-alias-brand-primary);border:1px solid var(--dsw-alias-brand-primary);color:var(--dsw-alias-bg-overlay);pointer-events:auto;cursor:pointer;z-index:90;border-radius:10px;align-items:center;gap:6px;padding:9px 14px;font-size:12px;font-weight:600;display:inline-flex;position:fixed;top:56px;right:12px;box-shadow:0 6px 20px #00000040}.NPLLIq_tab:hover{filter:brightness(1.08)}.NPLLIq_tabIcon{font-size:12px;line-height:1}.NPLLIq_tabLabel{white-space:nowrap}.NPLLIq_headerActions{flex:none;align-items:center;gap:4px;display:flex}.NPLLIq_settingsBtn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;flex:none;padding:2px 6px;font-size:11px}.NPLLIq_settingsBtn:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_settingsBtnActive{color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-layer-2,#0000000f);box-shadow:inset 0 0 0 1px var(--dsw-alias-brand-primary);font-weight:700}.NPLLIq_selectBtn{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-brand-primary);cursor:pointer;background:0 0;border-radius:6px;flex:none;padding:1px 6px;font-size:10px}.NPLLIq_selectBtn:hover{background:var(--dsw-alias-bg-layer-1)}.NPLLIq_gearBtn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;flex:none;margin-left:6px;padding:0 2px;font-size:12px;line-height:1}.NPLLIq_gearBtn:hover{color:var(--dsw-alias-label-primary)}.NPLLIq_fullNotice{color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-state-error-primary);border-radius:8px;margin:6px 12px;padding:8px 10px;font-size:12px}.NPLLIq_upgradeBanner{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-divider-1,#0000001a);border-radius:8px;margin:6px 12px;padding:10px 30px 10px 10px;font-size:12px;position:relative}@keyframes NPLLIq_upgradeBannerFlash{0%,to{border-color:var(--dsw-alias-divider-1,#0000001a);box-shadow:0 0 #f0a02000}50%{border-color:var(--dsw-alias-status-warning-foreground,#b56900);box-shadow:0 0 0 5px #f0a02073}}.NPLLIq_upgradeBannerFlash{border-color:var(--dsw-alias-status-warning-foreground,#b56900);animation:.6s ease-in-out 4 NPLLIq_upgradeBannerFlash}.NPLLIq_upgradeBannerText{margin-bottom:6px;font-weight:600}.NPLLIq_upgradeCommands{flex-direction:column;gap:4px;display:flex}.NPLLIq_upgradeCommandRow{align-items:center;gap:6px;display:flex}.NPLLIq_upgradeCommand{background:var(--dsw-alias-bg-layer-2,#0000000a);white-space:nowrap;border-radius:4px;flex:1;min-width:0;padding:4px 6px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px;overflow-x:auto}.NPLLIq_copyBtn{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-2,#0000000a);color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:4px;flex:none;padding:3px 8px;font-size:11px;transition:transform 80ms,background .12s,color .12s}.NPLLIq_copyBtn:hover{background:var(--dsw-alias-bg-layer-3,#00000014)}.NPLLIq_copyBtn:active{transform:scale(.92)}.NPLLIq_copyBtnDone{background:var(--dsw-alias-status-success-background,#14963c1f);border-color:var(--dsw-alias-status-success-foreground,#0a7d32);color:var(--dsw-alias-status-success-foreground,#0a7d32);font-weight:600}.NPLLIq_upgradeHint{color:var(--dsw-alias-label-secondary);margin-top:6px;font-size:11px}.NPLLIq_upgradeClose{width:20px;height:20px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:4px;font-size:16px;line-height:1;position:absolute;top:4px;right:6px}.NPLLIq_upgradeClose:hover{background:var(--dsw-alias-bg-layer-2,#0000000a);color:var(--dsw-alias-label-primary)}.NPLLIq_checkUpdatesRow{justify-content:space-between;align-items:center;gap:12px;display:flex}.NPLLIq_checkUpdatesLabel{color:var(--dsw-alias-label-primary);cursor:pointer;align-items:center;gap:6px;font-size:12px;display:flex}.NPLLIq_checkUpdatesLabel input{margin:0}.NPLLIq_checkUpdatesLabel input[type=range]{min-width:90px;accent-color:var(--dsw-alias-brand-primary);flex:1}.NPLLIq_checkUpdatesLabel select{background:var(--dsw-alias-bg-layer-2,#0000000a);min-width:90px;color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-divider-1,#00000026);border-radius:4px;flex:1;padding:2px 4px;font-size:12px}.NPLLIq_checkBtn{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-2,#0000000a);color:var(--dsw-alias-label-primary);cursor:pointer;white-space:nowrap;text-align:center;border-radius:4px;flex:none;min-width:72px;padding:4px 10px;font-size:12px}.NPLLIq_checkBtn:hover:not(:disabled){background:var(--dsw-alias-bg-layer-3,#00000014)}.NPLLIq_checkBtn:disabled{opacity:.6;cursor:default}.NPLLIq_checkErrorHint{color:var(--dsw-alias-state-error-primary,#c00);background:var(--dsw-alias-state-error-background,#ff00000f);border:1px solid var(--dsw-alias-state-error-border,#b4000040);word-break:break-all;border-radius:6px;margin-top:8px;padding:6px 8px;font-size:11px;line-height:1.4}.NPLLIq_dialog{z-index:100;box-sizing:border-box;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;flex-direction:column;gap:12px;width:430px;max-width:94vw;max-height:80vh;padding:14px;display:flex;position:fixed;top:50%;left:50%;overflow-y:auto;transform:translate(-50%,-50%);box-shadow:0 8px 28px #00000040}.NPLLIq_dialogTabs{border-bottom:1px solid var(--dsw-alias-divider-1,#00000014);gap:2px;margin:-6px -14px 0;padding:0 14px;display:flex}.NPLLIq_dialogTab{appearance:none;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-bottom:2px solid #0000;padding:6px 12px 8px;font-size:12px}.NPLLIq_dialogTab:hover{color:var(--dsw-alias-label-primary)}.NPLLIq_dialogTabActive{color:var(--dsw-alias-brand-primary);border-bottom-color:var(--dsw-alias-brand-primary);font-weight:600}.NPLLIq_settingsDialog{height:min(560px,80vh)}.NPLLIq_dialogTitle{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600}.NPLLIq_dialogSection{flex-direction:column;gap:6px;display:flex}.NPLLIq_dialogLabel{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:500}.NPLLIq_monitorHint{color:var(--dsw-alias-label-secondary);font-size:11px}.NPLLIq_dialogHint{color:var(--dsw-alias-label-secondary);margin-top:4px;font-size:11px;line-height:1.4}.NPLLIq_monitorList{flex-direction:column;gap:2px;max-height:180px;display:flex;overflow-y:auto}.NPLLIq_monitorRow{color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;align-items:center;gap:6px;padding:2px 4px;font-size:12px;display:flex}.NPLLIq_monitorRow:hover{background:var(--dsw-alias-bg-layer-1)}.NPLLIq_monitorName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.NPLLIq_radioRow{color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;align-items:center;gap:6px;padding:3px 4px;font-size:12px;display:flex}.NPLLIq_radioRow:hover{background:var(--dsw-alias-bg-layer-1)}.NPLLIq_dialogActions{justify-content:flex-end;gap:6px;display:flex}.NPLLIq_dialogBtn,.NPLLIq_dialogBtnPrimary{border:1px solid var(--dsw-alias-border-l1);cursor:pointer;border-radius:6px;padding:4px 12px;font-size:11px}.NPLLIq_dialogBtn{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary)}.NPLLIq_dialogBtnPrimary{background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary);color:var(--dsw-alias-bg-overlay)}.NPLLIq_dialogHeader{z-index:2;background:var(--dsw-alias-bg-overlay);cursor:grab;user-select:none;touch-action:none;justify-content:space-between;align-items:center;gap:8px;margin:-14px -14px 0;padding:14px 14px 8px;display:flex;position:sticky;top:-14px}.NPLLIq_dialogHeader:active{cursor:grabbing}.NPLLIq_dialogClose{width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:8px;flex:none;justify-content:center;align-items:center;font-size:18px;line-height:1;display:flex}.NPLLIq_dialogClose:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_resetRow{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.NPLLIq_resetSelect{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:6px;padding:3px 6px;font-size:12px}.NPLLIq_logTable{border-collapse:collapse;width:100%;font-size:11px}.NPLLIq_logTable th{text-align:left;color:var(--dsw-alias-label-secondary);border-bottom:1px solid var(--dsw-alias-border-l1);padding:4px 6px;font-weight:500}.NPLLIq_logTable td{color:var(--dsw-alias-label-primary);border-bottom:1px solid var(--dsw-alias-border-l1);font-variant-numeric:tabular-nums;padding:4px 6px}.NPLLIq_logDayCol{white-space:nowrap;color:var(--dsw-alias-label-secondary)}.NPLLIq_logModelCol{text-overflow:ellipsis;white-space:nowrap;max-width:160px;overflow:hidden}.NPLLIq_logUsedCol{text-align:right}.NPLLIq_logDialog{gap:0;width:380px;max-height:min(72vh,480px);padding:0}.NPLLIq_logHeader{background:var(--dsw-alias-bg-overlay);cursor:grab;user-select:none;touch-action:none;flex:none;justify-content:space-between;align-items:center;gap:8px;padding:14px 14px 8px;display:flex}.NPLLIq_logHeader:active{cursor:grabbing}.NPLLIq_logScroll{flex:1;min-height:0;padding:0 14px 14px;overflow:auto}.NPLLIq_logToolbar{flex:1;align-items:center;gap:6px;display:flex}.NPLLIq_logSearch{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);min-width:0;color:var(--dsw-alias-label-primary);border-radius:4px;flex:1;padding:3px 6px;font-size:11px}.NPLLIq_logSearch:focus{border-color:var(--dsw-alias-accent-1,#4a9eff);outline:none}.NPLLIq_logClearBtn{border:1px solid var(--dsw-alias-state-error-border,#b400004d);color:var(--dsw-alias-state-error-primary,#c00);cursor:pointer;white-space:nowrap;background:0 0;border-radius:4px;flex:none;padding:3px 8px;font-size:11px}.NPLLIq_logClearBtn:hover{background:var(--dsw-alias-state-error-background,#ff00000f)}.NPLLIq_logPager{border-top:1px solid var(--dsw-alias-divider-1,#00000014);background:var(--dsw-alias-bg-overlay);color:var(--dsw-alias-label-secondary);flex:none;justify-content:space-between;align-items:center;gap:8px;padding:6px 14px;font-size:11px;display:flex}.NPLLIq_logPagerInfo{white-space:nowrap}.NPLLIq_logPagerControls{align-items:center;gap:4px;display:flex}.NPLLIq_logPagerBtn{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);width:24px;height:24px;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:4px;font-size:13px;line-height:1}.NPLLIq_logPagerBtn:disabled{opacity:.4;cursor:default}.NPLLIq_logPagerPages{text-align:center;min-width:50px;color:var(--dsw-alias-label-secondary)}.NPLLIq_logPageSizeSelect{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:4px;padding:2px 4px;font-size:11px}.NPLLIq_dialogOverlay{z-index:100001;background:#0000004d;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.NPLLIq_logClearDialog{gap:0;width:320px;padding:16px}.NPLLIq_dialogBody{color:var(--dsw-alias-label-secondary);margin:6px 0 10px;font-size:12px;line-height:1.5}.NPLLIq_logClearDate{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);width:100%;color:var(--dsw-alias-label-primary);border-radius:6px;margin-bottom:12px;padding:6px 8px;font-size:13px}.NPLLIq_logClearDate:focus{border-color:var(--dsw-alias-accent-1,#4a9eff);outline:none}";
228
+ const css = ".NPLLIq_panel{box-sizing:border-box;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);pointer-events:auto;z-index:40;opacity:1;border-radius:12px;flex-direction:column;width:320px;max-height:min(72vh,560px);transition:opacity .18s;display:flex;position:fixed;top:56px;right:12px;overflow:hidden;box-shadow:0 8px 28px #0000002e}.NPLLIq_panelDim{opacity:.55}.NPLLIq_panelDimStrong{opacity:.3}.NPLLIq_header{border-bottom:1px solid var(--dsw-alias-border-l1);cursor:grab;user-select:none;touch-action:none;justify-content:space-between;align-items:flex-start;gap:8px;padding:10px 12px;display:flex}.NPLLIq_header:active{cursor:grabbing}.NPLLIq_headerText{flex-direction:column;gap:2px;min-width:0;display:flex}.NPLLIq_title{color:var(--dsw-alias-label-primary);align-items:baseline;gap:6px;font-size:13px;font-weight:600;display:flex}.NPLLIq_version{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:10px;font-weight:500}.NPLLIq_versionNew{color:var(--dsw-alias-status-warning-foreground,#b56900);background:var(--dsw-alias-status-warning-background,#fff6d7);cursor:default;border-radius:4px;padding:1px 6px}.NPLLIq_subtitle{color:var(--dsw-alias-label-secondary);font-size:11px}.NPLLIq_notesBar{flex-wrap:wrap;align-items:center;gap:4px;margin-top:4px;display:flex}.NPLLIq_noteChip{width:20px;height:20px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);cursor:pointer;border-radius:5px;flex:none;justify-content:center;align-items:center;padding:0;font-size:11px;line-height:1;transition:color .12s,border-color .12s;display:inline-flex}.NPLLIq_noteChip:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2)}.NPLLIq_noteChipOpen{color:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}.NPLLIq_noteNew{width:22px;height:20px;color:var(--dsw-alias-label-secondary);border:1px dashed var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:5px;flex:none;justify-content:center;align-items:center;padding:0;transition:color .12s,border-color .12s;display:inline-flex;position:relative}.NPLLIq_noteNew:hover:not(:disabled){color:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}.NPLLIq_noteNew:disabled{opacity:.4;cursor:not-allowed}.NPLLIq_noteNewPlus{color:inherit;font-size:10px;font-weight:700;line-height:1;position:absolute;bottom:-2px;right:-1px}.NPLLIq_noteWin{z-index:60;pointer-events:auto;box-sizing:border-box;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;flex-direction:column;display:flex;position:fixed;overflow:hidden;box-shadow:0 8px 24px #00000038}.NPLLIq_noteWinCollapsed{height:auto!important}.NPLLIq_noteWinBar{background:var(--dsw-alias-bg-layer-1);border-bottom:1px solid var(--dsw-alias-border-l1);cursor:grab;user-select:none;flex:none;align-items:center;gap:4px;padding:4px 6px;display:flex}.NPLLIq_noteWinBar:active{cursor:grabbing}.NPLLIq_noteWinGripBar{color:var(--dsw-alias-label-secondary);opacity:.7;flex:none;font-size:10px}.NPLLIq_noteWinTitle{min-width:0;color:var(--dsw-alias-label-primary);background:0 0;border:1px solid #0000;border-radius:4px;outline:none;flex:1;padding:1px 2px;font-size:11px;font-weight:600}.NPLLIq_noteWinTitle:hover{border-color:var(--dsw-alias-border-l1)}.NPLLIq_noteWinTitle:focus{background:var(--dsw-alias-bg-overlay);border-color:var(--dsw-alias-brand-primary)}.NPLLIq_noteWinBtn{width:18px;height:18px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:4px;flex:none;justify-content:center;align-items:center;padding:0;font-size:12px;line-height:1;display:inline-flex}.NPLLIq_noteWinBtn:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.NPLLIq_noteWinText{box-sizing:border-box;width:100%;min-height:0;color:var(--dsw-alias-label-primary);resize:none;background:0 0;border:none;outline:none;flex:1;padding:6px 8px;font-family:inherit;font-size:11px;line-height:1.5}.NPLLIq_noteWinResize{cursor:nwse-resize;background:linear-gradient(135deg, transparent 0 45%, var(--dsw-alias-border-l2) 45% 55%, transparent 55% 70%, var(--dsw-alias-border-l2) 70% 80%, transparent 80%);width:14px;height:14px;position:absolute;bottom:0;right:0}.NPLLIq_noteMenuBackdrop{z-index:100;pointer-events:auto;position:fixed;inset:0}.NPLLIq_noteMenu{z-index:101;pointer-events:auto;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex-direction:column;min-width:96px;padding:4px;display:flex;position:fixed;box-shadow:0 8px 24px #0000003d}.NPLLIq_noteMenuItem{text-align:left;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:5px;padding:5px 8px;font-size:11px}.NPLLIq_noteMenuItem:hover{background:var(--dsw-alias-bg-layer-2)}.NPLLIq_collapse{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;flex:none;padding:2px 6px;font-size:11px}.NPLLIq_collapse:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_body{padding:4px 0;overflow-y:auto}.NPLLIq_row{border-bottom:1px solid var(--dsw-alias-border-l1);flex-direction:column;gap:6px;padding:8px 12px;display:flex}.NPLLIq_rowHeader{justify-content:space-between;align-items:center;gap:8px;display:flex}.NPLLIq_rowDrag{cursor:grab;color:var(--dsw-alias-label-secondary);user-select:none;border-radius:4px;flex:none;margin-right:2px;padding:2px 3px;font-size:11px;line-height:1}.NPLLIq_rowDrag:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_rowDrag:active{cursor:grabbing}.NPLLIq_rowDragging{opacity:.45}.NPLLIq_rowDropTarget{box-shadow:inset 0 2px 0 var(--dsw-alias-brand-primary)}.NPLLIq_rowName{min-width:0;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;align-items:center;gap:6px;font-size:12px;font-weight:500;display:inline-flex;overflow:hidden}.NPLLIq_currentBadge{color:var(--dsw-alias-state-success-primary);border:1px solid var(--dsw-alias-state-success-primary);border-radius:8px;flex:none;padding:1px 6px;font-size:10px}.NPLLIq_rowMeta{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:11px}.NPLLIq_bar{background:var(--dsw-alias-bg-layer-1);border-radius:3px;height:6px;overflow:hidden}.NPLLIq_fillIdle{background:var(--dsw-alias-brand-primary);height:100%;transition:width .2s}.NPLLIq_fillWarn{background:var(--dsw-alias-state-warn-primary);height:100%;transition:width .2s}.NPLLIq_fillOver{background:var(--dsw-alias-state-error-primary);height:100%;transition:width .2s}.NPLLIq_controls{align-items:center;gap:6px;display:flex}.NPLLIq_input{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);min-width:0;color:var(--dsw-alias-label-primary);border-radius:6px;flex:1;padding:4px 8px;font-size:11px}.NPLLIq_input::placeholder{color:var(--dsw-alias-label-secondary)}.NPLLIq_save,.NPLLIq_switch{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;flex:none;padding:4px 10px;font-size:11px}.NPLLIq_save:hover,.NPLLIq_switch:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2)}.NPLLIq_switch:disabled{opacity:.5;cursor:default}.NPLLIq_notice,.NPLLIq_noticeError{color:var(--dsw-alias-label-secondary);padding:10px 12px;font-size:12px}.NPLLIq_noticeError{color:var(--dsw-alias-state-error-primary)}.NPLLIq_tab{background:var(--dsw-alias-brand-primary);border:1px solid var(--dsw-alias-brand-primary);color:var(--dsw-alias-bg-overlay);pointer-events:auto;cursor:pointer;z-index:90;border-radius:10px;align-items:center;gap:6px;padding:9px 14px;font-size:12px;font-weight:600;display:inline-flex;position:fixed;top:56px;right:12px;box-shadow:0 6px 20px #00000040}.NPLLIq_tab:hover{filter:brightness(1.08)}.NPLLIq_tabIcon{font-size:12px;line-height:1}.NPLLIq_tabLabel{white-space:nowrap}.NPLLIq_headerActions{flex:none;align-items:center;gap:4px;display:flex}.NPLLIq_settingsBtn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;flex:none;padding:2px 6px;font-size:11px}.NPLLIq_settingsBtn:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_settingsBtnActive{color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-layer-2,#0000000f);box-shadow:inset 0 0 0 1px var(--dsw-alias-brand-primary);font-weight:700}.NPLLIq_selectBtn{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-brand-primary);cursor:pointer;background:0 0;border-radius:6px;flex:none;padding:1px 6px;font-size:10px}.NPLLIq_selectBtn:hover{background:var(--dsw-alias-bg-layer-1)}.NPLLIq_gearBtn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;flex:none;margin-left:6px;padding:0 2px;font-size:12px;line-height:1}.NPLLIq_gearBtn:hover{color:var(--dsw-alias-label-primary)}.NPLLIq_fullNotice{color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-state-error-primary);border-radius:8px;margin:6px 12px;padding:8px 10px;font-size:12px}.NPLLIq_upgradeBanner{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-divider-1,#0000001a);border-radius:8px;margin:6px 12px;padding:10px 30px 10px 10px;font-size:12px;position:relative}@keyframes NPLLIq_upgradeBannerFlash{0%,to{border-color:var(--dsw-alias-divider-1,#0000001a);box-shadow:0 0 #f0a02000}50%{border-color:var(--dsw-alias-status-warning-foreground,#b56900);box-shadow:0 0 0 5px #f0a02073}}.NPLLIq_upgradeBannerFlash{border-color:var(--dsw-alias-status-warning-foreground,#b56900);animation:.6s ease-in-out 4 NPLLIq_upgradeBannerFlash}.NPLLIq_upgradeBannerText{margin-bottom:6px;font-weight:600}.NPLLIq_upgradeCommands{flex-direction:column;gap:4px;display:flex}.NPLLIq_upgradeCommandRow{align-items:center;gap:6px;display:flex}.NPLLIq_upgradeCommand{background:var(--dsw-alias-bg-layer-2,#0000000a);white-space:nowrap;border-radius:4px;flex:1;min-width:0;padding:4px 6px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px;overflow-x:auto}.NPLLIq_copyBtn{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-2,#0000000a);color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:4px;flex:none;padding:3px 8px;font-size:11px;transition:transform 80ms,background .12s,color .12s}.NPLLIq_copyBtn:hover{background:var(--dsw-alias-bg-layer-3,#00000014)}.NPLLIq_copyBtn:active{transform:scale(.92)}.NPLLIq_copyBtnDone{background:var(--dsw-alias-status-success-background,#14963c1f);border-color:var(--dsw-alias-status-success-foreground,#0a7d32);color:var(--dsw-alias-status-success-foreground,#0a7d32);font-weight:600}.NPLLIq_upgradeHint{color:var(--dsw-alias-label-secondary);margin-top:6px;font-size:11px}.NPLLIq_upgradeClose{width:20px;height:20px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:4px;font-size:16px;line-height:1;position:absolute;top:4px;right:6px}.NPLLIq_upgradeClose:hover{background:var(--dsw-alias-bg-layer-2,#0000000a);color:var(--dsw-alias-label-primary)}.NPLLIq_checkUpdatesRow{justify-content:space-between;align-items:center;gap:12px;display:flex}.NPLLIq_checkUpdatesLabel{color:var(--dsw-alias-label-primary);cursor:pointer;align-items:center;gap:6px;font-size:12px;display:flex}.NPLLIq_checkUpdatesLabel input{margin:0}.NPLLIq_checkUpdatesLabel input[type=range]{min-width:90px;accent-color:var(--dsw-alias-brand-primary);flex:1}.NPLLIq_checkUpdatesLabel select{background:var(--dsw-alias-bg-layer-2,#0000000a);min-width:90px;color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-divider-1,#00000026);border-radius:4px;flex:1;padding:2px 4px;font-size:12px}.NPLLIq_checkBtn{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-2,#0000000a);color:var(--dsw-alias-label-primary);cursor:pointer;white-space:nowrap;text-align:center;border-radius:4px;flex:none;min-width:72px;padding:4px 10px;font-size:12px}.NPLLIq_checkBtn:hover:not(:disabled){background:var(--dsw-alias-bg-layer-3,#00000014)}.NPLLIq_checkBtn:disabled{opacity:.6;cursor:default}.NPLLIq_checkErrorHint{color:var(--dsw-alias-state-error-primary,#c00);background:var(--dsw-alias-state-error-background,#ff00000f);border:1px solid var(--dsw-alias-state-error-border,#b4000040);word-break:break-all;border-radius:6px;margin-top:8px;padding:6px 8px;font-size:11px;line-height:1.4}.NPLLIq_dialog{z-index:100;pointer-events:auto;box-sizing:border-box;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;flex-direction:column;gap:12px;width:430px;max-width:94vw;max-height:80vh;padding:14px;display:flex;position:fixed;top:50%;left:50%;overflow-y:auto;transform:translate(-50%,-50%);box-shadow:0 8px 28px #00000040}.NPLLIq_dialogTabs{border-bottom:1px solid var(--dsw-alias-divider-1,#00000014);gap:2px;margin:-6px -14px 0;padding:0 14px;display:flex}.NPLLIq_dialogTab{appearance:none;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-bottom:2px solid #0000;padding:6px 12px 8px;font-size:12px}.NPLLIq_dialogTab:hover{color:var(--dsw-alias-label-primary)}.NPLLIq_dialogTabActive{color:var(--dsw-alias-brand-primary);border-bottom-color:var(--dsw-alias-brand-primary);font-weight:600}.NPLLIq_settingsDialog{height:min(560px,80vh)}.NPLLIq_dialogTitle{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600}.NPLLIq_dialogSection{flex-direction:column;gap:6px;display:flex}.NPLLIq_dialogLabel{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:500}.NPLLIq_monitorHint{color:var(--dsw-alias-label-secondary);font-size:11px}.NPLLIq_dialogHint{color:var(--dsw-alias-label-secondary);margin-top:4px;font-size:11px;line-height:1.4}.NPLLIq_monitorList{flex-direction:column;gap:2px;max-height:180px;display:flex;overflow-y:auto}.NPLLIq_monitorRow{color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;align-items:center;gap:6px;padding:2px 4px;font-size:12px;display:flex}.NPLLIq_monitorRow:hover{background:var(--dsw-alias-bg-layer-1)}.NPLLIq_monitorName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.NPLLIq_radioRow{color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;align-items:center;gap:6px;padding:3px 4px;font-size:12px;display:flex}.NPLLIq_radioRow:hover{background:var(--dsw-alias-bg-layer-1)}.NPLLIq_dialogActions{justify-content:flex-end;gap:6px;display:flex}.NPLLIq_dialogBtn,.NPLLIq_dialogBtnPrimary{border:1px solid var(--dsw-alias-border-l1);cursor:pointer;border-radius:6px;padding:4px 12px;font-size:11px}.NPLLIq_dialogBtn{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary)}.NPLLIq_dialogBtnPrimary{background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary);color:var(--dsw-alias-bg-overlay)}.NPLLIq_dialogHeader{z-index:2;background:var(--dsw-alias-bg-overlay);cursor:grab;user-select:none;touch-action:none;justify-content:space-between;align-items:center;gap:8px;margin:-14px -14px 0;padding:14px 14px 8px;display:flex;position:sticky;top:-14px}.NPLLIq_dialogHeader:active{cursor:grabbing}.NPLLIq_dialogClose{width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:8px;flex:none;justify-content:center;align-items:center;font-size:18px;line-height:1;display:flex}.NPLLIq_dialogClose:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_resetRow{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.NPLLIq_resetSelect{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:6px;padding:3px 6px;font-size:12px}.NPLLIq_logTable{border-collapse:collapse;width:100%;font-size:11px}.NPLLIq_logTable th{text-align:left;color:var(--dsw-alias-label-secondary);border-bottom:1px solid var(--dsw-alias-border-l1);padding:4px 6px;font-weight:500}.NPLLIq_logTable td{color:var(--dsw-alias-label-primary);border-bottom:1px solid var(--dsw-alias-border-l1);font-variant-numeric:tabular-nums;padding:4px 6px}.NPLLIq_logDayCol{white-space:nowrap;color:var(--dsw-alias-label-secondary)}.NPLLIq_logModelCol{text-overflow:ellipsis;white-space:nowrap;max-width:160px;overflow:hidden}.NPLLIq_logUsedCol{text-align:right}.NPLLIq_logDialog{gap:0;width:380px;max-height:min(72vh,480px);padding:0}.NPLLIq_logHeader{background:var(--dsw-alias-bg-overlay);cursor:grab;user-select:none;touch-action:none;flex:none;justify-content:space-between;align-items:center;gap:8px;padding:14px 14px 8px;display:flex}.NPLLIq_logHeader:active{cursor:grabbing}.NPLLIq_logScroll{flex:1;min-height:0;padding:0 14px 14px;overflow:auto}.NPLLIq_logToolbar{flex:1;align-items:center;gap:6px;display:flex}.NPLLIq_logSearch{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);min-width:0;color:var(--dsw-alias-label-primary);border-radius:4px;flex:1;padding:3px 6px;font-size:11px}.NPLLIq_logSearch:focus{border-color:var(--dsw-alias-accent-1,#4a9eff);outline:none}.NPLLIq_logClearBtn{border:1px solid var(--dsw-alias-state-error-border,#b400004d);color:var(--dsw-alias-state-error-primary,#c00);cursor:pointer;white-space:nowrap;background:0 0;border-radius:4px;flex:none;padding:3px 8px;font-size:11px}.NPLLIq_logClearBtn:hover{background:var(--dsw-alias-state-error-background,#ff00000f)}.NPLLIq_logPager{border-top:1px solid var(--dsw-alias-divider-1,#00000014);background:var(--dsw-alias-bg-overlay);color:var(--dsw-alias-label-secondary);flex:none;justify-content:space-between;align-items:center;gap:8px;padding:6px 14px;font-size:11px;display:flex}.NPLLIq_logPagerInfo{white-space:nowrap}.NPLLIq_logPagerControls{align-items:center;gap:4px;display:flex}.NPLLIq_logPagerBtn{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);width:24px;height:24px;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:4px;font-size:13px;line-height:1}.NPLLIq_logPagerBtn:disabled{opacity:.4;cursor:default}.NPLLIq_logPagerPages{text-align:center;min-width:50px;color:var(--dsw-alias-label-secondary)}.NPLLIq_logPageSizeSelect{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:4px;padding:2px 4px;font-size:11px}.NPLLIq_dialogOverlay{z-index:100001;pointer-events:auto;background:#0000004d;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.NPLLIq_logClearDialog{gap:0;width:320px;padding:16px}.NPLLIq_dialogBody{color:var(--dsw-alias-label-secondary);margin:6px 0 10px;font-size:12px;line-height:1.5}.NPLLIq_logClearDate{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);width:100%;color:var(--dsw-alias-label-primary);border-radius:6px;margin-bottom:12px;padding:6px 8px;font-size:13px}.NPLLIq_logClearDate:focus{border-color:var(--dsw-alias-accent-1,#4a9eff);outline:none}";
195
229
  const tagId = "@jxgame2020/dsh-token-quota/TokenQuotaPanel.module.css";
196
230
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
197
231
  const tag = document.createElement("style");
@@ -201,96 +235,115 @@ window.__ModuleLoader__.load({
201
235
  document.head.appendChild(tag);
202
236
  }
203
237
  var TokenQuotaPanel_module_css_default = {
204
- "body": "NPLLIq_body",
205
- "bar": "NPLLIq_bar",
206
- "rowName": "NPLLIq_rowName",
207
- "rowHeader": "NPLLIq_rowHeader",
208
- "gearBtn": "NPLLIq_gearBtn",
209
- "radioRow": "NPLLIq_radioRow",
238
+ "dialogSection": "NPLLIq_dialogSection",
210
239
  "resetRow": "NPLLIq_resetRow",
211
- "logModelCol": "NPLLIq_logModelCol",
240
+ "noteWinBtn": "NPLLIq_noteWinBtn",
241
+ "input": "NPLLIq_input",
242
+ "dialogLabel": "NPLLIq_dialogLabel",
243
+ "dialogClose": "NPLLIq_dialogClose",
244
+ "logPagerInfo": "NPLLIq_logPagerInfo",
245
+ "monitorName": "NPLLIq_monitorName",
246
+ "noteWin": "NPLLIq_noteWin",
247
+ "gearBtn": "NPLLIq_gearBtn",
248
+ "logPagerBtn": "NPLLIq_logPagerBtn",
212
249
  "logClearDialog": "NPLLIq_logClearDialog",
213
- "upgradeClose": "NPLLIq_upgradeClose",
250
+ "rowDragging": "NPLLIq_rowDragging",
251
+ "checkErrorHint": "NPLLIq_checkErrorHint",
252
+ "dialogTabActive": "NPLLIq_dialogTabActive",
253
+ "logTable": "NPLLIq_logTable",
254
+ "selectBtn": "NPLLIq_selectBtn",
255
+ "rowName": "NPLLIq_rowName",
256
+ "logToolbar": "NPLLIq_logToolbar",
257
+ "settingsDialog": "NPLLIq_settingsDialog",
258
+ "checkUpdatesLabel": "NPLLIq_checkUpdatesLabel",
259
+ "header": "NPLLIq_header",
260
+ "noteChip": "NPLLIq_noteChip",
214
261
  "subtitle": "NPLLIq_subtitle",
262
+ "noteChipOpen": "NPLLIq_noteChipOpen",
263
+ "noteWinResize": "NPLLIq_noteWinResize",
264
+ "rowMeta": "NPLLIq_rowMeta",
265
+ "save": "NPLLIq_save",
266
+ "headerActions": "NPLLIq_headerActions",
267
+ "fullNotice": "NPLLIq_fullNotice",
268
+ "rowHeader": "NPLLIq_rowHeader",
269
+ "noteWinCollapsed": "NPLLIq_noteWinCollapsed",
215
270
  "fillWarn": "NPLLIq_fillWarn",
216
- "noticeError": "NPLLIq_noticeError",
217
- "upgradeCommandRow": "NPLLIq_upgradeCommandRow",
271
+ "dialogTab": "NPLLIq_dialogTab",
218
272
  "logDialog": "NPLLIq_logDialog",
219
- "dialogLabel": "NPLLIq_dialogLabel",
220
- "settingsBtn": "NPLLIq_settingsBtn",
221
273
  "dialogHeader": "NPLLIq_dialogHeader",
222
- "upgradeBannerFlash": "NPLLIq_upgradeBannerFlash",
223
- "copyBtnDone": "NPLLIq_copyBtnDone",
224
- "upgradeBanner": "NPLLIq_upgradeBanner",
225
- "logScroll": "NPLLIq_logScroll",
226
- "logDayCol": "NPLLIq_logDayCol",
227
- "logPager": "NPLLIq_logPager",
228
- "upgradeCommands": "NPLLIq_upgradeCommands",
229
- "fillOver": "NPLLIq_fillOver",
274
+ "logSearch": "NPLLIq_logSearch",
275
+ "noteWinBar": "NPLLIq_noteWinBar",
276
+ "logClearBtn": "NPLLIq_logClearBtn",
277
+ "noteNew": "NPLLIq_noteNew",
278
+ "monitorRow": "NPLLIq_monitorRow",
279
+ "settingsBtn": "NPLLIq_settingsBtn",
280
+ "fillIdle": "NPLLIq_fillIdle",
281
+ "noticeError": "NPLLIq_noticeError",
282
+ "copyBtn": "NPLLIq_copyBtn",
283
+ "tabIcon": "NPLLIq_tabIcon",
284
+ "radioRow": "NPLLIq_radioRow",
285
+ "dialogBtnPrimary": "NPLLIq_dialogBtnPrimary",
230
286
  "checkUpdatesRow": "NPLLIq_checkUpdatesRow",
287
+ "logDayCol": "NPLLIq_logDayCol",
288
+ "noteMenuItem": "NPLLIq_noteMenuItem",
289
+ "logPagerControls": "NPLLIq_logPagerControls",
290
+ "dialogOverlay": "NPLLIq_dialogOverlay",
291
+ "bar": "NPLLIq_bar",
292
+ "noteWinGripBar": "NPLLIq_noteWinGripBar",
293
+ "monitorList": "NPLLIq_monitorList",
294
+ "logUsedCol": "NPLLIq_logUsedCol",
295
+ "noteWinText": "NPLLIq_noteWinText",
231
296
  "headerText": "NPLLIq_headerText",
232
- "switch": "NPLLIq_switch",
297
+ "notesBar": "NPLLIq_notesBar",
298
+ "upgradeCommands": "NPLLIq_upgradeCommands",
299
+ "rowDrag": "NPLLIq_rowDrag",
300
+ "tab": "NPLLIq_tab",
301
+ "checkBtn": "NPLLIq_checkBtn",
302
+ "noteNewPlus": "NPLLIq_noteNewPlus",
233
303
  "dialogHint": "NPLLIq_dialogHint",
234
- "dialogOverlay": "NPLLIq_dialogOverlay",
235
- "version": "NPLLIq_version",
236
- "input": "NPLLIq_input",
237
- "logPagerControls": "NPLLIq_logPagerControls",
238
- "settingsDialog": "NPLLIq_settingsDialog",
239
- "logPageSizeSelect": "NPLLIq_logPageSizeSelect",
240
- "panelDim": "NPLLIq_panelDim",
304
+ "dialogTabs": "NPLLIq_dialogTabs",
305
+ "copyBtnDone": "NPLLIq_copyBtnDone",
306
+ "dialogTitle": "NPLLIq_dialogTitle",
307
+ "notice": "NPLLIq_notice",
308
+ "currentBadge": "NPLLIq_currentBadge",
241
309
  "settingsBtnActive": "NPLLIq_settingsBtnActive",
242
- "versionNew": "NPLLIq_versionNew",
243
- "dialogBtnPrimary": "NPLLIq_dialogBtnPrimary",
244
- "dialogTabActive": "NPLLIq_dialogTabActive",
245
- "copyBtn": "NPLLIq_copyBtn",
246
- "headerActions": "NPLLIq_headerActions",
247
- "logSearch": "NPLLIq_logSearch",
248
- "checkUpdatesLabel": "NPLLIq_checkUpdatesLabel",
249
- "dialogTab": "NPLLIq_dialogTab",
250
- "upgradeHint": "NPLLIq_upgradeHint",
310
+ "version": "NPLLIq_version",
311
+ "upgradeCommand": "NPLLIq_upgradeCommand",
251
312
  "collapse": "NPLLIq_collapse",
252
- "dialogTabs": "NPLLIq_dialogTabs",
313
+ "dialogBtn": "NPLLIq_dialogBtn",
314
+ "resetSelect": "NPLLIq_resetSelect",
253
315
  "title": "NPLLIq_title",
316
+ "logModelCol": "NPLLIq_logModelCol",
317
+ "tabLabel": "NPLLIq_tabLabel",
254
318
  "controls": "NPLLIq_controls",
255
- "logClearBtn": "NPLLIq_logClearBtn",
256
- "header": "NPLLIq_header",
257
- "logPagerInfo": "NPLLIq_logPagerInfo",
258
- "logPagerPages": "NPLLIq_logPagerPages",
259
- "dialogClose": "NPLLIq_dialogClose",
319
+ "upgradeBanner": "NPLLIq_upgradeBanner",
320
+ "switch": "NPLLIq_switch",
321
+ "dialogActions": "NPLLIq_dialogActions",
260
322
  "logHeader": "NPLLIq_logHeader",
261
- "notice": "NPLLIq_notice",
323
+ "upgradeBannerText": "NPLLIq_upgradeBannerText",
324
+ "logClearDate": "NPLLIq_logClearDate",
262
325
  "dialogBody": "NPLLIq_dialogBody",
326
+ "versionNew": "NPLLIq_versionNew",
327
+ "noteMenuBackdrop": "NPLLIq_noteMenuBackdrop",
263
328
  "dialog": "NPLLIq_dialog",
329
+ "upgradeBannerFlash": "NPLLIq_upgradeBannerFlash",
330
+ "upgradeClose": "NPLLIq_upgradeClose",
331
+ "noteWinTitle": "NPLLIq_noteWinTitle",
332
+ "logPageSizeSelect": "NPLLIq_logPageSizeSelect",
333
+ "logPagerPages": "NPLLIq_logPagerPages",
334
+ "logScroll": "NPLLIq_logScroll",
335
+ "panel": "NPLLIq_panel",
336
+ "panelDim": "NPLLIq_panelDim",
264
337
  "panelDimStrong": "NPLLIq_panelDimStrong",
265
- "logClearDate": "NPLLIq_logClearDate",
266
- "save": "NPLLIq_save",
267
- "logUsedCol": "NPLLIq_logUsedCol",
268
- "monitorName": "NPLLIq_monitorName",
269
- "monitorRow": "NPLLIq_monitorRow",
270
- "dialogBtn": "NPLLIq_dialogBtn",
271
- "dialogActions": "NPLLIq_dialogActions",
272
- "upgradeBannerText": "NPLLIq_upgradeBannerText",
273
- "selectBtn": "NPLLIq_selectBtn",
274
- "logPagerBtn": "NPLLIq_logPagerBtn",
275
- "upgradeCommand": "NPLLIq_upgradeCommand",
338
+ "body": "NPLLIq_body",
339
+ "rowDropTarget": "NPLLIq_rowDropTarget",
340
+ "fillOver": "NPLLIq_fillOver",
341
+ "logPager": "NPLLIq_logPager",
276
342
  "row": "NPLLIq_row",
277
- "currentBadge": "NPLLIq_currentBadge",
278
- "monitorList": "NPLLIq_monitorList",
279
- "tabLabel": "NPLLIq_tabLabel",
280
- "fillIdle": "NPLLIq_fillIdle",
281
- "checkErrorHint": "NPLLIq_checkErrorHint",
282
- "dialogTitle": "NPLLIq_dialogTitle",
343
+ "noteMenu": "NPLLIq_noteMenu",
283
344
  "monitorHint": "NPLLIq_monitorHint",
284
- "tabIcon": "NPLLIq_tabIcon",
285
- "panel": "NPLLIq_panel",
286
- "resetSelect": "NPLLIq_resetSelect",
287
- "checkBtn": "NPLLIq_checkBtn",
288
- "logTable": "NPLLIq_logTable",
289
- "tab": "NPLLIq_tab",
290
- "rowMeta": "NPLLIq_rowMeta",
291
- "logToolbar": "NPLLIq_logToolbar",
292
- "fullNotice": "NPLLIq_fullNotice",
293
- "dialogSection": "NPLLIq_dialogSection"
345
+ "upgradeCommandRow": "NPLLIq_upgradeCommandRow",
346
+ "upgradeHint": "NPLLIq_upgradeHint"
294
347
  };
295
348
  //#endregion
296
349
  //#region lib/types/client/TokenQuotaPanel.js
@@ -361,6 +414,44 @@ window.__ModuleLoader__.load({
361
414
  window.addEventListener("pointerup", onUp);
362
415
  window.addEventListener("pointercancel", onUp);
363
416
  }
417
+ /**
418
+ * Pointer-driven resize of a note window from its bottom-right grip. Sizes are
419
+ * absolute pixels derived from the element's rect at grab time, so the window
420
+ * keeps its top-left anchor while the pointer moves. A floor keeps a window
421
+ * from collapsing to nothing.
422
+ */
423
+ function beginResize(event, el, apply) {
424
+ if (el === null) return;
425
+ event.preventDefault();
426
+ event.stopPropagation();
427
+ const startX = event.clientX;
428
+ const startY = event.clientY;
429
+ const rect = el.getBoundingClientRect();
430
+ const onMove = (ev) => {
431
+ apply({
432
+ width: Math.max(NOTE_MIN_WIDTH, Math.round(rect.width + (ev.clientX - startX))),
433
+ height: Math.max(NOTE_MIN_HEIGHT, Math.round(rect.height + (ev.clientY - startY)))
434
+ });
435
+ };
436
+ const onUp = () => {
437
+ window.removeEventListener("pointermove", onMove);
438
+ window.removeEventListener("pointerup", onUp);
439
+ window.removeEventListener("pointercancel", onUp);
440
+ };
441
+ window.addEventListener("pointermove", onMove);
442
+ window.addEventListener("pointerup", onUp);
443
+ window.addEventListener("pointercancel", onUp);
444
+ }
445
+ /** First visible character of a note title, for its header chip. */
446
+ function noteInitial(title) {
447
+ const trimmed = title.trim();
448
+ if (trimmed === "") return "·";
449
+ return Array.from(trimmed)[0] ?? "·";
450
+ }
451
+ /** Default geometry of a new note; later notes cascade so they don't stack. */
452
+ const NOTE_DEFAULT_SIZE = 220;
453
+ const NOTE_MIN_WIDTH = 150;
454
+ const NOTE_MIN_HEIGHT = 70;
364
455
  /** Persisted panel placement so a dragged position survives reloads. */
365
456
  const PANEL_POS_KEY = "dsh-token-quota:panel-pos";
366
457
  function loadPanelPos() {
@@ -377,13 +468,130 @@ window.__ModuleLoader__.load({
377
468
  * @param props - composed slot props.
378
469
  * @returns the panel element tree.
379
470
  */
380
- function TokenQuotaPanel({ t, load, setLimit, selectModel, setMonitored, setOnFull, setReset, setCheckUpdates, checkUpdatesNow, clearLogBefore, setDimWhenIdle, setMusicEnabled, setMusicVolume, setMusicStyle, setMusicOnlyCurrentSession, useStore, actions, useSessions }) {
471
+ function TokenQuotaPanel({ t, load, setLimit, selectModel, setMonitored, setOnFull, setReset, setCheckUpdates, checkUpdatesNow, clearLogBefore, setDimWhenIdle, setModelOrder, saveNotes, setMusicEnabled, setMusicVolume, setMusicStyle, setMusicOnlyCurrentSession, useStore, actions, useSessions }) {
381
472
  const [collapsed, setCollapsed] = (0, react.useState)(false);
382
473
  const [drafts, setDrafts] = (0, react.useState)({});
383
474
  const [editingKey, setEditingKey] = (0, react.useState)(null);
384
475
  const [hovered, setHovered] = (0, react.useState)(false);
385
476
  const [inputActive, setInputActive] = (0, react.useState)(false);
386
477
  const [settingsTab, setSettingsTab] = (0, react.useState)("quota");
478
+ const [dragKey, setDragKey] = (0, react.useState)(null);
479
+ const [dropKey, setDropKey] = (0, react.useState)(null);
480
+ const storedNotes = useStore((s) => s.notes);
481
+ const storedNotesLoaded = useStore((s) => s.notesLoaded);
482
+ const [notes, setNotes] = (0, react.useState)([]);
483
+ const notesSeeded = (0, react.useRef)(false);
484
+ const notesTimer = (0, react.useRef)(null);
485
+ const notesPending = (0, react.useRef)(null);
486
+ const [noteMenu, setNoteMenu] = (0, react.useState)(null);
487
+ const [activeNote, setActiveNote] = (0, react.useState)(null);
488
+ (0, react.useEffect)(() => {
489
+ if (!storedNotesLoaded || notesSeeded.current) return;
490
+ notesSeeded.current = true;
491
+ setNotes(storedNotes);
492
+ }, [storedNotesLoaded, storedNotes]);
493
+ (0, react.useEffect)(() => () => {
494
+ if (notesTimer.current !== null) window.clearTimeout(notesTimer.current);
495
+ const pending = notesPending.current;
496
+ if (pending !== null) {
497
+ notesPending.current = null;
498
+ saveNotes(pending);
499
+ }
500
+ }, []);
501
+ /**
502
+ * Apply a note change locally and persist it. Structural changes (create,
503
+ * close, collapse, drop) write straight through; free-form edits (typing,
504
+ * dragging, resizing) are debounced so a keystroke doesn't hit the Host.
505
+ */
506
+ const commitNotes = (next, immediate = true) => {
507
+ setNotes(next);
508
+ if (notesTimer.current !== null) window.clearTimeout(notesTimer.current);
509
+ if (immediate) {
510
+ notesPending.current = null;
511
+ saveNotes(next);
512
+ return;
513
+ }
514
+ notesPending.current = next;
515
+ notesTimer.current = window.setTimeout(() => {
516
+ notesTimer.current = null;
517
+ const pending = notesPending.current;
518
+ notesPending.current = null;
519
+ if (pending !== null) saveNotes(pending);
520
+ }, 400);
521
+ };
522
+ const patchNote = (id, patch, immediate = true) => {
523
+ commitNotes(notes.map((note) => note.id === id ? {
524
+ ...note,
525
+ ...patch
526
+ } : note), immediate);
527
+ };
528
+ /** Create a note, auto-titled 新建N with the lowest unused number. */
529
+ const createNote = () => {
530
+ if (notes.length >= 5) return;
531
+ let index = 1;
532
+ const used = new Set(notes.map((note) => /^新建(\d+)$/.exec(note.title.trim())?.[1]).filter(Boolean));
533
+ while (used.has(String(index))) index += 1;
534
+ const step = notes.length * 28;
535
+ commitNotes([...notes, {
536
+ id: `note-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`,
537
+ title: `新建${index}`,
538
+ text: "",
539
+ x: 120 + step,
540
+ y: 140 + step,
541
+ width: NOTE_DEFAULT_SIZE,
542
+ height: NOTE_DEFAULT_SIZE,
543
+ collapsed: false,
544
+ visible: true
545
+ }]);
546
+ };
547
+ const closeNote = (id) => {
548
+ patchNote(id, { visible: false });
549
+ };
550
+ const removeNote = (id) => {
551
+ commitNotes(notes.filter((note) => note.id !== id));
552
+ setNoteMenu(null);
553
+ };
554
+ /**
555
+ * Title-bar drag with a click/drag threshold: moving the pointer past a few
556
+ * pixels drags the window, while a plain click focuses the title input for
557
+ * editing. A title that is already being edited keeps native text behaviour
558
+ * (selection, caret placement) instead of turning into a window drag.
559
+ */
560
+ const beginNoteBarDrag = (event, id) => {
561
+ const win = event.currentTarget.parentElement;
562
+ if (win === null) return;
563
+ if (event.target.closest("button") !== null) return;
564
+ const input = event.target.closest("input");
565
+ if (input !== null && document.activeElement === input) return;
566
+ event.preventDefault();
567
+ const startX = event.clientX;
568
+ const startY = event.clientY;
569
+ const rect = win.getBoundingClientRect();
570
+ let dragging = false;
571
+ const onMove = (ev) => {
572
+ if (!dragging) {
573
+ if (Math.abs(ev.clientX - startX) < 3 && Math.abs(ev.clientY - startY) < 3) return;
574
+ dragging = true;
575
+ const active = document.activeElement;
576
+ if (active instanceof HTMLElement) active.blur();
577
+ }
578
+ patchNote(id, {
579
+ x: Math.round(rect.left + (ev.clientX - startX)),
580
+ y: Math.round(rect.top + (ev.clientY - startY))
581
+ }, false);
582
+ };
583
+ const onUp = () => {
584
+ window.removeEventListener("pointermove", onMove);
585
+ window.removeEventListener("pointerup", onUp);
586
+ window.removeEventListener("pointercancel", onUp);
587
+ if (dragging) return;
588
+ const title = win.querySelector("input");
589
+ if (title instanceof HTMLInputElement) title.focus();
590
+ };
591
+ window.addEventListener("pointermove", onMove);
592
+ window.addEventListener("pointerup", onUp);
593
+ window.addEventListener("pointercancel", onUp);
594
+ };
387
595
  const [copiedCmd, setCopiedCmd] = (0, react.useState)(null);
388
596
  const copyTimerRef = (0, react.useRef)(null);
389
597
  const [upgradeFlash, setUpgradeFlash] = (0, react.useState)(false);
@@ -409,6 +617,7 @@ window.__ModuleLoader__.load({
409
617
  const onFull = useStore((s) => s.onFull);
410
618
  const checkUpdates = useStore((s) => s.checkUpdates);
411
619
  const dimWhenIdle = useStore((s) => s.dimWhenIdle);
620
+ const order = useStore((s) => s.order);
412
621
  const musicEnabled = useStore((s) => s.musicEnabled);
413
622
  const musicVolume = useStore((s) => s.musicVolume);
414
623
  const musicStyle = useStore((s) => s.musicStyle);
@@ -464,15 +673,27 @@ window.__ModuleLoader__.load({
464
673
  if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
465
674
  };
466
675
  }, []);
467
- const rows = (0, react.useMemo)(() => mergeModelRows(groups, snapshot, current), [
676
+ const rows = (0, react.useMemo)(() => mergeModelRows(groups, snapshot, current, order), [
468
677
  groups,
469
678
  snapshot,
470
- current
679
+ current,
680
+ order
471
681
  ]);
472
- const allModels = (0, react.useMemo)(() => groups.flatMap((group) => group.models.map((model) => ({
473
- key: `${group.id}/${model.id}`,
474
- name: model.name
475
- }))).sort((a, b) => a.key.localeCompare(b.key)), [groups]);
682
+ const allModels = (0, react.useMemo)(() => {
683
+ const list = groups.flatMap((group) => group.models.map((model) => ({
684
+ key: `${group.id}/${model.id}`,
685
+ name: model.name
686
+ })));
687
+ const rank = new Map(order.map((key, index) => [key, index]));
688
+ return list.sort((left, right) => {
689
+ const leftRank = rank.get(left.key);
690
+ const rightRank = rank.get(right.key);
691
+ if (leftRank !== void 0 && rightRank !== void 0) return leftRank - rightRank;
692
+ if (leftRank !== void 0) return -1;
693
+ if (rightRank !== void 0) return 1;
694
+ return left.key.localeCompare(right.key);
695
+ });
696
+ }, [groups, order]);
476
697
  const isMonitoredKey = (key) => monitored === null || monitored.includes(key);
477
698
  const filteredLogEntries = (0, react.useMemo)(() => {
478
699
  if (log === null) return [];
@@ -568,22 +789,22 @@ window.__ModuleLoader__.load({
568
789
  };
569
790
  const visibleRows = rows.filter((row) => isMonitoredKey(row.key) || row.current);
570
791
  const panelDimClass = dimWhenIdle ? hovered || upgradeFlash ? "" : inputActive ? TokenQuotaPanel_module_css_default.panelDimStrong : TokenQuotaPanel_module_css_default.panelDim : "";
571
- return (0, react_jsx_runtime.jsxs)("div", {
572
- ref: panelRef,
573
- className: `${TokenQuotaPanel_module_css_default.panel}${panelDimClass !== "" ? ` ${panelDimClass}` : ""}`,
574
- style: panelPos !== null ? {
575
- left: panelPos.x,
576
- top: panelPos.y,
577
- right: "auto"
578
- } : void 0,
579
- onPointerEnter: () => {
580
- setHovered(true);
581
- },
582
- onPointerLeave: () => {
583
- setHovered(false);
584
- },
585
- children: [
586
- (0, react_jsx_runtime.jsxs)("div", {
792
+ return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
793
+ (0, react_jsx_runtime.jsxs)("div", {
794
+ ref: panelRef,
795
+ className: `${TokenQuotaPanel_module_css_default.panel}${panelDimClass !== "" ? ` ${panelDimClass}` : ""}`,
796
+ style: panelPos !== null ? {
797
+ left: panelPos.x,
798
+ top: panelPos.y,
799
+ right: "auto"
800
+ } : void 0,
801
+ onPointerEnter: () => {
802
+ setHovered(true);
803
+ },
804
+ onPointerLeave: () => {
805
+ setHovered(false);
806
+ },
807
+ children: [(0, react_jsx_runtime.jsxs)("div", {
587
808
  className: TokenQuotaPanel_module_css_default.header,
588
809
  onPointerDown: (event) => {
589
810
  beginDrag(event, panelRef.current, applyPanelPos);
@@ -597,17 +818,70 @@ window.__ModuleLoader__.load({
597
818
  title: t("upgradeAvailableHint"),
598
819
  children: [
599
820
  "v",
600
- "0.1.31",
821
+ "0.1.33",
601
822
  " → v",
602
823
  upgrade.latestVersion
603
824
  ]
604
825
  }) : (0, react_jsx_runtime.jsxs)("span", {
605
826
  className: TokenQuotaPanel_module_css_default.version,
606
- children: ["v", "0.1.31"]
827
+ children: ["v", "0.1.33"]
828
+ })]
829
+ }), (0, react_jsx_runtime.jsxs)("div", {
830
+ className: TokenQuotaPanel_module_css_default.notesBar,
831
+ onPointerDown: (event) => {
832
+ event.stopPropagation();
833
+ },
834
+ children: [notes.map((note) => {
835
+ const open = note.visible && !note.collapsed;
836
+ return (0, react_jsx_runtime.jsx)("button", {
837
+ type: "button",
838
+ className: `${TokenQuotaPanel_module_css_default.noteChip}${open ? ` ${TokenQuotaPanel_module_css_default.noteChipOpen}` : ""}`,
839
+ title: note.title.trim() === "" ? t("noteUntitled") : note.title,
840
+ onClick: () => {
841
+ patchNote(note.id, {
842
+ visible: true,
843
+ collapsed: false
844
+ });
845
+ },
846
+ onContextMenu: (event) => {
847
+ event.preventDefault();
848
+ setNoteMenu({
849
+ id: note.id,
850
+ x: event.clientX,
851
+ y: event.clientY
852
+ });
853
+ },
854
+ children: noteInitial(note.title)
855
+ }, note.id);
856
+ }), (0, react_jsx_runtime.jsxs)("button", {
857
+ type: "button",
858
+ className: TokenQuotaPanel_module_css_default.noteNew,
859
+ disabled: notes.length >= 5,
860
+ title: notes.length >= 5 ? t("noteMaxHint") : t("noteNewHint"),
861
+ onClick: createNote,
862
+ children: [(0, react_jsx_runtime.jsxs)("svg", {
863
+ viewBox: "0 0 16 16",
864
+ width: "13",
865
+ height: "13",
866
+ "aria-hidden": "true",
867
+ children: [(0, react_jsx_runtime.jsx)("path", {
868
+ d: "M4 1.6h4.6L12.4 5.4v9H4z",
869
+ fill: "none",
870
+ stroke: "currentColor",
871
+ strokeWidth: "1.2",
872
+ strokeLinejoin: "round"
873
+ }), (0, react_jsx_runtime.jsx)("path", {
874
+ d: "M8.4 1.6v3.9h4",
875
+ fill: "none",
876
+ stroke: "currentColor",
877
+ strokeWidth: "1.2",
878
+ strokeLinejoin: "round"
879
+ })]
880
+ }), (0, react_jsx_runtime.jsx)("span", {
881
+ className: TokenQuotaPanel_module_css_default.noteNewPlus,
882
+ children: "+"
883
+ })]
607
884
  })]
608
- }), (0, react_jsx_runtime.jsx)("div", {
609
- className: TokenQuotaPanel_module_css_default.subtitle,
610
- children: t("subtitle")
611
885
  })]
612
886
  }), (0, react_jsx_runtime.jsxs)("div", {
613
887
  className: TokenQuotaPanel_module_css_default.headerActions,
@@ -649,8 +923,7 @@ window.__ModuleLoader__.load({
649
923
  })
650
924
  ]
651
925
  })]
652
- }),
653
- (0, react_jsx_runtime.jsxs)("div", {
926
+ }), (0, react_jsx_runtime.jsxs)("div", {
654
927
  className: TokenQuotaPanel_module_css_default.body,
655
928
  children: [
656
929
  loading && (0, react_jsx_runtime.jsx)("div", {
@@ -716,40 +989,69 @@ window.__ModuleLoader__.load({
716
989
  const barClass = state === "over" ? TokenQuotaPanel_module_css_default.fillOver : state === "warn" ? TokenQuotaPanel_module_css_default.fillWarn : TokenQuotaPanel_module_css_default.fillIdle;
717
990
  const editing = editingKey === row.key;
718
991
  return (0, react_jsx_runtime.jsxs)("div", {
719
- className: TokenQuotaPanel_module_css_default.row,
992
+ className: `${TokenQuotaPanel_module_css_default.row}${dragKey === row.key ? ` ${TokenQuotaPanel_module_css_default.rowDragging}` : ""}${dropKey === row.key && dragKey !== row.key ? ` ${TokenQuotaPanel_module_css_default.rowDropTarget}` : ""}`,
993
+ onDragOver: (event) => {
994
+ if (dragKey === null || dragKey === row.key) return;
995
+ event.preventDefault();
996
+ setDropKey(row.key);
997
+ },
998
+ onDrop: (event) => {
999
+ event.preventDefault();
1000
+ if (dragKey !== null && dragKey !== row.key) setModelOrder(reorderKeys(rows.map((r) => r.key), dragKey, row.key));
1001
+ setDragKey(null);
1002
+ setDropKey(null);
1003
+ },
1004
+ onDragEnd: () => {
1005
+ setDragKey(null);
1006
+ setDropKey(null);
1007
+ },
720
1008
  children: [
721
1009
  (0, react_jsx_runtime.jsxs)("div", {
722
1010
  className: TokenQuotaPanel_module_css_default.rowHeader,
723
- children: [(0, react_jsx_runtime.jsxs)("span", {
724
- className: TokenQuotaPanel_module_css_default.rowName,
725
- title: row.key,
726
- children: [
727
- row.name,
728
- row.current && (0, react_jsx_runtime.jsx)("span", {
729
- className: TokenQuotaPanel_module_css_default.currentBadge,
730
- children: t("current")
731
- }),
732
- sessionId !== void 0 && !row.current && (0, react_jsx_runtime.jsx)("button", {
1011
+ children: [
1012
+ (0, react_jsx_runtime.jsx)("span", {
1013
+ className: TokenQuotaPanel_module_css_default.rowDrag,
1014
+ draggable: true,
1015
+ title: t("reorderHint"),
1016
+ onDragStart: (event) => {
1017
+ setDragKey(row.key);
1018
+ event.dataTransfer.effectAllowed = "move";
1019
+ event.dataTransfer.setData("text/plain", row.key);
1020
+ },
1021
+ children: "⠿"
1022
+ }),
1023
+ (0, react_jsx_runtime.jsxs)("span", {
1024
+ className: TokenQuotaPanel_module_css_default.rowName,
1025
+ title: row.key,
1026
+ children: [
1027
+ row.name,
1028
+ row.current && (0, react_jsx_runtime.jsx)("span", {
1029
+ className: TokenQuotaPanel_module_css_default.currentBadge,
1030
+ children: t("current")
1031
+ }),
1032
+ sessionId !== void 0 && !row.current && (0, react_jsx_runtime.jsx)("button", {
1033
+ type: "button",
1034
+ className: TokenQuotaPanel_module_css_default.selectBtn,
1035
+ onClick: () => {
1036
+ selectModel(sessionId, row.provider, row.model);
1037
+ },
1038
+ children: t("select")
1039
+ })
1040
+ ]
1041
+ }),
1042
+ (0, react_jsx_runtime.jsxs)("span", {
1043
+ className: TokenQuotaPanel_module_css_default.rowMeta,
1044
+ children: [row.limit > 0 ? `${formatTokens(row.used)} / ${formatTokens(row.limit)}` : `${formatTokens(row.used)} · ${t("unlimited")}`, (0, react_jsx_runtime.jsx)("button", {
733
1045
  type: "button",
734
- className: TokenQuotaPanel_module_css_default.selectBtn,
1046
+ className: TokenQuotaPanel_module_css_default.gearBtn,
1047
+ title: t("setLimitHint"),
735
1048
  onClick: () => {
736
- selectModel(sessionId, row.provider, row.model);
1049
+ setEditingKey(editing ? null : row.key);
737
1050
  },
738
- children: t("select")
739
- })
740
- ]
741
- }), (0, react_jsx_runtime.jsxs)("span", {
742
- className: TokenQuotaPanel_module_css_default.rowMeta,
743
- children: [row.limit > 0 ? `${formatTokens(row.used)} / ${formatTokens(row.limit)}` : `${formatTokens(row.used)} · ${t("unlimited")}`, (0, react_jsx_runtime.jsx)("button", {
744
- type: "button",
745
- className: TokenQuotaPanel_module_css_default.gearBtn,
746
- title: t("setLimitHint"),
747
- onClick: () => {
748
- setEditingKey(editing ? null : row.key);
749
- },
750
- children: "⚙"
751
- })]
752
- })]
1051
+ children: "⚙"
1052
+ })]
1053
+ })
1054
+ ]
753
1055
  }),
754
1056
  (0, react_jsx_runtime.jsx)("div", {
755
1057
  className: TokenQuotaPanel_module_css_default.bar,
@@ -789,484 +1091,588 @@ window.__ModuleLoader__.load({
789
1091
  }, row.key);
790
1092
  })
791
1093
  ]
792
- }),
793
- dialogOpen && (0, react_jsx_runtime.jsxs)("div", {
794
- ref: settingsRef,
795
- className: `${TokenQuotaPanel_module_css_default.dialog} ${TokenQuotaPanel_module_css_default.settingsDialog}`,
796
- style: settingsPos !== null ? {
797
- left: settingsPos.x,
798
- top: settingsPos.y,
799
- transform: "none"
800
- } : void 0,
801
- children: [
802
- (0, react_jsx_runtime.jsxs)("div", {
803
- className: TokenQuotaPanel_module_css_default.dialogHeader,
1094
+ })]
1095
+ }),
1096
+ dialogOpen && (0, react_jsx_runtime.jsxs)("div", {
1097
+ ref: settingsRef,
1098
+ className: `${TokenQuotaPanel_module_css_default.dialog} ${TokenQuotaPanel_module_css_default.settingsDialog}`,
1099
+ style: settingsPos !== null ? {
1100
+ left: settingsPos.x,
1101
+ top: settingsPos.y,
1102
+ transform: "none"
1103
+ } : void 0,
1104
+ children: [
1105
+ (0, react_jsx_runtime.jsxs)("div", {
1106
+ className: TokenQuotaPanel_module_css_default.dialogHeader,
1107
+ onPointerDown: (event) => {
1108
+ beginDrag(event, settingsRef.current, setSettingsPos);
1109
+ },
1110
+ children: [(0, react_jsx_runtime.jsx)("div", {
1111
+ className: TokenQuotaPanel_module_css_default.dialogTitle,
1112
+ children: t("settingsTitle")
1113
+ }), (0, react_jsx_runtime.jsx)("button", {
1114
+ type: "button",
1115
+ className: TokenQuotaPanel_module_css_default.dialogClose,
1116
+ title: t("close"),
1117
+ onClick: () => {
1118
+ actions.setDialogOpen(false);
1119
+ },
804
1120
  onPointerDown: (event) => {
805
- beginDrag(event, settingsRef.current, setSettingsPos);
1121
+ event.stopPropagation();
806
1122
  },
807
- children: [(0, react_jsx_runtime.jsx)("div", {
808
- className: TokenQuotaPanel_module_css_default.dialogTitle,
809
- children: t("settingsTitle")
810
- }), (0, react_jsx_runtime.jsx)("button", {
1123
+ children: "×"
1124
+ })]
1125
+ }),
1126
+ (0, react_jsx_runtime.jsxs)("div", {
1127
+ className: TokenQuotaPanel_module_css_default.dialogTabs,
1128
+ role: "tablist",
1129
+ children: [
1130
+ (0, react_jsx_runtime.jsx)("button", {
811
1131
  type: "button",
812
- className: TokenQuotaPanel_module_css_default.dialogClose,
813
- title: t("close"),
1132
+ role: "tab",
1133
+ "aria-selected": settingsTab === "quota",
1134
+ className: `${TokenQuotaPanel_module_css_default.dialogTab}${settingsTab === "quota" ? ` ${TokenQuotaPanel_module_css_default.dialogTabActive}` : ""}`,
814
1135
  onClick: () => {
815
- actions.setDialogOpen(false);
1136
+ setSettingsTab("quota");
816
1137
  },
817
- onPointerDown: (event) => {
818
- event.stopPropagation();
1138
+ children: t("settingsTabQuota")
1139
+ }),
1140
+ (0, react_jsx_runtime.jsx)("button", {
1141
+ type: "button",
1142
+ role: "tab",
1143
+ "aria-selected": settingsTab === "music",
1144
+ className: `${TokenQuotaPanel_module_css_default.dialogTab}${settingsTab === "music" ? ` ${TokenQuotaPanel_module_css_default.dialogTabActive}` : ""}`,
1145
+ onClick: () => {
1146
+ setSettingsTab("music");
819
1147
  },
820
- children: "×"
821
- })]
822
- }),
823
- (0, react_jsx_runtime.jsxs)("div", {
824
- className: TokenQuotaPanel_module_css_default.dialogTabs,
825
- role: "tablist",
826
- children: [
827
- (0, react_jsx_runtime.jsx)("button", {
828
- type: "button",
829
- role: "tab",
830
- "aria-selected": settingsTab === "quota",
831
- className: `${TokenQuotaPanel_module_css_default.dialogTab}${settingsTab === "quota" ? ` ${TokenQuotaPanel_module_css_default.dialogTabActive}` : ""}`,
832
- onClick: () => {
833
- setSettingsTab("quota");
834
- },
835
- children: t("settingsTabQuota")
836
- }),
837
- (0, react_jsx_runtime.jsx)("button", {
838
- type: "button",
839
- role: "tab",
840
- "aria-selected": settingsTab === "music",
841
- className: `${TokenQuotaPanel_module_css_default.dialogTab}${settingsTab === "music" ? ` ${TokenQuotaPanel_module_css_default.dialogTabActive}` : ""}`,
842
- onClick: () => {
843
- setSettingsTab("music");
844
- },
845
- children: t("settingsTabMusic")
846
- }),
847
- (0, react_jsx_runtime.jsx)("button", {
848
- type: "button",
849
- role: "tab",
850
- "aria-selected": settingsTab === "other",
851
- className: `${TokenQuotaPanel_module_css_default.dialogTab}${settingsTab === "other" ? ` ${TokenQuotaPanel_module_css_default.dialogTabActive}` : ""}`,
852
- onClick: () => {
853
- setSettingsTab("other");
854
- },
855
- children: t("settingsTabOther")
856
- })
857
- ]
858
- }),
859
- settingsTab === "quota" && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
860
- className: TokenQuotaPanel_module_css_default.dialogSection,
861
- children: [
862
- (0, react_jsx_runtime.jsx)("div", {
863
- className: TokenQuotaPanel_module_css_default.dialogLabel,
864
- children: t("monitorLabel")
865
- }),
866
- (0, react_jsx_runtime.jsx)("div", {
867
- className: TokenQuotaPanel_module_css_default.monitorHint,
868
- children: t("monitorHint")
869
- }),
870
- (0, react_jsx_runtime.jsx)("div", {
871
- className: TokenQuotaPanel_module_css_default.monitorList,
872
- children: allModels.map((model) => (0, react_jsx_runtime.jsxs)("label", {
873
- className: TokenQuotaPanel_module_css_default.monitorRow,
874
- children: [(0, react_jsx_runtime.jsx)("input", {
875
- type: "checkbox",
876
- checked: monitored === null || monitored.includes(model.key),
877
- onChange: (event) => {
878
- const base = monitored === null ? allModels.map((m) => m.key) : monitored;
879
- const next = new Set(base);
880
- if (event.target.checked) next.add(model.key);
881
- else next.delete(model.key);
882
- setMonitored(next.size === allModels.length ? null : [...next]);
883
- }
884
- }), (0, react_jsx_runtime.jsx)("span", {
885
- className: TokenQuotaPanel_module_css_default.monitorName,
886
- title: model.key,
887
- children: model.name
888
- })]
889
- }, model.key))
890
- })
891
- ]
892
- }), (0, react_jsx_runtime.jsxs)("div", {
893
- className: TokenQuotaPanel_module_css_default.dialogSection,
894
- children: [(0, react_jsx_runtime.jsx)("div", {
1148
+ children: t("settingsTabMusic")
1149
+ }),
1150
+ (0, react_jsx_runtime.jsx)("button", {
1151
+ type: "button",
1152
+ role: "tab",
1153
+ "aria-selected": settingsTab === "other",
1154
+ className: `${TokenQuotaPanel_module_css_default.dialogTab}${settingsTab === "other" ? ` ${TokenQuotaPanel_module_css_default.dialogTabActive}` : ""}`,
1155
+ onClick: () => {
1156
+ setSettingsTab("other");
1157
+ },
1158
+ children: t("settingsTabOther")
1159
+ })
1160
+ ]
1161
+ }),
1162
+ settingsTab === "quota" && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
1163
+ className: TokenQuotaPanel_module_css_default.dialogSection,
1164
+ children: [
1165
+ (0, react_jsx_runtime.jsx)("div", {
895
1166
  className: TokenQuotaPanel_module_css_default.dialogLabel,
896
- children: t("fullActionLabel")
897
- }), FULL_ACTIONS.map((action) => (0, react_jsx_runtime.jsxs)("label", {
898
- className: TokenQuotaPanel_module_css_default.radioRow,
899
- children: [(0, react_jsx_runtime.jsx)("input", {
900
- type: "radio",
901
- name: "token-quota-onfull",
902
- checked: onFull === action.value,
903
- onChange: () => {
904
- setOnFull(action.value);
1167
+ children: t("monitorLabel")
1168
+ }),
1169
+ (0, react_jsx_runtime.jsx)("div", {
1170
+ className: TokenQuotaPanel_module_css_default.monitorHint,
1171
+ children: t("monitorHint")
1172
+ }),
1173
+ (0, react_jsx_runtime.jsx)("div", {
1174
+ className: TokenQuotaPanel_module_css_default.monitorList,
1175
+ children: allModels.map((model) => (0, react_jsx_runtime.jsxs)("label", {
1176
+ className: TokenQuotaPanel_module_css_default.monitorRow,
1177
+ children: [(0, react_jsx_runtime.jsx)("input", {
1178
+ type: "checkbox",
1179
+ checked: monitored === null || monitored.includes(model.key),
1180
+ onChange: (event) => {
1181
+ const base = monitored === null ? allModels.map((m) => m.key) : monitored;
1182
+ const next = new Set(base);
1183
+ if (event.target.checked) next.add(model.key);
1184
+ else next.delete(model.key);
1185
+ setMonitored(next.size === allModels.length ? null : [...next]);
1186
+ }
1187
+ }), (0, react_jsx_runtime.jsx)("span", {
1188
+ className: TokenQuotaPanel_module_css_default.monitorName,
1189
+ title: model.key,
1190
+ children: model.name
1191
+ })]
1192
+ }, model.key))
1193
+ })
1194
+ ]
1195
+ }), (0, react_jsx_runtime.jsxs)("div", {
1196
+ className: TokenQuotaPanel_module_css_default.dialogSection,
1197
+ children: [(0, react_jsx_runtime.jsx)("div", {
1198
+ className: TokenQuotaPanel_module_css_default.dialogLabel,
1199
+ children: t("fullActionLabel")
1200
+ }), FULL_ACTIONS.map((action) => (0, react_jsx_runtime.jsxs)("label", {
1201
+ className: TokenQuotaPanel_module_css_default.radioRow,
1202
+ children: [(0, react_jsx_runtime.jsx)("input", {
1203
+ type: "radio",
1204
+ name: "token-quota-onfull",
1205
+ checked: onFull === action.value,
1206
+ onChange: () => {
1207
+ setOnFull(action.value);
1208
+ }
1209
+ }), (0, react_jsx_runtime.jsx)("span", { children: t(action.labelKey) })]
1210
+ }, action.value))]
1211
+ })] }),
1212
+ settingsTab === "other" && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
1213
+ className: TokenQuotaPanel_module_css_default.dialogSection,
1214
+ children: [
1215
+ (0, react_jsx_runtime.jsx)("div", {
1216
+ className: TokenQuotaPanel_module_css_default.dialogLabel,
1217
+ children: t("resetLabel")
1218
+ }),
1219
+ (0, react_jsx_runtime.jsx)("div", {
1220
+ className: TokenQuotaPanel_module_css_default.monitorHint,
1221
+ children: t("resetHint")
1222
+ }),
1223
+ (0, react_jsx_runtime.jsxs)("div", {
1224
+ className: TokenQuotaPanel_module_css_default.resetRow,
1225
+ children: [
1226
+ (0, react_jsx_runtime.jsx)("select", {
1227
+ className: TokenQuotaPanel_module_css_default.resetSelect,
1228
+ value: reset?.offsetHours ?? -(/* @__PURE__ */ new Date()).getTimezoneOffset() / 60,
1229
+ onChange: (event) => {
1230
+ setReset({
1231
+ offsetHours: Number(event.target.value),
1232
+ hour: reset?.hour ?? 0,
1233
+ minute: reset?.minute ?? 0
1234
+ });
1235
+ },
1236
+ children: Array.from({ length: 27 }, (_, i) => i - 12).map((offset) => (0, react_jsx_runtime.jsxs)("option", {
1237
+ value: offset,
1238
+ children: ["UTC", offset >= 0 ? `+${offset}` : offset]
1239
+ }, offset))
1240
+ }),
1241
+ (0, react_jsx_runtime.jsx)("select", {
1242
+ className: TokenQuotaPanel_module_css_default.resetSelect,
1243
+ value: reset?.hour ?? 0,
1244
+ onChange: (event) => {
1245
+ setReset({
1246
+ offsetHours: reset?.offsetHours ?? -(/* @__PURE__ */ new Date()).getTimezoneOffset() / 60,
1247
+ hour: Number(event.target.value),
1248
+ minute: reset?.minute ?? 0
1249
+ });
1250
+ },
1251
+ children: Array.from({ length: 24 }, (_, i) => i).map((hour) => (0, react_jsx_runtime.jsxs)("option", {
1252
+ value: hour,
1253
+ children: [String(hour).padStart(2, "0"), " 时"]
1254
+ }, hour))
1255
+ }),
1256
+ (0, react_jsx_runtime.jsx)("select", {
1257
+ className: TokenQuotaPanel_module_css_default.resetSelect,
1258
+ value: reset?.minute ?? 0,
1259
+ onChange: (event) => {
1260
+ setReset({
1261
+ offsetHours: reset?.offsetHours ?? -(/* @__PURE__ */ new Date()).getTimezoneOffset() / 60,
1262
+ hour: reset?.hour ?? 0,
1263
+ minute: Number(event.target.value)
1264
+ });
1265
+ },
1266
+ children: Array.from({ length: 12 }, (_, i) => i * 5).map((minute) => (0, react_jsx_runtime.jsxs)("option", {
1267
+ value: minute,
1268
+ children: [String(minute).padStart(2, "0"), " 分"]
1269
+ }, minute))
1270
+ })
1271
+ ]
1272
+ })
1273
+ ]
1274
+ }), (0, react_jsx_runtime.jsxs)("div", {
1275
+ className: TokenQuotaPanel_module_css_default.dialogSection,
1276
+ children: [(0, react_jsx_runtime.jsxs)("label", {
1277
+ className: TokenQuotaPanel_module_css_default.checkUpdatesLabel,
1278
+ children: [(0, react_jsx_runtime.jsx)("input", {
1279
+ type: "checkbox",
1280
+ checked: dimWhenIdle,
1281
+ onChange: (event) => {
1282
+ setDimWhenIdle(event.target.checked);
1283
+ }
1284
+ }), (0, react_jsx_runtime.jsx)("span", { children: t("dimWhenIdleLabel") })]
1285
+ }), (0, react_jsx_runtime.jsx)("div", {
1286
+ className: TokenQuotaPanel_module_css_default.dialogHint,
1287
+ children: t("dimWhenIdleHint")
1288
+ })]
1289
+ })] }),
1290
+ settingsTab === "music" && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
1291
+ className: TokenQuotaPanel_module_css_default.dialogSection,
1292
+ children: [(0, react_jsx_runtime.jsxs)("label", {
1293
+ className: TokenQuotaPanel_module_css_default.checkUpdatesLabel,
1294
+ children: [(0, react_jsx_runtime.jsx)("input", {
1295
+ type: "checkbox",
1296
+ checked: musicEnabled,
1297
+ onChange: (event) => {
1298
+ setMusicEnabled(event.target.checked);
1299
+ }
1300
+ }), (0, react_jsx_runtime.jsx)("span", { children: t("musicLabel") })]
1301
+ }), (0, react_jsx_runtime.jsx)("div", {
1302
+ className: TokenQuotaPanel_module_css_default.dialogHint,
1303
+ children: t("musicHint")
1304
+ })]
1305
+ }), musicEnabled && (0, react_jsx_runtime.jsxs)("div", {
1306
+ className: TokenQuotaPanel_module_css_default.dialogSection,
1307
+ children: [
1308
+ (0, react_jsx_runtime.jsxs)("label", {
1309
+ className: TokenQuotaPanel_module_css_default.checkUpdatesLabel,
1310
+ children: [(0, react_jsx_runtime.jsx)("span", { children: t("musicVolume") }), (0, react_jsx_runtime.jsx)("input", {
1311
+ type: "range",
1312
+ min: 0,
1313
+ max: 1,
1314
+ step: .05,
1315
+ value: musicVolume,
1316
+ onChange: (event) => {
1317
+ setMusicVolume(Number(event.target.value));
905
1318
  }
906
- }), (0, react_jsx_runtime.jsx)("span", { children: t(action.labelKey) })]
907
- }, action.value))]
908
- })] }),
909
- settingsTab === "other" && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
910
- className: TokenQuotaPanel_module_css_default.dialogSection,
911
- children: [
912
- (0, react_jsx_runtime.jsx)("div", {
913
- className: TokenQuotaPanel_module_css_default.dialogLabel,
914
- children: t("resetLabel")
915
- }),
916
- (0, react_jsx_runtime.jsx)("div", {
917
- className: TokenQuotaPanel_module_css_default.monitorHint,
918
- children: t("resetHint")
919
- }),
920
- (0, react_jsx_runtime.jsxs)("div", {
921
- className: TokenQuotaPanel_module_css_default.resetRow,
1319
+ })]
1320
+ }),
1321
+ (0, react_jsx_runtime.jsxs)("label", {
1322
+ className: TokenQuotaPanel_module_css_default.checkUpdatesLabel,
1323
+ children: [(0, react_jsx_runtime.jsx)("span", { children: t("musicStyle") }), (0, react_jsx_runtime.jsxs)("select", {
1324
+ value: musicStyle,
1325
+ onChange: (event) => {
1326
+ setMusicStyle(event.target.value);
1327
+ },
922
1328
  children: [
923
- (0, react_jsx_runtime.jsx)("select", {
924
- className: TokenQuotaPanel_module_css_default.resetSelect,
925
- value: reset?.offsetHours ?? -(/* @__PURE__ */ new Date()).getTimezoneOffset() / 60,
926
- onChange: (event) => {
927
- setReset({
928
- offsetHours: Number(event.target.value),
929
- hour: reset?.hour ?? 0,
930
- minute: reset?.minute ?? 0
931
- });
932
- },
933
- children: Array.from({ length: 27 }, (_, i) => i - 12).map((offset) => (0, react_jsx_runtime.jsxs)("option", {
934
- value: offset,
935
- children: ["UTC", offset >= 0 ? `+${offset}` : offset]
936
- }, offset))
1329
+ (0, react_jsx_runtime.jsx)("option", {
1330
+ value: "major",
1331
+ children: t("musicStyleMajor")
937
1332
  }),
938
- (0, react_jsx_runtime.jsx)("select", {
939
- className: TokenQuotaPanel_module_css_default.resetSelect,
940
- value: reset?.hour ?? 0,
941
- onChange: (event) => {
942
- setReset({
943
- offsetHours: reset?.offsetHours ?? -(/* @__PURE__ */ new Date()).getTimezoneOffset() / 60,
944
- hour: Number(event.target.value),
945
- minute: reset?.minute ?? 0
946
- });
947
- },
948
- children: Array.from({ length: 24 }, (_, i) => i).map((hour) => (0, react_jsx_runtime.jsxs)("option", {
949
- value: hour,
950
- children: [String(hour).padStart(2, "0"), " 时"]
951
- }, hour))
1333
+ (0, react_jsx_runtime.jsx)("option", {
1334
+ value: "minor",
1335
+ children: t("musicStyleMinor")
952
1336
  }),
953
- (0, react_jsx_runtime.jsx)("select", {
954
- className: TokenQuotaPanel_module_css_default.resetSelect,
955
- value: reset?.minute ?? 0,
956
- onChange: (event) => {
957
- setReset({
958
- offsetHours: reset?.offsetHours ?? -(/* @__PURE__ */ new Date()).getTimezoneOffset() / 60,
959
- hour: reset?.hour ?? 0,
960
- minute: Number(event.target.value)
961
- });
962
- },
963
- children: Array.from({ length: 12 }, (_, i) => i * 5).map((minute) => (0, react_jsx_runtime.jsxs)("option", {
964
- value: minute,
965
- children: [String(minute).padStart(2, "0"), " 分"]
966
- }, minute))
1337
+ (0, react_jsx_runtime.jsx)("option", {
1338
+ value: "pentatonic",
1339
+ children: t("musicStylePentatonic")
967
1340
  })
968
1341
  ]
969
- })
970
- ]
971
- }), (0, react_jsx_runtime.jsxs)("div", {
972
- className: TokenQuotaPanel_module_css_default.dialogSection,
973
- children: [(0, react_jsx_runtime.jsxs)("label", {
1342
+ })]
1343
+ }),
1344
+ (0, react_jsx_runtime.jsxs)("label", {
974
1345
  className: TokenQuotaPanel_module_css_default.checkUpdatesLabel,
975
1346
  children: [(0, react_jsx_runtime.jsx)("input", {
976
1347
  type: "checkbox",
977
- checked: dimWhenIdle,
1348
+ checked: musicOnlyCurrentSession,
978
1349
  onChange: (event) => {
979
- setDimWhenIdle(event.target.checked);
1350
+ setMusicOnlyCurrentSession(event.target.checked);
980
1351
  }
981
- }), (0, react_jsx_runtime.jsx)("span", { children: t("dimWhenIdleLabel") })]
982
- }), (0, react_jsx_runtime.jsx)("div", {
1352
+ }), (0, react_jsx_runtime.jsx)("span", { children: t("musicOnlyCurrentSessionLabel") })]
1353
+ }),
1354
+ (0, react_jsx_runtime.jsx)("div", {
983
1355
  className: TokenQuotaPanel_module_css_default.dialogHint,
984
- children: t("dimWhenIdleHint")
985
- })]
986
- })] }),
987
- settingsTab === "music" && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
988
- className: TokenQuotaPanel_module_css_default.dialogSection,
1356
+ children: t("musicOnlyCurrentSessionHint")
1357
+ })
1358
+ ]
1359
+ })] }),
1360
+ settingsTab === "other" && (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: (0, react_jsx_runtime.jsxs)("div", {
1361
+ className: TokenQuotaPanel_module_css_default.dialogSection,
1362
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1363
+ className: TokenQuotaPanel_module_css_default.checkUpdatesRow,
989
1364
  children: [(0, react_jsx_runtime.jsxs)("label", {
990
1365
  className: TokenQuotaPanel_module_css_default.checkUpdatesLabel,
991
1366
  children: [(0, react_jsx_runtime.jsx)("input", {
992
1367
  type: "checkbox",
993
- checked: musicEnabled,
1368
+ checked: checkUpdates,
994
1369
  onChange: (event) => {
995
- setMusicEnabled(event.target.checked);
1370
+ setCheckUpdates(event.target.checked);
996
1371
  }
997
- }), (0, react_jsx_runtime.jsx)("span", { children: t("musicLabel") })]
998
- }), (0, react_jsx_runtime.jsx)("div", {
999
- className: TokenQuotaPanel_module_css_default.dialogHint,
1000
- children: t("musicHint")
1372
+ }), (0, react_jsx_runtime.jsx)("span", { children: t("checkUpdatesLabel") })]
1373
+ }), (0, react_jsx_runtime.jsx)("button", {
1374
+ type: "button",
1375
+ className: TokenQuotaPanel_module_css_default.checkBtn,
1376
+ disabled: checkingUpdates,
1377
+ onClick: checkUpdatesNow,
1378
+ children: checkingUpdates ? t("checkingUpdates") : lastCheckResult === "up-to-date" ? t("checkUpToDate") : lastCheckResult === "error" ? t("checkFailed") : t("checkUpdatesNow")
1001
1379
  })]
1002
- }), musicEnabled && (0, react_jsx_runtime.jsxs)("div", {
1003
- className: TokenQuotaPanel_module_css_default.dialogSection,
1004
- children: [
1005
- (0, react_jsx_runtime.jsxs)("label", {
1006
- className: TokenQuotaPanel_module_css_default.checkUpdatesLabel,
1007
- children: [(0, react_jsx_runtime.jsx)("span", { children: t("musicVolume") }), (0, react_jsx_runtime.jsx)("input", {
1008
- type: "range",
1009
- min: 0,
1010
- max: 1,
1011
- step: .05,
1012
- value: musicVolume,
1013
- onChange: (event) => {
1014
- setMusicVolume(Number(event.target.value));
1015
- }
1016
- })]
1017
- }),
1018
- (0, react_jsx_runtime.jsxs)("label", {
1019
- className: TokenQuotaPanel_module_css_default.checkUpdatesLabel,
1020
- children: [(0, react_jsx_runtime.jsx)("span", { children: t("musicStyle") }), (0, react_jsx_runtime.jsxs)("select", {
1021
- value: musicStyle,
1022
- onChange: (event) => {
1023
- setMusicStyle(event.target.value);
1024
- },
1025
- children: [
1026
- (0, react_jsx_runtime.jsx)("option", {
1027
- value: "major",
1028
- children: t("musicStyleMajor")
1029
- }),
1030
- (0, react_jsx_runtime.jsx)("option", {
1031
- value: "minor",
1032
- children: t("musicStyleMinor")
1033
- }),
1034
- (0, react_jsx_runtime.jsx)("option", {
1035
- value: "pentatonic",
1036
- children: t("musicStylePentatonic")
1037
- })
1038
- ]
1039
- })]
1040
- }),
1041
- (0, react_jsx_runtime.jsxs)("label", {
1042
- className: TokenQuotaPanel_module_css_default.checkUpdatesLabel,
1043
- children: [(0, react_jsx_runtime.jsx)("input", {
1044
- type: "checkbox",
1045
- checked: musicOnlyCurrentSession,
1046
- onChange: (event) => {
1047
- setMusicOnlyCurrentSession(event.target.checked);
1048
- }
1049
- }), (0, react_jsx_runtime.jsx)("span", { children: t("musicOnlyCurrentSessionLabel") })]
1050
- }),
1051
- (0, react_jsx_runtime.jsx)("div", {
1052
- className: TokenQuotaPanel_module_css_default.dialogHint,
1053
- children: t("musicOnlyCurrentSessionHint")
1054
- })
1055
- ]
1056
- })] }),
1057
- settingsTab === "other" && (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: (0, react_jsx_runtime.jsxs)("div", {
1058
- className: TokenQuotaPanel_module_css_default.dialogSection,
1059
- children: [(0, react_jsx_runtime.jsxs)("div", {
1060
- className: TokenQuotaPanel_module_css_default.checkUpdatesRow,
1061
- children: [(0, react_jsx_runtime.jsxs)("label", {
1062
- className: TokenQuotaPanel_module_css_default.checkUpdatesLabel,
1063
- children: [(0, react_jsx_runtime.jsx)("input", {
1064
- type: "checkbox",
1065
- checked: checkUpdates,
1066
- onChange: (event) => {
1067
- setCheckUpdates(event.target.checked);
1068
- }
1069
- }), (0, react_jsx_runtime.jsx)("span", { children: t("checkUpdatesLabel") })]
1380
+ }), lastCheckResult === "error" && upgradeError !== null && (0, react_jsx_runtime.jsx)("div", {
1381
+ className: TokenQuotaPanel_module_css_default.checkErrorHint,
1382
+ role: "alert",
1383
+ children: upgradeError
1384
+ })]
1385
+ }) })
1386
+ ]
1387
+ }),
1388
+ logOpen && (0, react_jsx_runtime.jsxs)("div", {
1389
+ ref: logRef,
1390
+ className: `${TokenQuotaPanel_module_css_default.dialog} ${TokenQuotaPanel_module_css_default.logDialog}`,
1391
+ style: logPos !== null ? {
1392
+ left: logPos.x,
1393
+ top: logPos.y,
1394
+ transform: "none"
1395
+ } : void 0,
1396
+ children: [
1397
+ (0, react_jsx_runtime.jsxs)("div", {
1398
+ className: TokenQuotaPanel_module_css_default.logHeader,
1399
+ onPointerDown: (event) => {
1400
+ beginDrag(event, logRef.current, setLogPos);
1401
+ },
1402
+ children: [
1403
+ (0, react_jsx_runtime.jsx)("div", {
1404
+ className: TokenQuotaPanel_module_css_default.dialogTitle,
1405
+ children: t("logsTitle")
1406
+ }),
1407
+ (0, react_jsx_runtime.jsxs)("div", {
1408
+ className: TokenQuotaPanel_module_css_default.logToolbar,
1409
+ onPointerDown: (event) => {
1410
+ event.stopPropagation();
1411
+ },
1412
+ children: [(0, react_jsx_runtime.jsx)("input", {
1413
+ type: "search",
1414
+ className: TokenQuotaPanel_module_css_default.logSearch,
1415
+ placeholder: t("logSearchPlaceholder"),
1416
+ value: logSearch,
1417
+ onChange: (event) => {
1418
+ actions.setLogSearch(event.target.value);
1419
+ }
1070
1420
  }), (0, react_jsx_runtime.jsx)("button", {
1071
1421
  type: "button",
1072
- className: TokenQuotaPanel_module_css_default.checkBtn,
1073
- disabled: checkingUpdates,
1074
- onClick: checkUpdatesNow,
1075
- children: checkingUpdates ? t("checkingUpdates") : lastCheckResult === "up-to-date" ? t("checkUpToDate") : lastCheckResult === "error" ? t("checkFailed") : t("checkUpdatesNow")
1422
+ className: TokenQuotaPanel_module_css_default.logClearBtn,
1423
+ onClick: () => {
1424
+ actions.setLogClearOpen(true);
1425
+ },
1426
+ children: t("logClear")
1076
1427
  })]
1077
- }), lastCheckResult === "error" && upgradeError !== null && (0, react_jsx_runtime.jsx)("div", {
1078
- className: TokenQuotaPanel_module_css_default.checkErrorHint,
1079
- role: "alert",
1080
- children: upgradeError
1081
- })]
1082
- }) })
1083
- ]
1084
- }),
1085
- logOpen && (0, react_jsx_runtime.jsxs)("div", {
1086
- ref: logRef,
1087
- className: `${TokenQuotaPanel_module_css_default.dialog} ${TokenQuotaPanel_module_css_default.logDialog}`,
1088
- style: logPos !== null ? {
1089
- left: logPos.x,
1090
- top: logPos.y,
1091
- transform: "none"
1092
- } : void 0,
1093
- children: [
1094
- (0, react_jsx_runtime.jsxs)("div", {
1095
- className: TokenQuotaPanel_module_css_default.logHeader,
1096
- onPointerDown: (event) => {
1097
- beginDrag(event, logRef.current, setLogPos);
1098
- },
1099
- children: [
1100
- (0, react_jsx_runtime.jsx)("div", {
1101
- className: TokenQuotaPanel_module_css_default.dialogTitle,
1102
- children: t("logsTitle")
1428
+ }),
1429
+ (0, react_jsx_runtime.jsx)("button", {
1430
+ type: "button",
1431
+ className: TokenQuotaPanel_module_css_default.dialogClose,
1432
+ title: t("close"),
1433
+ onClick: () => {
1434
+ actions.setLogOpen(false);
1435
+ },
1436
+ children: "×"
1437
+ })
1438
+ ]
1439
+ }),
1440
+ log !== null && filteredLogEntries.length === 0 && (0, react_jsx_runtime.jsx)("div", {
1441
+ className: TokenQuotaPanel_module_css_default.notice,
1442
+ children: logSearch.trim() !== "" ? t("logNoMatch") : t("logEmpty")
1443
+ }),
1444
+ (0, react_jsx_runtime.jsx)("div", {
1445
+ className: TokenQuotaPanel_module_css_default.logScroll,
1446
+ children: (0, react_jsx_runtime.jsxs)("table", {
1447
+ className: TokenQuotaPanel_module_css_default.logTable,
1448
+ children: [(0, react_jsx_runtime.jsx)("thead", { children: (0, react_jsx_runtime.jsxs)("tr", { children: [
1449
+ (0, react_jsx_runtime.jsx)("th", { children: t("logDay") }),
1450
+ (0, react_jsx_runtime.jsx)("th", { children: t("logModel") }),
1451
+ (0, react_jsx_runtime.jsx)("th", {
1452
+ className: TokenQuotaPanel_module_css_default.logUsedCol,
1453
+ children: t("logUsed")
1454
+ })
1455
+ ] }) }), (0, react_jsx_runtime.jsx)("tbody", { children: logPageEntries.map((entry) => (0, react_jsx_runtime.jsxs)("tr", { children: [
1456
+ (0, react_jsx_runtime.jsx)("td", {
1457
+ className: TokenQuotaPanel_module_css_default.logDayCol,
1458
+ children: entry.day
1103
1459
  }),
1104
- (0, react_jsx_runtime.jsxs)("div", {
1105
- className: TokenQuotaPanel_module_css_default.logToolbar,
1106
- onPointerDown: (event) => {
1107
- event.stopPropagation();
1460
+ (0, react_jsx_runtime.jsx)("td", {
1461
+ className: TokenQuotaPanel_module_css_default.logModelCol,
1462
+ title: entry.key,
1463
+ children: entry.key
1464
+ }),
1465
+ (0, react_jsx_runtime.jsx)("td", {
1466
+ className: TokenQuotaPanel_module_css_default.logUsedCol,
1467
+ children: formatTokens(entry.used)
1468
+ })
1469
+ ] }, `${entry.day}/${entry.key}`)) })]
1470
+ })
1471
+ }),
1472
+ (0, react_jsx_runtime.jsxs)("div", {
1473
+ className: TokenQuotaPanel_module_css_default.logPager,
1474
+ children: [(0, react_jsx_runtime.jsx)("span", {
1475
+ className: TokenQuotaPanel_module_css_default.logPagerInfo,
1476
+ children: t("logPagerInfo").replace("{from}", String(logCurrentPage * logPageSize + 1)).replace("{to}", String(Math.min((logCurrentPage + 1) * logPageSize, filteredLogEntries.length))).replace("{total}", String(filteredLogEntries.length))
1477
+ }), (0, react_jsx_runtime.jsxs)("div", {
1478
+ className: TokenQuotaPanel_module_css_default.logPagerControls,
1479
+ children: [
1480
+ (0, react_jsx_runtime.jsx)("button", {
1481
+ type: "button",
1482
+ className: TokenQuotaPanel_module_css_default.logPagerBtn,
1483
+ disabled: logCurrentPage <= 0,
1484
+ onClick: () => {
1485
+ actions.setLogPage(logCurrentPage - 1);
1108
1486
  },
1109
- children: [(0, react_jsx_runtime.jsx)("input", {
1110
- type: "search",
1111
- className: TokenQuotaPanel_module_css_default.logSearch,
1112
- placeholder: t("logSearchPlaceholder"),
1113
- value: logSearch,
1114
- onChange: (event) => {
1115
- actions.setLogSearch(event.target.value);
1116
- }
1117
- }), (0, react_jsx_runtime.jsx)("button", {
1118
- type: "button",
1119
- className: TokenQuotaPanel_module_css_default.logClearBtn,
1120
- onClick: () => {
1121
- actions.setLogClearOpen(true);
1122
- },
1123
- children: t("logClear")
1124
- })]
1487
+ children: "‹"
1488
+ }),
1489
+ (0, react_jsx_runtime.jsxs)("span", {
1490
+ className: TokenQuotaPanel_module_css_default.logPagerPages,
1491
+ children: [
1492
+ logCurrentPage + 1,
1493
+ " / ",
1494
+ logTotalPages
1495
+ ]
1125
1496
  }),
1126
1497
  (0, react_jsx_runtime.jsx)("button", {
1127
1498
  type: "button",
1128
- className: TokenQuotaPanel_module_css_default.dialogClose,
1129
- title: t("close"),
1499
+ className: TokenQuotaPanel_module_css_default.logPagerBtn,
1500
+ disabled: logCurrentPage >= logTotalPages - 1,
1130
1501
  onClick: () => {
1131
- actions.setLogOpen(false);
1502
+ actions.setLogPage(logCurrentPage + 1);
1132
1503
  },
1133
- children: "×"
1504
+ children: "›"
1505
+ }),
1506
+ (0, react_jsx_runtime.jsx)("select", {
1507
+ className: TokenQuotaPanel_module_css_default.logPageSizeSelect,
1508
+ value: logPageSize,
1509
+ onChange: (event) => {
1510
+ actions.setLogPageSize(Number(event.target.value));
1511
+ },
1512
+ children: [
1513
+ 10,
1514
+ 15,
1515
+ 20,
1516
+ 50,
1517
+ 100
1518
+ ].map((size) => (0, react_jsx_runtime.jsxs)("option", {
1519
+ value: size,
1520
+ children: [size, t("logPerPage")]
1521
+ }, size))
1134
1522
  })
1135
1523
  ]
1136
- }),
1137
- log !== null && filteredLogEntries.length === 0 && (0, react_jsx_runtime.jsx)("div", {
1138
- className: TokenQuotaPanel_module_css_default.notice,
1139
- children: logSearch.trim() !== "" ? t("logNoMatch") : t("logEmpty")
1524
+ })]
1525
+ })
1526
+ ]
1527
+ }),
1528
+ logClearOpen && (0, react_jsx_runtime.jsx)("div", {
1529
+ className: TokenQuotaPanel_module_css_default.dialogOverlay,
1530
+ children: (0, react_jsx_runtime.jsxs)("div", {
1531
+ className: `${TokenQuotaPanel_module_css_default.dialog} ${TokenQuotaPanel_module_css_default.logClearDialog}`,
1532
+ children: [
1533
+ (0, react_jsx_runtime.jsx)("div", {
1534
+ className: TokenQuotaPanel_module_css_default.dialogTitle,
1535
+ children: t("logClearTitle")
1140
1536
  }),
1141
1537
  (0, react_jsx_runtime.jsx)("div", {
1142
- className: TokenQuotaPanel_module_css_default.logScroll,
1143
- children: (0, react_jsx_runtime.jsxs)("table", {
1144
- className: TokenQuotaPanel_module_css_default.logTable,
1145
- children: [(0, react_jsx_runtime.jsx)("thead", { children: (0, react_jsx_runtime.jsxs)("tr", { children: [
1146
- (0, react_jsx_runtime.jsx)("th", { children: t("logDay") }),
1147
- (0, react_jsx_runtime.jsx)("th", { children: t("logModel") }),
1148
- (0, react_jsx_runtime.jsx)("th", {
1149
- className: TokenQuotaPanel_module_css_default.logUsedCol,
1150
- children: t("logUsed")
1151
- })
1152
- ] }) }), (0, react_jsx_runtime.jsx)("tbody", { children: logPageEntries.map((entry) => (0, react_jsx_runtime.jsxs)("tr", { children: [
1153
- (0, react_jsx_runtime.jsx)("td", {
1154
- className: TokenQuotaPanel_module_css_default.logDayCol,
1155
- children: entry.day
1156
- }),
1157
- (0, react_jsx_runtime.jsx)("td", {
1158
- className: TokenQuotaPanel_module_css_default.logModelCol,
1159
- title: entry.key,
1160
- children: entry.key
1161
- }),
1162
- (0, react_jsx_runtime.jsx)("td", {
1163
- className: TokenQuotaPanel_module_css_default.logUsedCol,
1164
- children: formatTokens(entry.used)
1165
- })
1166
- ] }, `${entry.day}/${entry.key}`)) })]
1167
- })
1538
+ className: TokenQuotaPanel_module_css_default.dialogBody,
1539
+ children: t("logClearHint")
1540
+ }),
1541
+ (0, react_jsx_runtime.jsx)("input", {
1542
+ type: "date",
1543
+ className: TokenQuotaPanel_module_css_default.logClearDate,
1544
+ value: logClearBefore,
1545
+ onChange: (event) => {
1546
+ actions.setLogClearBefore(event.target.value);
1547
+ }
1168
1548
  }),
1169
1549
  (0, react_jsx_runtime.jsxs)("div", {
1170
- className: TokenQuotaPanel_module_css_default.logPager,
1171
- children: [(0, react_jsx_runtime.jsx)("span", {
1172
- className: TokenQuotaPanel_module_css_default.logPagerInfo,
1173
- children: t("logPagerInfo").replace("{from}", String(logCurrentPage * logPageSize + 1)).replace("{to}", String(Math.min((logCurrentPage + 1) * logPageSize, filteredLogEntries.length))).replace("{total}", String(filteredLogEntries.length))
1174
- }), (0, react_jsx_runtime.jsxs)("div", {
1175
- className: TokenQuotaPanel_module_css_default.logPagerControls,
1176
- children: [
1177
- (0, react_jsx_runtime.jsx)("button", {
1178
- type: "button",
1179
- className: TokenQuotaPanel_module_css_default.logPagerBtn,
1180
- disabled: logCurrentPage <= 0,
1181
- onClick: () => {
1182
- actions.setLogPage(logCurrentPage - 1);
1183
- },
1184
- children: "‹"
1185
- }),
1186
- (0, react_jsx_runtime.jsxs)("span", {
1187
- className: TokenQuotaPanel_module_css_default.logPagerPages,
1188
- children: [
1189
- logCurrentPage + 1,
1190
- " / ",
1191
- logTotalPages
1192
- ]
1193
- }),
1194
- (0, react_jsx_runtime.jsx)("button", {
1195
- type: "button",
1196
- className: TokenQuotaPanel_module_css_default.logPagerBtn,
1197
- disabled: logCurrentPage >= logTotalPages - 1,
1198
- onClick: () => {
1199
- actions.setLogPage(logCurrentPage + 1);
1200
- },
1201
- children: "›"
1202
- }),
1203
- (0, react_jsx_runtime.jsx)("select", {
1204
- className: TokenQuotaPanel_module_css_default.logPageSizeSelect,
1205
- value: logPageSize,
1206
- onChange: (event) => {
1207
- actions.setLogPageSize(Number(event.target.value));
1208
- },
1209
- children: [
1210
- 10,
1211
- 15,
1212
- 20,
1213
- 50,
1214
- 100
1215
- ].map((size) => (0, react_jsx_runtime.jsxs)("option", {
1216
- value: size,
1217
- children: [size, t("logPerPage")]
1218
- }, size))
1219
- })
1220
- ]
1550
+ className: TokenQuotaPanel_module_css_default.dialogActions,
1551
+ children: [(0, react_jsx_runtime.jsx)("button", {
1552
+ type: "button",
1553
+ className: TokenQuotaPanel_module_css_default.checkBtn,
1554
+ disabled: logClearBefore === "" || logClearing,
1555
+ onClick: () => {
1556
+ clearLogBefore(logClearBefore);
1557
+ },
1558
+ children: logClearing ? t("logClearing") : t("logClearConfirm")
1559
+ }), (0, react_jsx_runtime.jsx)("button", {
1560
+ type: "button",
1561
+ className: TokenQuotaPanel_module_css_default.checkBtn,
1562
+ onClick: () => {
1563
+ actions.setLogClearOpen(false);
1564
+ },
1565
+ children: t("logClearCancel")
1221
1566
  })]
1222
1567
  })
1223
1568
  ]
1224
- }),
1225
- logClearOpen && (0, react_jsx_runtime.jsx)("div", {
1226
- className: TokenQuotaPanel_module_css_default.dialogOverlay,
1227
- children: (0, react_jsx_runtime.jsxs)("div", {
1228
- className: `${TokenQuotaPanel_module_css_default.dialog} ${TokenQuotaPanel_module_css_default.logClearDialog}`,
1229
- children: [
1230
- (0, react_jsx_runtime.jsx)("div", {
1231
- className: TokenQuotaPanel_module_css_default.dialogTitle,
1232
- children: t("logClearTitle")
1233
- }),
1234
- (0, react_jsx_runtime.jsx)("div", {
1235
- className: TokenQuotaPanel_module_css_default.dialogBody,
1236
- children: t("logClearHint")
1237
- }),
1238
- (0, react_jsx_runtime.jsx)("input", {
1239
- type: "date",
1240
- className: TokenQuotaPanel_module_css_default.logClearDate,
1241
- value: logClearBefore,
1242
- onChange: (event) => {
1243
- actions.setLogClearBefore(event.target.value);
1244
- }
1245
- }),
1246
- (0, react_jsx_runtime.jsxs)("div", {
1247
- className: TokenQuotaPanel_module_css_default.dialogActions,
1248
- children: [(0, react_jsx_runtime.jsx)("button", {
1249
- type: "button",
1250
- className: TokenQuotaPanel_module_css_default.checkBtn,
1251
- disabled: logClearBefore === "" || logClearing,
1252
- onClick: () => {
1253
- clearLogBefore(logClearBefore);
1254
- },
1255
- children: logClearing ? t("logClearing") : t("logClearConfirm")
1256
- }), (0, react_jsx_runtime.jsx)("button", {
1257
- type: "button",
1258
- className: TokenQuotaPanel_module_css_default.checkBtn,
1259
- onClick: () => {
1260
- actions.setLogClearOpen(false);
1261
- },
1262
- children: t("logClearCancel")
1263
- })]
1264
- })
1265
- ]
1266
- })
1267
1569
  })
1268
- ]
1269
- });
1570
+ }),
1571
+ notes.filter((note) => note.visible).map((note) => (0, react_jsx_runtime.jsxs)("div", {
1572
+ className: `${TokenQuotaPanel_module_css_default.noteWin}${note.collapsed ? ` ${TokenQuotaPanel_module_css_default.noteWinCollapsed}` : ""}`,
1573
+ style: {
1574
+ left: `${note.x}px`,
1575
+ top: `${note.y}px`,
1576
+ width: `${note.width}px`,
1577
+ zIndex: activeNote === note.id ? 62 : 60,
1578
+ ...note.collapsed ? {} : { height: `${note.height}px` }
1579
+ },
1580
+ onPointerDown: () => {
1581
+ setActiveNote(note.id);
1582
+ },
1583
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1584
+ className: TokenQuotaPanel_module_css_default.noteWinBar,
1585
+ onPointerDown: (event) => {
1586
+ beginNoteBarDrag(event, note.id);
1587
+ },
1588
+ children: [
1589
+ (0, react_jsx_runtime.jsx)("span", {
1590
+ className: TokenQuotaPanel_module_css_default.noteWinGripBar,
1591
+ "aria-hidden": "true",
1592
+ children: "⠿"
1593
+ }),
1594
+ (0, react_jsx_runtime.jsx)("input", {
1595
+ className: TokenQuotaPanel_module_css_default.noteWinTitle,
1596
+ value: note.title,
1597
+ placeholder: t("noteUntitled"),
1598
+ title: t("noteRenameHint"),
1599
+ onChange: (event) => {
1600
+ patchNote(note.id, { title: event.target.value }, false);
1601
+ },
1602
+ onKeyDown: (event) => {
1603
+ if (event.key === "Enter") event.currentTarget.blur();
1604
+ }
1605
+ }),
1606
+ (0, react_jsx_runtime.jsx)("button", {
1607
+ type: "button",
1608
+ className: TokenQuotaPanel_module_css_default.noteWinBtn,
1609
+ title: note.collapsed ? t("noteExpand") : t("noteCollapse"),
1610
+ onClick: () => {
1611
+ patchNote(note.id, { collapsed: !note.collapsed });
1612
+ },
1613
+ children: note.collapsed ? "▸" : "▾"
1614
+ }),
1615
+ (0, react_jsx_runtime.jsx)("button", {
1616
+ type: "button",
1617
+ className: TokenQuotaPanel_module_css_default.noteWinBtn,
1618
+ title: t("noteCloseHint"),
1619
+ onClick: () => {
1620
+ closeNote(note.id);
1621
+ },
1622
+ children: "×"
1623
+ })
1624
+ ]
1625
+ }), !note.collapsed && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("textarea", {
1626
+ className: TokenQuotaPanel_module_css_default.noteWinText,
1627
+ value: note.text,
1628
+ placeholder: t("notePlaceholder"),
1629
+ spellCheck: false,
1630
+ onChange: (event) => {
1631
+ patchNote(note.id, { text: event.target.value }, false);
1632
+ }
1633
+ }), (0, react_jsx_runtime.jsx)("span", {
1634
+ className: TokenQuotaPanel_module_css_default.noteWinResize,
1635
+ title: t("noteResizeHint"),
1636
+ onPointerDown: (event) => {
1637
+ beginResize(event, event.currentTarget.parentElement, (size) => {
1638
+ patchNote(note.id, size, false);
1639
+ });
1640
+ }
1641
+ })] })]
1642
+ }, note.id)),
1643
+ noteMenu !== null && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
1644
+ className: TokenQuotaPanel_module_css_default.noteMenuBackdrop,
1645
+ onPointerDown: () => {
1646
+ setNoteMenu(null);
1647
+ },
1648
+ onContextMenu: (event) => {
1649
+ event.preventDefault();
1650
+ setNoteMenu(null);
1651
+ }
1652
+ }), (0, react_jsx_runtime.jsxs)("div", {
1653
+ className: TokenQuotaPanel_module_css_default.noteMenu,
1654
+ style: {
1655
+ left: `${noteMenu.x}px`,
1656
+ top: `${noteMenu.y}px`
1657
+ },
1658
+ children: [(0, react_jsx_runtime.jsx)("button", {
1659
+ type: "button",
1660
+ className: TokenQuotaPanel_module_css_default.noteMenuItem,
1661
+ onClick: () => {
1662
+ closeNote(noteMenu.id);
1663
+ setNoteMenu(null);
1664
+ },
1665
+ children: t("noteClose")
1666
+ }), (0, react_jsx_runtime.jsx)("button", {
1667
+ type: "button",
1668
+ className: TokenQuotaPanel_module_css_default.noteMenuItem,
1669
+ onClick: () => {
1670
+ removeNote(noteMenu.id);
1671
+ },
1672
+ children: t("noteDelete")
1673
+ })]
1674
+ })] })
1675
+ ] });
1270
1676
  }
1271
1677
  //#endregion
1272
1678
  //#region lib/types/client/music.js
@@ -1918,6 +2324,18 @@ window.__ModuleLoader__.load({
1918
2324
  settingsTabQuota: "限额设置",
1919
2325
  settingsTabMusic: "音乐设置",
1920
2326
  settingsTabOther: "其它",
2327
+ reorderHint: "拖动排序",
2328
+ noteNewHint: "新建笔记(最多 5 个)",
2329
+ noteMaxHint: "最多 5 个笔记",
2330
+ noteUntitled: "未命名",
2331
+ noteRenameHint: "点击可修改标题",
2332
+ noteCollapse: "收起",
2333
+ noteExpand: "展开",
2334
+ noteClose: "关闭(内容保留)",
2335
+ noteCloseHint: "关闭(内容保留,可从首字图标重新打开)",
2336
+ noteDelete: "删除笔记",
2337
+ noteResizeHint: "拖动改变大小",
2338
+ notePlaceholder: "在这里记录…",
1921
2339
  monitorLabel: "监控模型",
1922
2340
  monitorHint: "未勾选的模型不显示、不计入用量、不受限额限制",
1923
2341
  monitorAll: "全部",
@@ -1999,6 +2417,18 @@ window.__ModuleLoader__.load({
1999
2417
  settingsTabQuota: "Quota",
2000
2418
  settingsTabMusic: "Music",
2001
2419
  settingsTabOther: "Other",
2420
+ reorderHint: "Drag to reorder",
2421
+ noteNewHint: "New note (max 5)",
2422
+ noteMaxHint: "At most 5 notes",
2423
+ noteUntitled: "Untitled",
2424
+ noteRenameHint: "Click to rename",
2425
+ noteCollapse: "Collapse",
2426
+ noteExpand: "Expand",
2427
+ noteClose: "Close (keep content)",
2428
+ noteCloseHint: "Close but keep the content; reopen from its chip",
2429
+ noteDelete: "Delete note",
2430
+ noteResizeHint: "Drag to resize",
2431
+ notePlaceholder: "Write here…",
2002
2432
  monitorLabel: "Monitored models",
2003
2433
  monitorHint: "Unchecked models are hidden, not metered, and never capped",
2004
2434
  monitorAll: "All",
@@ -2135,6 +2565,28 @@ window.__ModuleLoader__.load({
2135
2565
  window.removeEventListener("pointerdown", autoStartMusic);
2136
2566
  window.removeEventListener("keydown", autoStartMusic);
2137
2567
  }, "token-quota-ui: music autostart gestures");
2568
+ /**
2569
+ * Coerce the persisted note array into complete notes: older documents may
2570
+ * lack fields added later, and a hand-edited file may hold junk. The cap is
2571
+ * enforced here too so a tampered document cannot grow past it.
2572
+ */
2573
+ const normalizeNotes = (raw) => {
2574
+ if (!Array.isArray(raw)) return [];
2575
+ return raw.slice(0, 5).flatMap((note) => {
2576
+ if (typeof note !== "object" || note === null || typeof note.id !== "string") return [];
2577
+ return [{
2578
+ id: note.id,
2579
+ title: typeof note.title === "string" ? note.title : "",
2580
+ text: typeof note.text === "string" ? note.text : "",
2581
+ x: typeof note.x === "number" ? note.x : 80,
2582
+ y: typeof note.y === "number" ? note.y : 80,
2583
+ width: typeof note.width === "number" ? note.width : 220,
2584
+ height: typeof note.height === "number" ? note.height : 220,
2585
+ collapsed: note.collapsed === true,
2586
+ visible: note.visible !== false
2587
+ }];
2588
+ });
2589
+ };
2138
2590
  /** Build a writable music-settings clone with defaults applied. */
2139
2591
  const musicDefaults = (raw) => ({
2140
2592
  enabled: raw?.enabled ?? false,
@@ -2250,6 +2702,8 @@ window.__ModuleLoader__.load({
2250
2702
  bound?.setSettings(lastMonitored, lastOnFull);
2251
2703
  bound?.setCheckUpdates(doc?.checkUpdates ?? true);
2252
2704
  bound?.setDimWhenIdle(doc?.dimWhenIdle ?? false);
2705
+ bound?.setOrder(Array.isArray(doc?.order) ? doc.order : []);
2706
+ bound?.setNotes(normalizeNotes(doc?.notes));
2253
2707
  bound?.setReset(lastReset);
2254
2708
  const musicSettings = musicDefaults(doc?.music);
2255
2709
  lastOnlyCurrentSession = musicSettings.onlyCurrentSession;
@@ -2330,6 +2784,15 @@ window.__ModuleLoader__.load({
2330
2784
  bound?.setDimWhenIdle(enabled);
2331
2785
  scope.set("dimWhenIdle", enabled);
2332
2786
  };
2787
+ /** Persist the drag-to-reorder display order of model rows. */
2788
+ const setModelOrder = (order) => {
2789
+ bound?.setOrder(order);
2790
+ scope.set("order", order);
2791
+ };
2792
+ /** Persist the floating scratchpad notes (content, title, placement). */
2793
+ const saveNotes = (notes) => {
2794
+ scope.set("notes", notes.slice(0, 5));
2795
+ };
2333
2796
  const setMusicEnabled = (enabled) => {
2334
2797
  const doc = scope.getSnapshot().value;
2335
2798
  const current = musicDefaults(doc?.music);
@@ -2442,7 +2905,9 @@ window.__ModuleLoader__.load({
2442
2905
  setMusicEnabled,
2443
2906
  setMusicVolume,
2444
2907
  setMusicStyle,
2445
- setMusicOnlyCurrentSession
2908
+ setMusicOnlyCurrentSession,
2909
+ setModelOrder,
2910
+ saveNotes
2446
2911
  };
2447
2912
  };
2448
2913
  ctx.slots.inject("shell.overlay", () => ctx.slots.register({