Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion scripts/preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,23 @@
*/

// Set Loading Screen Color before Everything Loads
document.documentElement.style.setProperty('--Loading-Screen-Color', localStorage.getItem('LoadingScreenColor') || "#bbd6fd");
document.documentElement.style.setProperty('--Loading-Screen-Color', localStorage.getItem('LoadingScreenColor') || "#000000ff");

// Early dark mode detection to prevent light→dark flash
// The CSS dark mode filter (invert + hue-rotate) normally depends on DOM elements
// that don't exist yet. Pre-apply the filter on <html> so the loading screen
// matches the dark mode appearance from the first paint.
(function () {
const preferredTheme = localStorage.getItem('preferredTheme');
const selectedTheme = localStorage.getItem('selectedTheme');
const savedBgType = localStorage.getItem('bgType');
const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches;

const isDarkMode = preferredTheme === 'dark' || (preferredTheme === 'system' && systemDark);
const isColorBg = savedBgType !== 'wallpaper'; // default to color if not saved
const isBlackTheme = selectedTheme === 'dark';

if (isDarkMode && isColorBg && !isBlackTheme) {
document.documentElement.classList.add('early-dark-filter');
}
})();
30 changes: 28 additions & 2 deletions scripts/theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,20 @@ syncThemeChange(systemTheme);
initializeThemeMode();
})();

// Hide loading screen with smooth fade-out
function hideLoadingScreen() {
const loadingScreen = document.getElementById("LoadingScreen");
if (!loadingScreen || loadingScreen.classList.contains("fade-out")) return;
loadingScreen.classList.add("fade-out");
loadingScreen.addEventListener("transitionend", () => {
loadingScreen.style.display = "none";
}, { once: true });
// Fallback in case transitionend doesn't fire
setTimeout(() => {
loadingScreen.style.display = "none";
}, 500);
}

