Roastmonday/scripts/roastmonday_common.js
2025-05-24 13:23:02 +02:00

222 lines
5.9 KiB
JavaScript

/*
* 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();
});
}