diff --git a/internal/web/static/js/weather.js b/internal/web/static/js/weather.js index 602642d..69415b1 100644 --- a/internal/web/static/js/weather.js +++ b/internal/web/static/js/weather.js @@ -8,7 +8,31 @@ if (!canvas) return; var variant = root.dataset.weather; if (!variant) return; - if (window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches) return; + var reducedMotion = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches; + + var STORAGE_KEY = "pete-weather-off"; + var toggleBtn = document.querySelector("[data-weather-toggle]"); + var star = document.querySelector("[data-weather-star]"); + + function userDisabled() { + try { return localStorage.getItem(STORAGE_KEY) === "1"; } catch (e) { return false; } + } + function setDisabled(v) { + try { + if (v) localStorage.setItem(STORAGE_KEY, "1"); + else localStorage.removeItem(STORAGE_KEY); + } catch (e) {} + } + function syncBtn(enabled) { + if (!toggleBtn) return; + toggleBtn.setAttribute("aria-pressed", enabled ? "true" : "false"); + toggleBtn.title = enabled ? "Turn off weather animation" : "Turn on weather animation"; + if (star) { + star.style.color = "var(--accent)"; + star.style.opacity = enabled ? "1" : "0.3"; + star.style.filter = enabled ? "none" : "grayscale(1)"; + } + } var ctx = canvas.getContext("2d"); var W = 0, H = 0, DPR = 1; @@ -232,15 +256,33 @@ } raf = requestAnimationFrame(step); } - raf = requestAnimationFrame(step); + function start() { + if (raf) return; + last = performance.now(); + raf = requestAnimationFrame(step); + } + function stop() { + if (raf) cancelAnimationFrame(raf); + raf = 0; + ctx.clearRect(0, 0, W, H); + } + + var enabled = !userDisabled() && !reducedMotion; + syncBtn(enabled); + if (enabled) start(); + + if (toggleBtn) { + toggleBtn.addEventListener("click", function () { + enabled = !enabled; + setDisabled(!enabled); + syncBtn(enabled); + if (enabled) start(); else stop(); + }); + } document.addEventListener("visibilitychange", function () { - if (document.hidden) { - cancelAnimationFrame(raf); - raf = 0; - } else if (!raf) { - last = performance.now(); - raf = requestAnimationFrame(step); - } + if (!enabled) return; + if (document.hidden) stop(); + else start(); }); })(); diff --git a/internal/web/templates/layout.html b/internal/web/templates/layout.html index 36f34c7..7a5369d 100644 --- a/internal/web/templates/layout.html +++ b/internal/web/templates/layout.html @@ -39,6 +39,17 @@ {{.SiteTitle}} + {{if .Weather.Variant}} + + {{end}}