Skip to content

Commit 28f65b3

Browse files
feat: enhance UI with icon buttons and improve theme toggle functionality
1 parent fe1b921 commit 28f65b3

1 file changed

Lines changed: 84 additions & 24 deletions

File tree

web/index.html

Lines changed: 84 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,11 @@
168168

169169
.theme-toggle {
170170
background: var(--card); border: 1px solid var(--border); border-radius: 8px;
171-
width: 36px; height: 36px; cursor: pointer; font-size: 1.125rem;
171+
width: 36px; height: 36px; cursor: pointer;
172172
display: flex; align-items: center; justify-content: center; transition: all 0.2s ease;
173+
color: var(--subtle);
173174
}
174-
.theme-toggle:hover { border-color: var(--border-hover); background: var(--input-hover-bg); }
175+
.theme-toggle:hover { border-color: var(--border-hover); background: var(--input-hover-bg); color: var(--fg); }
175176

176177
.target-table {
177178
width: 100%; border-collapse: collapse; font-size: 0.8125rem;
@@ -228,6 +229,7 @@
228229
.section-label {
229230
font-size: 0.6875rem; font-weight: 700; text-transform: uppercase;
230231
letter-spacing: 0.06em; color: var(--muted); margin-bottom: 0.5rem;
232+
display: flex; align-items: center; gap: 0.375rem;
231233
}
232234

233235
@media (max-width: 639px) {
@@ -239,12 +241,28 @@
239241
/* Settings button */
240242
.settings-btn {
241243
background: var(--card); border: 1px solid var(--border); border-radius: 8px;
242-
width: 36px; height: 36px; cursor: pointer; font-size: 1rem;
244+
width: 36px; height: 36px; cursor: pointer;
243245
display: flex; align-items: center; justify-content: center;
244246
transition: all 0.2s ease; color: var(--subtle);
245247
}
246248
.settings-btn:hover { border-color: var(--border-hover); background: var(--input-hover-bg); color: var(--fg); }
247249

250+
/* Icon button shared */
251+
.icon-btn svg { display: block; }
252+
253+
/* App logo */
254+
.app-logo {
255+
width: 38px; height: 38px; border-radius: 10px;
256+
background: var(--accent-soft); color: var(--accent);
257+
display: flex; align-items: center; justify-content: center;
258+
flex-shrink: 0;
259+
}
260+
261+
/* Section label with icon */
262+
.section-label {
263+
display: flex; align-items: center; gap: 0.375rem;
264+
}
265+
248266
/* Modal backdrop */
249267
.modal-backdrop {
250268
position: fixed; inset: 0; z-index: 50;
@@ -326,6 +344,9 @@
326344
<!-- Header -->
327345
<header class="flex flex-wrap justify-between items-center gap-3 mb-4 flex-shrink-0">
328346
<div class="flex items-center gap-3 sm:gap-4">
347+
<div class="app-logo">
348+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.55a11 11 0 0 1 14.08 0"/><path d="M1.42 9a16 16 0 0 1 21.16 0"/><path d="M8.53 16.11a6 6 0 0 1 6.95 0"/><circle cx="12" cy="20" r="1" fill="currentColor" stroke="none"/></svg>
349+
</div>
329350
<div>
330351
<div class="flex items-center gap-2.5">
331352
<h1 class="text-xl sm:text-2xl font-extrabold tracking-tight">Network Monitor</h1>
@@ -347,17 +368,27 @@ <h1 class="text-xl sm:text-2xl font-extrabold tracking-tight">Network Monitor</h
347368
<option>Last 1 hour</option>
348369
<option>Last 24 hours</option>
349370
</select>
350-
<button class="theme-toggle" id="themeToggle" title="Toggle dark mode">🌙</button>
351-
<button class="settings-btn" id="settingsBtn" title="Settings"></button>
371+
<button class="theme-toggle icon-btn" id="themeToggle" title="Toggle dark mode">
372+
<svg id="iconMoon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
373+
<svg id="iconSun" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display:none"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
374+
</button>
375+
<button class="settings-btn icon-btn" id="settingsBtn" title="Settings">
376+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
377+
</button>
352378
</div>
353379
</header>
354380

355381
<!-- Settings Modal -->
356382
<div class="modal-backdrop" id="modalBackdrop">
357383
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="modalTitle">
358384
<div class="modal-header">
359-
<h2 id="modalTitle">⚙ Monitor Settings</h2>
360-
<button class="modal-close" id="modalClose" title="Close"></button>
385+
<h2 id="modalTitle" style="display:flex;align-items:center;gap:0.5rem">
386+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="color:var(--accent)"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
387+
Monitor Settings
388+
</h2>
389+
<button class="modal-close" id="modalClose" title="Close">
390+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
391+
</button>
361392
</div>
362393
<div class="modal-body">
363394
<div class="field-group">
@@ -446,7 +477,10 @@ <h3><span class="chart-dot" style="background:var(--purple)"></span> DNS Resolut
446477

447478
<!-- Health score card -->
448479
<div class="card p-4 flex flex-col items-center" id="healthCard">
449-
<div class="section-label w-full text-center mb-3">Connection Health</div>
480+
<div class="section-label w-full text-center mb-3" style="justify-content:center">
481+
<svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 12h-4l-3 9L9 3l-3 9H2"/></svg>
482+
Connection Health
483+
</div>
450484
<div class="health-ring" id="healthRing">
451485
<svg viewBox="0 0 100 100" width="100" height="100">
452486
<circle class="ring-bg" cx="50" cy="50" r="42" />
@@ -476,7 +510,10 @@ <h3><span class="chart-dot" style="background:var(--purple)"></span> DNS Resolut
476510

477511
<!-- Targets table -->
478512
<div class="card p-4 flex-1 min-h-0 flex flex-col">
479-
<div class="section-label">Ping Targets</div>
513+
<div class="section-label">
514+
<svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/></svg>
515+
Ping Targets
516+
</div>
480517
<div class="overflow-y-auto flex-1">
481518
<table class="target-table" id="targetTable">
482519
<thead>
@@ -493,7 +530,10 @@ <h3><span class="chart-dot" style="background:var(--purple)"></span> DNS Resolut
493530

494531
<!-- DNS table -->
495532
<div class="card p-4 flex flex-col">
496-
<div class="section-label">DNS Lookups</div>
533+
<div class="section-label">
534+
<svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
535+
DNS Lookups
536+
</div>
497537
<table class="target-table" id="dnsTable">
498538
<thead>
499539
<tr>
@@ -507,7 +547,10 @@ <h3><span class="chart-dot" style="background:var(--purple)"></span> DNS Resolut
507547

508548
<!-- Quick stats footer -->
509549
<div class="card p-3 flex-shrink-0">
510-
<div class="section-label mb-2">24h Summary</div>
550+
<div class="section-label mb-2">
551+
<svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>
552+
24h Summary
553+
</div>
511554
<div class="grid grid-cols-2 gap-y-2 gap-x-4 text-xs">
512555
<div class="flex justify-between">
513556
<span style="color:var(--muted)">Uptime</span>
@@ -545,9 +588,12 @@ <h3><span class="chart-dot" style="background:var(--purple)"></span> DNS Resolut
545588
let chartInstances = {};
546589

547590
async function loadData() {
548-
const data = await fetch("/api/data").then(r => r.json()).catch(() => null);
591+
const [data, cfg] = await Promise.all([
592+
fetch("/api/data").then(r => r.json()).catch(() => null),
593+
fetch("/api/config").then(r => r.json()).catch(() => null),
594+
]);
549595
if (!data) return;
550-
renderHeader(data);
596+
renderHeader(data, cfg);
551597
renderSummary(data.summary);
552598
renderCharts(data.history, data.summary);
553599
renderHealth(data.summary);
@@ -556,11 +602,13 @@ <h3><span class="chart-dot" style="background:var(--purple)"></span> DNS Resolut
556602
renderQuickStats(data.summary, data.history);
557603
}
558604

559-
function renderHeader(data) {
605+
function renderHeader(data, cfg) {
560606
const now = new Date();
561607
$("#lastUpdated").textContent = now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
562-
$("#targetCount").textContent = (data.targets || []).length;
563-
$("#networkLabel").textContent = data.network_id || "unknown";
608+
const targetCount = cfg ? cfg.ping_targets.length : (data.targets || []).length;
609+
const intervalLabel = cfg ? ` · Ping every ${cfg.ping_interval_s}s` : "";
610+
$("#targetCount").textContent = targetCount;
611+
$("#networkLabel").textContent = (data.network_id || "unknown") + intervalLabel;
564612

565613
const loss = data.summary.packet_loss;
566614
const badge = $("#statusBadge");
@@ -576,12 +624,20 @@ <h3><span class="chart-dot" style="background:var(--purple)"></span> DNS Resolut
576624
}
577625
}
578626

627+
const SVG = {
628+
clock: `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>`,
629+
arrowDown: `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg>`,
630+
arrowUp: `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/></svg>`,
631+
activity: `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>`,
632+
};
633+
579634
function renderSummary(s) {
635+
const lossColor = s.packet_loss > 1 ? "red" : "green";
580636
const items = [
581-
{ label: "Avg Latency", value: s.latency_avg + " ms", icon: "⏱", color: "blue", sub: "p95 " + s.latency_p95 + " ms" },
582-
{ label: "Download", value: s.download_avg + " Mbps", icon: "↓", color: "green", sub: "avg throughput" },
583-
{ label: "Upload", value: s.upload_avg + " Mbps", icon: "↑", color: "purple", sub: "avg throughput" },
584-
{ label: "Packet Loss", value: s.packet_loss + "%", icon: "✕", color: s.packet_loss > 1 ? "red" : "green", sub: s.packet_loss < 1 ? "healthy" : "elevated" },
637+
{ label: "Avg Latency", value: s.latency_avg + " ms", icon: SVG.clock, color: "blue", sub: "p95 " + s.latency_p95 + " ms" },
638+
{ label: "Download", value: s.download_avg + " Mbps", icon: SVG.arrowDown, color: "green", sub: "avg throughput" },
639+
{ label: "Upload", value: s.upload_avg + " Mbps", icon: SVG.arrowUp, color: "purple", sub: "avg throughput" },
640+
{ label: "Packet Loss", value: s.packet_loss + "%", icon: SVG.activity, color: lossColor, sub: s.packet_loss < 1 ? "healthy" : "elevated" },
585641
];
586642
$("#summaryCards").innerHTML = items.map(m =>
587643
`<div class="card metric-card" data-color="${m.color}">
@@ -764,14 +820,18 @@ <h3><span class="chart-dot" style="background:var(--purple)"></span> DNS Resolut
764820

765821
// Theme toggle
766822
const toggle = $("#themeToggle");
767-
if (localStorage.getItem("theme") === "dark") {
768-
document.body.classList.add("dark-mode");
769-
toggle.textContent = "☀️";
823+
function applyTheme(dark) {
824+
document.body.classList.toggle("dark-mode", dark);
825+
$("#iconMoon").style.display = dark ? "none" : "";
826+
$("#iconSun").style.display = dark ? "" : "none";
770827
}
828+
applyTheme(localStorage.getItem("theme") === "dark");
771829
toggle.addEventListener("click", () => {
772830
const dark = document.body.classList.toggle("dark-mode");
773-
toggle.textContent = dark ? "☀️" : "🌙";
831+
applyTheme(dark);
774832
localStorage.setItem("theme", dark ? "dark" : "light");
833+
// re-render charts so tooltip theme updates
834+
loadData();
775835
});
776836

777837
// Settings modal

0 commit comments

Comments
 (0)