(file, index)
| 759 | |
| 760 | // Build a single result item card |
| 761 | function createResultItem(file, index) { |
| 762 | const item = document.createElement('div'); |
| 763 | item.className = 'results-item'; |
| 764 | item.dataset.index = index; |
| 765 | |
| 766 | const checkbox = document.createElement('input'); |
| 767 | checkbox.type = 'checkbox'; |
| 768 | checkbox.checked = state.selectedFiles.has(index); |
| 769 | // Allow toggling selection via the checkbox |
| 770 | checkbox.addEventListener('click', (e) => { |
| 771 | e.stopPropagation(); // Prevent the event from bubbling to the parent item |
| 772 | |
| 773 | const isChecked = checkbox.checked; |
| 774 | if (isChecked) { |
| 775 | state.selectedFiles.add(index); |
| 776 | item.classList.add('selected'); |
| 777 | } else { |
| 778 | state.selectedFiles.delete(index); |
| 779 | item.classList.remove('selected'); |
| 780 | } |
| 781 | |
| 782 | updateSelectionButtons(); |
| 783 | }); |
| 784 | |
| 785 | if (state.selectedFiles.has(index)) { |
| 786 | item.classList.add('selected'); |
| 787 | } |
| 788 | |
| 789 | const preview = document.createElement('div'); |
| 790 | preview.className = 'result-preview'; |
| 791 | |
| 792 | const img = document.createElement('img'); |
| 793 | const url = URL.createObjectURL(file.compressedFile || file.file); |
| 794 | img.src = url; |
| 795 | // Keep the blob URL alive for hover previews |
| 796 | // The URL is cleared on page unload or when the item is removed |
| 797 | preview.appendChild(img); |
| 798 | |
| 799 | // Store the blob URL for later cleanup |
| 800 | item.dataset.blobUrl = url; |
| 801 | |
| 802 | const name = document.createElement('div'); |
| 803 | name.className = 'result-name'; |
| 804 | name.textContent = file.newName || file.compressedFile.name; |
| 805 | |
| 806 | const size = document.createElement('div'); |
| 807 | size.className = 'result-size'; |
| 808 | |
| 809 | // Always show size changes as original → new (percentage) |
| 810 | if (file.originalSize && file.compressedSize) { |
| 811 | const ratio = file.originalSize > 0 |
| 812 | ? ((file.originalSize - file.compressedSize) / file.originalSize * 100).toFixed(1) |
| 813 | : '0.0'; |
| 814 | const savedSize = file.originalSize - file.compressedSize; |
| 815 | |
| 816 | if (savedSize > 0) { |
| 817 | // File size decreased (successful compression) |
| 818 | size.innerHTML = `<span style="color: var(--muted);">${formatFileSize(file.originalSize)}</span> <span style="color: var(--muted);">→</span> ${formatFileSize(file.compressedSize)} <span style="color: var(--success); font-weight: 600;">(-${ratio}%)</span>`; |
no test coverage detected