[object Object]

← back to Purelymail Fleet Viewer

viewer: add fleet-cover hero with 1-up/4-up rotate toggle

2aafd6e119a9541f4e789ce9428a1dec5fd1b22f · 2026-05-18 17:28:30 -0700 · SteveStudio2

Files touched

Diff

commit 2aafd6e119a9541f4e789ce9428a1dec5fd1b22f
Author: SteveStudio2 <steve@designerwallcoverings.com>
Date:   Mon May 18 17:28:30 2026 -0700

    viewer: add fleet-cover hero with 1-up/4-up rotate toggle
---
 public/index.html | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)

diff --git a/public/index.html b/public/index.html
index 0c66567..7acdb01 100644
--- a/public/index.html
+++ b/public/index.html
@@ -61,6 +61,22 @@
   .shot{width:100%;height:230px;object-fit:cover;object-position:top;
     background:#fff;display:block}
   .shot.tall{height:540px}
+  /* cover hero — 1 hi-res  vs  4-square */
+  .hero-bar{display:flex;align-items:center;justify-content:space-between;
+    gap:12px;margin:18px 0 6px}
+  .hero-bar h2{margin:0}
+  #heroToggle{background:var(--gold);color:#1a1710;border:0;border-radius:6px;
+    padding:7px 14px;font-size:12px;font-weight:600;cursor:pointer}
+  #heroToggle:hover{filter:brightness(1.08)}
+  .hero{border:1px solid var(--line);border-radius:10px;overflow:hidden;margin-bottom:8px}
+  .hero.one img{width:100%;height:460px;object-fit:cover;object-position:top;
+    background:#fff;display:block}
+  .hero.quad{display:grid;grid-template-columns:1fr 1fr;gap:2px;background:var(--line)}
+  .hero.quad img{width:100%;height:225px;object-fit:cover;object-position:top;
+    background:#fff;display:block}
+  .hero a{position:relative;display:block;text-decoration:none}
+  .hero-cap{position:absolute;left:9px;bottom:9px;background:rgba(13,12,10,.8);
+    color:var(--gold);font-size:11px;padding:3px 9px;border-radius:4px}
   .dcard .meta{padding:8px 10px}
   .dcard .meta .dn{font-size:12px;font-weight:600}
   .dcard .meta .dn a{color:var(--gold);text-decoration:none}
@@ -83,6 +99,12 @@
 <div class="wrap">
   <div id="err"></div>
 
+  <div class="hero-bar">
+    <h2>Fleet Cover</h2>
+    <button id="heroToggle">◱ Show 4-up</button>
+  </div>
+  <div id="hero" class="hero quad"></div>
+
   <h2>Fleet Health — 211 domains</h2>
   <div class="cards" id="cards"></div>
   <div class="sub" id="healthnote"></div>
@@ -187,6 +209,7 @@ function render(d){
   // avoids reloading every iframe on the 15s auto-refresh
   const sig = JSON.stringify(d.health.domains || []);
   if (sig !== lastSig){ lastSig = sig; draw(); }
+  if (!heroDrawn){ heroDrawn = true; drawHero(); }
   $('#foot').textContent = 'purelymail-fleet-viewer · 127.0.0.1:9779 · health source: email-deliverability-agent/output/domain-health.json';
 }
 
@@ -324,6 +347,41 @@ function setDensity(){
   localStorage.setItem('pmfv.density', n);
 }
 
+// --- fleet cover hero ------------------------------------------------------
+// One big hi-res screenshot, or a 2x2 of four lower-res ones. The toggle
+// re-picks four random fleet domains so each press rotates through the fleet.
+let heroMode = localStorage.getItem('pmfv.heroMode') || '4up';
+let heroPick = [];
+let heroDrawn = false;
+
+function pickHeroDomains(n){
+  const pool = (DATA && DATA.health.domains || []).map(d=>d.domain);
+  const out = [];
+  while (out.length < n && pool.length)
+    out.push(pool.splice(Math.floor(Math.random()*pool.length),1)[0]);
+  return out;
+}
+function heroCard(domain){
+  return '<a href="https://'+domain+'" target="_blank" rel="noopener">'
+    + '<img src="/api/shot?domain='+encodeURIComponent(domain)
+    + '" loading="lazy" onerror="shotFail(this,\''+domain+'\','+(heroMode==='1up'?460:225)+')">'
+    + '<span class="hero-cap">'+domain+'</span></a>';
+}
+function drawHero(){
+  if (!DATA) return;
+  if (heroPick.length < 4) heroPick = pickHeroDomains(4);
+  const h = $('#hero');
+  if (heroMode==='1up'){ h.className='hero one'; h.innerHTML = heroCard(heroPick[0]); }
+  else { h.className='hero quad'; h.innerHTML = heroPick.slice(0,4).map(heroCard).join(''); }
+  $('#heroToggle').textContent = heroMode==='1up' ? '◱ Show 4-up' : '▢ Show 1 hi-res';
+}
+function toggleHero(){
+  heroMode = heroMode==='1up' ? '4up' : '1up';
+  localStorage.setItem('pmfv.heroMode', heroMode);
+  heroPick = pickHeroDomains(4);   // re-pick so each toggle rotates the fleet
+  drawHero();
+}
+
 async function load(){
   try{
     const r = await fetch('/api/status');
@@ -343,6 +401,7 @@ async function load(){
   draw();
 }));
 $('#density').addEventListener('input', setDensity);
+$('#heroToggle').addEventListener('click', toggleHero);
 
 setDensity();
 load();

← d0d1ab6 viewer: server-rendered screenshots for every domain + Site  ·  back to Purelymail Fleet Viewer  ·  gitignore: broaden patterns to cover bak/pre/swp/orig/rej de e42a811 →