Files
phishingclub/frontend/src/lib/theme.js
T
Ronni Skansing 0f38561e15 fix missing html background change on theme toggle
Signed-off-by: Ronni Skansing <rskansing@gmail.com>
2025-10-08 19:25:10 +02:00

111 lines
2.8 KiB
JavaScript

import { writable } from 'svelte/store';
import { browser } from '$app/environment';
// mode constants
export const modeLight = 'light';
export const modeDark = 'dark';
const modeNotSet = 'not-set';
const modeKey = 'theme-mode';
/**
* theme store - either 'light' or 'dark'
* use it to know which theme is current and subscribe to know when it changes
*/
export const theme = writable(modeLight);
/**
* toggle the theme mode from light to dark or vice versa
* @returns {void}
*/
export const toggleMode = () => {
theme.update((current) => {
const newMode = current === modeLight ? modeDark : modeLight;
setModeToLocalStorage(newMode);
applyThemeToHTML(newMode);
return newMode;
});
};
/**
* setup the theme mode - must be called once during app bootstrapping
* checks localStorage, then OS preference, defaults to light
* @returns {string} the mode that was set
*/
export function setupTheme() {
if (!browser) return modeLight;
let mode = getModeFromLocalStorage();
if (mode === modeNotSet) {
mode = getOSPreferredMode();
setModeToLocalStorage(mode);
}
applyThemeToHTML(mode);
theme.set(mode);
return mode;
}
/**
* get the OS preferred light or dark mode
* @returns {string} either 'light' or 'dark'
*/
export const getOSPreferredMode = () => {
if (!browser) return modeLight;
const darkMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
return darkMediaQuery.matches ? modeDark : modeLight;
};
/**
* get the theme mode from localStorage
* @returns {string} the stored mode or 'not-set'
*/
export const getModeFromLocalStorage = () => {
if (!browser) return modeNotSet;
return localStorage.getItem(modeKey) ?? modeNotSet;
};
/**
* set the theme mode in localStorage
* @param {string} mode - either 'light' or 'dark'
*/
export const setModeToLocalStorage = (mode) => {
if (!browser) return;
localStorage.setItem(modeKey, mode);
};
/**
* apply the theme to the HTML element by adding/removing the 'dark' class
* @param {string} mode - either 'light' or 'dark'
*/
const applyThemeToHTML = (mode) => {
if (!browser) return;
const html = document.documentElement;
if (mode === modeDark) {
html.classList.add('dark');
html.style.backgroundColor = '#111827';
} else {
html.classList.remove('dark');
html.style.removeProperty('background-color');
}
};
/**
* set up theme change listener for OS preference changes
*/
export const setupOSThemeListener = () => {
if (!browser) return;
const darkMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
darkMediaQuery.addEventListener('change', (e) => {
// only update if user hasn't manually set a preference
const storedMode = getModeFromLocalStorage();
if (storedMode === modeNotSet) {
const newMode = e.matches ? modeDark : modeLight;
applyThemeToHTML(newMode);
theme.set(newMode);
}
});
};