← Commit history

Manager: symbol/footprint columns now render via CANONICAL adom-symbol/adom-footprint embed (trustworthy witnesses, no home-grown SVG); declare deps (2.2.0)

John Lauer ·8b380246b5 ·3mo ago ·parent 1c58223
2 files changed +51−12
src/manage.html+7−12
@@ -32,6 +32,8 @@   .cols{display:grid;grid-template-columns:1fr 1fr 1fr;gap:14px}   .card{background:var(--panel);border:1px solid var(--edge);border-radius:12px;overflow:hidden;display:flex;flex-direction:column}   .card h3{margin:0;padding:9px 12px;font-size:12px;text-transform:uppercase;letter-spacing:.06em;color:var(--mut);border-bottom:1px solid var(--edge)}+  .card h3 small{text-transform:none;letter-spacing:0;color:#5b6675;font-weight:400}+  .card iframe.embed{width:100%;height:440px;border:0;background:#161b22;display:block}   .card .body{aspect-ratio:1;width:100%;display:flex;align-items:center;justify-content:center;padding:10px;background:#161b22;overflow:hidden;cursor:grab;touch-action:none;position:relative}   .card .body svg{max-width:100%;max-height:100%;will-change:transform}   .card .hint2{position:absolute;bottom:6px;right:8px;font-size:10px;color:#b9c0cc;background:#0d0f14aa;border-radius:5px;padding:1px 6px;pointer-events:none}@@ -114,23 +116,16 @@ async function openPart(slug,el){   v.innerHTML=`     <h2 class="title">${p.mpn} <small>· ${p.pins} pins · ${p.pads} pads</small></h2>     <div class="cols">-      <div class="card"><h3>Schematic Symbol</h3><div class="body">${p.symbol_svg}<span class="hint2">drag · scroll to zoom</span></div></div>-      <div class="card"><h3>Footprint</h3>-        <div class="lfilter">${(p.layers||[]).map(l=>`<label class="chip"><input type="checkbox" checked data-key="${l.key}"><span class="sw" style="background:${COLORS[l.role]||'#888'}"></span>${l.role}</label>`).join('')}</div>-        <div class="body" id="fpbody">${p.footprint_svg}<span class="hint2">drag · scroll to zoom</span></div></div>+      <div class="card"><h3>Schematic Symbol <small>· via adom-symbol</small></h3><iframe class="embed" src="embed/symbol/${slug}" loading="lazy" title="symbol viewer"></iframe></div>+      <div class="card"><h3>Footprint <small>· via adom-footprint</small></h3><iframe class="embed" src="embed/footprint/${slug}" loading="lazy" title="footprint viewer"></iframe></div>       <div class="card"><h3>3D Model</h3>${glb}</div>     </div>     <div class="stacktitle">Footprint layer stackup — what each element becomes per EDA tool</div>     <table><thead><tr><th>Element (neutral role)</th><th>KiCad layer</th><th>Altium layer</th></tr></thead>     <tbody>${rows}</tbody></table>`;-  v.querySelectorAll('.card .body').forEach(makePannable);-  // footprint layer filter — toggle visibility of each layer's SVG elements-  v.querySelectorAll('.lfilter input').forEach(cb=>{-    cb.onchange=()=>{-      v.querySelectorAll('#fpbody svg .ly-'+cb.dataset.key).forEach(el=>{el.style.display=cb.checked?'':'none';});-    };-  });-  setupHighlight(v);+  // Symbol + footprint are now canonical interactive iframes (adom-symbol /+  // adom-footprint embed) with their OWN pan/zoom + layer/pin panels — nothing+  // to wire here. The 3D column keeps its own viewer. }  // Hover a pin (symbol) or pad (footprint) → highlight it + show its number and
src/manage.rs+44
@@ -64,6 +64,16 @@ fn route(method: &Method, url: &str) -> Response<Cursor<Vec<u8>>> {                 None => Response::from_string("no glb").with_status_code(404),             }         }+        // Canonical interactive viewers — the symbol/footprint columns render via+        // the AUTHORITATIVE tools (adom-symbol / adom-footprint `embed`) so the+        // Manager faithfully shows what the real pipeline produces, not a+        // home-grown SVG that could quietly diverge from ground truth.+        (Method::Get, p) if p.starts_with("/embed/symbol/") => {+            embed_view(&p["/embed/symbol/".len()..], "kicad_sym", "adom-symbol")+        }+        (Method::Get, p) if p.starts_with("/embed/footprint/") => {+            embed_view(&p["/embed/footprint/".len()..], "kicad_mod", "adom-footprint")+        }         _ => Response::from_string("not found").with_status_code(404),     } }@@ -124,6 +134,40 @@ fn list_components() -> Value {         "hints": ["click a component to open its viewer"] }) } +/// Render a component's canonical INTERACTIVE viewer by shelling out to the+/// authoritative tool's `embed` (`adom-symbol` / `adom-footprint`) on the wiki+/// source file. Self-contained HTML, iframed by the Manager — no external assets,+/// no home-grown SVG. Requires the tool to be installed (declared as a dep).+fn embed_view(slug: &str, ext: &str, tool: &str) -> Response<Cursor<Vec<u8>>> {+    let page = |msg: &str, code: u16| {+        Response::from_string(format!(+            "<body style='margin:0;background:#0d1117;color:#8b949e;font:13px -apple-system,sans-serif;display:flex;align-items:center;justify-content:center;height:100vh'><div>{msg}</div></body>"+        )).with_header(hdr("text/html; charset=utf-8")).with_status_code(code)+    };+    let mpn = up(slug);+    let src = match wiki_text(slug, &format!("{mpn}.{ext}")) {+        Some(t) if !t.trim_start().starts_with('<') && !t.contains("\"error\"") => t,+        _ => return page(&format!("no {ext} on the wiki for {mpn}"), 200),+    };+    let base = std::env::temp_dir().join(format!("adomlbr-mgr-{slug}"));+    let infile = base.with_extension(ext);+    let outfile = base.with_extension("embed.html");+    if std::fs::write(&infile, src.as_bytes()).is_err() {+        return page("temp write failed", 500);+    }+    let ok = Command::new(tool)+        .args(["embed", "--file", infile.to_str().unwrap_or(""),+               "--out", outfile.to_str().unwrap_or("")])+        .output().map(|o| o.status.success()).unwrap_or(false);+    if !ok {+        return page(&format!("{tool} embed unavailable — is {tool} installed?"), 200);+    }+    match std::fs::read(&outfile) {+        Ok(b) => Response::from_data(b).with_header(hdr("text/html; charset=utf-8")),+        Err(_) => page("embed read failed", 500),+    }+}+ /// Fetch a component and build its adom-lbr part FRESH on every call (nothing is /// cached), then render symbol/footprint SVG on the fly. The canonical adom-lbr /// JSON is the primary source; if the page has none, we import the KiCad files.