shadok-ai 0.2.60 → 0.2.62

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/public/index.html +60 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shadok-ai",
3
- "version": "0.2.60",
3
+ "version": "0.2.62",
4
4
  "main": "dist/session.js",
5
5
  "scripts": {
6
6
  "test": "node --import tsx --test test/*.ts .claude/skills/shadok-ai-agents/test/*.test.mjs",
package/public/index.html CHANGED
@@ -335,6 +335,11 @@
335
335
  /* The star lives in the header pill on desktop; its menu twin appears only on
336
336
  a phone (see the mobile query). */
337
337
  #starMenuItem { display: none; }
338
+ /* Overflowed header icons, shown as a compact row at the top of the menu.
339
+ Hidden entirely when nothing overflowed. */
340
+ .mm-tools { display: flex; flex-wrap: wrap; gap: 4px; padding-bottom: 4px; margin-bottom: 2px; border-bottom: 1px solid var(--line); }
341
+ .mm-tools:empty { display: none; }
342
+ #moreMenu .mm-tools button { width: auto; } /* override #moreMenu button width:100% */
338
343
  #moreMenu .mm-sep { height: 1px; background: var(--line); margin: 4px 2px; }
339
344
  #moreMenu .mm-label { padding: 2px 4px; font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-dim); }
340
345
  .mm-themes { display: flex; gap: 6px; padding: 2px 4px 4px; }
@@ -1087,10 +1092,11 @@
1087
1092
  #chanBar .gauge .label { display: none; } /* valeurs seules, plus compact */
1088
1093
  #chanBar { gap: 6px; padding: 6px 10px; }
1089
1094
  header { flex-wrap: wrap; row-gap: 6px; gap: 8px; padding: 8px 12px; }
1090
- /* Row 1: brand + dials. Row 2: every icon, left-aligned. They used to spread
1091
- across the two rows as space allowed, and the first of them (🔑) ended up
1092
- flush against the right edge. */
1093
- .hdr-tools { display: flex; flex: 1 0 100%; align-items: center; gap: 6px; }
1095
+ /* One header row: brand + dials + as many tool icons as fit. The spacer that
1096
+ right-aligns them on desktop is dropped so they pack left; whatever doesn't
1097
+ fit is moved into the menu by reflowHeaderTools (JS). .hdr-tools keeps
1098
+ its base `display: contents`, so the icons stay direct header flex items. */
1099
+ header .spacer { display: none; }
1094
1100
  header button.icon { padding: 5px 7px; }
1095
1101
  /* The star pill is the widest tool and would push an icon off the row; on a
1096
1102
  phone it moves into the ⋯ menu (#starMenuItem) instead. */
@@ -1451,6 +1457,10 @@
1451
1457
  <div class="more-wrap">
1452
1458
  <button id="moreBtn" class="icon" title="More">⋯</button>
1453
1459
  <div id="moreMenu" hidden>
1460
+ <!-- Header tool icons that didn't fit the row are moved here by
1461
+ reflowHeaderTools (the real buttons, so their handlers come along).
1462
+ Empty — and hidden — whenever everything fits. -->
1463
+ <div id="overflowTools" class="mm-tools"></div>
1454
1464
  <button id="toggleDiff">Diff</button>
1455
1465
  <button id="tourReplay">Guided tour</button>
1456
1466
  <!-- On a phone the header star pill is dropped (it's the widest tool, and
@@ -2903,6 +2913,7 @@
2903
2913
  if (brandName && !brandName.isContentEditable) brandName.textContent = cockpitTitle || "shadok-ai";
2904
2914
  titleBase = cockpitTitle || BASE_TITLE;
2905
2915
  paint(); // re-stamp document.title (with any notification badge)
2916
+ if (typeof scheduleReflow === "function") scheduleReflow(); // name width changed
2906
2917
  }
2907
2918
 
2908
2919
  // ── Colour palette: per instance, persisted server-side (like the name) ──
@@ -4821,6 +4832,46 @@
4821
4832
  window.open("https://github.com/shadok-ai/shadok-ai", "_blank", "noopener");
4822
4833
  });
4823
4834
 
4835
+ // ── Header tool overflow ─────────────────────────────────────────────
4836
+ // The header is one row: brand + dials + as many tool icons as fit. Any icon
4837
+ // that would push the ⋯ button onto a second line is moved INTO the ⋯ menu —
4838
+ // the real button element, so its click handler travels with it. Desktop has
4839
+ // room for them all. Recomputed on load, on resize, and when the name changes.
4840
+ const OVERFLOW_TOOLS = ["secretsBtn", "profilesBtn", "telegramBtn", "muteNotif"];
4841
+ function reflowHeaderTools() {
4842
+ const hdrTools = document.querySelector(".hdr-tools");
4843
+ const moreWrap = document.querySelector(".more-wrap");
4844
+ const moreBtn = $("moreBtn");
4845
+ const overflow = $("overflowTools");
4846
+ const brand = $("brandName");
4847
+ if (!hdrTools || !moreWrap || !moreBtn || !overflow || !brand) return;
4848
+ // 1. Reset: every tool back in the header, in the declared order.
4849
+ for (const id of OVERFLOW_TOOLS) {
4850
+ const el = $(id);
4851
+ if (el) hdrTools.insertBefore(el, moreWrap);
4852
+ }
4853
+ // 2. Only a narrow screen needs to shed icons.
4854
+ if (!matchMedia("(max-width: 640px)").matches) return;
4855
+ // 3. Move icons from the end into the menu until ⋯ is back on the first row.
4856
+ // Two rows → ⋯ sits a line-height below the brand; the 8px threshold
4857
+ // ignores sub-pixel jitter.
4858
+ const rowTop = () => brand.getBoundingClientRect().top;
4859
+ for (let i = OVERFLOW_TOOLS.length - 1; i >= 0; i--) {
4860
+ if (moreBtn.getBoundingClientRect().top - rowTop() < 8) break; // it fits now
4861
+ const el = $(OVERFLOW_TOOLS[i]);
4862
+ if (el) overflow.insertBefore(el, overflow.firstChild); // keep original order
4863
+ }
4864
+ }
4865
+ let reflowPending = false;
4866
+ function scheduleReflow() {
4867
+ if (reflowPending) return;
4868
+ reflowPending = true;
4869
+ requestAnimationFrame(() => { reflowPending = false; reflowHeaderTools(); });
4870
+ }
4871
+ window.addEventListener("resize", scheduleReflow);
4872
+ document.addEventListener("DOMContentLoaded", reflowHeaderTools);
4873
+ reflowHeaderTools();
4874
+
4824
4875
  // ── Diff panel ──────────────────────────────────────────
4825
4876
  function colorDiff(text) {
4826
4877
  const esc = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -5596,6 +5647,11 @@
5596
5647
  }
5597
5648
  if (r && r.ok) {
5598
5649
  $("authCode").value = "";
5650
+ // The login just wrote the OAuth credentials the usage gauges read from
5651
+ // (src/usage.ts, live-first). Repaint them now — otherwise a freshly
5652
+ // signed-in instance shows blank dials until the next 60s poll, which
5653
+ // reads as "usage is broken" right after onboarding.
5654
+ refreshUsage();
5599
5655
  // Name the account: a machine can serve several people, and "signed in"
5600
5656
  // without saying as whom is the kind of detail that costs an hour later.
5601
5657
  let who = "";