shadok-ai 0.13.1 → 0.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/package.json +1 -1
- package/public/index.html +79 -9
package/README.md
CHANGED
|
@@ -604,7 +604,10 @@ HTTP endpoints (same auth): `/usage`, `/live`, `/sessions`, `/recover`,
|
|
|
604
604
|
cockpit's name, per launch directory: click the header brand to rename it, so
|
|
605
605
|
several cockpits stay apart in the tab bar; an empty PUT reverts to the default),
|
|
606
606
|
`/theme` (GET/PUT — the cockpit's colour palette, per launch directory: an accent
|
|
607
|
-
key picked from the ⋯ menu, e.g. `emerald`; unknown/`amber` reverts to default
|
|
607
|
+
key picked from the ⋯ menu, e.g. `emerald`; unknown/`amber` reverts to default.
|
|
608
|
+
Light/dark **mode** is an orthogonal, **per-browser** choice in the same menu
|
|
609
|
+
(default dark; stored in `localStorage`, applied before first paint) and needs no
|
|
610
|
+
endpoint — the accent is the instance's shared identity, the mode is personal),
|
|
608
611
|
`/profiles`, `/secrets`, `/telegram`, `/defaults`, `/first-agent` (GET —
|
|
609
612
|
`{pending, reason}`: whether this instance's lead agent is being started
|
|
610
613
|
right now), `/version`, `/autoupdate`,
|
package/package.json
CHANGED
package/public/index.html
CHANGED
|
@@ -27,9 +27,33 @@
|
|
|
27
27
|
--phosphor: #ffb45c;
|
|
28
28
|
--ok: #7fc97f;
|
|
29
29
|
--err: #e07a6a;
|
|
30
|
+
/* Floating menus (⋯, version, tab, palette) sit a touch darker than a raised
|
|
31
|
+
panel for depth; kept as tokens so light mode can flip them. */
|
|
32
|
+
--menu-bg: #14140f;
|
|
33
|
+
--menu-hover: #26261c;
|
|
30
34
|
--mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
|
|
31
35
|
--sans: -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
|
|
32
36
|
}
|
|
37
|
+
/* Light mode. An ORTHOGONAL axis to the accent palette: only the base surfaces
|
|
38
|
+
and text flip; the instance's accent (--amber/--phosphor) stays its identity.
|
|
39
|
+
Applied via `data-mode="light"` on <html>, a PER-BROWSER comfort choice set
|
|
40
|
+
from localStorage before first paint (the small head script) — default dark.
|
|
41
|
+
--phosphor darkens here: the selection bar is a 3px inset of it, invisible as
|
|
42
|
+
a pale amber on white. Accent-tinted surfaces (--amber-soft) derive from
|
|
43
|
+
--amber and follow on their own. */
|
|
44
|
+
:root[data-mode="light"] {
|
|
45
|
+
--bg: #eef0f4;
|
|
46
|
+
--bg-raised: #ffffff;
|
|
47
|
+
--bg-inset: #e5e8ee;
|
|
48
|
+
--line: #d2d7e0;
|
|
49
|
+
--text: #1b2030;
|
|
50
|
+
--text-dim: #5c6577;
|
|
51
|
+
--ok: #2f9e44;
|
|
52
|
+
--err: #cf4436;
|
|
53
|
+
--phosphor: #c77800;
|
|
54
|
+
--menu-bg: #ffffff;
|
|
55
|
+
--menu-hover: #eceff5;
|
|
56
|
+
}
|
|
33
57
|
/* Colour palettes, chosen per instance from the ⋯ menu and stored server-side
|
|
34
58
|
(like the instance name). Only the accent family changes; the dark base
|
|
35
59
|
stays constant for readability, and every tinted surface follows because it
|
|
@@ -174,7 +198,7 @@
|
|
|
174
198
|
header .ver {
|
|
175
199
|
font-family: var(--mono);
|
|
176
200
|
font-size: 10px;
|
|
177
|
-
color:
|
|
201
|
+
color: var(--text-dim);
|
|
178
202
|
letter-spacing: 0;
|
|
179
203
|
cursor: pointer;
|
|
180
204
|
}
|
|
@@ -182,14 +206,14 @@
|
|
|
182
206
|
header .ver.stale { color: var(--amber); }
|
|
183
207
|
#verMenu {
|
|
184
208
|
position: fixed; top: 42px; left: 12px; z-index: 1001;
|
|
185
|
-
background:
|
|
209
|
+
background: var(--menu-bg); border: 1px solid var(--line); border-radius: 6px;
|
|
186
210
|
padding: 10px 12px; font-family: var(--mono); font-size: 12px;
|
|
187
211
|
min-width: 210px; box-shadow: 0 6px 20px rgba(0,0,0,0.5);
|
|
188
212
|
}
|
|
189
213
|
#verMenu .vm-row { display: flex; justify-content: space-between; gap: 16px; margin-bottom: 4px; }
|
|
190
|
-
#verMenu .vm-label { color:
|
|
214
|
+
#verMenu .vm-label { color: var(--text-dim); }
|
|
191
215
|
#verMenu .vm-check { display: flex; align-items: center; gap: 6px; margin-top: 9px; cursor: pointer; }
|
|
192
|
-
#verMenu .vm-hint { color:
|
|
216
|
+
#verMenu .vm-hint { color: var(--text-dim); font-size: 10px; margin-top: 7px; line-height: 1.4; }
|
|
193
217
|
#verMenu .vm-btn { margin-top: 10px; width: 100%; padding: 6px 10px; font-size: 11px; cursor: pointer;
|
|
194
218
|
color: var(--text, #e8e8ea); background: transparent; border: 1px solid var(--line, #3a3d42); border-radius: 6px; }
|
|
195
219
|
#verMenu .vm-btn:hover { border-color: var(--amber, #d0a000); }
|
|
@@ -198,7 +222,7 @@
|
|
|
198
222
|
the cursor. Home for the per-channel actions. */
|
|
199
223
|
#tabMenu {
|
|
200
224
|
position: fixed; z-index: 1002;
|
|
201
|
-
background:
|
|
225
|
+
background: var(--menu-bg); border: 1px solid var(--line); border-radius: 6px;
|
|
202
226
|
padding: 4px; font-family: var(--mono); font-size: 12px;
|
|
203
227
|
min-width: 170px; box-shadow: 0 6px 20px rgba(0,0,0,0.5);
|
|
204
228
|
}
|
|
@@ -207,7 +231,7 @@
|
|
|
207
231
|
background: none; border: 0; color: var(--text); font: inherit;
|
|
208
232
|
padding: 6px 9px; border-radius: 4px;
|
|
209
233
|
}
|
|
210
|
-
#tabMenu .tm-item:hover { background:
|
|
234
|
+
#tabMenu .tm-item:hover { background: var(--menu-hover); }
|
|
211
235
|
/* A muted channel says so on its own tab: silence must be explainable. */
|
|
212
236
|
.tab .mute { font-size: 10px; opacity: 0.75; flex: 0 0 auto; }
|
|
213
237
|
/* Same for the opposite: an agent with scheduled prompts can speak without
|
|
@@ -241,7 +265,7 @@
|
|
|
241
265
|
/* Right-click menu header: the agent's identity, not an action. */
|
|
242
266
|
#tabMenu .tm-head {
|
|
243
267
|
padding: 5px 9px 6px; color: var(--text-dim); font-size: 11px;
|
|
244
|
-
border-bottom: 1px solid
|
|
268
|
+
border-bottom: 1px solid var(--line); margin-bottom: 4px;
|
|
245
269
|
/* The profile name does not cut the menu in two: one line, cleanly
|
|
246
270
|
truncated when it is long. */
|
|
247
271
|
max-width: 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
@@ -273,7 +297,7 @@
|
|
|
273
297
|
display: inline-block;
|
|
274
298
|
width: 9px; height: 9px;
|
|
275
299
|
border-radius: 50%;
|
|
276
|
-
background:
|
|
300
|
+
background: var(--line);
|
|
277
301
|
vertical-align: -1px;
|
|
278
302
|
margin-right: 6px;
|
|
279
303
|
flex: none;
|
|
@@ -385,6 +409,15 @@
|
|
|
385
409
|
}
|
|
386
410
|
#moreMenu .mm-themes button:hover { border-color: var(--text-dim); }
|
|
387
411
|
#moreMenu .mm-themes button.active { border-color: var(--text); }
|
|
412
|
+
/* Dark / Light segmented toggle. Overrides `#moreMenu button { width:100% }`. */
|
|
413
|
+
.mm-mode { display: flex; gap: 6px; padding: 2px 4px 6px; }
|
|
414
|
+
#moreMenu .mm-mode button {
|
|
415
|
+
flex: 1; width: auto; padding: 5px 8px; font-size: 11px; cursor: pointer;
|
|
416
|
+
border: 1px solid var(--line); border-radius: 6px;
|
|
417
|
+
background: var(--bg-inset); color: var(--text-dim);
|
|
418
|
+
}
|
|
419
|
+
#moreMenu .mm-mode button:hover { border-color: var(--text-dim); color: var(--text); }
|
|
420
|
+
#moreMenu .mm-mode button.active { border-color: var(--amber); color: var(--amber); background: color-mix(in srgb, var(--amber) 12%, transparent); }
|
|
388
421
|
button:hover { border-color: var(--amber); color: var(--amber); }
|
|
389
422
|
button:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }
|
|
390
423
|
button.primary { background: var(--amber); border-color: var(--amber); color: #1a1205; font-weight: 600; }
|
|
@@ -1616,7 +1649,7 @@
|
|
|
1616
1649
|
#ledgerList .ldg-head { display: flex; align-items: baseline; gap: 8px; }
|
|
1617
1650
|
#ledgerList .ldg-status { font-size: 10px; text-transform: uppercase; letter-spacing: .04em; opacity: .8;
|
|
1618
1651
|
border: 1px solid var(--line, #3a3d42); border-radius: 4px; padding: 1px 5px; white-space: nowrap; }
|
|
1619
|
-
#ledgerList .ldg-meta { color:
|
|
1652
|
+
#ledgerList .ldg-meta { color: var(--text-dim); font-size: 10px; margin-top: 2px; }
|
|
1620
1653
|
#ledgerList .ldg-note { font-size: 12px; opacity: .85; margin-top: 3px; }
|
|
1621
1654
|
#secretsPanel .sec-repo { font-size: 12px; opacity: .8; margin-bottom: 4px; word-break: break-all; }
|
|
1622
1655
|
#secretsPanel .sec-note { font-size: 12px; opacity: .65; margin: 6px 0 12px; }
|
|
@@ -1667,6 +1700,12 @@
|
|
|
1667
1700
|
.sec-reload button { flex: none; padding: 5px 11px; border-radius: 6px; border: 1px solid var(--amber); background: none; color: var(--amber); cursor: pointer; font: inherit; font-size: 12px; }
|
|
1668
1701
|
.sec-reload button:hover { background: color-mix(in srgb, var(--amber) 15%, transparent); }
|
|
1669
1702
|
</style>
|
|
1703
|
+
<!-- Light/dark mode is a per-browser choice (localStorage). Set it BEFORE the
|
|
1704
|
+
body paints — here in <head> — so a light-preferring viewer never sees a
|
|
1705
|
+
flash of the dark default. Nonce'd like every inline script (invariant 12). -->
|
|
1706
|
+
<script nonce="__CSP_NONCE__">
|
|
1707
|
+
try { if (localStorage.getItem("cp.mode") === "light") document.documentElement.setAttribute("data-mode", "light"); } catch (e) {}
|
|
1708
|
+
</script>
|
|
1670
1709
|
</head>
|
|
1671
1710
|
<body>
|
|
1672
1711
|
|
|
@@ -1719,6 +1758,12 @@
|
|
|
1719
1758
|
pushed the icons off the row); it reappears here instead. -->
|
|
1720
1759
|
<button id="starMenuItem">★ Star on GitHub</button>
|
|
1721
1760
|
<div class="mm-sep"></div>
|
|
1761
|
+
<div class="mm-label">Appearance</div>
|
|
1762
|
+
<!-- Light / dark mode — per browser (localStorage), default dark. -->
|
|
1763
|
+
<div id="modeRow" class="mm-mode">
|
|
1764
|
+
<button type="button" data-mode="dark">☾ Dark</button>
|
|
1765
|
+
<button type="button" data-mode="light">☀ Light</button>
|
|
1766
|
+
</div>
|
|
1722
1767
|
<div class="mm-label">Palette</div>
|
|
1723
1768
|
<!-- Colour swatches, filled by JS from THEMES; picking one re-themes the
|
|
1724
1769
|
whole cockpit and persists per instance. -->
|
|
@@ -3759,6 +3804,31 @@
|
|
|
3759
3804
|
}
|
|
3760
3805
|
renderThemeSwatches(); // paint the swatches now; the load fetch sets the active one
|
|
3761
3806
|
|
|
3807
|
+
// ── Light / dark mode: per BROWSER (localStorage), not per instance ─────────
|
|
3808
|
+
// A comfort choice that belongs to the person, not the cockpit's identity (the
|
|
3809
|
+
// accent palette is the shared one). The <head> script already set the
|
|
3810
|
+
// attribute before paint; this syncs the toggle and re-paints the favicon
|
|
3811
|
+
// (which reads --bg / --amber live). Default dark → no attribute.
|
|
3812
|
+
function syncModeButtons() {
|
|
3813
|
+
const light = document.documentElement.getAttribute("data-mode") === "light";
|
|
3814
|
+
for (const b of document.querySelectorAll("#modeRow button")) {
|
|
3815
|
+
b.classList.toggle("active", b.dataset.mode === (light ? "light" : "dark"));
|
|
3816
|
+
}
|
|
3817
|
+
}
|
|
3818
|
+
function applyMode(mode) {
|
|
3819
|
+
const light = mode === "light";
|
|
3820
|
+
const root = document.documentElement;
|
|
3821
|
+
if (light) root.setAttribute("data-mode", "light");
|
|
3822
|
+
else root.removeAttribute("data-mode");
|
|
3823
|
+
try { localStorage.setItem("cp.mode", light ? "light" : "dark"); } catch (e) {}
|
|
3824
|
+
syncModeButtons();
|
|
3825
|
+
paint(); // the favicon tile follows --bg (safe here: user click, well after init)
|
|
3826
|
+
}
|
|
3827
|
+
for (const b of document.querySelectorAll("#modeRow button")) {
|
|
3828
|
+
b.addEventListener("click", (e) => { e.stopPropagation(); applyMode(b.dataset.mode); });
|
|
3829
|
+
}
|
|
3830
|
+
syncModeButtons(); // init: the <head> script already applied the attribute pre-paint
|
|
3831
|
+
|
|
3762
3832
|
/** A themed CSS custom property, read live so the favicon follows the palette.
|
|
3763
3833
|
A standalone SVG data-URI can't see the page's variables, so we inline the
|
|
3764
3834
|
resolved value. Palette accents are 6-digit hex (see the theme blocks). */
|