Browse Source

fix: Mermaid and HLJS theming

A recent refactor caused Mermaid and HLJS themes to not always be applied correctly, for example with theme pack default of light mode but user chosen Dark mode.
George Cushen 4 years ago
parent
commit
5b7f5daa5b
2 changed files with 100 additions and 63 deletions
  1. 64 15
      wowchemy/assets/js/wowchemy-theming.js
  2. 36 48
      wowchemy/assets/js/wowchemy.js

+ 64 - 15
wowchemy/assets/js/wowchemy-theming.js

@@ -8,6 +8,8 @@
 
 import {fadeIn} from './wowchemy-animation';
 
+const body = document.body;
+
 function getThemeMode() {
   return parseInt(localStorage.getItem('wcTheme') || 2);
 }
@@ -17,6 +19,8 @@ function canChangeTheme() {
   return Boolean(window.wc.darkLightEnabled);
 }
 
+// initThemeVariation is first called directly after <body> to prevent
+// flashing between the default theme mode and the user's choice.
 function initThemeVariation() {
   if (!canChangeTheme()) {
     return;
@@ -44,11 +48,14 @@ function initThemeVariation() {
       }
       break;
   }
-  if (isDarkTheme) {
+  if (isDarkTheme && !body.classList.contains('dark')) {
+    console.debug('Applying Wowchemy dark theme');
     document.body.classList.add("dark");
-  } else {
+  } else if (body.classList.contains('dark')) {
+    console.debug('Applying Wowchemy light theme');
     document.body.classList.remove("dark");
   }
+  return {isDarkTheme, currentThemeMode};
 }
 
 function changeThemeModeClick(newMode) {
@@ -62,7 +69,6 @@ function changeThemeModeClick(newMode) {
       localStorage.setItem('wcTheme', '1');
       isDarkTheme = true;
       console.info('User changed theme variation to Dark.');
-      showActiveTheme(0);
       break;
     case 1:
       localStorage.setItem('wcTheme', '2');
@@ -77,16 +83,14 @@ function changeThemeModeClick(newMode) {
         isDarkTheme = window.wc.isSiteThemeDark;
       }
       console.info('User changed theme variation to Auto.');
-      showActiveTheme(1);
       break;
     default:
       localStorage.setItem('wcTheme', '0');
       isDarkTheme = false;
       console.info('User changed theme variation to Light.');
-      showActiveTheme(2);
       break;
   }
-  renderThemeVariation(isDarkTheme);
+  renderThemeVariation(isDarkTheme, newMode);
 }
 
 function showActiveTheme(mode) {
@@ -119,16 +123,19 @@ function showActiveTheme(mode) {
  * Render theme variation (day or night).
  *
  * @param {boolean} isDarkTheme
- * @param {boolean} init
+ * @param {int} themeMode - {0: Dark, 1: Auto, 2: Light}
+ * @param {boolean} init - true only when called on document ready
  * @returns {undefined}
  */
-function renderThemeVariation(isDarkTheme, init = false) {
+function renderThemeVariation(isDarkTheme, themeMode = 2, init = false) {
   // Is code highlighting enabled in site config?
   const codeHlLight = document.querySelector('link[title=hl-light]');
   const codeHlDark = document.querySelector('link[title=hl-dark]');
-  const codeHlEnabled = codeHlLight || codeHlDark;
-  const diagramEnabled = document.querySelector('script[title=mermaid]');
-  const body = document.body;
+  const codeHlEnabled = (codeHlLight !== null) || (codeHlDark !== null);
+  const diagramEnabled = document.querySelector('script[title=mermaid]') !== null;
+
+  // Update active theme mode in navbar theme selector.
+  showActiveTheme(themeMode);
 
   // Check if re-render required.
   if (!init) {
@@ -147,10 +154,16 @@ function renderThemeVariation(isDarkTheme, init = false) {
     }
     body.classList.remove('dark');
     if (codeHlEnabled) {
-      codeHlLight.disabled = false;
-      codeHlDark.disabled = true;
+      console.debug('Setting HLJS theme to light');
+      if (codeHlLight) {
+        codeHlLight.disabled = false;
+      }
+      if (codeHlDark){
+        codeHlDark.disabled = true;
+      }
     }
     if (diagramEnabled) {
+      console.debug('Initializing Mermaid with light theme');
       if (init) {
         /** @namespace window.mermaid **/
         window.mermaid.initialize({theme: 'default', securityLevel: 'loose'});
@@ -167,10 +180,16 @@ function renderThemeVariation(isDarkTheme, init = false) {
     }
     body.classList.add("dark");
     if (codeHlEnabled) {
-      codeHlLight.disabled = true;
-      codeHlDark.disabled = false;
+      console.debug('Setting HLJS theme to dark');
+      if (codeHlLight) {
+        codeHlLight.disabled = true;
+      }
+      if (codeHlDark){
+        codeHlDark.disabled = false;
+      }
     }
     if (diagramEnabled) {
+      console.debug('Initializing Mermaid with dark theme');
       if (init) {
         /** @namespace window.mermaid **/
         window.mermaid.initialize({theme: 'dark', securityLevel: 'loose'});
@@ -182,6 +201,35 @@ function renderThemeVariation(isDarkTheme, init = false) {
   }
 }
 
+/**
+ * onMediaQueryListEvent.
+ *
+ * @param {MediaQueryListEvent} event
+ * @returns {undefined}
+ */
+function onMediaQueryListEvent(event) {
+  if (!canChangeTheme()) {
+    // Changing theme variation is not allowed by admin.
+    return;
+  }
+  const darkModeOn = event.matches;
+  console.debug(`OS dark mode preference changed to ${darkModeOn ? '🌒 on' : '☀️ off'}.`);
+  let currentThemeVariation = getThemeMode();
+  let isDarkTheme;
+  if (currentThemeVariation === 2) {
+    if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
+      // The visitor prefers dark themes.
+      isDarkTheme = true;
+    } else if (window.matchMedia('(prefers-color-scheme: light)').matches) {
+      // The visitor prefers light themes.
+      isDarkTheme = false;
+    } else {
+      // The visitor does not have a day or night preference, so use the theme's default setting.
+      isDarkTheme = window.wc.isSiteThemeDark;
+    }
+    renderThemeVariation(isDarkTheme, currentThemeVariation);
+  }
+}
 
 export {
   canChangeTheme,
@@ -189,4 +237,5 @@ export {
   changeThemeModeClick,
   renderThemeVariation,
   getThemeMode,
+  onMediaQueryListEvent,
 };

+ 36 - 48
wowchemy/assets/js/wowchemy.js

@@ -8,11 +8,10 @@
 import {hugoEnvironment} from '@params';
 
 import {
-  canChangeTheme,
   changeThemeModeClick,
-  getThemeMode,
   initThemeVariation,
-  renderThemeVariation
+  renderThemeVariation,
+  onMediaQueryListEvent,
 } from './wowchemy-theming';
 
 console.debug(`Environment: ${hugoEnvironment}`)
@@ -426,49 +425,9 @@ $(document).ready(function () {
     hljs.initHighlighting();
   }
 
-  // Initialize theme variation.
-  initThemeVariation();
-
-  // Change theme mode.
-  $('.js-set-theme-light').click(function (e) {
-    e.preventDefault();
-    changeThemeModeClick(2);
-  });
-  $('.js-set-theme-dark').click(function (e) {
-    e.preventDefault();
-    changeThemeModeClick(0);
-  });
-  $('.js-set-theme-auto').click(function (e) {
-    e.preventDefault();
-    changeThemeModeClick(1);
-  });
-
-  // Live update of day/night mode on system preferences update (no refresh required).
-  // Note: since we listen only for *dark* events, we won't detect other scheme changes such as light to no-preference.
-  const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
-  darkModeMediaQuery.addEventListener("change", (e) => {
-    if (!canChangeTheme()) {
-      // Changing theme variation is not allowed by admin.
-      return;
-    }
-    const darkModeOn = e.matches;
-    console.log(`OS dark mode preference changed to ${darkModeOn ? '🌒 on' : '☀️ off'}.`);
-    let currentThemeVariation = getThemeMode();
-    let isDarkTheme;
-    if (currentThemeVariation === 2) {
-      if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
-        // The visitor prefers dark themes.
-        isDarkTheme = true;
-      } else if (window.matchMedia('(prefers-color-scheme: light)').matches) {
-        // The visitor prefers light themes.
-        isDarkTheme = false;
-      } else {
-        // The visitor does not have a day or night preference, so use the theme's default setting.
-        isDarkTheme = window.wc.isSiteThemeDark;
-      }
-      renderThemeVariation(isDarkTheme);
-    }
-  });
+  // Render theme variation, including any HLJS and Mermaid themes.
+  let {isDarkTheme, themeMode} = initThemeVariation();
+  renderThemeVariation(isDarkTheme, themeMode, true);
 });
 
 /* ---------------------------------------------------------------------------
@@ -630,8 +589,37 @@ $(window).on('load', function () {
   fixScrollspy();
 });
 
-// Normalize Bootstrap carousel slide heights.
-$(window).on('load resize orientationchange', normalizeCarouselSlideHeights);
+// Theme chooser events.
+let linkLight = document.querySelector('.js-set-theme-light');
+let linkDark = document.querySelector('.js-set-theme-dark');
+let linkAuto = document.querySelector('.js-set-theme-auto');
+if (linkLight && linkDark && linkAuto) {
+  linkLight.addEventListener('click', event => {
+    event.preventDefault();
+    changeThemeModeClick(2);
+  });
+  linkDark.addEventListener('click', event => {
+    event.preventDefault();
+    changeThemeModeClick(0);
+  });
+  linkAuto.addEventListener('click', event => {
+    event.preventDefault();
+    changeThemeModeClick(1);
+  });
+}
+
+// Media Query events.
+// Live update of day/night mode on system preferences update (no refresh required).
+// Note: since we listen only for *dark* events, we won't detect other scheme changes such as light to no-preference.
+const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
+darkModeMediaQuery.addEventListener("change", (event) => {
+  onMediaQueryListEvent(event);
+});
+
+// Normalize Bootstrap carousel slide heights for Slider widget instances.
+window.addEventListener('load', normalizeCarouselSlideHeights);
+window.addEventListener('resize', normalizeCarouselSlideHeights);
+window.addEventListener('orientationchange', normalizeCarouselSlideHeights);
 
 // Automatic main menu dropdowns on mouse over.
 $('body').on('mouseenter mouseleave', '.dropdown', function (e) {