From d49af5d785019b5a76c8a3624cb49a722d3f9499 Mon Sep 17 00:00:00 2001
From: "Valentin V. Bartenev"
Date: Sat, 9 May 2026 17:40:51 +0300
Subject: [PATCH] Web: bring theme toggle to the login page for consistent UX
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The app and stats pages already use an explicit data-theme attribute
approach — reading the saved "repeater-theme" key from localStorage
and falling back to the OS preference — with a ☾/☀ toggle button in
the UI. The login page was the only page still relying solely on the
CSS @media (prefers-color-scheme) query with no manual override.
This commit mirrors the same pattern on the login page so the theme
switcher works consistently across all pages:
- Add --surface2 CSS variable to both light and dark theme blocks
- Replace @media (prefers-color-scheme: dark) with :root[data-theme="dark"]
- Add a theme toggle button (☾/☀) in the login card header
- Add getPreferredTheme(), applyTheme(), and toggleTheme() helpers,
identical in behaviour to those already present on the app page
---
src/helpers/web/WebPanelServer.cpp | 49 ++++++++++++++++++++++--------
1 file changed, 37 insertions(+), 12 deletions(-)
diff --git a/src/helpers/web/WebPanelServer.cpp b/src/helpers/web/WebPanelServer.cpp
index 807f8b01..2621438d 100644
--- a/src/helpers/web/WebPanelServer.cpp
+++ b/src/helpers/web/WebPanelServer.cpp
@@ -225,18 +225,18 @@ const char kWebPanelLoginHtml[] PROGMEM = R"HTML(
--text-muted:#4b5563;
--border:rgba(0,0,0,.08);
--surface:#ffffff;
+ --surface2:#f0f3f7;
}
- @media (prefers-color-scheme: dark) {
- :root {
- color-scheme: dark;
- --accent:#36a167;
- --accent-hover:#49c27d;
- --background:#222222;
- --text:#e6eaf0;
- --text-muted:#9aa4b2;
- --border:rgba(255,255,255,.08);
- --surface:#303030;
- }
+ :root[data-theme="dark"] {
+ color-scheme: dark;
+ --accent:#36a167;
+ --accent-hover:#49c27d;
+ --background:#222222;
+ --text:#e6eaf0;
+ --text-muted:#9aa4b2;
+ --border:rgba(255,255,255,.08);
+ --surface:#303030;
+ --surface2:#2a2a2a;
}
html { min-height:100%; background:linear-gradient(180deg,var(--background),var(--surface)); background-repeat:no-repeat; background-attachment:fixed; }
body { min-height:100vh; margin:0; display:grid; place-items:center; background:transparent; color:var(--text); font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono",monospace; }
@@ -249,12 +249,17 @@ const char kWebPanelLoginHtml[] PROGMEM = R"HTML(
button { border:none; background:var(--accent); color:#fff; cursor:pointer; font-weight:700; }
button:hover { background:var(--accent-hover); }
#status { min-height:1.4em; margin-top:12px; color:#c94a4a; white-space:pre-wrap; }
+ .themebtn { background:var(--surface2,var(--background)); color:var(--text); border:1px solid var(--border); }
+ .themebtn:hover { background:var(--surface); }
- Repeater Config
+
+
Repeater Config
+
+
Use the repeater admin password to unlock the panel.
@@ -262,6 +267,26 @@ const char kWebPanelLoginHtml[] PROGMEM = R"HTML(