// Resources Management let currentResourceTab = 'screenshots'; let selectedFiles = new Set(); // Switch between resource tabs function switchResourceTab(tab) { currentResourceTab = tab; // Clear selection when switching tabs selectedFiles.clear(); updateBulkActions(); // Update tab buttons const tabs = document.querySelectorAll('#resources .tab'); tabs.forEach(t => t.classList.remove('active')); event.target.classList.add('active'); // Show/hide content document.getElementById('screenshotsTab').style.display = tab === 'screenshots' ? 'block' : 'none'; document.getElementById('htmlTab').style.display = tab === 'html' ? 'block' : 'none'; } // Update bulk actions visibility and count function updateBulkActions() { const bulkActions = document.getElementById('bulkActions'); const selectedCount = document.getElementById('selectedCount'); if (selectedFiles.size > 0) { bulkActions.style.display = 'flex'; selectedCount.textContent = `${selectedFiles.size} selected`; } else { bulkActions.style.display = 'none'; } } // Toggle file selection function toggleFileSelection(filename, event) { event.stopPropagation(); if (selectedFiles.has(filename)) { selectedFiles.delete(filename); } else { selectedFiles.add(filename); } updateBulkActions(); updateSelectionUI(); } // Update selection UI function updateSelectionUI() { // Update screenshot cards document.querySelectorAll('.resource-card').forEach(card => { const checkbox = card.querySelector('.resource-checkbox'); if (checkbox) { const filename = checkbox.dataset.filename; checkbox.checked = selectedFiles.has(filename); if (selectedFiles.has(filename)) { card.classList.add('selected'); } else { card.classList.remove('selected'); } } }); // Update HTML list items document.querySelectorAll('.resource-list-item').forEach(item => { const checkbox = item.querySelector('.resource-list-checkbox'); if (checkbox) { const filename = checkbox.dataset.filename; checkbox.checked = selectedFiles.has(filename); if (selectedFiles.has(filename)) { item.classList.add('selected'); } else { item.classList.remove('selected'); } } }); } // Select all files function selectAll() { if (currentResourceTab === 'screenshots') { document.querySelectorAll('.resource-checkbox').forEach(checkbox => { selectedFiles.add(checkbox.dataset.filename); }); } else { document.querySelectorAll('.resource-list-checkbox').forEach(checkbox => { selectedFiles.add(checkbox.dataset.filename); }); } updateBulkActions(); updateSelectionUI(); } // Delete selected files async function deleteSelected() { if (selectedFiles.size === 0) return; if (!confirm(`Are you sure you want to delete ${selectedFiles.size} file(s)?`)) { return; } const type = currentResourceTab === 'screenshots' ? 'screenshot' : 'html'; const filesToDelete = Array.from(selectedFiles); let successCount = 0; let failCount = 0; for (const filename of filesToDelete) { try { const response = await fetch(`/delete/${type}/${filename}`, { method: 'DELETE' }); const data = await response.json(); if (data.success) { successCount++; selectedFiles.delete(filename); } else { failCount++; } } catch (err) { failCount++; } } // Show single notification for all deletions if (successCount > 0) { notificationManager.success('Deleted', `Successfully deleted ${successCount} file(s)`); } if (failCount > 0) { notificationManager.error('Error', `Failed to delete ${failCount} file(s)`); } updateBulkActions(); refreshResources(); } // Load resources when switching to resources page function loadResources() { const loading = document.getElementById('resourcesLoading'); const error = document.getElementById('resourcesError'); loading.classList.add('active'); error.style.display = 'none'; fetch('/list') .then(response => response.json()) .then(data => { displayScreenshots(data.screenshots || []); displayHtmlFiles(data.html_files || []); }) .catch(err => { error.textContent = 'Error loading resources: ' + err.message; error.style.display = 'block'; }) .finally(() => { loading.classList.remove('active'); }); } // Display screenshots function displayScreenshots(screenshots) { const container = document.getElementById('screenshotsList'); const noFiles = document.getElementById('noScreenshots'); // Remove resources-grid class from container since we inject our own grids per group container.classList.remove('resources-grid'); if (screenshots.length === 0) { container.innerHTML = ''; noFiles.style.display = 'block'; return; } noFiles.style.display = 'none'; // Group screenshots by base name (e.g., "1" from "1(1).png") const groups = {}; screenshots.forEach(filename => { let base = filename; const match = filename.match(/^(.+?)\(\d+\)\.png$/); if (match) { base = match[1]; } if (!groups[base]) groups[base] = []; groups[base].push(filename); }); // Sort bases ascending (numerically if numbers, else alphabetically) const sortedBases = Object.keys(groups).sort((a, b) => { const numA = parseInt(a); const numB = parseInt(b); if (!isNaN(numA) && !isNaN(numB)) { return numA - numB; } return a.localeCompare(b); }); // Store grouped data globally for modal navigation window.resourceGroups = groups; let html = ''; sortedBases.forEach(base => { const groupFiles = groups[base]; // Sort files within group by part number descending or ascending // e.g., 1(1).png before 1(2).png groupFiles.sort((a, b) => { const matchA = a.match(/\((\d+)\)\.png$/); const matchB = b.match(/\((\d+)\)\.png$/); if (matchA && matchB) { return parseInt(matchA[1]) - parseInt(matchB[1]); } return a.localeCompare(b); }); html += `
Adjust settings and regenerate screenshots from: ${htmlFilename}