Skip to content

Commit ef02c13

Browse files
committed
feat: enhance UI components and update mock API data for improved user experience
1 parent f842d51 commit ef02c13

4 files changed

Lines changed: 231 additions & 93 deletions

File tree

web/index.html

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,36 +8,33 @@
88
</head>
99
<body>
1010
<div id="app" class="app-shell">
11-
<header class="topbar">
12-
<div class="brand">
13-
<div class="brand-icon">☢️</div>
14-
<div class="brand-text">
15-
<div class="brand-title">MultiGeiger</div>
16-
<div class="brand-subtitle">Live readings</div>
17-
</div>
18-
</div>
19-
<div class="status-block">
20-
<div class="status-row">
21-
<span class="dot" id="connectionDot"></span>
22-
<span id="connectionState">Connecting…</span>
23-
</div>
24-
<div class="status-row small" id="lastUpdate"></div>
25-
</div>
26-
</header>
27-
2811
<main class="views">
2912
<div class="hero-simple card sticky-hero">
13+
<div class="hero-header">
14+
<div class="brand">
15+
<div class="brand-icon">☢️</div>
16+
<div class="brand-text">
17+
<div class="brand-title">MultiGeiger</div>
18+
<div class="brand-subtitle">Live readings</div>
19+
</div>
20+
</div>
21+
</div>
3022
<div class="hero-top">
3123
<div class="hero-label">Dose rate</div>
3224
<div class="hero-meta">
33-
<span class="status-badge" id="statusBadge">Live</span>
3425
<span id="hvWarning" class="chip danger hidden">HV error</span>
3526
</div>
3627
</div>
3728
<div class="hero-number">
3829
<span id="doseRate">--</span>
3930
<span class="hero-unit">µSv/h</span>
4031
</div>
32+
<div class="hero-status">
33+
<span class="status-badge" id="statusBadge">
34+
<span class="dot" id="connectionDot"></span>
35+
<span class="status-label" id="statusText">Online</span>
36+
</span>
37+
</div>
4138
<div class="panel-toggle">
4239
<button class="toggle-btn active" data-target="dashboard">Dashboard</button>
4340
<button class="toggle-btn" data-target="settings">Settings</button>
@@ -46,7 +43,10 @@
4643

4744
<section id="panel-dashboard" data-panel="dashboard">
4845
<div class="card env-card hidden" id="envCard">
49-
<div class="row-title">Weather</div>
46+
<div class="row-title">
47+
<span>Weather</span>
48+
<span id="sensorBadge" class="chip sensor hidden"></span>
49+
</div>
5050
<div class="row env-row">
5151
<div class="env-item">
5252
<span class="env-label">Temp</span>
@@ -63,6 +63,11 @@
6363
<span class="env-value" id="pressure">--</span>
6464
<span class="env-unit">hPa</span>
6565
</div>
66+
<div class="env-item" id="gasItem">
67+
<span class="env-label">Gas</span>
68+
<span class="env-value" id="gasValue">--</span>
69+
<span class="env-unit">Ω</span>
70+
</div>
6671
</div>
6772
</div>
6873

