Back

A script to toggle light and dark themes

Jour… Nuit… Jour…

file: assets/scripts/toggleTheme.js

 1{{ $light := site.Params.theme.light.background | default "#ffffff" }}
 2{{ $dark  := site.Params.theme.dark.background  | default "#000000" }}
 3
 4// Switch from one theme to another
 5function toggleTheme() {
 6  // The current theme is defined in <html data-theme="">
 7  // "data-theme" is an attribute of <html> which is refered to as "document.documentElement"
 8  // current theme is either "light" or "dark"
 9  const currentTheme = document.documentElement.getAttribute("data-theme");
10  const isDark = currentTheme === "dark";
11  // The alternative theme is the theme that is not the current theme
12  // if current theme is "light" alternative theme is "dark"
13  // if current theme is "dark" alternative theme is "light"
14  const alternativeTheme = isDark ? "light" : "dark";
15  const message = isDark ? '{{ i18n "light_on" }}' :  '{{ i18n "light_off" }}';
16  // The theme color is a RGB color value associated with the theme
17  // colors for both themes are defined in config.toml and defaults to values exposed above
18  // during compilation Hugo will replace the placeholders in the following expression by the actual values
19  // this metadata is used by Chrome to colorize its "chrome" on mobile (navigation bar)
20  // the theme color is exposed in a the page <head> as metadata : <meta name="theme-color" content="" />
21  const themeColor = document.querySelector("meta[name=theme-color]");
22  // The theme color me is a RGB color value associated with each theme
23  // they are defined in config.toml and defaults to values exposed above
24  // during compilation Hugo will replace the placeholders in the following expression by the actual values
25  // The alternative theme colot is the the RGB color associated to the alternative theme
26  const alternativeThemeColor = isDark ? "{{ $light }}" : "{{ $dark }}";
27  // Replace the current theme by the alternative theme
28  document.documentElement.setAttribute("data-theme", alternativeTheme);
29  console.log(message);
30  // Place a variable "theme" in browser's local storage (on the user device)
31  // the variable's value is the alternative theme ("dark" or "light" - the one we just set as current theme)
32  window.localStorage && window.localStorage.setItem("theme", alternativeTheme);
33  // Fill <meta name="theme-color" content="" /> with the alternative theme color
34  themeColor.setAttribute("content", alternativeThemeColor);
35}
36
37// Enable a specific theme
38function enableTheme(targetTheme) {
39  const currentTheme = document.documentElement.getAttribute("data-theme");
40  if (currentTheme !== targetTheme) {
41    toggleTheme();
42  }
43}
44
45// Set initial theme
46function initTheme(adminPref) {
47  // When visitors doesn't have JS, theme will be set according to his global preferences
48  // With JS we basically force a theme and the attribute must not be left empty
49  document.documentElement.setAttribute("data-theme", adminPref);
50  // Check user's global preference
51  const prefersDarkScheme = window.matchMedia("screen and (prefers-color-scheme: dark)");
52  const prefersLightScheme = window.matchMedia("screen and (prefers-color-scheme: light)");
53  const globalPref = prefersDarkScheme.matches ? "dark" : "light";
54  // Check user's local preference
55  const localPref = window.localStorage && window.localStorage.getItem("theme");
56  // Let local preference prevail
57  const userPref = !!localPref ? localPref : globalPref;
58  enableTheme(userPref);
59  // Observe change of mind
60  document.addEventListener("DOMContentLoaded", event => {
61    // Locally (on the website)
62    const toggle = document.querySelector(".theme");
63    toggle.addEventListener("click", toggleTheme, false);
64    // or globally (through the browser)
65    prefersDarkScheme.addListener(
66      e => e.matches && enableTheme("dark")
67    );
68    prefersLightScheme.addListener(
69      e => e.matches && enableTheme("light")
70    );
71  });
72}
73
74// Initialise Theme
75initTheme('{{ site.Params.theme.default | default "light" }}');
Metadata
PublicationMay 3, 2022
Last editMay 30, 2022
SourcesView source
LicenseCreative CommonsAttribution - Some rights reserved
ContributeSuggest change
Comments