From ee478e52efc71c581445af749b5848403e42107f Mon Sep 17 00:00:00 2001 From: Giuseppe Raffa <77052701+sesee3@users.noreply.github.com> Date: Tue, 21 Apr 2026 22:42:02 +0200 Subject: [PATCH] feat: implement dark mode toggle across application - Added dark mode detection and application logic in HTML files (dashboard.html, kioskedit.html, live.html, rulesets.html, sessions.html). - Introduced a theme toggle button for user interaction. - Created a new theme-toggle.js script to manage dark mode state and persistence using localStorage. - Updated CSS styles to support dark mode with appropriate color variables and transitions. - Enhanced user experience by preventing flash of unstyled content during theme initialization. --- .gitignore | 4 +- console/src/pages/dashboard.html | 136 ++++++++++++++++++++++++++-- console/src/pages/kioskedit.html | 23 +++++ console/src/pages/live.html | 22 +++++ console/src/pages/rulesets.html | 22 +++++ console/src/pages/sessions.html | 22 +++++ console/src/static/styles/style.css | 50 +++++++++- console/src/static/theme-toggle.js | 85 +++++++++++++++++ 8 files changed, 352 insertions(+), 12 deletions(-) create mode 100644 console/src/static/theme-toggle.js diff --git a/.gitignore b/.gitignore index 4547e93..d3f6653 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,6 @@ Thumbs.db **/tsconfig.tsbuildinfo .eslintcache -.venv/ \ No newline at end of file +.venv/ + +.claude/ \ No newline at end of file diff --git a/console/src/pages/dashboard.html b/console/src/pages/dashboard.html index 523df8a..665f546 100644 --- a/console/src/pages/dashboard.html +++ b/console/src/pages/dashboard.html @@ -3,6 +3,16 @@ + @@ -11,8 +21,9 @@

+

username

- + Impostazioni
@@ -24,6 +35,10 @@
+
+

Trasmissione e Analisi dati

+
+

Live

@@ -31,14 +46,7 @@
- - - +

Analisi Dati

Analizza i dati raccolti sulle performance e sulla navigazione.

@@ -52,11 +60,119 @@
+ +
+

Kiosk

+

Modifica cosa vede il pilota a bordo in tempo reale.

+
+
+ + + + +
+

Dati & Risorse

+
+ + + +
+

Rulesets

+

Gestisci i template di configurazione per weather, data e logs.

+
+
+ + +
+

Copernicus

+

Accedi alle risorse sui dati di Copernicus e crea dataset personalizzati.

+
+
+ + +
+ + + + + + + + + + +
+
+

Grafana

+

Spostati sulla Dashboard di Grafana per visualizzare grafici e dati.

+
+
+ +
+

ML

+
+ + + +
+

Dataset

+

Gestisci i dataset disponibili

+
+
+ + +
+

Documentazione

+

Consulta i file Markdown di documentazione sul server e risorse aggiuntive sui modelli ML.

+
+
+ + +
+

Diario di Bordo

+

Tieni traccia delle modifiche, dei progressi e dei cambiamenti del progetto.

+
+
+ + +
+ + + + + + + + + + +
+
+

Repositories

+

Controlla le repositories di codice di tutte le componenti del server, del plugin e + dei modelli ML +

+
+
+
+ \ No newline at end of file diff --git a/console/src/pages/kioskedit.html b/console/src/pages/kioskedit.html index f362d13..8cbd012 100644 --- a/console/src/pages/kioskedit.html +++ b/console/src/pages/kioskedit.html @@ -7,7 +7,18 @@ + + @@ -37,6 +48,7 @@

0 cards

