@iasiv5/dsh-quota-watch 0.1.2 → 0.1.4

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
@@ -234,6 +234,13 @@ var STYLE_TEXT = `
234
234
  .dqw-chev { font-size: 9px; line-height: 14px; opacity: .6; flex: none; width: 10px; text-align: center; }
235
235
  .dqw-stale-mark { flex: none; font-size: 9px; line-height: 14px; color: var(--dsw-alias-label-warning, #b46900); cursor: help; }
236
236
  .dqw-errtext { font-size: 10px; line-height: 14px; opacity: .7; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
237
+ .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; }
238
+ .dqw-rail-trigger svg { display: block; width: 16px; height: 16px; }
239
+ .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); }
240
+ .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); }
241
+ .dqw-rail-trigger:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary, #5b8def); outline-offset: 2px; }
242
+ :host([data-dsh-quota-watch-sidebar-collapsed]) .dqw-card { display: none; }
243
+ :host([data-dsh-quota-watch-sidebar-collapsed]) .dqw-rail-trigger { display: inline-flex; }
237
244
  @media print { :host { display: none !important; } }
238
245
  `;
239
246
  var FLOAT_STYLE_TEXT = `
@@ -266,7 +273,8 @@ var FLOAT_STYLE_TEXT = `
266
273
  .dqw-panel-back:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,.12)); color: var(--dsw-alias-label-primary, inherit); }
267
274
  .dqw-panel-close { display: inline-flex; flex: none; align-items: center; justify-content: center; width: 24px; height: 24px; margin: 0; padding: 0; border: 0; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, inherit); cursor: pointer; font: inherit; font-size: 12px; line-height: 1; }
268
275
  .dqw-panel-close:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,.12)); color: var(--dsw-alias-label-primary, inherit); }
269
- .dqw-overview-list { display: flex; flex-direction: column; gap: 2px; max-width: 240px; }
276
+ .dqw-overview-list { display: flex; flex-direction: column; gap: 2px; }
277
+ .dqw-bar { background: var(--dsw-alias-bg-tertiary, rgba(128,128,128,.38)); }
270
278
  .dqw-row-summary { display: flex; align-items: center; gap: 6px; padding: 3px 6px; margin: 0 -2px; border-radius: 8px; }
271
279
  .dqw-row-summary[data-expandable] { cursor: pointer; }
272
280
  .dqw-row-summary[data-expandable]:hover { background: var(--dsw-alias-bg-hover, rgba(128,128,128,.12)); }
@@ -345,6 +353,36 @@ function text(doc, tag, className, value) {
345
353
  node.textContent = String(value ?? "");
346
354
  return node;
347
355
  }
