[Perl] DAQ system for the FAPG.
refactor align with Bootstrap 5.3 best practices
- Use data-bs-theme="light" on <html> instead of bg-light text-dark on <body> (modern Bootstrap 5.3 color mode API) - Replace all text-muted with text-body-secondary (5.3 naming) - Replace bg-white on navbar with bg-body (theme-aware) - Add skip-to-content link (visually-hidden-focusable) - Add id="main-content" to <main> as skip link target - Use lead class on dashboard subtitle - Replace col-form-label on <legend> with fs-6 (proper usage) - Remove duplicate aria-label on inner graph-control div
Changed files
- roles/dashboard/public/js/dashboard/charts.js
- roles/dashboard/templates/dashboard/correlation-card.html.ep
- roles/dashboard/templates/dashboard/downloads.html.ep
- roles/dashboard/templates/dashboard/graph-control.html.ep
- roles/dashboard/templates/dashboard/index.html.ep
- roles/dashboard/templates/dashboard/probe-card.html.ep
- roles/dashboard/templates/dashboard/status.html.ep
- roles/dashboard/templates/layouts/default.html.ep
roles/dashboard/public/js/dashboard/charts.js
@@ -133,7 +133,7 @@
133
133
134
134
const percent = ((last - first) / Math.abs(first)) * 100;
135
135
const sign = percent >= 0 ? "+" : "";
136
Removed:
const color = percent > 0 ? "text-success" : percent < 0 ? "text-danger" : "text-muted";
136
Added:
const color = percent > 0 ? "text-success" : percent < 0 ? "text-danger" : "text-body-secondary";
137
137
138
138
element.className = `small fw-normal ${color}`;
139
139
element.textContent = `${sign}${percent.toFixed(1)}%`;
roles/dashboard/templates/dashboard/correlation-card.html.ep
@@ -3,7 +3,7 @@
3
3
<div class="card">
4
4
<div class="card-header">
5
5
<h2 class="h5 mb-0">Dissolved Oxygen vs ORP</h2>
6
Removed:
<p class="text-muted small mb-0 mt-1">Correlation scatter plot</p>
6
Added:
<p class="text-body-secondary small mb-0 mt-1">Correlation scatter plot</p>
7
7
</div>
8
8
<div class="card-body">
9
9
<div class="chart-wrap">
roles/dashboard/templates/dashboard/downloads.html.ep
@@ -6,7 +6,7 @@
6
6
<div class="card">
7
7
<div class="card-header">
8
8
<h1 class="h5 mb-0">Downloads</h1>
9
Removed:
<p class="text-muted small mb-0 mt-1">Download recorded DAQ readings as a CSV or Excel file.</p>
9
Added:
<p class="text-body-secondary small mb-0 mt-1">Download recorded DAQ readings as a CSV or Excel file.</p>
10
10
</div>
11
11
12
12
<div class="card-body">
@@ -14,7 +14,7 @@
14
14
<form action="/downloads/readings.csv" method="get" class="downloads-form d-flex flex-column gap-3">
15
15
16
16
<fieldset>
17
Removed:
<legend class="fw-bold col-form-label pt-0 mb-2">Probes</legend>
17
Added:
<legend class="fs-6 fw-bold pt-0 mb-2">Probes</legend>
18
18
<p class="form-text mt-0">Leave all boxes clear to download every probe.</p>
19
19
<div>
20
20
% for my $probe ($probes->@*) {
@@ -27,7 +27,7 @@
27
27
</fieldset>
28
28
29
29
<fieldset>
30
Removed:
<legend class="fw-bold col-form-label pt-0 mb-2">Date range</legend>
30
Added:
<legend class="fs-6 fw-bold pt-0 mb-2">Date range</legend>
31
31
<div class="btn-group flex-wrap download-range-control" role="group" aria-label="Date range">
32
32
<input class="btn-check" type="radio" name="date_range" id="range-today" value="today" data-download-range data-from="<%= $to %>" data-to="<%= $to %>">
33
33
<label class="btn btn-outline-secondary" for="range-today">Today</label>
roles/dashboard/templates/dashboard/graph-control.html.ep
@@ -1,7 +1,7 @@
1
1
<!-- -*- mode: web; -*- -->
2
2
3
3
<div class="graph-control-scroll overflow-x-auto" tabindex="0" role="region" aria-label="<%= $aria_label %>">
4
Removed:
<div class="graph-control d-inline-flex gap-2 flex-nowrap" aria-label="<%= $aria_label %>">
4
Added:
<div class="graph-control d-inline-flex gap-2 flex-nowrap">
5
5
<div class="input-group input-group-sm range-control" aria-label="Adjust range">
6
6
<button
7
7
class="btn btn-outline-secondary"
roles/dashboard/templates/dashboard/index.html.ep
@@ -7,7 +7,7 @@
7
7
<section class="mb-4" aria-label="DAQ status overview">
8
8
<div class="mb-3">
9
9
<h1 class="display-5 fw-bold mb-1">FAPG DAQ Dashboard</h1>
10
Removed:
<p class="text-muted mb-2">Live aquaponic sensor readings</p>
10
Added:
<p class="lead text-body-secondary mb-2">Live aquaponic sensor readings</p>
11
11
<nav aria-label="Quick links">
12
12
<ul class="nav nav-pills">
13
13
<li class="nav-item"><a class="nav-link" href="/probes">Probes</a></li>
@@ -18,7 +18,7 @@
18
18
</div>
19
19
20
20
<section class="reading-quick-status" aria-label="Sensor reading quick status">
21
Removed:
<h2 class="h6 fw-semibold text-uppercase text-muted mb-3">Live readings</h2>
21
Added:
<h2 class="h6 fw-semibold text-uppercase text-body-secondary mb-3">Live readings</h2>
22
22
<div class="row g-3" data-reading-quick-status>
23
23
% for my $probe ($probes->@*) {
24
24
<div class="col-12 col-sm-6 col-xl-3">
@@ -31,12 +31,12 @@
31
31
<div class="card-body d-flex flex-column gap-2">
32
32
<div class="reading-quick-header">
33
33
<h3 class="fs-6 fw-bold mb-0"><%= $probe->{label} %></h3>
34
Removed:
<p class="text-muted small mb-0" data-reading-quick-value>Waiting for data</p>
34
Added:
<p class="text-body-secondary small mb-0" data-reading-quick-value>Waiting for data</p>
35
35
</div>
36
36
<div class="reading-range" role="meter" aria-valuemin="0" aria-valuemax="100" aria-valuenow="50">
37
37
<span class="reading-range-marker" data-reading-quick-marker></span>
38
38
</div>
39
Removed:
<div class="reading-range-labels d-grid gap-1 small text-muted">
39
Added:
<div class="reading-range-labels d-grid gap-1 small text-body-secondary">
40
40
<span data-reading-quick-min></span>
41
41
<span class="fw-bold text-center" data-reading-quick-target></span>
42
42
<span class="text-end" data-reading-quick-max></span>
roles/dashboard/templates/dashboard/probe-card.html.ep
@@ -5,9 +5,9 @@
5
5
<div class="probe-card-title min-w-0">
6
6
<h1 class="h5 mb-0">
7
7
<a class="text-body text-decoration-none" href="/probes/<%= $probe->{key} %>"><%= $probe->{label} %></a>
8
Removed:
<span class="small fw-normal text-muted" data-variation="<%= $probe->{key} %>"></span>
8
Added:
<span class="small fw-normal text-body-secondary" data-variation="<%= $probe->{key} %>"></span>
9
9
</h1>
10
Removed:
<p class="text-muted small mb-0 mt-1">
10
Added:
<p class="text-body-secondary small mb-0 mt-1">
11
11
Unit: <strong><%= $probe->{unit} %></strong>
12
12
</p>
13
13
</div>
@@ -36,7 +36,7 @@
36
36
<canvas id="chart-<%= $probe->{key} %>" role="img" aria-label="<%= $probe->{label} %> readings chart"></canvas>
37
37
</div>
38
38
% unless (stash('single_probe')) {
39
Removed:
<p class="text-muted small mt-2 mb-0 reading-status placeholder-glow" data-status="<%= $probe->{key} %>">
39
Added:
<p class="text-body-secondary small mt-2 mb-0 reading-status placeholder-glow" data-status="<%= $probe->{key} %>">
40
40
<span class="placeholder col-8">Waiting for data…</span>
41
41
</p>
42
42
% }
roles/dashboard/templates/dashboard/status.html.ep
@@ -6,7 +6,7 @@
6
6
<div class="card">
7
7
<div class="card-header">
8
8
<h1 class="h5 mb-0">DAQ Status</h1>
9
Removed:
<p class="text-muted small mb-0 mt-1">Current connection status for the hub and sensor probes.</p>
9
Added:
<p class="text-body-secondary small mb-0 mt-1">Current connection status for the hub and sensor probes.</p>
10
10
</div>
11
11
12
12
<div class="list-group list-group-flush">
@@ -25,7 +25,7 @@
25
25
</h2>
26
26
<span class="badge status-pill is-unknown" data-status-page-state>Checking</span>
27
27
</div>
28
Removed:
<div class="row row-cols-1 row-cols-sm-2 g-1 mt-1 small text-muted">
28
Added:
<div class="row row-cols-1 row-cols-sm-2 g-1 mt-1 small text-body-secondary">
29
29
<div class="col">
30
30
<span class="fw-semibold text-uppercase status-node-dt">Node:</span>
31
31
<span data-status-page-node>Checking…</span>
roles/dashboard/templates/layouts/default.html.ep
@@ -1,7 +1,7 @@
1
1
<!-- -*- mode: web; -*- -->
2
2
3
3
<!doctype html>
4
Removed:
<html lang="en">
4
Added:
<html lang="en" data-bs-theme="light">
5
5
<head>
6
6
<meta charset="utf-8">
7
7
<title><%= title %></title>
@@ -16,9 +16,11 @@
16
16
crossorigin="anonymous">
17
17
<link rel="stylesheet" href="/css/app.css">
18
18
</head>
19
Removed:
<body class="bg-light text-dark">
19
Added:
<body>
20
20
21
Removed:
<nav class="navbar navbar-expand-md bg-white border-bottom shadow-sm sticky-top mb-3" aria-label="Dashboard navigation">
21
Added:
<a class="visually-hidden-focusable" href="#main-content">Skip to main content</a>
22
Added:
23
Added:
<nav class="navbar navbar-expand-md bg-body border-bottom shadow-sm sticky-top mb-3" aria-label="Dashboard navigation">
22
24
<div class="container-fluid px-3">
23
25
24
26
<a class="navbar-brand fw-bold text-success" href="/">FAPG</a>
@@ -73,14 +75,14 @@
73
75
</div>
74
76
</nav>
75
77
76
Removed:
<main class="container">
78
Added:
<main id="main-content" class="container">
77
79
%= include 'dashboard/toolbar', breadcrumbs => (stash('breadcrumbs') // []), graph_control_aria_label => stash('graph_control_aria_label')
78
80
<%= content %>
79
81
</main>
80
82
81
Removed:
<footer class="text-center text-muted small py-3 mt-4 bg-body-tertiary border-top">
83
Added:
<footer class="text-center text-body-secondary small py-3 mt-4 bg-body-tertiary border-top">
82
84
<p class="mb-0">
83
Removed:
<a class="text-muted" href="https://www.lafermeaquaponique.com/">lafermeaquaponique.com</a>
85
Added:
<a class="text-body-secondary" href="https://www.lafermeaquaponique.com/">lafermeaquaponique.com</a>
84
86
</p>
85
87
<p class="mb-0">Copyright © 2026 Marius Peter</p>
86
88
</footer>