diff --git a/web_app/static/index.html b/web_app/static/index.html index 0d56371..a9e2343 100644 --- a/web_app/static/index.html +++ b/web_app/static/index.html @@ -116,7 +116,10 @@

Lyrics

- + diff --git a/web_app/static/script.js b/web_app/static/script.js index 441a4ed..1d27fcb 100644 --- a/web_app/static/script.js +++ b/web_app/static/script.js @@ -613,7 +613,16 @@ function handleLyricLineClick(lineNumber) { async function generatePoster() { if (!currentMetadata) return; - loadingOverlay.style.display = 'flex'; + const btnText = generateBtn.querySelector('.btn-text'); + const btnSpinner = generateBtn.querySelector('.button-spinner'); + + const resetButtonState = () => { + generateBtn.disabled = false; + generateBtn.classList.remove('loading'); + if(btnText) btnText.textContent = 'Generate Poster'; + if(btnSpinner) btnSpinner.style.display = 'none'; + generateBtn.removeAttribute('aria-label'); + }; const indexingToggle = document.getElementById('indexingToggle'); const accentToggle = document.getElementById('accentToggle'); @@ -628,14 +637,12 @@ 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"); return; } @@ -644,10 +651,16 @@ async function generatePoster() { payload.lyrics_end = end; } else { - // Album Logic payload.indexing = indexingToggle ? indexingToggle.checked : false; } + // Set loading state AFTER validation + generateBtn.disabled = true; + generateBtn.classList.add('loading'); + if(btnText) btnText.textContent = 'Generating...'; + if(btnSpinner) btnSpinner.style.display = 'block'; + generateBtn.setAttribute('aria-label', 'Generating poster, please wait'); + try { const response = await fetch('/api/generate', { method: 'POST', @@ -669,13 +682,17 @@ async function generatePoster() { posterContainer.innerHTML = ''; posterContainer.appendChild(img); showDownloadButton(imageUrl, data.filename); - loadingOverlay.style.display = 'none'; + resetButtonState(); + }; + img.onerror = () => { + showToast('Error: Failed to load the generated poster image.', 'error'); + resetButtonState(); }; } catch (error) { console.error("Generation failed", error); showToast(`Error: ${error.message}`, "error"); - loadingOverlay.style.display = 'none'; + resetButtonState(); } } diff --git a/web_app/static/style.css b/web_app/static/style.css index 468eb76..a63b9bb 100644 --- a/web_app/static/style.css +++ b/web_app/static/style.css @@ -166,6 +166,28 @@ header p { transform: translateY(-1px); } +.primary-btn:disabled { + background: var(--surface-elevated); + color: var(--text-muted); + cursor: not-allowed; + transform: none; +} + +.primary-btn.loading .btn-text { + visibility: hidden; + opacity: 0; +} + +.button-spinner { + position: absolute; + width: 20px; + height: 20px; + border: 2px solid rgba(0, 0, 0, 0.2); + border-top-color: var(--surface-base); + border-radius: 50%; + animation: spin 0.8s linear infinite; +} + .secondary-btn { background: transparent; border-color: var(--border-color);