From 9016697472b9aa9f1c52ccd50b55a4dda6894d5a Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Tue, 13 Jan 2026 20:15:45 +0000
Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20Enhance=20button=20lo?=
=?UTF-8?q?ading=20state=20for=20poster=20generation?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
💡 What: Replaced the full-screen loading overlay with an inline spinner and disabled state on the "Generate Poster" button.
🎯 Why: The previous full-screen loader was disruptive and hid the context of the action. This change provides immediate, focused feedback directly on the button, preventing multiple clicks and reassuring the user that the request is in progress.
♿ Accessibility: Added a dynamic `aria-label` ("Generating poster, please wait") to the button during its loading state. This ensures screen reader users are aware of the button's status, as the visual text change is hidden from assistive technology.
---
web_app/static/index.html | 5 ++++-
web_app/static/script.js | 27 +++++++++++++++++++++------
web_app/static/style.css | 22 ++++++++++++++++++++++
3 files changed, 47 insertions(+), 7 deletions(-)
diff --git a/web_app/static/index.html b/web_app/static/index.html
index 0d56371..d57b35e 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..f480a56 100644
--- a/web_app/static/script.js
+++ b/web_app/static/script.js
@@ -20,7 +20,7 @@ const startLineInput = document.getElementById('startLine');
const endLineInput = document.getElementById('endLine');
const themeInput = document.getElementById('themeInput');
const fontInput = document.getElementById('fontInput');
-const loadingOverlay = document.getElementById('loadingOverlay');
+const loadingOverlay = document.getElementById('loadingOverlay'); // Keep for now, might be used elsewhere
let currentMetadata = null;
let searchDebounceTimer = null;
@@ -611,9 +611,17 @@ function handleLyricLineClick(lineNumber) {
}
async function generatePoster() {
- if (!currentMetadata) return;
+ if (!currentMetadata || generateBtn.classList.contains('loading')) return;
- loadingOverlay.style.display = 'flex';
+ const btnText = generateBtn.querySelector('.btn-text');
+ const spinner = generateBtn.querySelector('.spinner');
+
+ // --- 1. Set Loading State ---
+ generateBtn.classList.add('loading');
+ generateBtn.disabled = true;
+ btnText.textContent = 'Generating...'; // Update text for visual consistency
+ generateBtn.setAttribute('aria-label', 'Generating poster, please wait'); // Set accessible name
+ spinner.style.display = 'block';
const indexingToggle = document.getElementById('indexingToggle');
const accentToggle = document.getElementById('accentToggle');
@@ -635,8 +643,8 @@ async function generatePoster() {
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");
+ // No loading overlay to hide, just return
return;
}
@@ -669,13 +677,20 @@ async function generatePoster() {
posterContainer.innerHTML = '';
posterContainer.appendChild(img);
showDownloadButton(imageUrl, data.filename);
- loadingOverlay.style.display = 'none';
+ // No loading overlay to hide
};
} catch (error) {
console.error("Generation failed", error);
showToast(`Error: ${error.message}`, "error");
- loadingOverlay.style.display = 'none';
+ // No loading overlay to hide
+ } finally {
+ // --- 2. Reset Button State ---
+ generateBtn.classList.remove('loading');
+ generateBtn.disabled = false;
+ btnText.textContent = 'Generate Poster';
+ generateBtn.removeAttribute('aria-label'); // Remove accessible name
+ spinner.style.display = 'none';
}
}
diff --git a/web_app/static/style.css b/web_app/static/style.css
index 468eb76..eacd76a 100644
--- a/web_app/static/style.css
+++ b/web_app/static/style.css
@@ -178,6 +178,28 @@ header p {
border-color: var(--text-muted);
}
+.primary-btn.loading {
+ cursor: not-allowed;
+ background: var(--accent-hover);
+}
+
+.primary-btn.loading .btn-text {
+ display: none;
+}
+
+.primary-btn.loading .spinner {
+ display: block;
+ margin-bottom: 0; /* Override default margin */
+}
+
+/* Scoped spinner for button */
+.primary-btn .spinner {
+ width: 20px;
+ height: 20px;
+ border-width: 2px;
+ border-top-color: #1a1a1f; /* Dark color for contrast */
+}
+
/* Inputs */
input[type="text"],
input[type="number"] {