3 The code below is based on the Doxygen Awesome project with some minor modifications
4 https://github.com/jothepro/doxygen-awesome-css
8 Copyright (c) 2021 - 2022 jothepro
10 Permission is hereby granted, free of charge, to any person obtaining a copy
11 of this software and associated documentation files (the "Software"), to deal
12 in the Software without restriction, including without limitation the rights
13 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 copies of the Software, and to permit persons to whom the Software is
15 furnished to do so, subject to the following conditions:
17 The above copyright notice and this permission notice shall be included in all
18 copies or substantial portions of the Software.
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 class DarkModeToggle extends HTMLElement {
31 static icon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" height="1.2em" width="1.2em"><g fill="none" fill-rule="evenodd"><path d="M0 0h24v24H0z"></path><rect width="1" height="3" x="12" fill="currentColor" rx=".5"></rect><rect width="1" height="3" x="12" y="21" fill="currentColor" rx=".5"></rect><rect width="1" height="3" x="22" y="10.5" fill="currentColor" rx=".5" transform="rotate(90 22.5 12)"></rect><rect width="1" height="3" x="1" y="10.5" fill="currentColor" rx=".5" transform="rotate(90 1.5 12)"></rect><rect width="1" height="3" x="19" y="3" fill="currentColor" rx=".5" transform="rotate(-135 19.5 4.5)"></rect><rect width="1" height="3" x="19" y="18" fill="currentColor" rx=".5" transform="rotate(135 19.5 19.5)"></rect><rect width="1" height="3" x="4" y="3" fill="currentColor" rx=".5" transform="scale(1 -1) rotate(45 15.37 0)"></rect><rect width="1" height="3" x="4" y="18" fill="currentColor" rx=".5" transform="scale(1 -1) rotate(-45 -42.57 0)"></rect><circle cx="12" cy="12" r="6.5" stroke="currentColor"></circle></g></svg>'
32 static icond = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" height="1.2em" width="1.2em"><g fill="none" fill-rule="evenodd"><path d="M0 0h24v24H0z"></path><rect width="1" height="3" x="12" fill="currentColor" rx=".5"></rect><rect width="1" height="3" x="12" y="21" fill="currentColor" rx=".5"></rect><rect width="1" height="3" x="22" y="10.5" fill="currentColor" rx=".5" transform="rotate(90 22.5 12)"></rect><rect width="1" height="3" x="1" y="10.5" fill="currentColor" rx=".5" transform="rotate(90 1.5 12)"></rect><rect width="1" height="3" x="19" y="3" fill="currentColor" rx=".5" transform="rotate(-135 19.5 4.5)"></rect><rect width="1" height="3" x="19" y="18" fill="currentColor" rx=".5" transform="rotate(135 19.5 19.5)"></rect><rect width="1" height="3" x="4" y="3" fill="currentColor" rx=".5" transform="scale(1 -1) rotate(45 15.37 0)"></rect><rect width="1" height="3" x="4" y="18" fill="currentColor" rx=".5" transform="scale(1 -1) rotate(-45 -42.57 0)"></rect><circle cx="12" cy="12" r="6.5" stroke="currentColor" fill="currentColor"></circle></g></svg>'
33 static title = "Toggle Light/Dark Mode"
35 static prefersLightModeInDarkModeKey = "prefers-light-mode-in-dark-mode"
36 static prefersDarkModeInLightModeKey = "prefers-dark-mode-in-light-mode"
38 static _staticConstructor = function() {
39 DarkModeToggle.enableDarkMode(DarkModeToggle.userPreference)
40 // Update the color scheme when the browsers preference changes
41 // without user interaction on the website.
42 window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
43 DarkModeToggle.onSystemPreferenceChanged()
45 // Update the color scheme when the tab is made visible again.
46 // It is possible that the appearance was changed in another tab
47 // while this tab was in the background.
48 document.addEventListener("visibilitychange", visibilityState => {
49 if (document.visibilityState === 'visible') {
50 DarkModeToggle.onSystemPreferenceChanged()
57 var tbuttons = document.getElementsByTagName("dark-mode-toggle");
59 var titleArea = document.getElementById("titlearea");
60 var searchBox = document.getElementById("MSearchBox");
61 var mainMenu = document.getElementById("main-menu");
62 var navRow1 = document.getElementById("navrow1");
63 var mainMenuVisible = false;
64 if (!tbuttons.length){
65 toggleButton = document.createElement('dark-mode-toggle')
66 toggleButton.title = DarkModeToggle.title
67 } else {toggleButton=tbuttons[0]}
70 if (DarkModeToggle.darkModeEnabled){
71 toggleButton.innerHTML=DarkModeToggle.icond
73 toggleButton.innerHTML=DarkModeToggle.icon
77 var menuStyle = window.getComputedStyle(mainMenu);
78 mainMenuVisible = menuStyle.display!=='none'
80 var searchBoxPos1 = document.getElementById("searchBoxPos1");
81 if (searchBox) { // (1) search box visible
82 searchBox.parentNode.appendChild(toggleButton)
83 } else if (navRow1) { // (2) no search box, static menu bar
84 var li = document.createElement('li');
85 li.style = 'float: right;'
86 li.appendChild(toggleButton);
87 toggleButton.style = 'width: 24px; height: 25px; padding-top: 11px; float: right;';
88 var row = document.querySelector('#navrow1 > ul:first-of-type');
90 } else if (mainMenu && mainMenuVisible) { // (3) no search box + dynamic menu bar expanded
91 var li = document.createElement('li');
92 li.style = 'float: right;'
93 li.appendChild(toggleButton);
94 toggleButton.style = 'width: 14px; height: 36px; padding-top: 10px; float: right;';
95 mainMenu.appendChild(li)
96 } else if (searchBoxPos1) { // (4) no search box + dynamic menu bar collapsed
97 toggleButton.style = 'width: 24px; height: 36px; padding-top: 10px; float: right;';
98 searchBoxPos1.style = 'top: 0px;'
99 searchBoxPos1.appendChild(toggleButton);
100 } else if (titleArea) { // (5) no search box and no navigation tabs
101 toggleButton.style = 'width: 24px; height: 24px; position: absolute; right: 0px; top: 34px;';
102 titleArea.append(toggleButton);
108 $(document).ready(function() {
110 $(document).ready(function(){
111 DarkModeToggle.addButton();
113 $(window).resize(function(){
114 DarkModeToggle.addButton();
116 DarkModeToggle.setDarkModeVisibility(DarkModeToggle.darkModeEnabled)
123 this.onclick=this.toggleDarkMode
127 static createCookie(name, value, days) {
129 var date = new Date();
130 date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
131 var expires = "; expires=" + date.toGMTString();
133 else var expires = "";
135 document.cookie = name + "=" + value + expires + "; path=/";
138 static readCookie(name) {
139 var nameEQ = name + "=";
140 var ca = document.cookie.split(';');
141 for (var i = 0; i < ca.length; i++) {
143 while (c.charAt(0) == ' ') c = c.substring(1, c.length);
144 if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
149 static eraseCookie(name) {
150 DarkModeToggle.createCookie(name, "", -1);
154 * @returns `true` for dark-mode, `false` for light-mode system preference
156 static get systemPreference() {
157 return window.matchMedia('(prefers-color-scheme: dark)').matches
160 static get prefersDarkModeInLightMode() {
161 if (window.chrome) { // Chrome supports localStorage in combination with file:// but not cookies
162 return localStorage.getItem(DarkModeToggle.prefersDarkModeInLightModeKey)
163 } else { // Other browsers support cookies in combination with file:// but not localStorage
164 return DarkModeToggle.readCookie('doxygen_prefers_dark')=='1'
168 static set prefersDarkModeInLightMode(preference) {
171 localStorage.setItem(DarkModeToggle.prefersDarkModeInLightModeKey, true)
173 localStorage.removeItem(DarkModeToggle.prefersDarkModeInLightModeKey)
177 DarkModeToggle.createCookie('doxygen_prefers_dark','1',365)
179 DarkModeToggle.eraseCookie('doxygen_prefers_dark')
184 static get prefersLightModeInDarkMode() {
185 if (window.chrome) { // Chrome supports localStorage in combination with file:// but not cookies
186 return localStorage.getItem(DarkModeToggle.prefersLightModeInDarkModeKey)
187 } else { // Other browsers support cookies in combination with file:// but not localStorage
188 return DarkModeToggle.readCookie('doxygen_prefers_light')=='1'
192 static set prefersLightModeInDarkMode(preference) {
195 localStorage.setItem(DarkModeToggle.prefersLightModeInDarkModeKey, true)
197 localStorage.removeItem(DarkModeToggle.prefersLightModeInDarkModeKey)
201 DarkModeToggle.createCookie('doxygen_prefers_light','1',365)
203 DarkModeToggle.eraseCookie('doxygen_prefers_light')
210 * @returns `true` for dark-mode, `false` for light-mode user preference
212 static get userPreference() {
213 return (!DarkModeToggle.systemPreference && DarkModeToggle.prefersDarkModeInLightMode) ||
214 (DarkModeToggle.systemPreference && !DarkModeToggle.prefersLightModeInDarkMode)
217 static set userPreference(userPreference) {
218 DarkModeToggle.darkModeEnabled = userPreference
219 if (!userPreference) {
220 if (DarkModeToggle.systemPreference) {
221 DarkModeToggle.prefersLightModeInDarkMode = true
223 DarkModeToggle.prefersDarkModeInLightMode = false
226 if (!DarkModeToggle.systemPreference) {
227 DarkModeToggle.prefersDarkModeInLightMode = true
229 DarkModeToggle.prefersLightModeInDarkMode = false
232 DarkModeToggle.onUserPreferenceChanged()
235 static setDarkModeVisibility(enable) {
236 var darkModeStyle, lightModeStyle;
238 darkModeStyle = 'inline-block';
239 lightModeStyle = 'none'
241 darkModeStyle = 'none';
242 lightModeStyle = 'inline-block'
244 document.querySelectorAll('.dark-mode-visible').forEach(function(el) {
245 el.style.display = darkModeStyle;
247 document.querySelectorAll('.light-mode-visible').forEach(function(el) {
248 el.style.display = lightModeStyle;
251 static enableDarkMode(enable) {
253 DarkModeToggle.darkModeEnabled = true
254 document.documentElement.classList.add("dark-mode")
255 document.documentElement.classList.remove("light-mode")
257 DarkModeToggle.darkModeEnabled = false
258 document.documentElement.classList.remove("dark-mode")
259 document.documentElement.classList.add("light-mode")
261 DarkModeToggle.setDarkModeVisibility(enable)
264 static onSystemPreferenceChanged() {
265 DarkModeToggle.darkModeEnabled = DarkModeToggle.userPreference
266 DarkModeToggle.enableDarkMode(DarkModeToggle.darkModeEnabled)
269 static onUserPreferenceChanged() {
270 DarkModeToggle.enableDarkMode(DarkModeToggle.darkModeEnabled)
274 DarkModeToggle.userPreference = !DarkModeToggle.userPreference
275 DarkModeToggle.addButton();
279 customElements.define("dark-mode-toggle", DarkModeToggle);
281 DarkModeToggle.init();