Skip to content

Commit 1ea8ec8

Browse files
Copilotdorkmo
andcommitted
Update Config Generator styling to match Dashboard and Viewer
Co-authored-by: dorkmo <[email protected]>
1 parent 045a621 commit 1ea8ec8

File tree

1 file changed

+237
-24
lines changed

1 file changed

+237
-24
lines changed

TankAlarm-112025-Server-BluesOpta/TankAlarm-112025-Server-BluesOpta.ino

Lines changed: 237 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -241,33 +241,228 @@ static const char CONFIG_GENERATOR_HTML[] PROGMEM = R"HTML(
241241
<meta name="viewport" content="width=device-width, initial-scale=1">
242242
<title>Config Generator</title>
243243
<style>
244-
:root { color-scheme: light dark; font-family: "Segoe UI", Arial, sans-serif; }
245-
body { margin: 0; background: #f4f6f8; color: #1f2933; }
246-
header { padding: 16px 24px; background: #1d3557; color: #fff; box-shadow: 0 2px 6px rgba(0,0,0,0.2); display: flex; justify-content: space-between; align-items: center; }
247-
header h1 { margin: 0; font-size: 1.6rem; }
248-
header a { color: #fff; text-decoration: none; font-size: 0.95rem; }
249-
main { padding: 20px; max-width: 800px; margin: 0 auto; }
250-
.card { background: #fff; border-radius: 12px; box-shadow: 0 10px 30px rgba(15,23,42,0.08); padding: 20px; }
251-
h2 { margin-top: 0; font-size: 1.3rem; }
252-
h3 { margin: 20px 0 10px; font-size: 1.1rem; border-bottom: 1px solid #e2e8f0; padding-bottom: 6px; }
253-
.field { display: flex; flex-direction: column; margin-bottom: 12px; }
254-
.field span { font-size: 0.9rem; color: #475569; margin-bottom: 4px; }
255-
.field input, .field select { padding: 8px 10px; border-radius: 6px; border: 1px solid #cbd5f5; font-size: 0.95rem; }
256-
.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; }
257-
.sensor-card { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 16px; margin-bottom: 16px; position: relative; }
258-
.sensor-header { display: flex; justify-content: space-between; margin-bottom: 12px; }
259-
.sensor-title { font-weight: 600; color: #334155; }
260-
.remove-btn { color: #ef4444; cursor: pointer; font-size: 0.9rem; border: none; background: none; padding: 0; }
261-
.actions { margin-top: 24px; display: flex; gap: 12px; }
262-
button { border: none; border-radius: 6px; padding: 10px 16px; font-size: 0.95rem; cursor: pointer; background: #1d4ed8; color: #fff; }
263-
button.secondary { background: #64748b; }
264-
button:hover { opacity: 0.9; }
244+
:root {
245+
font-family: "Segoe UI", Arial, sans-serif;
246+
color-scheme: light dark;
247+
}
248+
* {
249+
box-sizing: border-box;
250+
}
251+
body {
252+
margin: 0;
253+
min-height: 100vh;
254+
background: var(--bg);
255+
color: var(--text);
256+
transition: background 0.2s ease, color 0.2s ease;
257+
}
258+
body[data-theme="light"] {
259+
--bg: #f8fafc;
260+
--surface: #ffffff;
261+
--muted: #475569;
262+
--header-bg: #e2e8f0;
263+
--card-border: rgba(15,23,42,0.08);
264+
--card-shadow: rgba(15,23,42,0.08);
265+
--accent: #2563eb;
266+
--accent-strong: #1d4ed8;
267+
--accent-contrast: #f8fafc;
268+
--chip: #f8fafc;
269+
--input-border: #cbd5e1;
270+
--danger: #ef4444;
271+
}
272+
body[data-theme="dark"] {
273+
--bg: #0f172a;
274+
--surface: #1e293b;
275+
--muted: #94a3b8;
276+
--header-bg: #16213d;
277+
--card-border: rgba(15,23,42,0.55);
278+
--card-shadow: rgba(0,0,0,0.55);
279+
--accent: #38bdf8;
280+
--accent-strong: #22d3ee;
281+
--accent-contrast: #0f172a;
282+
--chip: rgba(148,163,184,0.15);
283+
--input-border: rgba(148,163,184,0.4);
284+
--danger: #f87171;
285+
}
286+
header {
287+
background: var(--header-bg);
288+
padding: 28px 24px;
289+
box-shadow: 0 20px 45px var(--card-shadow);
290+
}
291+
header .bar {
292+
display: flex;
293+
justify-content: space-between;
294+
gap: 16px;
295+
flex-wrap: wrap;
296+
align-items: flex-start;
297+
}
298+
header h1 {
299+
margin: 0;
300+
font-size: 1.9rem;
301+
}
302+
header p {
303+
margin: 8px 0 0;
304+
color: var(--muted);
305+
max-width: 640px;
306+
line-height: 1.4;
307+
}
308+
.header-actions {
309+
display: flex;
310+
gap: 12px;
311+
flex-wrap: wrap;
312+
align-items: center;
313+
}
314+
.pill {
315+
border-radius: 999px;
316+
padding: 10px 20px;
317+
text-decoration: none;
318+
font-weight: 600;
319+
background: rgba(37,99,235,0.12);
320+
color: var(--accent);
321+
border: 1px solid transparent;
322+
transition: transform 0.15s ease;
323+
}
324+
body[data-theme="dark"] .pill {
325+
background: rgba(56,189,248,0.18);
326+
}
327+
.pill:hover {
328+
transform: translateY(-1px);
329+
}
330+
.icon-button {
331+
width: 42px;
332+
height: 42px;
333+
border-radius: 50%;
334+
border: 1px solid var(--card-border);
335+
background: var(--surface);
336+
color: var(--text);
337+
font-size: 1.2rem;
338+
cursor: pointer;
339+
transition: transform 0.15s ease;
340+
}
341+
.icon-button:hover {
342+
transform: translateY(-1px);
343+
}
344+
main {
345+
padding: 24px;
346+
max-width: 1000px;
347+
margin: 0 auto;
348+
width: 100%;
349+
}
350+
.card {
351+
background: var(--surface);
352+
border-radius: 24px;
353+
border: 1px solid var(--card-border);
354+
padding: 20px;
355+
box-shadow: 0 25px 55px var(--card-shadow);
356+
}
357+
h2 {
358+
margin-top: 0;
359+
font-size: 1.3rem;
360+
}
361+
h3 {
362+
margin: 20px 0 10px;
363+
font-size: 1.1rem;
364+
border-bottom: 1px solid var(--card-border);
365+
padding-bottom: 6px;
366+
color: var(--text);
367+
}
368+
.field {
369+
display: flex;
370+
flex-direction: column;
371+
margin-bottom: 12px;
372+
}
373+
.field span {
374+
font-size: 0.9rem;
375+
color: var(--muted);
376+
margin-bottom: 4px;
377+
}
378+
.field input, .field select {
379+
padding: 10px 12px;
380+
border-radius: 8px;
381+
border: 1px solid var(--input-border);
382+
font-size: 0.95rem;
383+
background: var(--bg);
384+
color: var(--text);
385+
}
386+
.form-grid {
387+
display: grid;
388+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
389+
gap: 12px;
390+
}
391+
.sensor-card {
392+
background: var(--chip);
393+
border: 1px solid var(--card-border);
394+
border-radius: 12px;
395+
padding: 16px;
396+
margin-bottom: 16px;
397+
position: relative;
398+
}
399+
.sensor-header {
400+
display: flex;
401+
justify-content: space-between;
402+
margin-bottom: 12px;
403+
}
404+
.sensor-title {
405+
font-weight: 600;
406+
color: var(--text);
407+
}
408+
.remove-btn {
409+
color: var(--danger);
410+
cursor: pointer;
411+
font-size: 0.9rem;
412+
border: none;
413+
background: none;
414+
padding: 0;
415+
font-weight: 600;
416+
}
417+
.remove-btn:hover {
418+
opacity: 0.8;
419+
}
420+
.actions {
421+
margin-top: 24px;
422+
display: flex;
423+
gap: 12px;
424+
flex-wrap: wrap;
425+
}
426+
button {
427+
border: none;
428+
border-radius: 10px;
429+
padding: 10px 16px;
430+
font-size: 0.95rem;
431+
font-weight: 600;
432+
cursor: pointer;
433+
background: var(--accent);
434+
color: var(--accent-contrast);
435+
transition: transform 0.15s ease;
436+
}
437+
button.secondary {
438+
background: transparent;
439+
border: 1px solid var(--card-border);
440+
color: var(--text);
441+
}
442+
button:hover {
443+
transform: translateY(-1px);
444+
}
445+
button:disabled {
446+
opacity: 0.5;
447+
cursor: not-allowed;
448+
transform: none;
449+
}
265450
</style>
266451
</head>
267-
<body>
452+
<body data-theme="light">
268453
<header>
269-
<h1>Config Generator</h1>
270-
<a href="/">&larr; Back to Dashboard</a>
454+
<div class="bar">
455+
<div>
456+
<h1>Config Generator</h1>
457+
<p>
458+
Create new client configurations with sensor definitions and upload settings for Tank Alarm field units.
459+
</p>
460+
</div>
461+
<div class="header-actions">
462+
<button class="icon-button" id="themeToggle" aria-label="Switch to dark mode">&#9789;</button>
463+
<a class="pill" href="/">&larr; Back to Dashboard</a>
464+
</div>
465+
</div>
271466
</header>
272467
<main>
273468
<div class="card">
@@ -294,6 +489,24 @@ static const char CONFIG_GENERATOR_HTML[] PROGMEM = R"HTML(
294489
</div>
295490
</main>
296491
<script>
492+
// Theme support
493+
const THEME_KEY = 'tankalarmTheme';
494+
const themeToggle = document.getElementById('themeToggle');
495+
496+
function applyTheme(next) {
497+
const theme = next === 'dark' ? 'dark' : 'light';
498+
document.body.dataset.theme = theme;
499+
themeToggle.textContent = theme === 'dark' ? '☀' : '☾';
500+
themeToggle.setAttribute('aria-label', theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode');
501+
localStorage.setItem(THEME_KEY, theme);
502+
}
503+
504+
applyTheme(localStorage.getItem(THEME_KEY) || 'light');
505+
themeToggle.addEventListener('click', () => {
506+
const next = document.body.dataset.theme === 'dark' ? 'light' : 'dark';
507+
applyTheme(next);
508+
});
509+
297510
const sensorTypes = [
298511
{ value: 0, label: 'Digital Input' },
299512
{ value: 1, label: 'Analog Input (0-10V)' },

0 commit comments

Comments
 (0)