github.com/shoshinnikita/budget-manager@v0.7.1-0.20220131195411-8c46ff1c6778/static/js/theme-switcher.js (about) 1 const localStorageKey = "theme"; 2 const themeChangeEventName = "theme-change"; 3 const darkThemeMedia = "(prefers-color-scheme: dark)"; 4 5 const lightTheme = "light"; 6 const systemTheme = "system"; 7 const darkTheme = "dark"; 8 9 /** 10 * Saves a new theme in the local storage and updates the styles 11 */ 12 function switchTheme(newTheme) { 13 if (newTheme !== lightTheme && newTheme !== systemTheme && newTheme !== darkTheme) { 14 return; 15 } 16 localStorage.setItem(localStorageKey, newTheme); 17 18 updateStyles(); 19 } 20 21 function updateStyles() { 22 let newTheme = lightTheme; 23 if (isDarkTheme()) { 24 newTheme = darkTheme; 25 } 26 27 document.getElementsByTagName("html")[0].setAttribute("data-theme", newTheme); 28 29 window.dispatchEvent(new Event(themeChangeEventName)); 30 } 31 32 /** 33 * Returns true if: 34 * * the local theme is set to 'dark' 35 * * the local theme is set to 'system' and the system theme is set to 'dark' 36 */ 37 function isDarkTheme() { 38 const localStorageTheme = getLocalStorageTheme(); 39 if (localStorageTheme !== systemTheme) { 40 return localStorageTheme === darkTheme; 41 } 42 43 return getSystemTheme() === darkTheme; 44 } 45 46 function getLocalStorageTheme() { 47 let value = localStorage.getItem(localStorageKey); 48 if (!value) { 49 // Use the system theme by default 50 value = systemTheme; 51 localStorage.setItem(localStorageKey, value); 52 } 53 return value; 54 } 55 56 function getSystemTheme() { 57 if (window.matchMedia(darkThemeMedia).matches) { 58 return darkTheme; 59 } 60 return lightTheme; 61 } 62 63 window.matchMedia(darkThemeMedia).addEventListener("change", function () { 64 if (getLocalStorageTheme() !== systemTheme) { 65 // Ignore changes 66 return; 67 } 68 69 updateStyles(); 70 }); 71 72 // Update styles on the page load. Don't use 'window.addEventListener("load")' to avoid flickering 73 updateStyles();