← Commit history
Cargo.lock+1−1
@@ -10,7 +10,7 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"  [[package]] name = "adom-shotlog"-version = "0.29.0"+version = "0.29.1" dependencies = [  "axum",  "base64",
Cargo.toml+1−1
@@ -1,6 +1,6 @@ [package] name = "adom-shotlog"-version = "0.29.0"+version = "0.29.1" edition = "2021" description = "Screenshot log viewer and CLI for Adom" license = "MIT"
VERSION+1−1
@@ -1 +1 @@-0.29.0+0.29.1
bin/adom-shotlog
⋯ 1 unchanged line ⋯
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "adom-shotlog",-  "version": "0.29.0",+  "version": "0.29.1",   "type": "app",   "title": "Shotlog - Screenshot Log",   "description": "See the shots your AI never showed you, and know it actually SAW them. adom-shotlog streams every screenshot the AI gathers into a live gallery (webview/pup/browser/phone), reports whether a human is really watching and on which surface, and ingests Adom Bridge child-window arrays via --meta.",
page.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "adom-shotlog",-  "version": "0.29.0",+  "version": "0.29.1",   "type": "app",   "title": "Shotlog - Screenshot Log",   "description": "See the shots your AI never showed you, and know it actually SAW them. adom-shotlog streams every screenshot the AI gathers into a live gallery (webview/pup/browser/phone), reports whether a human is really watching and on which surface, and ingests Adom Bridge child-window arrays via --meta.",
src/html/index.html+31−14
@@ -259,12 +259,13 @@ body.compact .card-popups .ph { padding-top: 4px; } .card-refbar .rb-ref { letter-spacing: .2px; } /* copy button (Ray, PR #5): hover-revealed like ⛶, never on the thumbnail */ .card-refbar .rb-copy svg { width: 13px; height: 13px; display: block; }-.card-refbar .rb-copy { margin-left: 4px; padding: 2px 4px; border-radius: 5px; cursor: pointer;+.card-refbar .rb-copy { margin-left: 2px; padding: 2px 5px; border-radius: 5px; cursor: pointer; flex-shrink: 0;   display: inline-flex; align-items: center; justify-content: center;-  font: inherit; line-height: 1.5; color: var(--text3); background: transparent;-  border: 1px solid var(--border-muted); opacity: 0; transition: opacity .12s, color .12s, border-color .12s; }+  font: inherit; line-height: 1.5; color: var(--accent-bright); background: rgba(0,184,176,.10);+  border: 1px solid rgba(0,184,176,.55); opacity: 1; transition: color .12s, border-color .12s, background .12s; }+/* Always visible (Ray, 2026-10-16: hover-revealed and grey, it was too faint to find). */ .shot-card:hover .card-refbar .rb-copy, .card-refbar .rb-copy:focus-visible { opacity: 1; }-.card-refbar .rb-copy:hover { color: var(--accent-bright); border-color: rgba(0,184,176,.5); }+.card-refbar .rb-copy:hover { color: #fff; background: rgba(0,184,176,.30); border-color: var(--accent-bright); } .card-refbar .rb-copy.done { opacity: 1; color: var(--accent-bright); border-color: rgba(0,184,176,.5); } @media (hover: none) { .card-refbar .rb-copy { opacity: .8; } } .card-refbar .rb-tag { color: var(--accent-bright); background: rgba(0,184,176,.12); border: 1px solid rgba(0,184,176,.45);@@ -1180,6 +1181,14 @@ body:not(.compact) .card-refbar .rb-cap { display: none; }     // COMPACT mode hides it and reveals it as a hover overlay (the ⓘ chip on     // the image), so the gallery is ~90% thumbnails.     const info=document.createElement('div'); info.className='card-info';+    // Reveal the compact overlay BELOW the ref bar, never over it: the bar+    // holds the copy button and the caption pill, and an overlay covering+    // them blocked the copy button (Ray, 2026-10-16).+    const showInfo=()=>{+      const rb=c.querySelector('.card-refbar');+      info.style.top = rb ? (rb.offsetTop + rb.offsetHeight) + 'px' : '';+      info.classList.add('show'); window._hideTip&&window._hideTip();+    };     // For auto-captures the WHY is the headline: show the prompt the thread     // was serving, and demote the generic "auto-captured: file.png" to a     // small mono sub-line. Deliberate injects keep their description first.@@ -1283,14 +1292,6 @@ body:not(.compact) .card-refbar .rb-cap { display: none; }       if (e.tag){ const tg=document.createElement('span'); tg.className='rb-tag'; tg.textContent=e.tag;         tg.setAttribute('data-tooltip','Handle "'+e.tag+'" given by the AI that injected this shot (--tag). Say "'+e.tag+'" to mean exactly this shot.');         rb.appendChild(tg); }-      if (e.auto_description && e.description) {-        const cp=document.createElement('span'); cp.className='rb-cap'; cp.textContent=e.description;-        cp.setAttribute('aria-label','Caption: '+e.description);-        // Same reveal as the ⓘ: hover shows the full info overlay (caption,-        // prompt, file, chips); click toggles it for touch.-        cp.addEventListener('mouseenter', ()=>{ info.classList.add('show'); window._hideTip&&window._hideTip(); });-        cp.addEventListener('click', ev=>{ ev.stopPropagation(); info.classList.toggle('show'); });-        rb.appendChild(cp); }       // Copy the WHOLE reference, "#158 hero-final", not just one half (Ray,       // PR #5): the ref is globally unambiguous and the handle is what a human       // actually says, so pasting both lets the AI resolve it either way and@@ -1310,6 +1311,21 @@ body:not(.compact) .card-refbar .rb-cap { display: none; }           } else { legacyCopy(txt, done); }         });         rb.appendChild(cp); }+      // The caption pill comes AFTER the copy button (Ray, 2026-10-16): the+      // button copies "#id handle", so it sits beside them, not past the caption.+      if (e.auto_description && e.description) {+        const cp=document.createElement('span'); cp.className='rb-cap'; cp.textContent=e.description;+        cp.setAttribute('aria-label','Caption: '+e.description);+        // Same reveal as the ⓘ: hover shows the full info overlay (caption,+        // prompt, file, chips); click toggles it for touch.+        // Hover INTENT, not a bare mouseenter: the pointer crosses this pill on+        // its way to the copy button, and an instant overlay got in the way.+        let capTimer=null;+        cp.addEventListener('mouseenter', ()=>{ capTimer=setTimeout(showInfo, 350); });+        cp.addEventListener('mouseleave', ()=>{ clearTimeout(capTimer); });+        cp.addEventListener('click', ev=>{ ev.stopPropagation(); clearTimeout(capTimer);+          if (info.classList.contains('show')) info.classList.remove('show'); else showInfo(); });+        rb.appendChild(cp); }       c.appendChild(rb); }   // info (hidden in compact) -> refbar -> imgWrap (appended below)     // COMPACT mode's reveal chip: hover (or tap, on touch) the ⓘ on the image     // to overlay the full info block; it hides again when the pointer leaves@@ -1319,8 +1335,9 @@ body:not(.compact) .card-refbar .rb-cap { display: none; }     // No data-tooltip on the ⓘ: its hover REVEALS the info overlay, and a     // tooltip 600ms later landed right on top of what the human was reading.     infoHot.title='';-    infoHot.addEventListener('mouseenter', ()=>{ info.classList.add('show'); window._hideTip&&window._hideTip(); });-    infoHot.addEventListener('click', ev=>{ ev.stopPropagation(); info.classList.toggle('show'); });+    infoHot.addEventListener('mouseenter', showInfo);+    infoHot.addEventListener('click', ev=>{ ev.stopPropagation();+      if (info.classList.contains('show')) info.classList.remove('show'); else showInfo(); });     c.addEventListener('mouseleave', ()=>info.classList.remove('show'));     imgWrap.appendChild(infoHot);     // Additional path: jump STRAIGHT to fullscreen, no modal first. The click