+ @@ -555,4 +567,15 @@ ws.onclose = () => { + + + diff --git a/console/src/pages/live.html b/console/src/pages/live.html index 0dc610f..36c68d2 100644 --- a/console/src/pages/live.html +++ b/console/src/pages/live.html @@ -11,6 +11,16 @@ .expanded-chart-container { display: none; } .comparison-sidebar { display: none; } + @@ -50,6 +60,7 @@

In attesa di dati...

+

Sensore

@@ -777,3 +788,14 @@ document.getElementById('saveSessionLabelBtn').onclick = async () => { }; + + + diff --git a/console/src/pages/rulesets.html b/console/src/pages/rulesets.html index 6abe57a..be5c19e 100644 --- a/console/src/pages/rulesets.html +++ b/console/src/pages/rulesets.html @@ -4,6 +4,16 @@ + @@ -24,6 +34,7 @@
+ Salvato
@@ -594,5 +605,16 @@ function flash(text, elId = 'savingIndicator') { document.addEventListener('DOMContentLoaded', () => loadRules()); + + + + diff --git a/console/src/pages/sessions.html b/console/src/pages/sessions.html index 0992c78..9d46e46 100644 --- a/console/src/pages/sessions.html +++ b/console/src/pages/sessions.html @@ -244,6 +244,16 @@ .map-bar .filter button { color: #cbd5e1; } .map-bar .filter button.active { background: #3b82f6; color: #fff; } + @@ -279,6 +289,7 @@

Sessioni

+
@@ -918,5 +929,16 @@ document.getElementById('changeSessionBtn').onclick = () => { // --- Init --- document.addEventListener('DOMContentLoaded', loadSessionsList); + + + diff --git a/console/src/static/styles/style.css b/console/src/static/styles/style.css index 8b7defd..0b3b772 100644 --- a/console/src/static/styles/style.css +++ b/console/src/static/styles/style.css @@ -20,6 +20,53 @@ --radius-lg: 12px; } +/* DARK MODE */ +@media (prefers-color-scheme: dark) { + :root { + --accent-color: #3b82f6; + --accent-hover: #2563eb; + --accent-light: #1e3a8a; + --accent-border: #1e40af; + + --text-primary: #f1f5f9; + --text-secondary: #cbd5e1; + --text-tertiary: #94a3b8; + + --surface: #0f172a; + + --header-bg: rgba(15, 23, 42, 0.85); + --header-border: #334155; + + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3); + --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -1px rgba(0, 0, 0, 0.2); + } +} + +/* Manual dark mode toggle */ +body.dark-mode { + --accent-color: #3b82f6; + --accent-hover: #2563eb; + --accent-light: #1e3a8a; + --accent-border: #1e40af; + + --text-primary: #f1f5f9; + --text-secondary: #cbd5e1; + --text-tertiary: #94a3b8; + + --surface: #0f172a; + + --header-bg: rgba(15, 23, 42, 0.85); + --header-border: #334155; + + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3); + --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -1px rgba(0, 0, 0, 0.2); +} + +/* Smooth transition for dark mode */ +body { + transition: background-color 0.3s ease, color 0.3s ease; +} + * { margin: 0; padding: 0; @@ -42,6 +89,7 @@ body { font-family: 'Normal', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; color: var(--text-primary); + background-color: var(--surface); -webkit-font-smoothing: antialiased; } @@ -49,7 +97,7 @@ button { padding: 10px 24px; border-radius: var(--radius-lg); border: 1px solid var(--header-border); - background-color: var(--bg-surface); + background-color: var(--surface); color: var(--text-primary); font-size: 14px; font-weight: 600; diff --git a/console/src/static/theme-toggle.js b/console/src/static/theme-toggle.js new file mode 100644 index 0000000..9309ff6 --- /dev/null +++ b/console/src/static/theme-toggle.js @@ -0,0 +1,85 @@ +/** + * Dark Mode Theme Toggle + * Manages light/dark theme with localStorage persistence + */ + +const THEME_STORAGE_KEY = 'meb-console-theme'; +const DARK_MODE_CLASS = 'dark-mode'; + +/** + * Initialize theme on page load + */ +function initializeTheme() { + const savedTheme = localStorage.getItem(THEME_STORAGE_KEY); + const prefersDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches; + + // Use saved preference, or fallback to system preference + const shouldBeDark = savedTheme ? savedTheme === 'dark' : prefersDarkMode; + + if (shouldBeDark) { + enableDarkMode(); + } else { + disableDarkMode(); + } +} + +/** + * Enable dark mode + */ +function enableDarkMode() { + document.documentElement.classList.add(DARK_MODE_CLASS); + document.body.classList.add(DARK_MODE_CLASS); + localStorage.setItem(THEME_STORAGE_KEY, 'dark'); + updateThemeToggleButton(); +} + +/** + * Disable dark mode (light mode) + */ +function disableDarkMode() { + document.documentElement.classList.remove(DARK_MODE_CLASS); + document.body.classList.remove(DARK_MODE_CLASS); + localStorage.setItem(THEME_STORAGE_KEY, 'light'); + updateThemeToggleButton(); +} + +/** + * Toggle dark mode + */ +function toggleDarkMode() { + const isDarkMode = document.body.classList.contains(DARK_MODE_CLASS); + + if (isDarkMode) { + disableDarkMode(); + } else { + enableDarkMode(); + } +} + +/** + * Update theme toggle button appearance + */ +function updateThemeToggleButton() { + const themeBtn = document.getElementById('theme-toggle-btn'); + if (themeBtn) { + const isDarkMode = document.body.classList.contains(DARK_MODE_CLASS); + themeBtn.textContent = isDarkMode ? '☀️' : '🌙'; + themeBtn.title = isDarkMode ? 'Light Mode' : 'Dark Mode'; + } +} + +/** + * Listen for system theme preference changes + */ +function listenToSystemThemeChanges() { + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => { + if (!localStorage.getItem(THEME_STORAGE_KEY)) { + // If no manual preference set, follow system preference + e.matches ? enableDarkMode() : disableDarkMode(); + } + }); +} + +// Initialize on load +document.addEventListener('DOMContentLoaded', initializeTheme); +listenToSystemThemeChanges();