Skip to content
Open
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
63 changes: 29 additions & 34 deletions scripts/theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@ syncThemeChange(systemTheme);
const indicator = segment.querySelector(".themeIndicator");
const buttons = segment.querySelectorAll(".themeSegBtn");

// Helper to determine and broadcast the actual color being used
const emitThemeChanged = (theme) => {
const effectiveTheme = theme === "system"
? (systemTheme.matches ? "dark" : "light")
: theme;

window.dispatchEvent(new CustomEvent("themeChanged", {
detail: { theme, effectiveTheme }
}));
};

// Move indicator to correct position
function moveIndicator(theme) {
const ltrIndex = theme === "light" ? 0 : theme === "dark" ? 1 : 2;
Expand All @@ -48,6 +59,9 @@ syncThemeChange(systemTheme);
if (theme === "system") {
syncThemeChange(systemTheme);
}

// Dispatch custom event for real-time synchronization
emitThemeChanged(theme);
}

// Button click handlers
Expand All @@ -57,8 +71,13 @@ syncThemeChange(systemTheme);
});
});

// System theme change listener
systemTheme.addEventListener('change', syncThemeChange);
// System theme change listener to handle automatic OS flips
systemTheme.addEventListener('change', (event) => {
syncThemeChange(event);
if (segment.dataset.active === "system") {
emitThemeChanged("system");
}
});

function initializeThemeMode() {
const darkModeCheckboxState = localStorage.getItem(darkModeCheckboxKey);
Expand Down Expand Up @@ -89,7 +108,6 @@ document.addEventListener("DOMContentLoaded", () => {
const storedCustomColor = localStorage.getItem(customThemeStorageKey);
if (storedCustomColor) {
applyCustomTheme(storedCustomColor);
// Uncheck all radio buttons
radioButtons.forEach(radio => {
radio.checked = false;
});
Expand All @@ -106,26 +124,20 @@ document.addEventListener("DOMContentLoaded", () => {
}
}

// Remove Loading Screen when the DOM and the theme has loaded
document.getElementById("LoadingScreen").style.display = "none";

// Stop blinking of some elements when the page is reloaded
setTimeout(() => {
document.documentElement.classList.add("theme-transition");
}, 25);
});

// Function to load background color
function ApplyLoadingColor() {
let LoadingScreenColor = getComputedStyle(document.body).getPropertyValue("background-color");
localStorage.setItem("LoadingScreenColor", LoadingScreenColor);
}

const resetDarkTheme = () => {
// Remove the dark theme class
document.documentElement.classList.remove("black-theme");

// Reset inline styles that were applied specifically for dark mode
const resetElements = ["searchQ", "searchIconDark", "darkFeelsLikeIcon", "menuButton", "menuCloseButton", "closeBtnX"];

resetElements.forEach((id) => {
Expand All @@ -135,24 +147,17 @@ const resetDarkTheme = () => {
}
});

// Reset fill color for elements with the class "accentColor"
const accentElements = document.querySelectorAll(".accentColor");
accentElements.forEach((element) => {
element.style.fill = ""; // Reset fill color
element.style.fill = "";
});
};

// Function to apply the selected theme
const applySelectedTheme = (colorValue) => {
const isDarkMode = colorValue === "dark";

// Reset dark theme if not in dark mode
if (!isDarkMode) resetDarkTheme();

// Reset color picker label border when switching to predefined theme
colorPickerLabel.style.borderColor = "";

// Set CSS variables based on the selected color theme
if (colorValue === "blue") {
document.documentElement.style.setProperty("--bg-color-blue", "#BBD6FD");
document.documentElement.style.setProperty("--accentLightTint-blue", "#E2EEFF");
Expand All @@ -173,7 +178,6 @@ const applySelectedTheme = (colorValue) => {
}
}

// Handle dark mode specific changes
if (isDarkMode) {
document.documentElement.classList.add("black-theme");
document.querySelectorAll(".accentColor").forEach(el => {
Expand All @@ -186,10 +190,8 @@ const applySelectedTheme = (colorValue) => {
};

function changeFaviconColor() {
// Fetch colors from CSS variables
const rootStyles = getComputedStyle(document.documentElement);
const darkColor = rootStyles.getPropertyValue("--darkColor-blue");
//const bgColor = rootStyles.getPropertyValue("--bg-color-blue");

const svg = `
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
Expand All @@ -204,7 +206,6 @@ function changeFaviconColor() {
}
changeFaviconColor();

// --------------------- Color Picker ---------------------
function adjustHexColor(hex, factor, isLighten = true) {
hex = hex.replace("#", "");
if (hex.length === 3) {
Expand Down Expand Up @@ -254,37 +255,32 @@ const applyCustomTheme = (color) => {
ApplyLoadingColor();
};

// Handle radio button changes
const handleThemeChange = function () {
if (this.checked) {
const colorValue = this.value;
localStorage.setItem(themeStorageKey, colorValue);
localStorage.removeItem(customThemeStorageKey); // Clear custom theme
localStorage.removeItem(customThemeStorageKey);
applySelectedTheme(colorValue);
}
};

// Remove any previously attached listeners and add only one
radioButtons.forEach(radioButton => {
radioButton.removeEventListener("change", handleThemeChange); // Remove if already attached
radioButton.addEventListener("change", handleThemeChange); // Add fresh listener
radioButton.removeEventListener("change", handleThemeChange);
radioButton.addEventListener("change", handleThemeChange);
});

// Handle color picker changes
const handleColorPickerChange = function (event) {
const selectedColor = event.target.value;
resetDarkTheme(); // Clear dark theme if active
localStorage.setItem(customThemeStorageKey, selectedColor); // Save custom color
localStorage.removeItem(themeStorageKey); // Clear predefined theme
resetDarkTheme();
localStorage.setItem(customThemeStorageKey, selectedColor);
localStorage.removeItem(themeStorageKey);
applyCustomTheme(selectedColor);

// Uncheck all radio buttons
radioButtons.forEach(radio => {
radio.checked = false;
});
};

// Throttle for performance optimization
const throttle = (func, limit) => {
let lastFunc;
let lastRan;
Expand All @@ -304,6 +300,5 @@ const throttle = (func, limit) => {
};
};

// Add listeners for color picker
colorPicker.removeEventListener("input", handleColorPickerChange); // Ensure no duplicate listeners
colorPicker.removeEventListener("input", handleColorPickerChange);
colorPicker.addEventListener("input", throttle(handleColorPickerChange, 10));