feat(dashboard): 3-col layout with Overview stats, speed chart fixes
- base.html: fix notification badge positioning (inline style, no overflow clip); remove py-4 from main; update footer text - index.html: split bottom row into 3 cols (GPS / Overview / Speed); Overview card with 6 live stats from /api/stats; speed chart auto-expands on desktop; shown.bs.collapse triggers speedChart.resize() Co-authored-by: Copilot <[email protected]>
This commit is contained in:
+3
-3
@@ -68,7 +68,7 @@
|
||||
<button class="btn btn-link position-relative p-2" id="alert-toggle" type="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false" aria-label="System alerts">
|
||||
<i class="fas fa-bell fa-fw text-secondary"></i>
|
||||
<span id="alert-count" class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger" hidden></span>
|
||||
<span id="alert-count" class="position-absolute badge rounded-pill bg-danger" style="top:2px;right:2px;font-size:.6rem;min-width:1.1em;padding:.2em .35em;" hidden></span>
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-end shadow" id="alert-menu" aria-labelledby="alert-toggle">
|
||||
<h6 class="dropdown-header">System alerts</h6>
|
||||
@@ -84,12 +84,12 @@
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="container-fluid py-4 px-3 px-md-4 main-content">
|
||||
<main class="container-fluid px-3 px-md-4 main-content">
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<footer class="bg-white border-top text-center py-3 small text-muted d-none d-md-block">
|
||||
© Yaris OBD {{ car.model }}
|
||||
© vroom vroom yaris de course 2023
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
||||
+69
-9
@@ -91,9 +91,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# ── GPS map (with inline coords footer) ─────────────────────────────── #}
|
||||
{# ── GPS map + Stats + Speed history ──────────────────────────────────── #}
|
||||
<div class="row g-3 mb-3">
|
||||
<div class="col-lg-5 col-xl-4">
|
||||
<div class="col-lg-4 col-xl-3">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-header py-2">
|
||||
<h6 class="text-primary fw-bold m-0">Live GPS</h6>
|
||||
@@ -113,16 +113,50 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-7 col-xl-8">
|
||||
<div class="col-lg-3 col-xl-2">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-header py-2 d-flex align-items-center gap-3">
|
||||
<div class="card-header py-2">
|
||||
<h6 class="text-primary fw-bold m-0">Overview</h6>
|
||||
</div>
|
||||
<div class="card-body py-3 px-3" id="stats-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-6 col-lg-12">
|
||||
<div class="text-xs text-muted fw-bold text-uppercase mb-1">Trips</div>
|
||||
<div class="fw-bold fs-5 text-dark" id="stat-trips">—</div>
|
||||
</div>
|
||||
<div class="col-6 col-lg-12">
|
||||
<div class="text-xs text-muted fw-bold text-uppercase mb-1">Total distance</div>
|
||||
<div class="fw-bold fs-5 text-dark" id="stat-km">—</div>
|
||||
</div>
|
||||
<div class="col-6 col-lg-12">
|
||||
<div class="text-xs text-muted fw-bold text-uppercase mb-1">Drive time</div>
|
||||
<div class="fw-bold fs-5 text-dark" id="stat-time">—</div>
|
||||
</div>
|
||||
<div class="col-6 col-lg-12">
|
||||
<div class="text-xs text-muted fw-bold text-uppercase mb-1">Top speed ever</div>
|
||||
<div class="fw-bold fs-5 text-dark" id="stat-topspeed">—</div>
|
||||
</div>
|
||||
<div class="col-6 col-lg-12">
|
||||
<div class="text-xs text-muted fw-bold text-uppercase mb-1">Videos on Pi</div>
|
||||
<div class="fw-bold fs-5 text-dark" id="stat-videos">—</div>
|
||||
</div>
|
||||
<div class="col-6 col-lg-12">
|
||||
<div class="text-xs text-muted fw-bold text-uppercase mb-1">Active DTC</div>
|
||||
<div class="fw-bold fs-5" id="stat-dtc">—</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-5 col-xl-7">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-header py-2 d-flex align-items-center gap-2">
|
||||
<h6 class="text-primary fw-bold m-0 me-auto">Speed history</h6>
|
||||
{# Live speed badge — visible even when graph is collapsed #}
|
||||
<span class="text-xs text-muted fw-bold text-uppercase">Now</span>
|
||||
<span id="speed-now-badge" class="fw-bold text-dark" style="min-width:3.5rem;text-align:right;">—</span>
|
||||
<span class="text-xs text-muted fw-bold text-uppercase ms-2">Max</span>
|
||||
<span id="speed-max-badge" class="fw-bold text-danger" style="min-width:3.5rem;text-align:right;">—</span>
|
||||
<button class="btn btn-link btn-sm p-0 text-muted ms-2" id="speed-graph-toggle" type="button"
|
||||
<span id="speed-now-badge" class="fw-bold text-dark" style="min-width:3rem;text-align:right;">—</span>
|
||||
<span class="text-xs text-muted fw-bold text-uppercase ms-2 speed-max-group">Max</span>
|
||||
<span id="speed-max-badge" class="fw-bold text-danger speed-max-group" style="min-width:3rem;text-align:right;">—</span>
|
||||
<button class="btn btn-link btn-sm p-0 text-muted ms-1" id="speed-graph-toggle" type="button"
|
||||
aria-expanded="false" aria-controls="speed-graph-body">
|
||||
<i class="fas fa-chevron-down"></i>
|
||||
</button>
|
||||
@@ -158,11 +192,37 @@
|
||||
btn.setAttribute('aria-expanded', 'true');
|
||||
btn.querySelector('i').className = 'fas fa-chevron-up';
|
||||
});
|
||||
body.addEventListener('shown.bs.collapse', function () {
|
||||
if (window.speedChart) window.speedChart.resize();
|
||||
});
|
||||
body.addEventListener('hide.bs.collapse', function () {
|
||||
btn.setAttribute('aria-expanded', 'false');
|
||||
btn.querySelector('i').className = 'fas fa-chevron-down';
|
||||
});
|
||||
btn.addEventListener('click', function () { bsCollapse.toggle(); });
|
||||
// Auto-expand on desktop; stay collapsed on mobile
|
||||
if (window.innerWidth >= 768) {
|
||||
bsCollapse.show();
|
||||
}
|
||||
})();
|
||||
|
||||
// Overview stats card
|
||||
(function () {
|
||||
function fmtDuration(s) {
|
||||
const h = Math.floor(s / 3600);
|
||||
const m = Math.floor((s % 3600) / 60);
|
||||
return h > 0 ? h + 'h ' + m + 'm' : m + 'm';
|
||||
}
|
||||
fetch('/api/stats').then(r => r.json()).then(d => {
|
||||
document.getElementById('stat-trips').textContent = d.trip_count;
|
||||
document.getElementById('stat-km').textContent = d.total_km.toFixed(1) + ' km';
|
||||
document.getElementById('stat-time').textContent = d.total_duration_s > 0 ? fmtDuration(d.total_duration_s) : '—';
|
||||
document.getElementById('stat-topspeed').textContent = d.all_time_max_speed > 0 ? d.all_time_max_speed + ' km/h' : '—';
|
||||
document.getElementById('stat-videos').textContent = d.video_count;
|
||||
const dtcEl = document.getElementById('stat-dtc');
|
||||
dtcEl.textContent = d.active_dtc;
|
||||
dtcEl.className = 'fw-bold fs-5 ' + (d.active_dtc > 0 ? 'text-danger' : 'text-success');
|
||||
}).catch(() => {});
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user