From a6946c38fcbf18e3325ae1c22d7eb47b8d95eb80 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 7 Jan 2026 20:10:55 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20Replace=20loading=20o?= =?UTF-8?q?verlay=20with=20in-button=20spinner?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 💡 What: Replaced the disruptive full-screen loading overlay with a subtle spinner inside the "Generate Poster" button. 🎯 Why: The previous full-screen loader was jarring and blocked the entire UI. This change provides loading feedback directly at the point of interaction, creating a smoother and more modern user experience. ♿ Accessibility: The button is disabled during the loading state, preventing multiple submissions and providing a clear visual cue that the action is in progress. --- web_app/static/index.html | 5 ++++- web_app/static/script.js | 25 +++++++++++++++++++++---- web_app/static/style.css | 19 ++++++++++++++++++- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/web_app/static/index.html b/web_app/static/index.html index 0d56371..69569a5 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..d2e7b10 100644 --- a/web_app/static/script.js +++ b/web_app/static/script.js @@ -613,7 +613,20 @@ function handleLyricLineClick(lineNumber) { async function generatePoster() { if (!currentMetadata) return; - loadingOverlay.style.display = 'flex'; + const btn = document.getElementById('generateBtn'); + const btnText = btn.querySelector('.btn-text'); + const btnSpinner = btn.querySelector('.btn-spinner'); + + btn.disabled = true; + btnText.style.display = 'none'; + btnSpinner.style.display = 'block'; + + const resetBtn = () => { + btn.disabled = false; + btnText.style.display = 'inline'; + btnSpinner.style.display = 'none'; + }; + const indexingToggle = document.getElementById('indexingToggle'); const accentToggle = document.getElementById('accentToggle'); @@ -635,7 +648,7 @@ async function generatePoster() { const end = endVal; if (isNaN(start) || isNaN(end) || start >= end) { - loadingOverlay.style.display = 'none'; + resetBtn(); showToast("Please enter a valid range (Start must be less than End).", "error"); return; } @@ -669,13 +682,17 @@ async function generatePoster() { posterContainer.innerHTML = ''; posterContainer.appendChild(img); showDownloadButton(imageUrl, data.filename); - loadingOverlay.style.display = 'none'; + resetBtn(); + }; + img.onerror = () => { + showToast('Failed to load the generated poster image.', 'error'); + resetBtn(); }; } catch (error) { console.error("Generation failed", error); showToast(`Error: ${error.message}`, "error"); - loadingOverlay.style.display = 'none'; + resetBtn(); } } diff --git a/web_app/static/style.css b/web_app/static/style.css index 468eb76..1ef50bb 100644 --- a/web_app/static/style.css +++ b/web_app/static/style.css @@ -908,4 +908,21 @@ input:focus { .result-action svg { pointer-events: none; -} \ No newline at end of file +} +.primary-btn:disabled { + background-color: var(--accent-hover); + opacity: 0.7; + cursor: not-allowed; + transform: none; +} + +.btn-spinner { + width: 20px; + height: 20px; + border-width: 2px; + border-top-color: #1a1a1f; /* Match button text color */ + border-right-color: rgba(26, 26, 31, 0.2); + border-bottom-color: rgba(26, 26, 31, 0.2); + border-left-color: rgba(26, 26, 31, 0.2); + margin: 0; /* Override margin from .spinner */ +}