${r.name}
${r.width} × ${r.height} px
${fmtSize(r.originalSize)} → ${fmtSize(r.webpBlob.size)} ${isPos ? '▼ ' : '▲ '}${Math.abs(saving)}%
⬇ Download WEBP `; resultsGrid.appendChild(card); } function buildSummary() { const totalOrig = results.reduce((a, r) => a + r.originalSize, 0); const totalWebp = results.reduce((a, r) => a + r.webpBlob.size, 0); const saved = ((1 - totalWebp / totalOrig) * 100).toFixed(1); const alphaCount = results.filter(r => r.hasAlpha).length; resultsSummary.innerHTML = `
${results.length} file(s) ${alphaCount ? `
α ${alphaCount} transparent ` : ''}
${fmtSize(totalOrig)} → ${fmtSize(totalWebp)} ${parseFloat(saved) > 0 ? '▼ ' : '▲ '}${Math.abs(saved)}% total `; } /* ── DOWNLOAD ── */ function dlSingle(idx) { const r = results[idx]; const url = URL.createObjectURL(r.webpBlob); triggerDl(url, r.name); setTimeout(() => URL.revokeObjectURL(url), 5000); } downloadAllBtn.addEventListener('click', async () => { if (!results.length) return; if (results.length === 1) { dlSingle(0); return; } toast('📦 Preparing ZIP…'); try { const JSZip = await loadJSZip(); const zip = new JSZip(); results.forEach(r => zip.file(r.name, r.webpBlob)); const blob = await zip.generateAsync({ type: 'blob', compression: 'DEFLATE', compressionOptions: { level: 1 } }); triggerDl(URL.createObjectURL(blob), 'webp-images.zip'); toast('✅ ZIP downloaded!'); } catch { for (let i = 0; i < results.length; i++) { await delay(300 * i); dlSingle(i); } } }); function triggerDl(url, name) { const a = document.createElement('a'); a.href = url; a.download = name; document.body.appendChild(a); a.click(); document.body.removeChild(a); } function loadJSZip() { return new Promise((resolve, reject) => { if (window.JSZip) { resolve(window.JSZip); return; } const s = document.createElement('script'); s.src = 'https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js'; s.onload = () => resolve(window.JSZip); s.onerror = reject; document.head.appendChild(s); }); } /* ── RESET ── */ resetBtn.addEventListener('click', () => { files = []; results = []; resultsGrid.innerHTML = ''; resultsSection.classList.remove('active'); progressWrap.classList.remove('active'); fileInput.value = ''; emptyState.style.display = 'block'; convertBtn.disabled = true; toast('🔄 Reset complete.'); }); /* ── HELPERS ── */ function fmtSize(b) { if (b < 1024) return b + ' B'; if (b < 1048576) return (b / 1024).toFixed(1) + ' KB'; return (b / 1048576).toFixed(2) + ' MB'; } function delay(ms) { return new Promise(r => setTimeout(r, ms)); } let toastTimer; function toast(msg, ok = true) { $('toastIcon').textContent = ok ? '✅' : '⚠️'; $('toastMsg').textContent = msg; const el = $('toast'); el.classList.add('show'); clearTimeout(toastTimer); toastTimer = setTimeout(() => el.classList.remove('show'), 3500); } window.dlSingle = dlSingle;