diff --git a/static/app.css b/static/app.css index 603c937..8ca4b2d 100644 --- a/static/app.css +++ b/static/app.css @@ -314,4 +314,32 @@ footer { .locked { background-color:#eee; } -.unlocked { background-color: #fff3cd; } \ No newline at end of file +.unlocked { background-color: #fff3cd; } + + + +/* full-screen semi-transparent backdrop */ +#fullscreen-loader { + position: fixed; + top: 0; left: 0; + width: 100vw; height: 100vh; + background: rgba(0,0,0,0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 9999; /* ensure it’s on top */ +} + +/* your spinner graphic */ +.loader { + border: 4px solid rgba(255,255,255,0.3); + border-top-color: #fff; + border-radius: 50%; + width: 40px; + height: 40px; + animation: spin 1s linear infinite; +} + +@keyframes spin { + to { transform: rotate(360deg); } +} \ No newline at end of file diff --git a/static/app.js b/static/app.js index 37fed4c..82c2931 100644 --- a/static/app.js +++ b/static/app.js @@ -192,13 +192,27 @@ function renderContent(data) { attachEventListeners(); } +// Helper function to show the spinner +function showSpinner() { + const overlay = document.getElementById('fullscreen-loader'); + if (overlay) overlay.style.display = 'flex'; +} + +function hideSpinner() { + const overlay = document.getElementById('fullscreen-loader'); + if (overlay) overlay.style.display = 'none'; +} + // Fetch directory data from the API. function loadDirectory(subpath) { + const spinnerTimer = setTimeout(showSpinner, 500); const encodedPath = encodeSubpath(subpath); const apiUrl = '/api/path/' + encodedPath; return fetch(apiUrl) .then(response => response.json()) .then(data => { + clearTimeout(spinnerTimer); + hideSpinner(); renderContent(data); if (data.playfile) { const playFileLink = document.querySelector(`.play-file[data-url="${data.playfile}"]`); @@ -210,6 +224,8 @@ function loadDirectory(subpath) { return data; // return data for further chaining }) .catch(error => { + clearTimeout(spinnerTimer); + hideSpinner(); console.error('Error loading directory:', error); document.getElementById('content').innerHTML = `
Error loading directory!
${error}
`; throw error; // Propagate the error @@ -282,8 +298,6 @@ document.querySelectorAll('.play-file').forEach(link => { // Delay preloading to avoid blocking playback. setTimeout(preload_audio, 1000); - - } else if (fileType === 'image') { // Open the gallery modal for image files. openGalleryModal(relUrl); diff --git a/static/audioplayer.js b/static/audioplayer.js index 219e1d1..5b920c2 100644 --- a/static/audioplayer.js +++ b/static/audioplayer.js @@ -140,7 +140,8 @@ async function startPlaying(relUrl) { const loaderTimeout = setTimeout(() => { playerButton.innerHTML = playIcon; nowPlayingInfo.textContent = "Wird geladen..."; - }, 500); + }, 250); + const spinnerTimer = setTimeout(showSpinner, 500); footer.style.display = 'flex'; @@ -171,6 +172,8 @@ async function startPlaying(relUrl) { audioPlayer.src = mediaUrl; audioPlayer.load(); await audioPlayer.play(); + clearTimeout(spinnerTimer); + hideSpinner(); currentTrackPath = relUrl; playerButton.innerHTML = pauseIcon; diff --git a/templates/app.html b/templates/app.html index 1eb2bec..820facd 100644 --- a/templates/app.html +++ b/templates/app.html @@ -238,6 +238,10 @@ + +