document.addEventListener("DOMContentLoaded", () => {
// Check for custom color
const storedCustomColor = localStorage.getItem(customThemeStorageKey);
Expand All @@ -106,8 +120,20 @@ document.addEventListener("DOMContentLoaded", () => {
}
}

// Remove Loading Screen when the DOM and the theme has loaded
document.getElementById("LoadingScreen").style.display = "none";
// Signal that theme is ready; loading screen will be hidden
// once both theme and wallpaper are ready
window._themeReady = true;
if (window._wallpaperReady) {
hideLoadingScreen();
}

// Safety: ensure loading screen is hidden even if wallpaper never signals
setTimeout(() => {
if (!window._wallpaperReady) {
window._wallpaperReady = true;
hideLoadingScreen();
}
}, 3000);

// Stop blinking of some elements when the page is reloaded
setTimeout(() => {
Expand Down
52 changes: 43 additions & 9 deletions scripts/wallpaper.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,36 @@ async function applyRandomImage(showConfirmation = true) {

// Function to update the background type attribute
function toggleBackgroundType(hasWallpaper) {
document.body.setAttribute("data-bg", hasWallpaper ? "wallpaper" : "color");
const bgType = hasWallpaper ? "wallpaper" : "color";
document.body.setAttribute("data-bg", bgType);
localStorage.setItem("bgType", bgType);
document.documentElement.classList.remove("early-dark-filter");
}

// Signal that wallpaper is ready and trigger loading screen hide if theme is also ready
function signalWallpaperReady() {
window._wallpaperReady = true;
if (window._themeReady) {
hideLoadingScreen();
}
}

// Helper to preload and decode an image before applying it as background
function preloadAndApplyBackground(imageUrl) {
return new Promise((resolve) => {
const img = new Image();
img.src = imageUrl;
img.decode().then(() => {
document.body.style.setProperty("--bg-image", `url(${imageUrl})`);
toggleBackgroundType(true);
resolve();
}).catch(() => {
// Fallback: apply even if decode fails
document.body.style.setProperty("--bg-image", `url(${imageUrl})`);
toggleBackgroundType(true);
resolve();
});
});
}

// Check and update image on page load
Expand All @@ -137,33 +166,38 @@ function checkAndUpdateImage() {
// No image or invalid data
if (!blob || !savedTimestamp || isNaN(lastUpdate)) {
toggleBackgroundType(false);
signalWallpaperReady();
return;
}

// Create a new Blob URL dynamically
const imageUrl = URL.createObjectURL(blob);

if (imageType === "upload") {
document.body.style.setProperty("--bg-image", `url(${imageUrl})`);
toggleBackgroundType(true);
preloadAndApplyBackground(imageUrl).then(() => {
signalWallpaperReady();
});
return;
}

if (lastUpdate.toDateString() !== now.toDateString()) {
// Refresh random image if a new day
applyRandomImage(false);
applyRandomImage(false).then(() => {
signalWallpaperReady();
});
} else {
// Reapply the saved random image
document.body.style.setProperty("--bg-image", `url(${imageUrl})`);
toggleBackgroundType(true);
preloadAndApplyBackground(imageUrl).then(() => {
signalWallpaperReady();
// Clean up the Blob URL after setting the background
setTimeout(() => URL.revokeObjectURL(imageUrl), 1500);
});
}

// Clean up the Blob URL after setting the background
setTimeout(() => URL.revokeObjectURL(imageUrl), 1500);
})
.catch((error) => {
console.error("Error loading image details:", error);
toggleBackgroundType(false);
signalWallpaperReady();
});
}

Expand Down
29 changes: 25 additions & 4 deletions style.css
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,20 @@ body {
margin: 0;
}

/* Early dark mode filter applied by preload.js before DOM elements exist.
Prevents light→dark flash by pre-applying the invert filter on <html>.
Removed by wallpaper.js once the proper CSS selectors can take over. */
html.early-dark-filter {
-webkit-filter: invert(1) hue-rotate(180deg);
filter: invert(1) hue-rotate(180deg);

& #darkTheme,
& .favicon {
-webkit-filter: invert(1) hue-rotate(180deg);
filter: invert(1) hue-rotate(180deg);
}
}

/* Apply dark mode when: Dark Mode is selected manually, OR System Theme is selected */
html:has(body[data-bg="color"] .menuBar .themeSegment[data-active="dark"]):not(
:has(#darkTheme:checked)
Expand All @@ -230,13 +244,13 @@ html:has(
.menuBar
.themeSegment[data-active="system"]
):not(:has(#darkTheme:checked)) {
filter: invert(1) hue-rotate(180deg);
-webkit-filter: invert(1) hue-rotate(180deg);
filter: invert(1) hue-rotate(180deg);

& #darkTheme,
& .favicon {
filter: invert(1) hue-rotate(180deg);
-webkit-filter: invert(1) hue-rotate(180deg);
filter: invert(1) hue-rotate(180deg);
}

& .menuBar,
Expand Down Expand Up @@ -268,13 +282,13 @@ body[data-bg="wallpaper"][sysTheme="systemDark"]:has(
.menuBar .themeSegment[data-active="system"]
):not(:has(#darkTheme:checked))
:is(.menuCont, .bookmark-sidebar) {
filter: invert(1) hue-rotate(180deg);
-webkit-filter: invert(1) hue-rotate(180deg);
filter: invert(1) hue-rotate(180deg);

& #darkTheme,
& .favicon {
filter: invert(1) hue-rotate(180deg);
-webkit-filter: invert(1) hue-rotate(180deg);
filter: invert(1) hue-rotate(180deg);
}

--whitishColor-blue: #f2f2f2;
Expand Down Expand Up @@ -4330,6 +4344,13 @@ body[data-bg="wallpaper"] .dropdown-content {
width: 100%;
inset: 0;
z-index: 99999;
opacity: 1;
transition: opacity 0.3s ease;
}

#LoadingScreen.fade-out {
opacity: 0;
pointer-events: none;
}

.toggleTextsCont .ttcont:has(#hideWeatherBox) {
Expand Down