feat: add splash screen with logo on app load and after login
- Show sofarr logo splash screen while app initialises - On page load: splash stays visible while checking auth and fetching data - After login: splash reappears while fetching initial downloads - Minimum 1.2s display with smooth fade-out transition - Subtle pulse animation on the logo
This commit is contained in:
@@ -4,6 +4,7 @@ let refreshInterval = null;
|
|||||||
let currentRefreshRate = 5000; // default 5 seconds
|
let currentRefreshRate = 5000; // default 5 seconds
|
||||||
let isAdmin = false;
|
let isAdmin = false;
|
||||||
let showAll = false;
|
let showAll = false;
|
||||||
|
const SPLASH_MIN_MS = 1200; // minimum splash display time
|
||||||
|
|
||||||
// Apply saved theme immediately (before DOMContentLoaded to avoid flash)
|
// Apply saved theme immediately (before DOMContentLoaded to avoid flash)
|
||||||
(function() {
|
(function() {
|
||||||
@@ -63,7 +64,30 @@ function stopAutoRefresh() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showSplash() {
|
||||||
|
const splash = document.getElementById('splash-screen');
|
||||||
|
splash.style.display = 'flex';
|
||||||
|
splash.style.opacity = '1';
|
||||||
|
splash.classList.remove('fade-out');
|
||||||
|
}
|
||||||
|
|
||||||
|
function dismissSplash(startTime) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const elapsed = Date.now() - (startTime || 0);
|
||||||
|
const remaining = Math.max(0, SPLASH_MIN_MS - elapsed);
|
||||||
|
setTimeout(() => {
|
||||||
|
const splash = document.getElementById('splash-screen');
|
||||||
|
splash.classList.add('fade-out');
|
||||||
|
splash.addEventListener('transitionend', () => {
|
||||||
|
splash.style.display = 'none';
|
||||||
|
resolve();
|
||||||
|
}, { once: true });
|
||||||
|
}, remaining);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function checkAuthentication() {
|
async function checkAuthentication() {
|
||||||
|
const splashStart = Date.now();
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/auth/me');
|
const response = await fetch('/api/auth/me');
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
@@ -72,13 +96,16 @@ async function checkAuthentication() {
|
|||||||
currentUser = data.user;
|
currentUser = data.user;
|
||||||
isAdmin = !!data.user.isAdmin;
|
isAdmin = !!data.user.isAdmin;
|
||||||
showDashboard();
|
showDashboard();
|
||||||
fetchUserDownloads(true);
|
await fetchUserDownloads(true);
|
||||||
startAutoRefresh();
|
startAutoRefresh();
|
||||||
|
await dismissSplash(splashStart);
|
||||||
} else {
|
} else {
|
||||||
|
await dismissSplash(splashStart);
|
||||||
showLogin();
|
showLogin();
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Authentication check failed:', err);
|
console.error('Authentication check failed:', err);
|
||||||
|
await dismissSplash(splashStart);
|
||||||
showLogin();
|
showLogin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,9 +130,12 @@ async function handleLogin(e) {
|
|||||||
if (data.success) {
|
if (data.success) {
|
||||||
currentUser = data.user;
|
currentUser = data.user;
|
||||||
isAdmin = !!data.user.isAdmin;
|
isAdmin = !!data.user.isAdmin;
|
||||||
|
showSplash();
|
||||||
showDashboard();
|
showDashboard();
|
||||||
fetchUserDownloads(true);
|
const splashStart = Date.now();
|
||||||
|
await fetchUserDownloads(true);
|
||||||
startAutoRefresh();
|
startAutoRefresh();
|
||||||
|
await dismissSplash(splashStart);
|
||||||
} else {
|
} else {
|
||||||
showLoginError(data.error || 'Login failed');
|
showLoginError(data.error || 'Login failed');
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
public/images/sofarr-flashscreen.png
Normal file
BIN
public/images/sofarr-flashscreen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 85 KiB |
@@ -7,6 +7,11 @@
|
|||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<!-- Splash Screen -->
|
||||||
|
<div id="splash-screen" class="splash-screen">
|
||||||
|
<img src="images/sofarr-flashscreen.png" alt="sofarr" class="splash-logo">
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="app">
|
<div class="app">
|
||||||
<!-- Login Form -->
|
<!-- Login Form -->
|
||||||
<div id="login-container" class="login-container" style="display: none;">
|
<div id="login-container" class="login-container" style="display: none;">
|
||||||
|
|||||||
@@ -1,3 +1,34 @@
|
|||||||
|
/* ===== Splash Screen ===== */
|
||||||
|
.splash-screen {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #f8f9fa;
|
||||||
|
z-index: 9999;
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 0.4s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.splash-screen.fade-out {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.splash-logo {
|
||||||
|
max-width: 280px;
|
||||||
|
width: 60%;
|
||||||
|
animation: splashPulse 1.8s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes splashPulse {
|
||||||
|
0%, 100% { transform: scale(1); opacity: 1; }
|
||||||
|
50% { transform: scale(1.03); opacity: 0.85; }
|
||||||
|
}
|
||||||
|
|
||||||
/* ===== Theme Variables ===== */
|
/* ===== Theme Variables ===== */
|
||||||
:root, [data-theme="light"] {
|
:root, [data-theme="light"] {
|
||||||
--bg-gradient-start: #667eea;
|
--bg-gradient-start: #667eea;
|
||||||
|
|||||||
Reference in New Issue
Block a user