diff --git a/web_app/static/index.html b/web_app/static/index.html
index 0d56371..802e1f3 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..6dba927 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.classList.add('loading');
const indexingToggle = document.getElementById('indexingToggle');
const accentToggle = document.getElementById('accentToggle');
@@ -635,7 +636,8 @@ async function generatePoster() {
const end = endVal;
if (isNaN(start) || isNaN(end) || start >= end) {
- loadingOverlay.style.display = 'none';
+ generateBtn.disabled = false;
+ generateBtn.classList.remove('loading');
showToast("Please enter a valid range (Start must be less than End).", "error");
return;
}
@@ -651,7 +653,9 @@ async function generatePoster() {
try {
const response = await fetch('/api/generate', {
method: 'POST',
- headers: { 'Content-Type': 'application/json' },
+ headers: {
+ 'Content-Type': 'application/json'
+ },
body: JSON.stringify(payload)
});
@@ -663,19 +667,27 @@ 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';
+ generateBtn.disabled = false;
+ generateBtn.classList.remove('loading');
+ };
+ img.onerror = () => {
+ showToast('Error: Failed to load the generated poster image.', 'error');
+ generateBtn.disabled = false;
+ generateBtn.classList.remove('loading');
};
} catch (error) {
console.error("Generation failed", error);
showToast(`Error: ${error.message}`, "error");
- loadingOverlay.style.display = 'none';
+ generateBtn.disabled = false;
+ generateBtn.classList.remove('loading');
}
}
diff --git a/web_app/static/style.css b/web_app/static/style.css
index 468eb76..08338d0 100644
--- a/web_app/static/style.css
+++ b/web_app/static/style.css
@@ -161,11 +161,40 @@ header p {
width: 100%;
}
-.primary-btn:hover {
+.primary-btn:hover:not(:disabled) {
background: var(--accent-hover);
transform: translateY(-1px);
}
+.primary-btn:disabled,
+.primary-btn.loading {
+ background: var(--accent-hover);
+ cursor: not-allowed;
+ transform: none;
+ opacity: 0.7;
+}
+
+.primary-btn .spinner {
+ display: none;
+}
+
+.primary-btn.loading .btn-text {
+ display: none;
+}
+
+.primary-btn.loading .spinner {
+ display: block;
+ width: 20px;
+ height: 20px;
+ border-width: 2px;
+ border-style: solid;
+ border-color: rgba(0, 0, 0, 0.2);
+ border-top-color: #1a1a1f;
+ margin-bottom: 0;
+ border-radius: 50%;
+ animation: spin 0.8s linear infinite;
+}
+
.secondary-btn {
background: transparent;
border-color: var(--border-color);