Skip to content

Commit 0d66885

Browse files
author
Datanoise
committed
feat: add animated spinners for long-running actions and library scanning
1 parent 92f1f5b commit 0d66885

2 files changed

Lines changed: 18 additions & 4 deletions

File tree

server/templates/admin.html

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868

6969
.action-overlay { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(22, 27, 44, 0.8); backdrop-filter: blur(12px); border: 1px solid var(--border); padding: 2rem; border-radius: 24px; display: none; flex-direction: column; align-items: center; gap: 1rem; z-index: 2000; box-shadow: 0 20px 50px rgba(0,0,0,0.5); min-width: 150px; }
7070
.action-overlay i { width: 48px; height: 48px; }
71-
.action-overlay .spinner { animation: rotate 2s linear infinite; color: var(--primary); }
71+
.spinner { animation: rotate 2s linear infinite; color: var(--primary); display: inline-block; }
7272
.action-overlay .success { color: var(--success); }
7373
.action-overlay .error { color: var(--danger); }
7474
@keyframes rotate { 100% { transform: rotate(360deg); } }
@@ -722,21 +722,32 @@ <h2>Edit AutoDJ</h2>
722722
function submitForm(event, reload = false, onSuccess) {
723723
if (event) event.preventDefault();
724724
const form = event.target;
725-
const formData = new FormData(form);
725+
if (form.dataset.submitting === 'true') return false;
726726

727+
const formData = new FormData(form);
727728
const overlay = document.getElementById('action-overlay');
728729
const iconContainer = document.getElementById('action-icon-container');
729730
const text = document.getElementById('action-text');
730731

732+
form.dataset.submitting = 'true';
731733
overlay.style.display = 'flex';
732734
iconContainer.innerHTML = '<i data-lucide="loader-2" class="spinner"></i>';
733735
text.textContent = 'Processing...';
734736
lucide.createIcons();
735737

738+
// For actions that take longer than 2 seconds, update the text
739+
const longActionTimeout = setTimeout(() => {
740+
if (form.dataset.submitting === 'true') {
741+
text.textContent = 'Still working...';
742+
}
743+
}, 2000);
744+
736745
fetch(form.action, {
737746
method: 'POST',
738747
body: formData
739748
}).then(r => {
749+
clearTimeout(longActionTimeout);
750+
form.dataset.submitting = 'false';
740751
if (r.ok) {
741752
iconContainer.innerHTML = '<i data-lucide="check-circle-2" class="success"></i>';
742753
text.textContent = 'Success';
@@ -757,6 +768,8 @@ <h2>Edit AutoDJ</h2>
757768
});
758769
}
759770
}).catch(err => {
771+
clearTimeout(longActionTimeout);
772+
form.dataset.submitting = 'false';
760773
iconContainer.innerHTML = '<i data-lucide="alert-triangle" class="error"></i>';
761774
text.textContent = 'Error';
762775
lucide.createIcons();
@@ -847,9 +860,10 @@ <h2>Edit AutoDJ</h2>
847860
container.dataset.loaded = 'false';
848861
return;
849862
}
850-
container.innerHTML = '<div style="text-align:center; padding: 1rem; color: var(--text-dim); font-size: 0.8rem;">Scanning directory...</div>';
863+
container.innerHTML = '<div style="text-align:center; padding: 2rem;"><i data-lucide="loader-2" class="spinner" style="width: 24px; height: 24px;"></i><div style="color: var(--text-dim); font-size: 0.8rem; margin-top: 0.5rem;">Scanning directory...</div></div>';
851864
container.style.display = 'block';
852865
container.dataset.loaded = 'true';
866+
lucide.createIcons();
853867

854868
fetch('/admin/player/files?mount=' + encodeURIComponent(mount) + '&path=' + encodeURIComponent(subPath))
855869
.then(r => {

tinyice.pid

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
36403
1+
36463

0 commit comments

Comments
 (0)