// part.js — part detail. Left: a tabbed visualization (real 3D model / schematic symbol / footprint), // all built from the curated data. Right: the full record (specs, pins, SPICE, downloads). import { mountViewer } from '/assets/viewer.js'; const esc = (s) => (s == null ? '' : String(s).replace(/[&<>"]/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c]))); const id = new URLSearchParams(location.search).get('id'); function dl(name, text, mime = 'text/plain') { const a = document.createElement('a'); a.href = URL.createObjectURL(new Blob([text], { type: mime })); a.download = name; a.click(); } function spendCredit() { let c = parseInt(localStorage.getItem('ppcb_credits') || '5', 10); if (c <= 0) { alert('Out of download credits — contribute a curated part to earn 5 more.'); return false; } localStorage.setItem('ppcb_credits', --c); document.getElementById('cred-n').textContent = c; return true; } // ---- footprint SVG from real pad geometry (top-down, copper pads, pad numbers, outline) ---- function footprintSVG(p) { const pads = p.footprint_pads || []; if (!pads.length) return '
${esc(p.summary)}
${esc(p.when_to_use)}
${esc(p.spice_mixed_note || '')}
${p.spice_mixed_verified ? `Verified — ${esc(p.spice_mixed_verified)}
` : ''} ${(p.spice_mixed_ports || []).length ? `.SUBCKT ${esc(p.spice_mixed_subckt || '')} ${esc((p.spice_mixed_ports || []).join(' '))}
` : ''}${esc(p.spice_mixed)}${esc(p.spice)}