356
+ function quotaIcon(doc) {
357
+ const namespace = "http://www.w3.org/2000/svg";
358
+ const svg = doc.createElementNS(namespace, "svg");
359
+ svg.setAttribute("viewBox", "0 0 24 24");
360
+ svg.setAttribute("width", "16");
361
+ svg.setAttribute("height", "16");
362
+ svg.setAttribute("fill", "none");
363
+ svg.setAttribute("stroke", "currentColor");
364
+ svg.setAttribute("stroke-width", "2");
365
+ svg.setAttribute("stroke-linecap", "round");
366
+ svg.setAttribute("stroke-linejoin", "round");
367
+ svg.setAttribute("aria-hidden", "true");
368
+ svg.setAttribute("focusable", "false");
369
+ const dial = doc.createElementNS(namespace, "circle");
370
+ dial.setAttribute("cx", "12");
371
+ dial.setAttribute("cy", "12");
372
+ dial.setAttribute("r", "10");
373
+ const ticks = doc.createElementNS(namespace, "path");
374
+ ticks.setAttribute("d", "M12 2.4v1.6M12 20v1.6M2.4 12h1.6M20 12h1.6M5.2 5.2l1.1 1.1M18.8 18.8l-1.1-1.1M18.8 5.2l-1.1 1.1M5.2 18.8l1.1-1.1");
375
+ const needle = doc.createElementNS(namespace, "path");
376
+ needle.setAttribute("d", "M12 12l4.5-4");
377
+ const hub = doc.createElementNS(namespace, "circle");
378
+ hub.setAttribute("cx", "12");
379
+ hub.setAttribute("cy", "12");
380
+ hub.setAttribute("r", "1.4");
381
+ hub.setAttribute("fill", "currentColor");
382
+ hub.setAttribute("stroke", "none");
383
+ svg.append(dial, ticks, needle, hub);
384
+ return svg;
385
+ }
348
386
  function menuItem(doc, action, label) {
349
387
  const item = doc.createElement("button");
350
388
  item.type = "button";
@@ -451,7 +489,16 @@ function mountQuotaCard({
451
489
  const lastUpdated = text(doc, "p", "dqw-meta", copy.loading);
452
490
  lastUpdated.dataset.role = "updated";
453
491
  body.append(lastUpdated);
454
- card.append(body);
492
+ const railTrigger = doc.createElement("button");
493
+ railTrigger.type = "button";
494
+ railTrigger.className = "dqw-rail-trigger";
495
+ railTrigger.dataset.dshQuotaWatchRail = "";
496
+ railTrigger.title = copy.title;
497
+ railTrigger.setAttribute("aria-label", copy.title);
498
+ railTrigger.setAttribute("aria-haspopup", "dialog");
499
+ railTrigger.setAttribute("aria-expanded", "false");
500
+ railTrigger.append(quotaIcon(doc));
501
+ card.append(body, railTrigger);
455
502
  cardRoot.append(style, card);
456
503
  const panel = doc.createElement("div");
457
504
  panel.className = "dqw-panel";
@@ -784,6 +831,7 @@ function mountQuotaCard({
784
831
  lastAnchor = null;
785
832
  panelNav = false;
786
833
  surface.setAttribute("aria-expanded", "false");
834
+ railTrigger.setAttribute("aria-expanded", "false");
787
835
  return;
788
836
  }
789
837
  if (openKey === "overview") {
@@ -794,6 +842,7 @@ function mountQuotaCard({
794
842
  panel.hidden = false;
795
843
  placePanel();
796
844
  surface.setAttribute("aria-expanded", "true");
845
+ railTrigger.setAttribute("aria-expanded", "true");
797
846
  return;
798
847
  }
799
848
  const provider = (snapshot?.providers ?? []).find((item) => item?.key === openKey);
@@ -810,6 +859,7 @@ function mountQuotaCard({
810
859
  panel.hidden = false;
811
860
  placePanel();
812
861
  surface.setAttribute("aria-expanded", "true");
862
+ railTrigger.setAttribute("aria-expanded", "true");
813
863
  };
814
864
  const renderFloatFace = () => {
815
865
  const providers = snapshot?.providers ?? [];
@@ -881,6 +931,14 @@ function mountQuotaCard({
881
931
  event.preventDefault();
882
932
  openMenu();
883
933
  };
934
+ const onRailClick = () => {
935
+ if (openKey !== void 0 && !panel.hidden) {
936
+ openKey = void 0;
937
+ syncPop();
938
+ return;
939
+ }
940
+ openOverview(railTrigger);
941
+ };
884
942
  const onMenuClick = (event) => {
885
943
  const item = event.target?.closest?.("[data-menu]");
886
944
  if (!item) return;
@@ -901,7 +959,13 @@ function mountQuotaCard({
901
959
  };
902
960
  const syncCardVisibility = () => {
903
961
  syncFootNarrowness();
904
- container.hidden = surfaceFlags.cardHidden || sidebarCollapsed || footTooNarrow || noDataHidden;
962
+ const cardOn = !surfaceFlags.cardHidden;
963
+ const narrowOrCollapsed = footTooNarrow || sidebarCollapsed;
964
+ const showCard = cardOn && !narrowOrCollapsed && !noDataHidden;
965
+ const showRail = cardOn && narrowOrCollapsed && !noDataHidden;
966
+ container.hidden = !showCard && !showRail;
967
+ if (showRail) container.dataset.dshQuotaWatchSidebarCollapsed = "";
968
+ else delete container.dataset.dshQuotaWatchSidebarCollapsed;
905
969
  };
906
970
  const footResizeObserver = typeof win.ResizeObserver === "function" ? new win.ResizeObserver(() => {
907
971
  syncCardVisibility();
@@ -1099,6 +1163,7 @@ function mountQuotaCard({
1099
1163
  surface.addEventListener("click", onSurfaceClick);
1100
1164
  surface.addEventListener("keydown", onSurfaceKeydown);
1101
1165
  surface.addEventListener("contextmenu", onSurfaceContext);
1166
+ railTrigger.addEventListener("click", onRailClick);
1102
1167
  let disposeDrag = attachDrag(surface);
1103
1168
  doc.addEventListener("visibilitychange", onVisibilityChange);
1104
1169
  doc.addEventListener("pointerdown", onDocPointerDown, true);
@@ -1121,6 +1186,7 @@ function mountQuotaCard({
1121
1186
  surface.removeEventListener("click", onSurfaceClick);
1122
1187
  surface.removeEventListener("keydown", onSurfaceKeydown);
1123
1188
  surface.removeEventListener("contextmenu", onSurfaceContext);
1189
+ railTrigger.removeEventListener("click", onRailClick);
1124
1190
  menu.removeEventListener("click", onMenuClick);
1125
1191
  disposeDrag();
1126
1192
  container.remove();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iasiv5/dsh-quota-watch",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
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
@@ -107,6 +107,13 @@ const STYLE_TEXT = `
107
107
  .dqw-chev { font-size: 9px; line-height: 14px; opacity: .6; flex: none; width: 10px; text-align: center; }
108
108
  .dqw-stale-mark { flex: none; font-size: 9px; line-height: 14px; color: var(--dsw-alias-label-warning, #b46900); cursor: help; }
109
109
  .dqw-errtext { font-size: 10px; line-height: 14px; opacity: .7; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
110
+ .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; }
111
+ .dqw-rail-trigger svg { display: block; width: 16px; height: 16px; }
112
+ .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); }
113
+ .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); }
114
+ .dqw-rail-trigger:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary, #5b8def); outline-offset: 2px; }
115
+ :host([data-dsh-quota-watch-sidebar-collapsed]) .dqw-card { display: none; }
116
+ :host([data-dsh-quota-watch-sidebar-collapsed]) .dqw-rail-trigger { display: inline-flex; }
110
117
  @media print { :host { display: none !important; } }
111
118
  `
112
119
 
@@ -145,7 +152,8 @@ const FLOAT_STYLE_TEXT = `
145
152
  .dqw-panel-back:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,.12)); color: var(--dsw-alias-label-primary, inherit); }
146
153
  .dqw-panel-close { display: inline-flex; flex: none; align-items: center; justify-content: center; width: 24px; height: 24px; margin: 0; padding: 0; border: 0; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, inherit); cursor: pointer; font: inherit; font-size: 12px; line-height: 1; }
147
154
  .dqw-panel-close:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,.12)); color: var(--dsw-alias-label-primary, inherit); }
148
- .dqw-overview-list { display: flex; flex-direction: column; gap: 2px; max-width: 240px; }
155
+ .dqw-overview-list { display: flex; flex-direction: column; gap: 2px; }
156
+ .dqw-bar { background: var(--dsw-alias-bg-tertiary, rgba(128,128,128,.38)); }
149
157
  .dqw-row-summary { display: flex; align-items: center; gap: 6px; padding: 3px 6px; margin: 0 -2px; border-radius: 8px; }
150
158
  .dqw-row-summary[data-expandable] { cursor: pointer; }
151
159
  .dqw-row-summary[data-expandable]:hover { background: var(--dsw-alias-bg-hover, rgba(128,128,128,.12)); }
@@ -384,7 +392,18 @@ export function mountQuotaCard({
384
392
  const lastUpdated = text(doc, 'p', 'dqw-meta', copy.loading)
385
393
  lastUpdated.dataset.role = 'updated'
386
394
  body.append(lastUpdated)
387
- card.append(body)
395
+ // Collapsed web rail (0.0.18 behaviour, card opt-in only): a 36px gauge icon
396
+ // replaces the card body; the shadow CSS swaps them on the host's collapsed flag.
397
+ const railTrigger = doc.createElement('button')
398
+ railTrigger.type = 'button'
399
+ railTrigger.className = 'dqw-rail-trigger'
400
+ railTrigger.dataset.dshQuotaWatchRail = ''
401
+ railTrigger.title = copy.title
402
+ railTrigger.setAttribute('aria-label', copy.title)
403
+ railTrigger.setAttribute('aria-haspopup', 'dialog')
404
+ railTrigger.setAttribute('aria-expanded', 'false')
405
+ railTrigger.append(quotaIcon(doc))
406
+ card.append(body, railTrigger)
388
407
  cardRoot.append(style, card)
389
408
  // Details open in a viewport-level floating panel — the only detail surface.
390
409
  const panel = doc.createElement('div')
@@ -752,6 +771,7 @@ export function mountQuotaCard({
752
771
  lastAnchor = null
753
772
  panelNav = false
754
773
  surface.setAttribute('aria-expanded', 'false')
774
+ railTrigger.setAttribute('aria-expanded', 'false')
755
775
  return
756
776
  }
757
777
  if (openKey === 'overview') {
@@ -762,6 +782,7 @@ export function mountQuotaCard({
762
782
  panel.hidden = false
763
783
  placePanel()
764
784
  surface.setAttribute('aria-expanded', 'true')
785
+ railTrigger.setAttribute('aria-expanded', 'true')
765
786
  return
766
787
  }
767
788
  const provider = (snapshot?.providers ?? []).find((item) => item?.key === openKey)
@@ -778,6 +799,7 @@ export function mountQuotaCard({
778
799
  panel.hidden = false
779
800
  placePanel()
780
801
  surface.setAttribute('aria-expanded', 'true')
802
+ railTrigger.setAttribute('aria-expanded', 'true')
781
803
  }
782
804
 
783
805
  const renderFloatFace = () => {
@@ -855,6 +877,15 @@ export function mountQuotaCard({
855
877
  event.preventDefault()
856
878
  openMenu()
857
879
  }
880
+ /** Collapsed-rail gauge icon: toggles the panel, exactly like the capsule. */
881
+ const onRailClick = () => {
882
+ if (openKey !== undefined && !panel.hidden) {
883
+ openKey = undefined
884
+ syncPop()
885
+ return
886
+ }
887
+ openOverview(railTrigger)
888
+ }
858
889
  const onMenuClick = (event) => {
859
890
  const item = event.target?.closest?.('[data-menu]')
860
891
  if (!item) return
@@ -880,7 +911,17 @@ export function mountQuotaCard({
880
911
  }
881
912
  const syncCardVisibility = () => {
882
913
  syncFootNarrowness()
883
- container.hidden = surfaceFlags.cardHidden || sidebarCollapsed || footTooNarrow || noDataHidden
914
+ // Rail entry follows the WIDTH signal, not the host attribute: this DSH
915
+ // build (0.2.0-rc.2 web) never writes data-sidebar-collapsed on collapse
916
+ // (verified via CDP + bundle grep), but the foot container measurably
917
+ // narrows — and the 36px gauge icon fits any rail.
918
+ const cardOn = !surfaceFlags.cardHidden
919
+ const narrowOrCollapsed = footTooNarrow || sidebarCollapsed
920
+ const showCard = cardOn && !narrowOrCollapsed && !noDataHidden
921
+ const showRail = cardOn && narrowOrCollapsed && !noDataHidden
922
+ container.hidden = !showCard && !showRail
923
+ if (showRail) container.dataset.dshQuotaWatchSidebarCollapsed = ''
924
+ else delete container.dataset.dshQuotaWatchSidebarCollapsed
884
925
  }
885
926
  const footResizeObserver = typeof win.ResizeObserver === 'function'
886
927
  ? new win.ResizeObserver(() => { syncCardVisibility() })
@@ -1090,6 +1131,7 @@ export function mountQuotaCard({
1090
1131
  surface.addEventListener('click', onSurfaceClick)
1091
1132
  surface.addEventListener('keydown', onSurfaceKeydown)
1092
1133
  surface.addEventListener('contextmenu', onSurfaceContext)
1134
+ railTrigger.addEventListener('click', onRailClick)
1093
1135
  let disposeDrag = attachDrag(surface)
1094
1136
  doc.addEventListener('visibilitychange', onVisibilityChange)
1095
1137
  doc.addEventListener('pointerdown', onDocPointerDown, true)
@@ -1113,6 +1155,7 @@ export function mountQuotaCard({
1113
1155
  surface.removeEventListener('click', onSurfaceClick)
1114
1156
  surface.removeEventListener('keydown', onSurfaceKeydown)
1115
1157
  surface.removeEventListener('contextmenu', onSurfaceContext)
1158
+ railTrigger.removeEventListener('click', onRailClick)
1116
1159
  menu.removeEventListener('click', onMenuClick)
1117
1160
  disposeDrag()
1118
1161
  container.remove()