Skip to content

Instantly share code, notes, and snippets.

@dalf
Created September 29, 2021 14:04
Show Gist options
  • Save dalf/0f983799c20b75b441f8c089372f0cfe to your computer and use it in GitHub Desktop.
Save dalf/0f983799c20b75b441f8c089372f0cfe to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html class="no-js theme-auto">
<head>
<!--
* theme-auto by default
* theme-dark / theme-light according to the preferences (set in the Jinja2 templates)
so it follows the user preference even if javascript is disabled.
-->
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, maximum-scale=1.0, user-scalable=1">
<title>Theme</title>
<style>
html {
--brand-basic: #dee8f3;
--brand-accent: #31456a;
--theme-variant: "light";
}
html.theme-dark {
--brand-basic: #31456a;
--brand-accent: #dee8f3;
--theme-variant: "dark";
}
@media (prefers-color-scheme: dark) {
html.theme-auto {
/* I don't know how to avoid a copy / paste of the values
between html.theme-auto and html.theme-dark
:is is supported only on recent browsers
(and I'm not sure it supports media queries)
if there is no solution, we can include the dark theme values twice from a .less file
*/
--brand-basic: #31456a;
--brand-accent: #dee8f3;
--theme-variant: "dark";
}
}
html.no-js #toggleDarkMode {
/* hide the button when javascript is disabled */
display: none;
}
body {
margin: 0
}
.container {
background-color: var(--brand-basic);
/* start of out of topic statmements */
height: 100vh;
display: flex;
justify-content: right;
align-items: flex-start;
transition: color 0.3s, background-color 0.3s;
}
.btn {
background-color: var(--brand-basic);
color: var(--brand-accent);
border: 3px solid var(--brand-accent);
/* start of out of topic statmements */
height: 48px;
width: 200px;
font-family: sans-serif;
font-size: 16px;
border-radius: 6px;
letter-spacing: 3px;
font-weight: bold;
text-decoration: none;
display: flex;
justify-content: center;
align-items: center;
transition: color 0.3s, background-color 0.3s;
cursor: pointer;
margin: 1rem;
}
.btn:focus {
outline: none;
}
</style>
</head>
<body>
<div class="container">
<a class="btn" href="theme.html">RELOAD</a>
<button id="toggleDarkMode" type="button" class="btn" onclick="toggleDarkMode()"></button>
</div>
<script>
/* ------------------------------------------------------ */
// update of https://github.com/searxng/searxng/blob/a582cf3d8231f5ed8a881aa87576dfc0600e1c07/searx/static/themes/simple/src/js/main/00_searx_toolkit.js#L73-L110
const searx = {
_timers: new Map(),
_unloading: false,
http: function (method, url, data=null) {
var req = new XMLHttpRequest(),
resolve = function () { },
reject = function () { },
promise = {
then: function (callback) { resolve = callback; return promise; },
catch: function (callback) { reject = callback; return promise; }
};
try {
req.open(method, url, true);
// On load
req.onload = function () {
if (req.status == 200) {
resolve(req.response, req.responseType);
} else {
reject(Error(req.statusText));
}
};
// Handle network errors
req.onerror = function () {
reject(Error("Network Error"));
};
req.onabort = function () {
reject(Error("Transaction is aborted"));
};
//
if (data) {
// from https://developer.mozilla.org/en-US/docs/Learn/Forms/Sending_forms_through_JavaScript
let urlEncodedData = "",
urlEncodedDataPairs = [],
name;
// Turn the data object into an array of URL-encoded key/value pairs.
for( name in data ) {
urlEncodedDataPairs.push( encodeURIComponent( name ) + '=' + encodeURIComponent( data[name] ) );
}
// Combine the pairs into a single string and replace all %-encoded spaces to
// the '+' character; matches the behavior of browser form submissions.
urlEncodedData = urlEncodedDataPairs.join( '&' ).replace( /%20/g, '+' );
req.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
// Make the request
req.send(urlEncodedData);
} else {
// Make the request
req.send();
}
} catch (ex) {
reject(ex);
}
return promise;
},
delay: function(name, delay, f) {
if (searx._timers.has(name)) {
clearTimeout(searx._timers.get(name)[0]);
}
function call_f() {
searx._timers.delete(name);
f();
}
h = setTimeout(call_f, delay);
searx._timers.set(name, [h, f]);
},
beforeunload: function() {
searx._unloading = true;
for(v in searx._timers.values()) {
v[1]();
}
}
};
/* ------------------------------------------------------ */
function getThemeVariant() {
const themeVariant = getComputedStyle(document.documentElement).getPropertyValue('--theme-variant');
// Chrom* browsers require trim()
return themeVariant.trim().slice(1, -1);
}
function updateThemeVariantButton() {
const buttonDarkMode = document.getElementById('toggleDarkMode');
if (getThemeVariant() == "dark") {
buttonDarkMode.innerHTML = '☀️ LIGHT MODE';
} else {
buttonDarkMode.innerHTML = '🌑 DARK MODE';
}
}
function saveThemeVariant(themeVariant) {
// send a POST request to /preferences so on the next HTTP request, <html class=""> will get the right CSS class (theme-dark, theme-light)
// theme-variant is similar to the oscar-style preference.
searx.delay('theme-variant', 300, function() {
searx.http('post', 'preferences', data = {
'theme-variant': themeVariant,
// new parameter in webapp.py to avoid HTTP redirect
// see https://github.com/searxng/searxng/blob/a582cf3d8231f5ed8a881aa87576dfc0600e1c07/searx/webapp.py#L911
// alternative: an HTTP header
'$redirect': 0,
});
});
}
function toggleDarkMode() {
const htmlElement = document.getElementsByTagName('html')[0];
const themeVariant = getThemeVariant();
["theme-light", "theme-dark", "theme-auto"].forEach(v => htmlElement.classList.remove(v));
if (themeVariant == "dark") {
htmlElement.classList.add("theme-light");
} else {
htmlElement.classList.add("theme-dark");
}
updateThemeVariantButton();
saveThemeVariant(themeVariant);
}
document.addEventListener("DOMContentLoaded", function () {
// https://github.com/searxng/searxng/blob/c23aa5760cb42003c1372ccdef1611695504eb9e/searx/static/themes/simple/src/js/head/00_init.js#L39-L40
// set the classes instead of updating them.
const htmlElement = document.getElementsByTagName('html')[0];
const touch = (("ontouchstart" in window) || window.DocumentTouch && document instanceof DocumentTouch) || false;
htmlElement.classList.replace("no-js", "js");
if (touch) {
htmlElement.classList.add("touch");
}
// new
updateThemeVariantButton();
});
//
window.addEventListener("beforeunload", searx.beforeunload);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment