← Commit history
Cargo.lock+1−1
@@ -10,7 +10,7 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"  [[package]] name = "adom-shotlog"-version = "0.4.1"+version = "0.4.2" dependencies = [  "axum",  "base64",
Cargo.toml+1−1
@@ -1,6 +1,6 @@ [package] name = "adom-shotlog"-version = "0.4.1"+version = "0.4.2" edition = "2021" description = "Screenshot log viewer and CLI for Adom" 
VERSION+1−1
@@ -1 +1 @@-0.4.1+0.4.2
bin/adom-shotlog
⋯ 1 unchanged line ⋯
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "adom-shotlog",-  "version": "0.4.1",+  "version": "0.4.2",   "type": "app",   "title": "adom-shotlog",   "description": "See the shots your AI never showed you. Your AI screenshots your app while it tests but never surfaces them (it thinks in text) \u2014 adom-shotlog streams every shot it gathered into a live gallery you open in a webview, pup, your browser, or your phone. Now ingests Adom Desktop owned-popup arrays + coordMap via --meta.",
page.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "adom-shotlog",-  "version": "0.4.1",+  "version": "0.4.2",   "type": "app",   "title": "adom-shotlog",   "description": "See the shots your AI never showed you. Your AI screenshots your app while it tests but never surfaces them (it thinks in text) — adom-shotlog streams every shot it gathered into a live gallery you open in a webview, pup, your browser, or your phone. Now ingests Adom Desktop owned-popup arrays + coordMap via --meta.",
screenshots/hero.png
⋯ 1 unchanged line ⋯
screenshots/popups.png
⋯ 1 unchanged line ⋯
src/html/index.html+73−7
@@ -107,8 +107,32 @@ header { /* Popup-array badge + nerd info chip on a card */ .shot-card-meta .badge-pop { background: rgba(0,184,176,.16); color: var(--accent); border: 1px solid rgba(0,184,176,.4);   border-radius: 999px; padding: 0 7px; font-weight: 600; cursor: help; }-.shot-card-meta .badge-nerd { color: var(--text3); cursor: help; border: 1px solid var(--border);-  border-radius: 4px; padding: 0 5px; }+.shot-card-meta .badge-nerd { color: var(--text3); cursor: pointer; border: 1px solid var(--border);+  border-radius: 4px; padding: 0 5px; user-select: none; }+.shot-card-meta .badge-nerd:hover { color: var(--accent); border-color: rgba(0,184,176,.4); }+.shot-card-meta .badge-nerd.active { color: var(--accent); border-color: rgba(0,184,176,.5); background: rgba(0,184,176,.10); }+/* Owned-popup row, inline on the card — all array shots in ONE row, no zoom needed */+.card-popups { display: flex; gap: 8px; padding: 9px 13px 4px; overflow-x: auto; flex-shrink: 0; }+.card-popups .ph { flex: 0 0 auto; align-self: center; font: 600 10px 'Familjen Grotesk', sans-serif;+  color: var(--text2); white-space: nowrap; padding-right: 2px; }+.card-popups .pc { flex: 0 0 auto; width: 168px; background: #000; border: 1px solid var(--border);+  border-radius: 8px; overflow: hidden; cursor: zoom-in; transition: border-color .12s; }+.card-popups .pc:hover { border-color: rgba(0,184,176,.5); }+.card-popups .pc img { width: 100%; height: 96px; object-fit: contain; background: #111; display: block; }+.card-popups .pc .cap { padding: 3px 7px; font-family: 'JetBrains Mono', monospace; font-size: 9px;+  color: var(--text3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }+/* Nerd metadata revealed INLINE on the card (not just the zoom modal) */+.card-nerd { display: none; margin: 6px 13px 12px; border: 1px solid var(--border); border-radius: 8px;+  background: var(--elevated); flex-shrink: 0; }+.card-nerd.open { display: block; }+.card-nerd .nhead { display: flex; align-items: center; gap: 8px; padding: 7px 11px; font: 600 10px 'JetBrains Mono', monospace; color: var(--text2); }+.card-nerd .nhead .copy { margin-left: auto; font-size: 9px; color: var(--accent); border: 1px solid rgba(0,184,176,.4);+  border-radius: 4px; padding: 1px 7px; cursor: pointer; }+.card-nerd .nbody { padding: 0 11px 9px; }+.card-nerd .row { display: flex; gap: 8px; font-family: 'JetBrains Mono', monospace; font-size: 10px;+  padding: 2px 0; border-top: 1px solid rgba(255,255,255,.04); }+.card-nerd .row .k { color: var(--text3); min-width: 120px; }+.card-nerd .row .v { color: var(--text); user-select: all; word-break: break-all; }  /* Zoom modal — full card */ .modal { position: fixed; inset: 0; background: rgba(0,0,0,.88); display: none;@@ -300,9 +324,27 @@ header {     }   } +  // Inline nerd-metadata panel, rendered ON the card (revealed in place — no zoom).+  function buildNerdInline(e) {+    const pops=popList(e);+    const raw=JSON.stringify({meta:e.meta||null, popups:pops.length?pops:undefined}, null, 2);+    const panel=document.createElement('div'); panel.className='card-nerd';+    const head=document.createElement('div'); head.className='nhead'; head.textContent='⌗ capture metadata';+    const cp=document.createElement('span'); cp.className='copy'; cp.textContent='copy JSON';+    cp.addEventListener('click', ev=>{ ev.stopPropagation();+      navigator.clipboard?.writeText(raw).then(()=>{ cp.textContent='copied ✓'; setTimeout(()=>cp.textContent='copy JSON',1200); }); });+    head.appendChild(cp); panel.appendChild(head);+    const body=document.createElement('div'); body.className='nbody';+    metaRows(e).forEach(([k,v])=>{ const r=document.createElement('div'); r.className='row';+      const kk=document.createElement('span'); kk.className='k'; kk.textContent=k;+      const vv=document.createElement('span'); vv.className='v'; vv.textContent=v;+      r.appendChild(kk); r.appendChild(vv); body.appendChild(r); });+    panel.appendChild(body);+    return panel;+  }+   function card(e) {     const c=document.createElement('div'); c.className='shot-card'; c.dataset.id=e.id;-    c.addEventListener('click',()=>openModal(e));     const desc=document.createElement('div');     if (e.description) { desc.className='shot-card-desc'; desc.textContent=e.description; }     else { desc.className='shot-card-desc no-desc'; desc.textContent='⚠ No description — inject with -d "what and why"'; }@@ -318,15 +360,39 @@ header {     const pops=popList(e);     if (pops.length){ const s=document.createElement('span'); s.className='sep'; s.textContent='·'; meta.appendChild(s);       const b=document.createElement('span'); b.className='badge-pop'; b.textContent='+'+pops.length+' popup'+(pops.length>1?'s':'');-      b.setAttribute('data-tooltip','This shot captured '+pops.length+' owned popup'+(pops.length>1?'s':'')+' (dropdowns / dialogs).
Open the shot to view each one.');+      b.setAttribute('data-tooltip','This shot also captured '+pops.length+' owned popup'+(pops.length>1?'s':'')+' (dropdowns / dialogs) — shown below.');       meta.appendChild(b); }+    // ⓘ meta chip toggles the inline metadata panel right here on the card.+    let nerd=null, chip=null;     if (e.meta){ const s=document.createElement('span'); s.className='sep'; s.textContent='·'; meta.appendChild(s);-      const n=document.createElement('span'); n.className='badge-nerd'; n.textContent='ⓘ meta';-      n.setAttribute('data-tooltip', metaRows(e).map(([k,v])=>k+': '+v).join('
')||'capture metadata');-      meta.appendChild(n); }+      chip=document.createElement('span'); chip.className='badge-nerd'; chip.textContent='ⓘ meta';+      chip.setAttribute('data-tooltip','Tap to reveal the capture metadata (coordMap, DPI, screen rect) inline.');+      meta.appendChild(chip); }     c.appendChild(meta);     const img=document.createElement('img'); img.className='shot-card-img'; img.src=imgUrl(e); img.alt=e.description||e.filename;+    img.addEventListener('click', ()=>openModal(e));   // image still zooms if you want it     c.appendChild(img);+    // All owned popups in ONE row, inline — no need to open the shot.+    if (pops.length){+      const row=document.createElement('div'); row.className='card-popups';+      const ph=document.createElement('span'); ph.className='ph'; ph.textContent='popups ▸'; row.appendChild(ph);+      pops.forEach(p=>{+        const cell=document.createElement('div'); cell.className='pc';+        const im=document.createElement('img'); im.src=popUrl(p.filename); im.alt=p.title||p.kind||'popup'; im.loading='lazy';+        const cap=document.createElement('div'); cap.className='cap';+        cap.textContent=(p.kind?p.kind+' · ':'')+(p.title||p.filename)+(p.w&&p.h?'  '+p.w+'×'+p.h:'');+        cell.appendChild(im); cell.appendChild(cap);+        cell.addEventListener('click', ev=>{ ev.stopPropagation();+          openModal({filename:p.filename, description:p.title||p.kind||'popup', w:p.w, h:p.h, kb:p.kb,+            timestamp:e.timestamp, source:'popup', meta:p.coordMap?{coordMap:p.coordMap,shotId:p.shotId}:null}); });+        row.appendChild(cell);+      });+      c.appendChild(row);+    }+    // Inline nerd panel + wire the chip to toggle it in place.+    if (e.meta){ nerd=buildNerdInline(e); c.appendChild(nerd);+      chip.addEventListener('click', ev=>{ ev.stopPropagation();+        const open=nerd.classList.toggle('open'); chip.classList.toggle('active', open); }); }     return c;   }