fix improve WCAG accessibility compliance

- Add role="img" and aria-label to all chart canvas elements so screen readers can identify them - Add tabindex="0" and role="region" to scrollable graph controls container for keyboard accessibility - Add aria-pressed to timeframe toggle buttons to convey state - Add aria-label to percentage variation span for screen reader context on the color-coded change indicator

Commit
ff635998ffe4c84cd6030a932e28c6148bad9726
Author
GPT-5 medium <codex@openai.com>
Author date
Committer
GPT-5 medium <codex@openai.com>
Committer date
Changed files
roles/dashboard/public/js/dashboard/charts.js
index 43126479..283c2f50 100644..100644
@@ -137,6 +137,7 @@
137 137
138 138 element.className = `small fw-normal ${color}`;
139 139 element.textContent = `${sign}${percent.toFixed(1)}%`;
140 Added: element.setAttribute("aria-label", `${sign}${percent.toFixed(1)} percent change over period`);
140 141 }
141 142
142 143 function registerTopLeftTooltipPositioner() {
roles/dashboard/public/js/dashboard/graph-controls.js
index 1a68d769..ff36afe3 100644..100644
@@ -16,7 +16,9 @@
16 16 const range = timeframe.range();
17 17
18 18 document.querySelectorAll(".timeframe-button").forEach(button => {
19 Removed: button.classList.toggle("is-active", button.dataset.timeframe === timeframe.selected());
19 Added: const active = button.dataset.timeframe === timeframe.selected();
20 Added: button.classList.toggle("is-active", active);
21 Added: button.setAttribute("aria-pressed", active ? "true" : "false");
20 22 });
21 23
22 24 document.querySelectorAll("[data-range-label]").forEach(label => {
roles/dashboard/templates/dashboard/correlation-card.html.ep
index 16961ffd..048a67ad 100644..100644
@@ -7,7 +7,7 @@
7 7 </div>
8 8 <div class="card-body">
9 9 <div class="chart-wrap">
10 Removed: <canvas id="chart-correlation"></canvas>
10 Added: <canvas id="chart-correlation" role="img" aria-label="Dissolved Oxygen vs ORP correlation scatter chart"></canvas>
11 11 </div>
12 12 </div>
13 13 </div>
roles/dashboard/templates/dashboard/graph-control.html.ep
index 99df4b76..5469c173 100644..100644
@@ -1,6 +1,6 @@
1 1 <!-- -*- mode: web; -*- -->
2 2
3 Removed: <div class="graph-control-scroll overflow-x-auto">
3 Added: <div class="graph-control-scroll overflow-x-auto" tabindex="0" role="region" aria-label="<%= $aria_label %>">
4 4 <div class="graph-control d-inline-flex gap-2 flex-nowrap" aria-label="<%= $aria_label %>">
5 5 <div class="input-group input-group-sm range-control" aria-label="Adjust range">
6 6 <button
roles/dashboard/templates/dashboard/probe-card.html.ep
index 183b5f0e..66500941 100644..100644
@@ -33,7 +33,7 @@
33 33 <div class="card-body">
34 34 <section id="probe-<%= $probe->{key} %>" class="tab-panel is-active" data-panel="<%= $probe->{key} %>">
35 35 <div class="chart-wrap">
36 Removed: <canvas id="chart-<%= $probe->{key} %>"></canvas>
36 Added: <canvas id="chart-<%= $probe->{key} %>" role="img" aria-label="<%= $probe->{label} %> readings chart"></canvas>
37 37 </div>
38 38 % unless (stash('single_probe')) {
39 39 <p class="text-muted small mt-2 mb-0 reading-status placeholder-glow" data-status="<%= $probe->{key} %>">