web/public/mock/api.js

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
const DEFAULT_STATUS = {
2-
counts: 1200,
3-
cpm: 42.5,
4-
dose_uSvh: 0.12,
5-
uptime_s: 3600,
1+
const BASE_STATUS = {
2+
counts: 1500,
3+
cpm: 40.0,
4+
dose_uSvh: 0.116,
65
hv_error: false,
76
temperature: 22.8,
87
humidity: 48.2,
98
pressure: 1014.2,
10-
has_thp: true,
9+
sensor: 'BME280',
1110
version: 'v1.0.0-mock',
1211
};
1312

@@ -67,18 +66,26 @@ function saveToStorage(key, value) {
6766

6867
export class MockAPI {
6968
constructor() {
70-
this.status = { ...DEFAULT_STATUS };
69+
this.status = { ...BASE_STATUS };
70+
this.startedAt = Date.now();
71+
this.baseCounts = this.status.counts;
72+
this.cps = (this.status.cpm || 0) / 60;
7173
this.config = loadFromStorage('multigeiger:config', { ...DEFAULT_CONFIG });
7274
}
7375

7476
async getStatus() {
75-
// Simulate slight changes
76-
this.status.counts += Math.floor(Math.random() * 4);
77-
this.status.cpm = this.status.cpm + (Math.random() - 0.5);
78-
this.status.dose_uSvh = this.status.cpm * 0.0029;
79-
this.status.uptime_s += POLL_STEP_SECONDS;
77+
const elapsed = Math.max(0, Math.floor((Date.now() - this.startedAt) / 1000));
78+
const counts = this.baseCounts + Math.round(this.cps * elapsed);
79+
const cpm = this.cps * 60;
80+
const dose = cpm * 0.0029;
8081
await sleep();
81-
return { ...this.status };
82+
return {
83+
...this.status,
84+
counts,
85+
cpm: Number(cpm.toFixed(1)),
86+
dose_uSvh: Number(dose.toFixed(3)),
87+
uptime_s: elapsed,
88+
};
8289
}
8390

8491
async getConfig() {

web/src/app.js

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -227,29 +227,77 @@ export class MultiGeigerApp {
227227
hvWarning.classList.toggle('hidden', !data.hv_error);
228228
}
229229

230-
const hasEnv = data.has_thp;
230+
// Environment fields
231+
const temp = data.temperature;
232+
const humidity = data.humidity;
233+
const pressure = data.pressure;
234+
const gas = data.gas ?? data.gas_resistance;
235+
const hasTemp = temp !== undefined && temp !== null;
236+
const hasHumidity = humidity !== undefined && humidity !== null;
237+
const hasPressure = pressure !== undefined && pressure !== null;
238+
const hasGas = gas !== undefined && gas !== null;
239+
const hasEnv = hasTemp || hasHumidity || hasPressure || hasGas || data.has_thp;
240+
231241
const envCard = qs('envCard');
232242
if (envCard) {
233243
envCard.classList.toggle('hidden', !hasEnv);
234244
}
235245

236-
if (hasEnv) {
237-
this.updateText('temperature', clampDecimals(Number(data.temperature), 1));
238-
this.updateText('humidity', clampDecimals(Number(data.humidity), 1));
239-
this.updateText('pressure', clampDecimals(Number(data.pressure), 1));
246+
if (hasTemp) {
247+
this.updateText('temperature', clampDecimals(Number(temp), 1));
248+
qs('temperature')?.parentElement?.classList.remove('hidden');
249+
} else {
250+
qs('temperature')?.parentElement?.classList.add('hidden');
251+
}
252+
253+
if (hasHumidity) {
254+
this.updateText('humidity', clampDecimals(Number(humidity), 1));
255+
qs('humidity')?.parentElement?.classList.remove('hidden');
256+
} else {
257+
qs('humidity')?.parentElement?.classList.add('hidden');
258+
}
259+
260+
if (hasPressure) {
261+
this.updateText('pressure', clampDecimals(Number(pressure), 1));
262+
qs('pressure')?.parentElement?.classList.remove('hidden');
263+
} else {
264+
qs('pressure')?.parentElement?.classList.add('hidden');
240265
}
241266

242-
if (this.statusBadge) {
243-
this.statusBadge.textContent = 'Live';
267+
const gasItem = qs('gasItem');
268+
if (hasGas && gasItem) {
269+
gasItem.classList.remove('hidden');
270+
this.updateText('gasValue', clampDecimals(Number(gas), 0));
271+
} else if (gasItem) {
272+
gasItem.classList.add('hidden');
244273
}
274+
275+
const sensorBadge = qs('sensorBadge');
276+
if (sensorBadge) {
277+
const sensorName = this.resolveSensorName({ hasGas, hasHumidity, hasPressure, hasTemp });
278+
if (sensorName) {
279+
sensorBadge.textContent = sensorName;
280+
sensorBadge.classList.remove('hidden');
281+
} else {
282+
sensorBadge.classList.add('hidden');
283+
}
284+
}
285+
286+
}
287+
288+
resolveSensorName({ hasGas, hasHumidity, hasPressure, hasTemp }) {
289+
if (hasGas) return 'BME680';
290+
if (hasHumidity && hasPressure && hasTemp) return 'BME280';
291+
if (hasPressure && hasTemp) return 'BMP280';
292+
if (hasTemp) return 'Temp sensor';
293+
return null;
245294
}
246295

247296
setConnectionState(online) {
248-
const stateEl = qs('connectionState');
297+
const stateEl = qs('statusText');
249298
const dot = qs('connectionDot');
250299
if (stateEl) {
251300
stateEl.textContent = online ? 'Online' : 'Offline';
252-
stateEl.style.color = online ? 'var(--text)' : 'var(--muted)';
253301
}
254302
if (dot) {
255303
dot.classList.toggle('online', online);

0 commit comments

Comments
 (0)