Change dashboard theme

This commit is contained in:
2026-04-22 19:32:52 +02:00
parent 080a6af776
commit 728233998b
2 changed files with 1242 additions and 127 deletions
+69 -127
View File
@@ -12,147 +12,101 @@
<link rel="apple-touch-icon" href="/icon-512.png">
<meta name="apple-mobile-web-app-title" content="Fleet C2">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet">
<style>
<style>
/* --- TEMA NOC (Network Operations Center) --- */
:root {
--primary: #3b82f6; --success: #10b981; --danger: #ef4444; --accent: #8b5cf6;
--bg-gradient: linear-gradient(135deg, #e0e7ff 0%, #ede9fe 100%);
--card-bg: rgba(255, 255, 255, 0.6);
--border-color: rgba(255, 255, 255, 0.8);
--text-main: #1e293b; --text-muted: #64748b;
--glass-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.07);
--topbar-bg: rgba(255, 255, 255, 0.8);
--primary: #2f81f7; --success: #2ea043; --danger: #da3633; --accent: #a371f7;
--bg-gradient: #0d1117; /* Sfondo nero/grigio profondissimo */
--card-bg: #161b22; /* Sfondo grigio antracite per i pannelli */
--border-color: #30363d;/* Bordi netti e sottili */
--text-main: #c9d1d9; /* Bianco attenuato anti-affaticamento */
--text-muted: #8b949e; /* Grigio tecnico per label */
--topbar-bg: #161b22;
}
/* Modalità scura "pura" se il toggle viene premuto */
body.dark-mode {
--bg-gradient: linear-gradient(135deg, #0f172a 0%, #1e1b4b 50%, #020617 100%);
--card-bg: rgba(30, 41, 59, 0.5);
--border-color: rgba(255, 255, 255, 0.08);
--text-main: #f8fafc; --text-muted: #94a3b8;
--glass-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.4);
--topbar-bg: rgba(15, 23, 42, 0.8);
--bg-gradient: #010409; --card-bg: #0d1117; --border-color: #21262d;
--text-main: #f0f6fc; --topbar-bg: #0d1117;
}
* { box-sizing: border-box; }
body { font-family: 'Inter', sans-serif; background: var(--bg-gradient); background-attachment: fixed; margin: 0; padding: 0; color: var(--text-main); transition: color 0.3s; min-height: 100vh; }
body { font-family: 'Inter', sans-serif; background: var(--bg-gradient); margin: 0; padding: 0; color: var(--text-main); transition: background-color 0.3s; min-height: 100vh; }
/* Floating Top Bar */
/* Barra superiore squadrata e tecnica */
#top-bar-container { position: sticky; top: 15px; z-index: 100; padding: 0 20px; display: flex; justify-content: center; }
#top-bar { background: var(--topbar-bg); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); padding: 12px 30px; display: flex; justify-content: space-between; align-items: center; border-radius: 50px; box-shadow: var(--glass-shadow); border: 1px solid var(--border-color); width: 100%; max-width: 1400px; }
#top-bar { background: var(--topbar-bg); padding: 12px 30px; display: flex; justify-content: space-between; align-items: center; border-radius: 6px; border: 1px solid var(--border-color); width: 100%; max-width: 1400px; }
.title-brand { font-size: 1.2rem; font-weight: 800; letter-spacing: 2px; color: var(--text-main); font-family: 'JetBrains Mono', monospace; }
.title-brand { font-size: 1.3rem; font-weight: 800; letter-spacing: 1px; background: linear-gradient(to right, var(--primary), var(--accent)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
.theme-switch { background: transparent; border: 1px solid var(--border-color); color: var(--text-muted); padding: 6px 14px; border-radius: 4px; cursor: pointer; font-weight: 600; font-size: 0.85rem; font-family: 'JetBrains Mono', monospace; }
.theme-switch:hover { color: var(--text-main); border-color: var(--text-main); }
.theme-switch { background: rgba(128, 128, 128, 0.1); border: 1px solid var(--border-color); color: var(--text-main); padding: 8px 18px; border-radius: 20px; cursor: pointer; font-weight: 600; transition: all 0.2s ease; font-size: 0.85rem; }
.theme-switch:hover { background: rgba(128, 128, 128, 0.2); transform: translateY(-1px); }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 20px; max-width: 1400px; margin: 30px auto; padding: 0 20px; }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 30px; max-width: 1400px; margin: 40px auto; padding: 0 20px; }
/* Pannelli Ripetitori - Zero ombre, bordi netti */
.card { background: var(--card-bg) !important; border-radius: 4px; padding: 20px; border: 1px solid var(--border-color); border-top: 4px solid var(--border-color) !important; display: flex; flex-direction: column; box-shadow: none !important; filter: none !important; opacity: 1 !important; }
.card.online { border-top-color: var(--success) !important; }
/* Glass Cards */
.card { background: var(--card-bg); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); border-radius: 20px; padding: 25px; box-shadow: var(--glass-shadow); border: 1px solid var(--border-color); border-top: 5px solid #64748b; transition: transform 0.3s ease, box-shadow 0.3s ease; display: flex; flex-direction: column; }
.card:hover { transform: translateY(-4px); box-shadow: 0 12px 40px 0 rgba(0,0,0,0.15); }
.card.online { border-top-color: var(--success); }
.card-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; border-bottom: 1px solid var(--border-color); padding-bottom: 10px; }
.client-name { font-size: 1.1rem; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1; }
.badge-id { font-size: 0.75rem; font-family: 'JetBrains Mono', monospace; background: #010409; padding: 4px 8px; border-radius: 3px; border: 1px solid var(--border-color); color: var(--text-muted); }
.card-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; }
.client-name { font-size: 1.25rem; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1; }
.badge-id { font-size: 0.7rem; font-weight: 800; background: rgba(128, 128, 128, 0.15); padding: 4px 10px; border-radius: 12px; letter-spacing: 0.5px; border: 1px solid var(--border-color); }
/* Telemetria stile terminale */
.health-bar { display: flex; justify-content: space-between; font-size: 0.75rem; font-weight: 600; background: #010409; padding: 8px 12px; border-radius: 3px; margin-bottom: 15px; border: 1px solid var(--border-color); font-family: 'JetBrains Mono', monospace; }
.health-bar { display: flex; justify-content: space-between; font-size: 0.75rem; font-weight: 600; background: rgba(0,0,0,0.05); padding: 8px 12px; border-radius: 12px; margin-bottom: 15px; border: 1px solid rgba(128,128,128,0.1); }
body.dark-mode .health-bar { background: rgba(0,0,0,0.2); }
/* Display Stato */
.status-display { text-align: center; font-family: 'JetBrains Mono', monospace; font-size: 0.9rem; font-weight: 700; padding: 8px; border-radius: 3px; background: #010409; border: 1px solid var(--border-color); margin-bottom: 15px; color: var(--text-muted); }
.card.online .status-display { color: var(--success); border-color: rgba(46, 160, 67, 0.4); }
.status-offline { color: var(--danger) !important; border-color: rgba(218, 54, 51, 0.4) !important; }
.status-display { text-align: center; font-family: 'JetBrains Mono', monospace; font-size: 0.9rem; font-weight: 700; padding: 10px; border-radius: 12px; background: rgba(0,0,0,0.05); border: 1px solid var(--border-color); margin-bottom: 15px; transition: all 0.3s; }
body.dark-mode .status-display { background: rgba(0,0,0,0.2); color: #10b981; }
.status-offline { color: var(--danger) !important; opacity: 0.8; }
/* TimeSlots Override */
.ts-container { display: flex; flex-direction: column; gap: 6px; margin-bottom: 15px; }
.dmr-info { font-size: 0.85rem; font-weight: 600; font-family: 'JetBrains Mono', monospace; padding: 8px 12px; border-radius: 3px; background: #010409 !important; border: 1px solid var(--border-color); border-left: 4px solid var(--border-color) !important; color: var(--text-muted) !important; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* TimeSlots */
.ts-container { display: flex; flex-direction: column; gap: 8px; margin-bottom: 15px; }
.dmr-info { font-size: 0.85rem; font-weight: 600; padding: 10px 15px; border-radius: 12px; background: rgba(59, 130, 246, 0.1); border-left: 4px solid var(--primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: all 0.2s; }
/* Terminal Log interno ai pannelli */
.terminal-log { background: #010409; color: var(--text-muted); font-family: 'JetBrains Mono', monospace; font-size: 0.75rem; border-radius: 3px; padding: 10px; height: 130px; overflow-y: auto; border: 1px solid var(--border-color); line-height: 1.4; margin-bottom: 15px; box-shadow: inset 0 2px 10px rgba(0,0,0,0.5); }
/* Terminal Log */
.terminal-log { background: #0f172a; color: #10b981; font-family: 'JetBrains Mono', monospace; font-size: 0.75rem; border-radius: 12px; padding: 12px; height: 130px; overflow-y: auto; border: 1px solid rgba(255,255,255,0.1); line-height: 1.5; margin-bottom: 15px; box-shadow: inset 0 2px 10px rgba(0,0,0,0.5); }
/* Bottoni flat */
.actions { display: none; gap: 8px; flex-wrap: wrap; margin-top: auto; }
.btn-cmd { flex: 1; padding: 8px 10px; border: 1px solid var(--border-color); background: #010409 !important; border-radius: 3px; font-weight: 600; font-size: 0.75rem; cursor: pointer; color: var(--text-main) !important; font-family: 'JetBrains Mono', monospace; transition: border-color 0.2s ease; display: flex; align-items: center; justify-content: center; gap: 5px; box-shadow: none !important; }
.btn-cmd:hover { border-color: var(--text-main); }
/* Buttons */
.actions { display: none; gap: 10px; flex-wrap: wrap; margin-top: auto; }
.btn-cmd { flex: 1; padding: 10px 12px; border: none; border-radius: 12px; font-weight: 700; font-size: 0.8rem; cursor: pointer; color: white; transition: all 0.2s ease; box-shadow: 0 4px 6px rgba(0,0,0,0.1); display: flex; align-items: center; justify-content: center; gap: 5px; }
.btn-cmd:hover { transform: translateY(-2px); filter: brightness(1.1); box-shadow: 0 6px 12px rgba(0,0,0,0.15); }
.btn-cmd:active { transform: translateY(0); }
/* Tabella LastHeard */
.table-container { background: var(--card-bg); border-radius: 6px; border: 1px solid var(--border-color); overflow: hidden; max-height: 400px; overflow-y: auto; margin: 0 20px 40px 20px; box-shadow: none; }
table { width: 100%; border-collapse: collapse; text-align: left; font-size: 0.85rem; font-family: 'JetBrains Mono', monospace; }
thead { background: var(--topbar-bg); position: sticky; top: 0; z-index: 1; border-bottom: 1px solid var(--border-color); }
th { padding: 12px 15px; font-weight: 600; text-transform: uppercase; font-size: 0.75rem; color: var(--text-muted); }
td { padding: 10px 15px; border-bottom: 1px solid var(--border-color); color: var(--text-main); }
.table-container { background: var(--card-bg); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); border-radius: 20px; border: 1px solid var(--border-color); overflow: hidden; max-height: 400px; overflow-y: auto; box-shadow: var(--glass-shadow); margin: 0 20px 40px 20px; }
table { width: 100%; border-collapse: collapse; text-align: left; font-size: 0.9rem; }
/* Animazioni Flat per i transiti */
@keyframes flat-blink { 0% { border-color: var(--border-color); } 50% { border-color: var(--danger); } 100% { border-color: var(--border-color); } }
.blink { animation: flat-blink 1.5s infinite; color: var(--danger) !important; }
/* Table Header Frosted Glass */
thead { background: rgba(255, 255, 255, 0.9); position: sticky; top: 0; z-index: 1; backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05); }
body.dark-mode thead { background: rgba(15, 23, 42, 0.95); box-shadow: 0 4px 6px -1px rgba(0,0,0,0.3); }
th { padding: 15px; font-weight: 700; text-transform: uppercase; font-size: 0.75rem; letter-spacing: 0.5px; color: var(--text-muted); }
td { padding: 12px 15px; border-bottom: 1px solid var(--border-color); }
@keyframes flat-tx { 0% { border-left-color: var(--border-color); background: #010409; } 50% { border-left-color: var(--primary); background: rgba(47, 129, 247, 0.1); } 100% { border-left-color: var(--border-color); background: #010409; } }
.tx-active { animation: flat-tx 1.5s infinite !important; color: var(--text-main) !important; border-color: var(--border-color) !important; }
@keyframes pulse-glow { 0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(239, 68, 68, 0); } 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); } }
.blink { animation: pulse-glow 1.5s infinite; color: var(--danger) !important; font-weight: 800 !important; background: rgba(239, 68, 68, 0.1) !important; border-left-color: var(--danger) !important; }
@keyframes tx-glow { 0% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.5); } 70% { box-shadow: 0 0 0 10px rgba(59, 130, 246, 0); } 100% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0); } }
.tx-active { animation: tx-glow 1.5s infinite; font-weight: 800 !important; color: var(--text-main) !important; background: rgba(59, 130, 246, 0.25) !important; border-left-color: var(--primary) !important; }
/* Finestre Modali (Popup) */
.modal-overlay { display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(1, 4, 9, 0.85); z-index:1000; align-items:center; justify-content:center; }
.modal-content { background:var(--card-bg); border:1px solid var(--border-color); padding:25px; border-radius:6px; max-height: 90vh; overflow-y: auto; box-shadow: 0 10px 30px rgba(0,0,0,0.8); }
/* Modals (Dark Glass) */
.modal-overlay { display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.6); backdrop-filter:blur(5px); -webkit-backdrop-filter:blur(5px); z-index:1000; align-items:center; justify-content:center; }
.modal-content { background:var(--card-bg); backdrop-filter:blur(20px); border:1px solid var(--border-color); padding:30px; border-radius:24px; box-shadow:0 25px 50px -12px rgba(0,0,0,0.5); max-height: 90vh; overflow-y: auto; }
/* Elementi Input e Form */
.auth-btn { background: #010409; color: var(--text-main); border: 1px solid var(--border-color); padding: 6px 12px; border-radius: 4px; font-weight: 600; cursor: pointer; font-size: 0.8rem; font-family: 'JetBrains Mono', monospace; transition: border-color 0.2s; }
.auth-btn:hover { border-color: var(--text-main); }
input, select { background: #010409; border: 1px solid var(--border-color); color: var(--text-main); padding: 8px 12px; border-radius: 4px; font-family: 'JetBrains Mono', monospace; outline: none; }
input:focus { border-color: var(--primary); }
input:disabled { opacity: 0.5; cursor: not-allowed; }
option { background: var(--bg-main); color: var(--text-main); }
/* Auth Buttons Style */
.auth-btn { background: var(--text-main); color: var(--bg-gradient); border: none; padding: 8px 16px; border-radius: 20px; font-weight: 700; cursor: pointer; font-size: 0.85rem; transition: 0.2s; }
.auth-btn:hover { opacity: 0.8; }
input, select { background: rgba(128,128,128,0.1); border: 1px solid var(--border-color); color: var(--text-main); padding: 10px 15px; border-radius: 12px; font-family: inherit; outline: none; transition: 0.2s; }
input:focus { border-color: var(--primary); box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2); }
input:disabled { opacity: 0.6; cursor: not-allowed; }
/* Dropdown Fix in Dark Mode */
option { background: #ffffff; color: #1e293b; }
/* --- OTTIMIZZAZIONE MOBILE (PWA / SMARTPHONE) --- */
/* Ottimizzazione Mobile */
@media (max-width: 768px) {
#top-bar-container { top: 10px; padding: 0 10px; }
#top-bar {
flex-direction: column;
border-radius: 24px;
padding: 15px;
gap: 12px;
#top-bar { flex-direction: column; padding: 15px; gap: 12px; border-radius: 8px; }
.title-brand { font-size: 1.1rem; text-align: center; width: 100%; }
#top-bar > div { width: 100%; flex-wrap: wrap; justify-content: center; gap: 8px !important; }
#auth-container { width: 100%; justify-content: center; flex-wrap: wrap; padding-top: 12px; border-top: 1px solid var(--border-color); }
#auth-container > span { width: 100%; text-align: center; margin-bottom: 8px; font-family: 'JetBrains Mono', monospace; }
.auth-btn, .theme-switch { flex: 1 1 auto; text-align: center; }
}
.title-brand { font-size: 1.15rem; text-align: center; width: 100%; }
/* Contenitore dei tasti lingua/tema */
#top-bar > div {
width: 100%;
flex-wrap: wrap;
justify-content: center;
gap: 8px !important;
}
/* Contenitore Bottoni Login / Admin */
#auth-container {
width: 100%;
justify-content: center;
flex-wrap: wrap;
padding-top: 12px;
margin-top: 4px;
border-top: 1px solid rgba(128, 128, 128, 0.2);
}
/* Username centrato */
#auth-container > span {
width: 100%;
text-align: center;
margin-bottom: 8px;
margin-left: 0 !important;
margin-right: 0 !important;
}
/* Bottoni ingranditi perfetti per il touch */
.auth-btn {
flex: 1 1 auto;
min-width: 100px;
padding: 12px !important;
text-align: center;
font-size: 0.9rem;
}
.theme-switch {
flex: 1 1 auto;
text-align: center;
padding: 10px;
}
}
body.dark-mode option { background: #0f172a; color: #f8fafc; }
</style>
</head>
<body>
@@ -162,7 +116,6 @@
<div class="title-brand">FLEET CONTROL CONSOLE</div>
<div style="display: flex; align-items: center; gap: 12px;">
<button class="theme-switch" id="lang-btn" onclick="toggleLang()" data-i18n-title="ttLang">🇮🇹 ITA</button>
<button class="theme-switch" id="theme-btn" onclick="toggleTheme()" data-i18n-title="ttTheme">🌙 DARK</button>
<button class="theme-switch" id="push-btn" onclick="subscribeToPush()">🔔 PUSH</button>
<div id="auth-container" style="display:flex; align-items:center; gap:8px;"></div>
</div>
@@ -460,12 +413,6 @@
let currentResetHatId = null;
let confirmActionCallback = null;
function toggleTheme() {
const isDark = document.body.classList.toggle('dark-mode');
localStorage.setItem('theme', isDark ? 'dark' : 'light');
document.getElementById('theme-btn').innerText = isDark ? t('themeLight') : t('themeDark');
}
// --- NEW GLOBAL GLASSMORPHISM POPUPS ---
function customAlert(title, desc, isError = false) {
const color = isError ? 'var(--danger)' : 'var(--success)';
@@ -585,11 +532,6 @@
const grid = document.getElementById('client-grid');
const authContainer = document.getElementById('auth-container');
if (localStorage.getItem('theme') === 'dark') {
document.body.classList.add('dark-mode');
document.getElementById('theme-btn').innerText = t('themeLight');
} else { document.getElementById('theme-btn').innerText = t('themeDark'); }
const role = sessionStorage.getItem('user_role');
const allowed = sessionStorage.getItem('allowed_nodes') || "";
File diff suppressed because it is too large Load Diff