Files
Tim Bond 22369731e3 UI - Follow the device's light/dark setting by default (#4507)
Currently dark mode is only available to users that have opted-in by
selecting a cookie.  Users that have set their device preference to
dark still see light mode until they've specifically clicked the button
to set the cookie.

Without a css_dark_mode cookie the page now renders data-darkmode="auto",
and the dark styles apply under @media (prefers-color-scheme: dark), so a
device in dark mode gets the dark theme without opting in from the menu.
Pure CSS - no flash of the wrong theme and no JS needed.

The cookie set by the menu toggle still wins either way, so light-mode
devices can choose dark and vice versa. In "auto" the toggle reads the
current effective theme via matchMedia so the first click always flips it.

A dark-mode SCSS mixin emits each dark block for both
html[data-darkmode="true"] and the auto+media-query case; the processor
badge and tag colour rules generated outside SCSS get the same pair.
2026-10-16 11:36:52 +02:00

80 lines
2.7 KiB
JavaScript

/**
* @file
* Toggles theme between light and dark mode.
*/
$(document).ready(function () {
$(".toggle-light-mode").on("click", function () {
// "auto" (no cookie yet) follows the device setting, so flip whatever is currently shown
const state = $("html").attr("data-darkmode");
const isDark = state === "true" ||
(state === "auto" && window.matchMedia("(prefers-color-scheme: dark)").matches);
$("html").attr("data-darkmode", !isDark);
setCookieValue(!isDark);
});
// AI mode toggle — persisted in localStorage
(function initAiMode() {
const enabled = localStorage.getItem('ai-mode') === 'true';
$("html").attr("data-ai-mode", enabled ? "true" : "false");
})();
$(".toggle-ai-mode").on("click", function () {
if ($(this).data("llm-configured") !== true && $(this).data("llm-configured") !== "true") {
document.getElementById("llm-not-configured-modal").showModal();
return;
}
const current = $("html").attr("data-ai-mode") === "true";
const next = !current;
$("html").attr("data-ai-mode", next ? "true" : "false");
localStorage.setItem('ai-mode', next ? 'true' : 'false');
});
$("#close-llm-not-configured-modal").on("click", function () {
document.getElementById("llm-not-configured-modal").close();
});
const setCookieValue = (value) => {
document.cookie = `css_dark_mode=${value};max-age=31536000;path=/`
}
// Search input box behaviour
const toggle_search = document.getElementById("toggle-search");
const search_q = document.getElementById("search-q");
if(search_q) {
window.addEventListener('keydown', function (e) {
if (e.altKey == true && e.keyCode == 83) {
search_q.classList.toggle('expanded');
search_q.focus();
}
});
search_q.onkeydown = (e) => {
var key = e.keyCode || e.which;
if (key === 13) {
document.searchForm.submit();
}
};
toggle_search.onclick = () => {
// Could be that they want to search something once text is in there
if (search_q.value.length) {
document.searchForm.submit();
} else {
// If not..
search_q.classList.toggle('expanded');
search_q.focus();
}
};
}
$('#heart-us').click(function () {
$("#overlay").toggleClass('visible');
heartpath.style.fill = document.getElementById("overlay").classList.contains("visible") ? '#ff0000' : 'var(--color-background)';
});
setInterval(function () {
$('body').toggleClass('spinner-active', $.active > 0);
}, 2000);
});