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();