diff --git a/web_app/static/script.js b/web_app/static/script.js index 441a4ed..465ca6b 100644 --- a/web_app/static/script.js +++ b/web_app/static/script.js @@ -613,7 +613,8 @@ function handleLyricLineClick(lineNumber) { async function generatePoster() { if (!currentMetadata) return; - loadingOverlay.style.display = 'flex'; + generateBtn.disabled = true; + generateBtn.innerHTML = ` Generating...`; const indexingToggle = document.getElementById('indexingToggle'); const accentToggle = document.getElementById('accentToggle'); @@ -628,23 +629,21 @@ async function generatePoster() { }; if (payload.type === 'track') { - // Lyrics Logic (Same as before) const startVal = parseInt(startLineInput.value) || 1; const endVal = parseInt(endLineInput.value) || 1; const start = startVal - 1; const end = endVal; if (isNaN(start) || isNaN(end) || start >= end) { - loadingOverlay.style.display = 'none'; showToast("Please enter a valid range (Start must be less than End).", "error"); + generateBtn.disabled = false; + generateBtn.innerHTML = 'Generate Poster'; return; } payload.lyrics_start = start; payload.lyrics_end = end; - } else { - // Album Logic payload.indexing = indexingToggle ? indexingToggle.checked : false; } @@ -663,19 +662,23 @@ async function generatePoster() { const data = await response.json(); const imageUrl = data.is_base64 ? data.image_data : `${data.image_url}?t=${new Date().getTime()}`; - const img = document.createElement('img'); + const img = new Image(); img.src = imageUrl; img.onload = () => { posterContainer.innerHTML = ''; posterContainer.appendChild(img); showDownloadButton(imageUrl, data.filename); - loadingOverlay.style.display = 'none'; }; + img.onerror = () => { + showToast("Error: Failed to load the generated image.", "error"); + } } catch (error) { console.error("Generation failed", error); showToast(`Error: ${error.message}`, "error"); - loadingOverlay.style.display = 'none'; + } finally { + generateBtn.disabled = false; + generateBtn.innerHTML = 'Generate Poster'; } } diff --git a/web_app/static/style.css b/web_app/static/style.css index 468eb76..4f50baa 100644 --- a/web_app/static/style.css +++ b/web_app/static/style.css @@ -143,6 +143,7 @@ header p { display: inline-flex; align-items: center; justify-content: center; + gap: var(--space-2); height: 44px; /* Improved tap target */ padding: 0 var(--space-6); @@ -166,6 +167,29 @@ header p { transform: translateY(-1px); } +.primary-btn:disabled { + opacity: 0.6; + cursor: not-allowed; + transform: none; +} + +/* Spinner for inside buttons */ +.btn-spinner { + width: 18px; + height: 18px; + border: 2px solid rgba(0, 0, 0, 0.2); + border-top-color: #1a1a1f; + /* Match button text color */ + border-radius: 50%; + animation: spin 0.8s linear infinite; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + .secondary-btn { background: transparent; border-color: var(--border-color);