@iasiv5/dsh-quota-watch 0.0.13 → 0.0.15

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
@@ -88,7 +88,7 @@ var CARD_SELECTOR = "[data-dsh-quota-watch-card]";
88
88
  var FETCH_TIMEOUT_MS = 15e3;
89
89
  var COPY = {
90
90
  zh: {
91
- title: "\u5957\u9910\u76D1\u63A7",
91
+ title: "Token\u989D\u5EA6",
92
92
  openDetails: "\u67E5\u770B\u8BE6\u60C5",
93
93
  backToOverview: "\u8FD4\u56DE\u989D\u5EA6\u6982\u89C8",
94
94
  providerNames: { glm: "GLM", copilot: "Copilot" },
@@ -166,19 +166,20 @@ var STYLE_TEXT = `
166
166
  .dqw-stale-mark { flex: none; font-size: 9px; line-height: 14px; color: var(--dsw-alias-label-warning, #b46900); cursor: help; }
167
167
  .dqw-errtext { font-size: 10px; line-height: 14px; opacity: .7; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
168
168
  .dqw-rail-trigger { display: none; flex: none; align-items: center; justify-content: center; width: 36px; height: 36px; margin: 0; padding: 0; border: 0; border-radius: 50%; background: transparent; color: var(--dsw-alias-label-primary, inherit); cursor: pointer; transition: background-color .12s, color .12s; }
169
- .dqw-rail-trigger svg { display: block; width: 16px; height: 16px; }
169
+ .dqw-rail-trigger svg { display: block; width: 20px; height: 20px; }
170
170
  .dqw-rail-trigger:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,.12)); color: var(--dsw-alias-label-primary, inherit); }
171
171
  .dqw-rail-trigger:active:not(:disabled), .dqw-rail-trigger[aria-expanded="true"] { background: var(--dsw-alias-interactive-bg-active, rgba(128,128,128,.18)); color: var(--dsw-alias-label-primary, inherit); }
172
172
  .dqw-rail-trigger:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary, #5b8def); outline-offset: 2px; }
173
- [data-dsh-frame][data-sidebar-collapsed] [data-dsh-quota-watch-card] { display: flex; align-items: center; justify-content: center; width: 36px; margin: 0 0 12px; }
174
- [data-dsh-frame][data-sidebar-collapsed] [data-dsh-quota-watch-card] > .dqw-card { display: none; }
175
- [data-dsh-frame][data-sidebar-collapsed] [data-dsh-quota-watch-card] > .dqw-rail-trigger { display: inline-flex; }
173
+ [data-sidebar-collapsed] [data-dsh-quota-watch-card] { display: flex; align-items: center; justify-content: center; width: 36px; margin: 0 0 12px; }
174
+ [data-sidebar-collapsed] [data-dsh-quota-watch-card] > .dqw-card { display: none; }
175
+ [data-sidebar-collapsed] [data-dsh-quota-watch-card] > .dqw-rail-trigger { display: inline-flex; }
176
176
  .dqw-pop { position: fixed; z-index: 2147483000; min-width: 166px; max-width: 320px; padding: 10px 12px; border: 1px solid var(--dsw-alias-border-secondary, rgba(128,128,128,.35)); border-radius: 10px; background: var(--dsw-alias-bg-elevated, var(--dsw-alias-bg-base, #1f1f1f)); background: color-mix(in srgb, var(--dsw-alias-bg-base, #1f1f1f) 86%, transparent); -webkit-backdrop-filter: blur(14px) saturate(1.3); backdrop-filter: blur(14px) saturate(1.3); box-shadow: 0 8px 24px rgba(0,0,0,.25); color: var(--dsw-alias-label-primary, inherit); display: flex; flex-direction: column; gap: 8px; font: inherit; }
177
177
  @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { .dqw-pop { background: var(--dsw-alias-bg-elevated, var(--dsw-alias-bg-base, #1f1f1f)); } }
178
178
  .dqw-pop[hidden] { display: none; }
179
179
  .dqw-pop *, .dqw-pop *::before, .dqw-pop *::after { box-sizing: border-box; }
180
180
  .dqw-pop-title { margin: 0; font-size: 11px; font-weight: 600; line-height: 16px; }
181
- .dqw-pop-back { align-self: flex-start; margin: 0; padding: 3px 5px; border: 0; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, inherit); font: inherit; font-size: 10.5px; line-height: 14px; cursor: pointer; }
181
+ .dqw-pop-back { display: inline-flex; flex: none; align-items: center; justify-content: center; width: 28px; height: 28px; margin: 0; padding: 0; border: 0; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, inherit); cursor: pointer; }
182
+ .dqw-pop-back svg { display: block; width: 16px; height: 16px; }
182
183
  .dqw-pop-back:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,.12)); color: var(--dsw-alias-label-primary, inherit); }
183
184
  .dqw-overview-list { display: flex; flex-direction: column; gap: 2px; }
184
185
  .dqw-overview-row { display: flex; align-items: center; width: 100%; gap: 6px; margin: 0; padding: 5px 4px; border: 0; border-radius: 8px; background: transparent; color: inherit; font: inherit; text-align: left; cursor: pointer; }
@@ -229,10 +230,16 @@ function formatTime(value, locale) {
229
230
  if (typeof value !== "string" || value === "") return "";
230
231
  const date = new Date(value);
231
232
  if (Number.isNaN(date.getTime())) return "";
232
- return new Intl.DateTimeFormat(locale === "zh" ? "zh-CN" : "en-US", {
233
- dateStyle: "short",
234
- timeStyle: "short"
235
- }).format(date);
233
+ const dateLocale = locale === "zh" ? "zh-CN" : "en-US";
234
+ const dateParts = new Intl.DateTimeFormat(dateLocale, {
235
+ year: "numeric",
236
+ month: "2-digit",
237
+ day: "2-digit"
238
+ }).formatToParts(date);
239
+ const part = (type) => dateParts.find((item) => item.type === type)?.value ?? "";
240
+ const dateText = `${part("year")}/${part("month")}/${part("day")}`;
241
+ const timeText = new Intl.DateTimeFormat(dateLocale, { timeStyle: "short" }).format(date);
242
+ return `${dateText} ${timeText}`;
236
243
  }
237
244
  function text(doc, tag, className, value) {
238
245
  const node = doc.createElement(tag);
@@ -244,8 +251,8 @@ function quotaIcon(doc) {
244
251
  const namespace = "http://www.w3.org/2000/svg";
245
252
  const svg = doc.createElementNS(namespace, "svg");
246
253
  svg.setAttribute("viewBox", "0 0 24 24");
247
- svg.setAttribute("width", "16");
248
- svg.setAttribute("height", "16");
254
+ svg.setAttribute("width", "20");
255
+ svg.setAttribute("height", "20");
249
256
  svg.setAttribute("fill", "none");
250
257
  svg.setAttribute("stroke", "currentColor");
251
258
  svg.setAttribute("stroke-width", "1.7");
@@ -254,7 +261,7 @@ function quotaIcon(doc) {
254
261
  svg.setAttribute("aria-hidden", "true");
255
262
  svg.setAttribute("focusable", "false");
256
263
  const arc = doc.createElementNS(namespace, "path");
257
- arc.setAttribute("d", "M4 17a8 8 0 0 1 16 0");
264
+ arc.setAttribute("d", "M4 17a8 8 0 0 1 16 0H4");
258
265
  const needle = doc.createElementNS(namespace, "path");
259
266
  needle.setAttribute("d", "m12 17 3.2-5.2");
260
267
  const hub = doc.createElementNS(namespace, "circle");
@@ -266,6 +273,24 @@ function quotaIcon(doc) {
266
273
  svg.append(arc, needle, hub);
267
274
  return svg;
268
275
  }
276
+ function backIcon(doc) {
277
+ const namespace = "http://www.w3.org/2000/svg";
278
+ const svg = doc.createElementNS(namespace, "svg");
279
+ svg.setAttribute("viewBox", "0 0 16 16");
280
+ svg.setAttribute("width", "16");
281
+ svg.setAttribute("height", "16");
282
+ svg.setAttribute("fill", "none");
283
+ svg.setAttribute("stroke", "currentColor");
284
+ svg.setAttribute("stroke-width", "1.7");
285
+ svg.setAttribute("stroke-linecap", "round");
286
+ svg.setAttribute("stroke-linejoin", "round");
287
+ svg.setAttribute("aria-hidden", "true");
288
+ svg.setAttribute("focusable", "false");
289
+ const chevrons = doc.createElementNS(namespace, "path");
290
+ chevrons.setAttribute("d", "M11 4 7 8l4 4M7 4 3 8l4 4");
291
+ svg.append(chevrons);
292
+ return svg;
293
+ }
269
294
  function kvRow(doc, label, value) {
270
295
  const row = doc.createElement("div");
271
296
  row.className = "dqw-kv";
@@ -477,7 +502,8 @@ function mountQuotaCard({
477
502
  back.className = "dqw-pop-back";
478
503
  back.dataset.action = "back-to-overview";
479
504
  back.setAttribute("aria-label", copy.backToOverview);
480
- back.textContent = copy.backToOverview;
505
+ back.title = copy.backToOverview;
506
+ back.append(backIcon(doc));
481
507
  detail.append(back, text(doc, "p", "dqw-pop-title", copy.providerNames[key]));
482
508
  }
483
509
  if (provider?.status === "stale") {
@@ -678,9 +704,9 @@ function mountQuotaCard({
678
704
  if (!disposed) place();
679
705
  });
680
706
  };
681
- let sidebarCollapsed = Boolean(doc.querySelector("[data-dsh-frame][data-sidebar-collapsed]"));
707
+ let sidebarCollapsed = Boolean(doc.querySelector("[data-sidebar-collapsed]"));
682
708
  const syncSidebarMode = () => {
683
- const nextCollapsed = Boolean(doc.querySelector("[data-dsh-frame][data-sidebar-collapsed]"));
709
+ const nextCollapsed = Boolean(doc.querySelector("[data-sidebar-collapsed]"));
684
710
  if (nextCollapsed === sidebarCollapsed) return;
685
711
  sidebarCollapsed = nextCollapsed;
686
712
  if (openKey !== void 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iasiv5/dsh-quota-watch",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "description": "DSH Web sidebar monitor for GLM Coding Plan quotas and GitHub Copilot credits",
5
5
  "type": "module",
6
6
  "main": "./src/host.mjs",
package/src/client.mjs CHANGED
@@ -9,7 +9,7 @@ const FETCH_TIMEOUT_MS = 15_000
9
9
 
10
10
  const COPY = {
11
11
  zh: {
12
- title: '套餐监控',
12
+ title: 'Token额度',
13
13
  openDetails: '查看详情',
14
14
  backToOverview: '返回额度概览',
15
15
  providerNames: { glm: 'GLM', copilot: 'Copilot' },
@@ -88,19 +88,20 @@ const STYLE_TEXT = `
88
88
  .dqw-stale-mark { flex: none; font-size: 9px; line-height: 14px; color: var(--dsw-alias-label-warning, #b46900); cursor: help; }
89
89
  .dqw-errtext { font-size: 10px; line-height: 14px; opacity: .7; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
90
90
  .dqw-rail-trigger { display: none; flex: none; align-items: center; justify-content: center; width: 36px; height: 36px; margin: 0; padding: 0; border: 0; border-radius: 50%; background: transparent; color: var(--dsw-alias-label-primary, inherit); cursor: pointer; transition: background-color .12s, color .12s; }
91
- .dqw-rail-trigger svg { display: block; width: 16px; height: 16px; }
91
+ .dqw-rail-trigger svg { display: block; width: 20px; height: 20px; }
92
92
  .dqw-rail-trigger:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,.12)); color: var(--dsw-alias-label-primary, inherit); }
93
93
  .dqw-rail-trigger:active:not(:disabled), .dqw-rail-trigger[aria-expanded="true"] { background: var(--dsw-alias-interactive-bg-active, rgba(128,128,128,.18)); color: var(--dsw-alias-label-primary, inherit); }
94
94
  .dqw-rail-trigger:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary, #5b8def); outline-offset: 2px; }
95
- [data-dsh-frame][data-sidebar-collapsed] [data-dsh-quota-watch-card] { display: flex; align-items: center; justify-content: center; width: 36px; margin: 0 0 12px; }
96
- [data-dsh-frame][data-sidebar-collapsed] [data-dsh-quota-watch-card] > .dqw-card { display: none; }
97
- [data-dsh-frame][data-sidebar-collapsed] [data-dsh-quota-watch-card] > .dqw-rail-trigger { display: inline-flex; }
95
+ [data-sidebar-collapsed] [data-dsh-quota-watch-card] { display: flex; align-items: center; justify-content: center; width: 36px; margin: 0 0 12px; }
96
+ [data-sidebar-collapsed] [data-dsh-quota-watch-card] > .dqw-card { display: none; }
97
+ [data-sidebar-collapsed] [data-dsh-quota-watch-card] > .dqw-rail-trigger { display: inline-flex; }
98
98
  .dqw-pop { position: fixed; z-index: 2147483000; min-width: 166px; max-width: 320px; padding: 10px 12px; border: 1px solid var(--dsw-alias-border-secondary, rgba(128,128,128,.35)); border-radius: 10px; background: var(--dsw-alias-bg-elevated, var(--dsw-alias-bg-base, #1f1f1f)); background: color-mix(in srgb, var(--dsw-alias-bg-base, #1f1f1f) 86%, transparent); -webkit-backdrop-filter: blur(14px) saturate(1.3); backdrop-filter: blur(14px) saturate(1.3); box-shadow: 0 8px 24px rgba(0,0,0,.25); color: var(--dsw-alias-label-primary, inherit); display: flex; flex-direction: column; gap: 8px; font: inherit; }
99
99
  @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { .dqw-pop { background: var(--dsw-alias-bg-elevated, var(--dsw-alias-bg-base, #1f1f1f)); } }
100
100
  .dqw-pop[hidden] { display: none; }
101
101
  .dqw-pop *, .dqw-pop *::before, .dqw-pop *::after { box-sizing: border-box; }
102
102
  .dqw-pop-title { margin: 0; font-size: 11px; font-weight: 600; line-height: 16px; }
103
- .dqw-pop-back { align-self: flex-start; margin: 0; padding: 3px 5px; border: 0; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, inherit); font: inherit; font-size: 10.5px; line-height: 14px; cursor: pointer; }
103
+ .dqw-pop-back { display: inline-flex; flex: none; align-items: center; justify-content: center; width: 28px; height: 28px; margin: 0; padding: 0; border: 0; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, inherit); cursor: pointer; }
104
+ .dqw-pop-back svg { display: block; width: 16px; height: 16px; }
104
105
  .dqw-pop-back:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,.12)); color: var(--dsw-alias-label-primary, inherit); }
105
106
  .dqw-overview-list { display: flex; flex-direction: column; gap: 2px; }
106
107
  .dqw-overview-row { display: flex; align-items: center; width: 100%; gap: 6px; margin: 0; padding: 5px 4px; border: 0; border-radius: 8px; background: transparent; color: inherit; font: inherit; text-align: left; cursor: pointer; }
@@ -156,10 +157,16 @@ function formatTime(value, locale) {
156
157
  if (typeof value !== 'string' || value === '') return ''
157
158
  const date = new Date(value)
158
159
  if (Number.isNaN(date.getTime())) return ''
159
- return new Intl.DateTimeFormat(locale === 'zh' ? 'zh-CN' : 'en-US', {
160
- dateStyle: 'short',
161
- timeStyle: 'short',
162
- }).format(date)
160
+ const dateLocale = locale === 'zh' ? 'zh-CN' : 'en-US'
161
+ const dateParts = new Intl.DateTimeFormat(dateLocale, {
162
+ year: 'numeric',
163
+ month: '2-digit',
164
+ day: '2-digit',
165
+ }).formatToParts(date)
166
+ const part = (type) => dateParts.find((item) => item.type === type)?.value ?? ''
167
+ const dateText = `${part('year')}/${part('month')}/${part('day')}`
168
+ const timeText = new Intl.DateTimeFormat(dateLocale, { timeStyle: 'short' }).format(date)
169
+ return `${dateText} ${timeText}`
163
170
  }
164
171
 
165
172
  function text(doc, tag, className, value) {
@@ -173,8 +180,8 @@ function quotaIcon(doc) {
173
180
  const namespace = 'http://www.w3.org/2000/svg'
174
181
  const svg = doc.createElementNS(namespace, 'svg')
175
182
  svg.setAttribute('viewBox', '0 0 24 24')
176
- svg.setAttribute('width', '16')
177
- svg.setAttribute('height', '16')
183
+ svg.setAttribute('width', '20')
184
+ svg.setAttribute('height', '20')
178
185
  svg.setAttribute('fill', 'none')
179
186
  svg.setAttribute('stroke', 'currentColor')
180
187
  svg.setAttribute('stroke-width', '1.7')
@@ -183,7 +190,7 @@ function quotaIcon(doc) {
183
190
  svg.setAttribute('aria-hidden', 'true')
184
191
  svg.setAttribute('focusable', 'false')
185
192
  const arc = doc.createElementNS(namespace, 'path')
186
- arc.setAttribute('d', 'M4 17a8 8 0 0 1 16 0')
193
+ arc.setAttribute('d', 'M4 17a8 8 0 0 1 16 0H4')
187
194
  const needle = doc.createElementNS(namespace, 'path')
188
195
  needle.setAttribute('d', 'm12 17 3.2-5.2')
189
196
  const hub = doc.createElementNS(namespace, 'circle')
@@ -196,6 +203,25 @@ function quotaIcon(doc) {
196
203
  return svg
197
204
  }
198
205
 
206
+ function backIcon(doc) {
207
+ const namespace = 'http://www.w3.org/2000/svg'
208
+ const svg = doc.createElementNS(namespace, 'svg')
209
+ svg.setAttribute('viewBox', '0 0 16 16')
210
+ svg.setAttribute('width', '16')
211
+ svg.setAttribute('height', '16')
212
+ svg.setAttribute('fill', 'none')
213
+ svg.setAttribute('stroke', 'currentColor')
214
+ svg.setAttribute('stroke-width', '1.7')
215
+ svg.setAttribute('stroke-linecap', 'round')
216
+ svg.setAttribute('stroke-linejoin', 'round')
217
+ svg.setAttribute('aria-hidden', 'true')
218
+ svg.setAttribute('focusable', 'false')
219
+ const chevrons = doc.createElementNS(namespace, 'path')
220
+ chevrons.setAttribute('d', 'M11 4 7 8l4 4M7 4 3 8l4 4')
221
+ svg.append(chevrons)
222
+ return svg
223
+ }
224
+
199
225
  /** Aligned label/value line used by the simplified Copilot detail. */
200
226
  function kvRow(doc, label, value) {
201
227
  const row = doc.createElement('div')
@@ -426,7 +452,8 @@ export function mountQuotaCard({
426
452
  back.className = 'dqw-pop-back'
427
453
  back.dataset.action = 'back-to-overview'
428
454
  back.setAttribute('aria-label', copy.backToOverview)
429
- back.textContent = copy.backToOverview
455
+ back.title = copy.backToOverview
456
+ back.append(backIcon(doc))
430
457
  detail.append(back, text(doc, 'p', 'dqw-pop-title', copy.providerNames[key]))
431
458
  }
432
459
  if (provider?.status === 'stale') {
@@ -647,9 +674,9 @@ export function mountQuotaCard({
647
674
  })
648
675
  }
649
676
 
650
- let sidebarCollapsed = Boolean(doc.querySelector('[data-dsh-frame][data-sidebar-collapsed]'))
677
+ let sidebarCollapsed = Boolean(doc.querySelector('[data-sidebar-collapsed]'))
651
678
  const syncSidebarMode = () => {
652
- const nextCollapsed = Boolean(doc.querySelector('[data-dsh-frame][data-sidebar-collapsed]'))
679
+ const nextCollapsed = Boolean(doc.querySelector('[data-sidebar-collapsed]'))
653
680
  if (nextCollapsed === sidebarCollapsed) return
654
681
  sidebarCollapsed = nextCollapsed
655
682
  if (openKey !== undefined) {