/* * JS doesn't support directly declaring objects * with '--' and '-' in their properties. * * Well technically it deos using bracket-notation like this: * foo['--bar'] =42; * But that's not that much better. * * So instead this JSON.parse is used. */ window.themes = JSON.parse('{\ "white": {\ "--main-highlight-color": "#EF940B",\ "--main-bg-color": "white", \ "--secondary-bg-color": "white", \ "--main-text-color": "black",\ "--main-link-color": "#106BF4",\ "--shadow-color": "#888",\ "--gray-light": "#cacaca",\ "--gray-medium": "#e0e0e0",\ "--gray-dark": "#4c4c4c",\ "--red": "red",\ "--green": "green"\ },\ "black": {\ "--main-highlight-color": "#EE6E1F",\ "--main-link-color": "#1191e0",\ "--main-bg-color": "black",\ "--secondary-bg-color": "black", \ "--main-text-color": "white",\ "--shadow-color": "#777",\ "--gray-light": "#4c4c4c",\ "--gray-medium": "#333",\ "--gray-dark": "#cacaca",\ "--red": "#ef0000",\ "--green": "#00ab00"\ },\ "ash": {\ "--main-highlight-color": "#EE6E1F",\ "--main-link-color": "#1191e0",\ "--main-bg-color": "#333",\ "--secondary-bg-color": "#333", \ "--main-text-color": "#d0d0d0",\ "--shadow-color": "#656565",\ "--gray-light": "#4c4c4c",\ "--gray-medium": "#3b3b3b",\ "--gray-dark": "#cacaca",\ "--red": "#e4053e",\ "--green": "#04c446"\ },\ "midnight": {\ "--main-highlight-color": "#1caff6",\ "--main-link-color": "#1caff6",\ "--main-bg-color": "#111",\ "--secondary-bg-color": "#045d89", \ "--main-text-color": "#d0d0d0",\ "--shadow-color": "#656565",\ "--gray-light": "#3f3f3f",\ "--gray-medium": "#3b3b3b",\ "--gray-dark": "#cacaca",\ "--red": "#f72900",\ "--green": "#82dd00"\ }\ }'); window.IS_TOUCH_DEVICE = false; window.addEventListener('touchstart', function() { window.IS_TOUCH_DEVICE = true; }); window.queries = getQueries(); setTheme(queries.theme); if (queries.debugTouch) { IS_TOUCH_DEVICE = true; console.log("Touch device mode set"); } document.addEventListener("DOMContentLoaded", function() { displayThemeChooser(); }); function setTheme(t, save = true, element = null) { let themeName = 'white'; if (!!t && (t in themes)) { themeName = t; } else { const ls = localStorage.getItem('theme'); if (!!ls && (ls in themes)) { themeName = ls; } else { save = false; // Use default. Switch to ash if dark mode and don't save if (matchMedia("(prefers-color-scheme: dark)")) { themeName = 'ash'; } } } if (save) { localStorage.setItem('theme', themeName); } const theme = themes[themeName]; const doc = element || document.querySelector(':root'); Object.keys(theme).forEach(varName => { doc.style.setProperty(varName, theme[varName]); }); } function displayThemeChooser() { const wrapper = document.getElementById('themeChooser'); if (!wrapper) { return; } const themeNames = Object.keys(themes); if (themeNames.length < 2) { return; } const list = document.createElement('ul'); list.classList.add('theme-chooser-list'); themeNames.forEach(t => { const link = document.createElement('a'); link.style.position = 'relative'; link.href = `?theme=${t}`; link.onclick = function (e) { const t = this.href.split('theme=')[1]; e.preventDefault(); if (!IS_TOUCH_DEVICE) { setTheme(t); return; } const callout = document.querySelector('.theme-preview'); if (callout && callout.getAttribute('currentTheme') == t) { // Clicked on already seelcted theme - apply! callout.style.display = "none"; document.querySelector('.themelist').style.filter = ''; try { let d = document.querySelector('.dimmer').remove(); } catch (err) { // Do nothing } setTheme(t); return; } else { const rect = list.getBoundingClientRect(); setTheme(t, false, callout); callout.setAttribute('currentTheme', t); callout.style.display = "inherit"; callout.style.bottom = document.querySelector('.theme-chooser-list').getBoundingClientRect().top + "px"; console.log(callout, callout.style); document.querySelector('.themelist').style.filter = 'blur(5px)'; if (!document.querySelector('.dimmer')) { let dimmer = document.createElement('div'); dimmer.classList.add('dimmer'); document.body.appendChild(dimmer); } } }; link.onmouseenter = function (e) { if (!IS_TOUCH_DEVICE) { const t = this.href.split('theme=')[1]; setTheme(t, false); } }; link.onmouseleave = function (e) { if (!IS_TOUCH_DEVICE) { setTheme(null, false); } }; const container = document.createElement('li'); container.classList.add('theme-chooser-list-item'); const textContainer = document.createElement('span'); link.appendChild(container); textContainer.innerText = t; container.appendChild(textContainer); list.appendChild(link); }); wrapper.appendChild(list); } function getQueries() { const query = window.location.search.substring(1); const vars = query.split('&'); const queries = {}; vars.forEach(v => { const pair = v.split('='); if (pair.length > 1) { queries[pair[0]] = decodeURIComponent(pair[1]); } else { queries[pair[0]] = null; } }); return queries; } function get(url) { // Return a new promise. return new Promise(function(resolve, reject) { // Do the usual XHR stuff let req = new XMLHttpRequest(); req.open('GET', url); req.onload = function() { // This is called even on 404 etc // so check the status if (req.status == 200) { // Resolve the promise with the response text resolve(req.response); } else { // Otherwise reject with the status text // which will hopefully be a meaningful error reject(Error(req.statusText)); } }; // Handle network errors req.onerror = function() { reject(Error('Network Error')); }; // Make the request req.send(); }); }