wowchemy-theming.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*************************************************
  2. * Wowchemy
  3. * https://github.com/wowchemy/wowchemy-hugo-modules
  4. *
  5. * Wowchemy Theming System
  6. * Supported Modes: {0: Day, 1: Night, 2: Auto}
  7. **************************************************/
  8. import {fadeIn} from './wowchemy-animation';
  9. function getThemeMode() {
  10. return parseInt(localStorage.getItem('wcTheme') || 2);
  11. }
  12. function canChangeTheme() {
  13. // If var is set, then user is allowed to change the theme variation.
  14. return Boolean(window.wc.darkLightEnabled);
  15. }
  16. function initThemeVariation() {
  17. if (!canChangeTheme()) {
  18. return;
  19. }
  20. let currentThemeMode = getThemeMode();
  21. let isDarkTheme;
  22. switch (currentThemeMode) {
  23. case 0:
  24. isDarkTheme = false;
  25. break;
  26. case 1:
  27. isDarkTheme = true;
  28. break;
  29. default:
  30. if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
  31. // The visitor prefers dark themes and switching to the dark variation is allowed by admin.
  32. isDarkTheme = true;
  33. } else if (window.matchMedia('(prefers-color-scheme: light)').matches) {
  34. // The visitor prefers light themes and switching to the dark variation is allowed by admin.
  35. isDarkTheme = false;
  36. } else {
  37. // Use the site's default theme variation based on `light` in the theme file.
  38. isDarkTheme = window.wc.isSiteThemeDark;
  39. }
  40. break;
  41. }
  42. if (isDarkTheme) {
  43. document.body.classList.add("dark");
  44. } else {
  45. document.body.classList.remove("dark");
  46. }
  47. }
  48. function changeThemeModeClick(newMode) {
  49. if (!canChangeTheme()) {
  50. console.info('Cannot set theme - admin disabled theme selector.');
  51. return;
  52. }
  53. let isDarkTheme;
  54. switch (newMode) {
  55. case 0:
  56. localStorage.setItem('wcTheme', '1');
  57. isDarkTheme = true;
  58. console.info('User changed theme variation to Dark.');
  59. showActiveTheme(0);
  60. break;
  61. case 1:
  62. localStorage.setItem('wcTheme', '2');
  63. if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
  64. // The visitor prefers dark themes and switching to the dark variation is allowed by admin.
  65. isDarkTheme = true;
  66. } else if (window.matchMedia('(prefers-color-scheme: light)').matches) {
  67. // The visitor prefers light themes and switching to the dark variation is allowed by admin.
  68. isDarkTheme = false;
  69. } else {
  70. // Use the site's default theme variation based on `light` in the theme file.
  71. isDarkTheme = window.wc.isSiteThemeDark;
  72. }
  73. console.info('User changed theme variation to Auto.');
  74. showActiveTheme(1);
  75. break;
  76. default:
  77. localStorage.setItem('wcTheme', '0');
  78. isDarkTheme = false;
  79. console.info('User changed theme variation to Light.');
  80. showActiveTheme(2);
  81. break;
  82. }
  83. renderThemeVariation(isDarkTheme);
  84. }
  85. function showActiveTheme(mode) {
  86. let linkLight = document.querySelector('.js-set-theme-light');
  87. let linkDark = document.querySelector('.js-set-theme-dark');
  88. let linkAuto = document.querySelector('.js-set-theme-auto');
  89. switch (mode) {
  90. case 0:
  91. // Dark.
  92. linkLight.classList.remove('dropdown-item-active');
  93. linkDark.classList.add('dropdown-item-active');
  94. linkAuto.classList.remove('dropdown-item-active');
  95. break;
  96. case 1:
  97. // Auto.
  98. linkLight.classList.remove('dropdown-item-active');
  99. linkDark.classList.remove('dropdown-item-active');
  100. linkAuto.classList.add('dropdown-item-active');
  101. break;
  102. default:
  103. // Light.
  104. linkLight.classList.add('dropdown-item-active');
  105. linkDark.classList.remove('dropdown-item-active');
  106. linkAuto.classList.remove('dropdown-item-active');
  107. break;
  108. }
  109. }
  110. /**
  111. * Render theme variation (day or night).
  112. *
  113. * @param {boolean} isDarkTheme
  114. * @param {boolean} init
  115. * @returns {undefined}
  116. */
  117. function renderThemeVariation(isDarkTheme, init = false) {
  118. // Is code highlighting enabled in site config?
  119. const codeHlLight = document.querySelector('link[title=hl-light]');
  120. const codeHlDark = document.querySelector('link[title=hl-dark]');
  121. const codeHlEnabled = codeHlLight || codeHlDark;
  122. const diagramEnabled = document.querySelector('script[title=mermaid]');
  123. const body = document.body;
  124. // Check if re-render required.
  125. if (!init) {
  126. // If request to render light when light variation already rendered, return.
  127. // If request to render dark when dark variation already rendered, return.
  128. if ((isDarkTheme === false && !body.classList.contains('dark')) || (isDarkTheme === true && body.classList.contains('dark'))) {
  129. return;
  130. }
  131. }
  132. if (isDarkTheme === false) {
  133. if (!init) {
  134. // Only fade in the page when changing the theme variation.
  135. Object.assign(document.body.style, {opacity: 0, visibility: 'visible'});
  136. fadeIn(document.body, 600);
  137. }
  138. body.classList.remove('dark');
  139. if (codeHlEnabled) {
  140. codeHlLight.disabled = false;
  141. codeHlDark.disabled = true;
  142. }
  143. if (diagramEnabled) {
  144. if (init) {
  145. /** @namespace window.mermaid **/
  146. window.mermaid.initialize({theme: 'default', securityLevel: 'loose'});
  147. } else {
  148. // Have to reload to re-initialise Mermaid with the new theme and re-parse the Mermaid code blocks.
  149. location.reload();
  150. }
  151. }
  152. } else if (isDarkTheme === true) {
  153. if (!init) {
  154. // Only fade in the page when changing the theme variation.
  155. Object.assign(document.body.style, {opacity: 0, visibility: 'visible'});
  156. fadeIn(document.body, 600);
  157. }
  158. body.classList.add("dark");
  159. if (codeHlEnabled) {
  160. codeHlLight.disabled = true;
  161. codeHlDark.disabled = false;
  162. }
  163. if (diagramEnabled) {
  164. if (init) {
  165. /** @namespace window.mermaid **/
  166. window.mermaid.initialize({theme: 'dark', securityLevel: 'loose'});
  167. } else {
  168. // Have to reload to re-initialise Mermaid with the new theme and re-parse the Mermaid code blocks.
  169. location.reload();
  170. }
  171. }
  172. }
  173. }
  174. export {
  175. canChangeTheme,
  176. initThemeVariation,
  177. changeThemeModeClick,
  178. renderThemeVariation,
  179. getThemeMode,
  180. };