brouter-web: robust dark toggle (floating button + injected style)

The navbar toggle was invisible/zero-width; replaced with a fixed floating
button (bottom-right). Dark mode now injects a <style> keyed on body.bw-dark
covering the tile layer, right sidebar, left toolbar (zoom/draw controls) and
the bottom elevation profile panel (incl. the chart drawn later on route).
This commit is contained in:
4aiman 2026-09-09 14:57:12 +03:00
commit d7b77f5bc5

View file

@ -1,31 +1,60 @@
(function () {
var LS_DARK = "baldav_bw_dark";
function apply() { document.body.classList.toggle("bw-dark", localStorage.getItem(LS_DARK) === "1"); }
function toggle() {
var on = localStorage.getItem(LS_DARK) !== "1";
localStorage.setItem(LS_DARK, on ? "1" : "0");
apply();
var b = document.getElementById("baldav-daynight");
if (b) b.textContent = on ? "☀" : "☾"; // sun / moon
function isDark() { try { return localStorage.getItem(LS_DARK) === "1"; } catch (e) { return false; } }
// Inject the dark rules as a <style> in <head> (no dependency on an external CSS file,
// and it covers elements created later — e.g. the elevation chart, drawn only once a
// route exists). Toggling body.bw-dark activates/deactivates everything.
function injectStyle() {
if (document.getElementById("baldav-dark-style")) return;
var st = document.createElement("style");
st.id = "baldav-dark-style";
st.textContent = [
"body.bw-dark .leaflet-tile-pane{filter:invert(1) hue-rotate(180deg) brightness(1.5)}",
"body.bw-dark .leaflet-container{background:#1b1f24}",
// right sidebar / layers panel
"body.bw-dark #sidebar,body.bw-dark #sidebar .leaflet-sidebar-content,body.bw-dark .leaflet-sidebar-pane,body.bw-dark .leaflet-control-layers,body.bw-dark .leaflet-control-layers-expanded{background:#20242a!important;color:#dfe3e8!important}",
"body.bw-dark #sidebar label,body.bw-dark #sidebar span,body.bw-dark #sidebar a,body.bw-dark #sidebar h1,body.bw-dark #sidebar h2{color:#dfe3e8!important}",
"body.bw-dark #sidebar input[type=text],body.bw-dark #sidebar select{background:#2b3038!important;color:#dfe3e8!important;border-color:#454b54!important}",
// left toolbar + all leaflet control buttons (zoom, draw, etc.)
"body.bw-dark .leaflet-bar a,body.bw-dark .leaflet-control-zoom a,body.bw-dark .leaflet-control a,body.bw-dark .leaflet-control button{background:#2b3038!important;color:#fff!important;border-color:#454b54!important}",
"body.bw-dark .leaflet-bar a:hover,body.bw-dark .leaflet-control a:hover{background:#3a4048!important}",
// bottom elevation profile panel
"body.bw-dark .elevation,body.bw-dark #elevation-chart,body.bw-dark .elevation-summary{background:#20242a!important;color:#dfe3e8!important}",
"body.bw-dark .elevation text{fill:#dfe3e8!important}",
"body.bw-dark .elevation .domain,body.bw-dark .elevation .tick line,body.bw-dark .elevation .grid line{stroke:#55606a!important}",
"body.bw-dark .elevation path.area,body.bw-dark .elevation .area{fill:#2b3038!important;opacity:.6}"
].join("\n");
(document.head || document.documentElement).appendChild(st);
}
function apply() {
document.body.classList.toggle("bw-dark", isDark());
var b = document.getElementById("baldav-daynight");
if (b) b.textContent = isDark() ? "☀ День" : "☾ Ночь";
}
function toggle() {
try { localStorage.setItem(LS_DARK, isDark() ? "0" : "1"); } catch (e) {}
apply();
}
// Standalone floating button — independent of the navbar so it can't be invisible or
// zero-width. Fixed bottom-right, explicit colours/size.
function addButton() {
if (document.getElementById("baldav-daynight")) return true;
var exp = document.getElementById("exportButton");
if (!exp) return false;
var item = exp.closest(".nav-item") || exp.parentNode;
var li = document.createElement("div"); li.className = item.className || "nav-item";
var a = document.createElement("a");
a.id = "baldav-daynight"; a.className = exp.className || "nav-link"; a.href = "#";
a.title = "Тёмная карта";
a.textContent = (localStorage.getItem(LS_DARK) === "1") ? "☀" : "☾";
a.onclick = function (e) { e.preventDefault(); toggle(); };
li.appendChild(a);
item.parentNode.insertBefore(li, item);
var a = document.createElement("button");
a.id = "baldav-daynight";
a.type = "button";
a.textContent = isDark() ? "☀ День" : "☾ Ночь";
a.style.cssText = "position:fixed;bottom:24px;right:24px;z-index:100000;" +
"padding:8px 12px;font:600 14px sans-serif;background:#2b3038;color:#fff;" +
"border:1px solid #667;border-radius:8px;cursor:pointer;box-shadow:0 2px 6px rgba(0,0,0,.5)";
a.addEventListener("click", function (e) { e.preventDefault(); e.stopPropagation(); toggle(); });
document.body.appendChild(a);
return true;
}
var WANT = ["Cycling","Hiking","Bench","Toilets","Bank","ATM","Bar","BBQ","Cafe","Drinking water","Fast food","Food court","Pub","Restaurant","Bicycle parking","Bus station","Bakery","Beverages","Coffee","Supermarket","Picnic site","Viewpoint","Shelter","Route quality"];
function setDefaultOverlays() {
if (localStorage.getItem("baldav_bw_overlays_v1") === "1") return true;
try { if (localStorage.getItem("baldav_bw_overlays_v1") === "1") return true; } catch (e) {}
var labels = document.querySelectorAll("#layers-control-wrapper label, .leaflet-control-layers-overlays label");
if (!labels.length) return false;
labels.forEach(function (lab) {
@ -34,16 +63,17 @@
var cb = lab.querySelector("input[type=checkbox]") || lab.control || (lab.htmlFor && document.getElementById(lab.htmlFor));
if (cb && cb.type === "checkbox" && !cb.checked) cb.click();
});
localStorage.setItem("baldav_bw_overlays_v1", "1");
try { localStorage.setItem("baldav_bw_overlays_v1", "1"); } catch (e) {}
return true;
}
function init() {
injectStyle();
apply();
var tries = 0;
var iv = setInterval(function () {
tries++;
var b = addButton(), o = setDefaultOverlays();
if ((b && o) || tries > 40) clearInterval(iv);
var b = addButton(); var o = setDefaultOverlays();
if ((b && o) || tries > 60) clearInterval(iv);
}, 500);
}
if (document.readyState !== "loading") init(); else document.addEventListener("DOMContentLoaded", init);