shadok-ai 0.16.24 → 0.16.26
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/package.json +1 -1
- package/public/index.html +99 -2
package/package.json
CHANGED
package/public/index.html
CHANGED
|
@@ -1256,6 +1256,18 @@
|
|
|
1256
1256
|
border-radius: 8px; padding: 7px 14px;
|
|
1257
1257
|
}
|
|
1258
1258
|
#lightboxDl:hover { background: rgba(0, 0, 0, 0.75); }
|
|
1259
|
+
/* Media gallery popin: a wider panel than the default so the thumbnail grid
|
|
1260
|
+
breathes, and a square-cell auto-fill grid that reflows from phone to
|
|
1261
|
+
desktop with no breakpoints of its own. */
|
|
1262
|
+
.gal-panel { width: min(760px, 100%); max-height: min(82vh, 820px); }
|
|
1263
|
+
.gal-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); gap: 10px; }
|
|
1264
|
+
.gal-cell {
|
|
1265
|
+
position: relative; aspect-ratio: 1 / 1; padding: 0; overflow: hidden; cursor: zoom-in;
|
|
1266
|
+
border: 1px solid var(--line); border-radius: 8px; background: var(--bg-raised);
|
|
1267
|
+
}
|
|
1268
|
+
.gal-cell img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
|
1269
|
+
.gal-cell:hover { border-color: var(--amber); }
|
|
1270
|
+
.gal-empty { color: var(--text-dim); font-size: 13px; text-align: center; padding: 24px 4px; }
|
|
1259
1271
|
.att-file .att-ic { color: var(--amber); flex: none; }
|
|
1260
1272
|
.att-file .att-nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1261
1273
|
/* Composer attachment strip: the SAME dropped/pasted files, previewed above the
|
|
@@ -2367,11 +2379,11 @@
|
|
|
2367
2379
|
#chanBar .gauge .label { display: none; }
|
|
2368
2380
|
#chanBar .gauge .value { color: var(--text-dim); font-size: 12px; }
|
|
2369
2381
|
#chanBar .gauge:nth-of-type(3) { display: none; } /* the session id: in the tooltip of the menu */
|
|
2370
|
-
#chanBar .chan-actions #chanCron, #chanBar .chan-actions #chanTerm {
|
|
2382
|
+
#chanBar .chan-actions #chanGallery, #chanBar .chan-actions #chanCron, #chanBar .chan-actions #chanTerm {
|
|
2371
2383
|
position: relative; align-self: stretch; display: inline-flex; align-items: center; gap: 6px;
|
|
2372
2384
|
border: 0; border-radius: 0; background: none; padding: 0 10px; color: var(--text-dim); font-size: 14px;
|
|
2373
2385
|
}
|
|
2374
|
-
#chanBar .chan-actions #chanCron:hover, #chanBar .chan-actions #chanTerm:hover { color: var(--text); background: none; }
|
|
2386
|
+
#chanBar .chan-actions #chanGallery:hover, #chanBar .chan-actions #chanCron:hover, #chanBar .chan-actions #chanTerm:hover { color: var(--text); background: none; }
|
|
2375
2387
|
#chanBar .chan-actions #chanTerm.on { color: var(--text); font-weight: 600; background: none; border: 0; }
|
|
2376
2388
|
#chanBar .chan-actions #chanTerm.on::after {
|
|
2377
2389
|
content: ""; position: absolute; left: 10px; right: 10px; bottom: 0; height: 3px; border-radius: 3px 3px 0 0; background: var(--amber);
|
|
@@ -3151,6 +3163,7 @@
|
|
|
3151
3163
|
</div>
|
|
3152
3164
|
<span class="chan-actions">
|
|
3153
3165
|
<button id="chanUpdate" class="icon" title="Claude Code updated — reload this agent to apply it" aria-label="Reload to apply update" hidden>↻ update</button>
|
|
3166
|
+
<button id="chanGallery" class="icon" title="Media gallery — every image in this conversation" aria-label="Media gallery"><svg viewBox="0 0 24 24" width="15" height="15" style="vertical-align:-2px" aria-hidden="true"><rect x="3.5" y="5" width="17" height="14" rx="2" fill="none" stroke="currentColor" stroke-width="1.8"/><circle cx="8.5" cy="9.5" r="1.4" fill="currentColor"/><path d="M5 17l4.5-4.5 3 3 2.5-2.5L19 16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
|
|
3154
3167
|
<button id="chanCron" class="icon" title="Scheduled prompts for this agent (monitoring / reporting)" aria-label="Schedule"><svg viewBox="0 0 24 24" width="15" height="15" style="vertical-align:-2px" aria-hidden="true"><circle cx="12" cy="13" r="6.3" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="M12 9.8V13l2.2 1.4" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/><path d="M4.8 6.6 7.2 4.6M19.2 6.6 16.8 4.6" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg><span class="ct-txt">Schedule</span></button>
|
|
3155
3168
|
<button id="chanStop" class="icon stop" title="End session" aria-label="End session"><svg viewBox="0 0 24 24" width="15" height="15" style="vertical-align:-2px" aria-hidden="true"><path d="M12 4v7" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/><path d="M8.5 6.8a6 6 0 1 0 7 0" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg></button>
|
|
3156
3169
|
<button id="chanTerm" class="icon" title="Terminal — the raw TUI for this agent" aria-label="Terminal"><svg viewBox="0 0 24 24" width="15" height="15" style="vertical-align:-2px" aria-hidden="true"><rect x="2.5" y="4" width="19" height="16" rx="2.5" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="M6 9.5l3 2.5-3 2.5" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/><path d="M12.5 15h5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg><span class="ct-txt">Terminal</span></button>
|
|
@@ -3256,6 +3269,27 @@
|
|
|
3256
3269
|
<div id="lightboxBar"><a id="lightboxDl" download>⭳ Download</a></div>
|
|
3257
3270
|
</div>
|
|
3258
3271
|
|
|
3272
|
+
<!-- Media gallery: every image in the ACTIVE agent's conversation, as a grid of
|
|
3273
|
+
thumbnails. Clicking one opens the lightbox above (the "classic flow"). The
|
|
3274
|
+
grid is scanned from the live transcript DOM, so it covers all three image
|
|
3275
|
+
kinds the lightbox already knows (agent file cards, user attachments,
|
|
3276
|
+
markdown images) with no extra bookkeeping. -->
|
|
3277
|
+
<div id="galleryOverlay" class="overlay" hidden>
|
|
3278
|
+
<div class="sec-panel pinned gal-panel">
|
|
3279
|
+
<div class="pin-head">
|
|
3280
|
+
<div class="sec-head">
|
|
3281
|
+
<strong>Media gallery</strong>
|
|
3282
|
+
<button id="galleryClose" title="Close">✕</button>
|
|
3283
|
+
</div>
|
|
3284
|
+
<p class="sec-note" id="galleryNote">Every image in this conversation. Click one to view it full-size.</p>
|
|
3285
|
+
</div>
|
|
3286
|
+
<div class="pin-body">
|
|
3287
|
+
<div id="galleryGrid" class="gal-grid"></div>
|
|
3288
|
+
<div id="galleryEmpty" class="gal-empty" hidden>No images in this conversation yet.</div>
|
|
3289
|
+
</div>
|
|
3290
|
+
</div>
|
|
3291
|
+
</div>
|
|
3292
|
+
|
|
3259
3293
|
<link rel="stylesheet" href="/vendor/xterm.css">
|
|
3260
3294
|
<script src="/vendor/xterm.js"></script>
|
|
3261
3295
|
<script src="/vendor/addon-fit.js"></script>
|
|
@@ -5519,6 +5553,9 @@
|
|
|
5519
5553
|
// Viewing the channel clears its "unread response" highlight.
|
|
5520
5554
|
if (tab.btnEl.classList.contains("unread")) setTabMood(tab, null);
|
|
5521
5555
|
const switched = !!prev && prev !== tab && !restoring;
|
|
5556
|
+
// The gallery is per-agent; switching agents under it would show the old
|
|
5557
|
+
// one's media. Close it rather than silently mislabel the grid.
|
|
5558
|
+
if (switched) closeGallery();
|
|
5522
5559
|
tabs.forEach((t) => {
|
|
5523
5560
|
t.btnEl.classList.toggle("active", t === tab);
|
|
5524
5561
|
t.transcriptEl.hidden = t !== tab;
|
|
@@ -6027,6 +6064,8 @@
|
|
|
6027
6064
|
// talking about an agent that does not exist.
|
|
6028
6065
|
$("chanCron").disabled = true;
|
|
6029
6066
|
$("chanStop").disabled = true;
|
|
6067
|
+
$("chanGallery").disabled = true;
|
|
6068
|
+
closeGallery(); // no agent → its media grid is stale; don't leave it up
|
|
6030
6069
|
paintChanUpdate();
|
|
6031
6070
|
// Two different truths behind the same empty panel — the server tells us
|
|
6032
6071
|
// which (see syncFirstAgent), so a newcomer is never invited to create a
|
|
@@ -6039,6 +6078,7 @@
|
|
|
6039
6078
|
$("startingState").classList.remove("visible");
|
|
6040
6079
|
$("chanCron").disabled = !t.sessionId;
|
|
6041
6080
|
$("chanStop").disabled = false;
|
|
6081
|
+
$("chanGallery").disabled = !t.sessionId;
|
|
6042
6082
|
paintChanUpdate();
|
|
6043
6083
|
$("led").className = "led " +
|
|
6044
6084
|
({ setup: "", connecting: "busy", ready: "on", busy: "busy", dead: "off" }[t.status]);
|
|
@@ -9171,6 +9211,59 @@
|
|
|
9171
9211
|
});
|
|
9172
9212
|
$("lightboxClose").addEventListener("click", closeLightbox);
|
|
9173
9213
|
|
|
9214
|
+
// Media gallery: the grid of every image in the active conversation. It reads
|
|
9215
|
+
// the live transcript DOM rather than a separate media model, so it stays in
|
|
9216
|
+
// lockstep with what the lightbox handles — the same three selectors — and a
|
|
9217
|
+
// newly streamed image shows up the next time the gallery is opened, with no
|
|
9218
|
+
// extra wiring. De-duped by src: the same file sent twice is one tile.
|
|
9219
|
+
function collectGalleryImages() {
|
|
9220
|
+
const host = active && active.transcriptEl;
|
|
9221
|
+
if (!host) return [];
|
|
9222
|
+
const out = [], seen = new Set();
|
|
9223
|
+
for (const img of host.querySelectorAll(".file-img img, .att-img img, .bubble.md img")) {
|
|
9224
|
+
const src = img.currentSrc || img.src;
|
|
9225
|
+
if (!src || seen.has(src)) continue;
|
|
9226
|
+
seen.add(src);
|
|
9227
|
+
out.push({ src, name: img.alt || "" });
|
|
9228
|
+
}
|
|
9229
|
+
return out;
|
|
9230
|
+
}
|
|
9231
|
+
function openGallery() {
|
|
9232
|
+
if (!active) return;
|
|
9233
|
+
const items = collectGalleryImages();
|
|
9234
|
+
const grid = $("galleryGrid");
|
|
9235
|
+
grid.innerHTML = "";
|
|
9236
|
+
for (const it of items) {
|
|
9237
|
+
const cell = document.createElement("button");
|
|
9238
|
+
cell.type = "button";
|
|
9239
|
+
cell.className = "gal-cell";
|
|
9240
|
+
cell.title = it.name || "image";
|
|
9241
|
+
const im = document.createElement("img");
|
|
9242
|
+
im.src = it.src; im.alt = it.name; im.loading = "lazy";
|
|
9243
|
+
cell.appendChild(im);
|
|
9244
|
+
// "Retombe sur le flow classique": a thumbnail opens the lightbox on top
|
|
9245
|
+
// of the gallery, so closing it returns here to pick another.
|
|
9246
|
+
cell.addEventListener("click", () => openLightbox(it.src, it.name));
|
|
9247
|
+
grid.appendChild(cell);
|
|
9248
|
+
}
|
|
9249
|
+
$("galleryEmpty").hidden = items.length > 0;
|
|
9250
|
+
$("galleryNote").textContent = items.length
|
|
9251
|
+
? "Every image in this conversation — " + items.length + (items.length > 1 ? " images" : " image") + ". Click one to view it full-size."
|
|
9252
|
+
: "Every image in this conversation. Click one to view it full-size.";
|
|
9253
|
+
$("galleryOverlay").hidden = false;
|
|
9254
|
+
$("galleryClose").focus();
|
|
9255
|
+
}
|
|
9256
|
+
function closeGallery() {
|
|
9257
|
+
if ($("galleryOverlay").hidden) return;
|
|
9258
|
+
$("galleryOverlay").hidden = true;
|
|
9259
|
+
$("galleryGrid").innerHTML = ""; // drop the decoded thumbnails
|
|
9260
|
+
}
|
|
9261
|
+
$("chanGallery").addEventListener("click", openGallery);
|
|
9262
|
+
$("galleryClose").addEventListener("click", closeGallery);
|
|
9263
|
+
$("galleryOverlay").addEventListener("click", (e) => {
|
|
9264
|
+
if (e.target === $("galleryOverlay")) closeGallery();
|
|
9265
|
+
});
|
|
9266
|
+
|
|
9174
9267
|
// The Escape key sends esc to the active session (like the engine room's Esc
|
|
9175
9268
|
// button). Precedence: an open overlay/panel is closed first (Escape does not
|
|
9176
9269
|
// reach down to the session); a pending clickable dialog is left intact;
|
|
@@ -9182,6 +9275,10 @@
|
|
|
9182
9275
|
// The image viewer sits on top of everything, including the terminal, so it
|
|
9183
9276
|
// is closed before any other Escape handling.
|
|
9184
9277
|
if (!lightbox.hidden) { closeLightbox(); e.preventDefault(); return; }
|
|
9278
|
+
// The gallery is a modal overlay on top of the terminal too, so it is closed
|
|
9279
|
+
// before the terminal gets to claim Escape — but after the lightbox, which
|
|
9280
|
+
// may be stacked above it.
|
|
9281
|
+
if (!$("galleryOverlay").hidden) { closeGallery(); e.preventDefault(); return; }
|
|
9185
9282
|
// In the interactive terminal, xterm owns every key (incl. Esc) — the raw
|
|
9186
9283
|
// keystroke already flows to the pane via term.onData; don't double-handle.
|
|
9187
9284
|
if (active && active.termOn) return;
|