From 2de8e28879263a70607722c29f4ed9f066894004 Mon Sep 17 00:00:00 2001 From: Christopher Rotnes Date: Sun, 3 May 2026 18:00:44 +0200 Subject: [PATCH] a11y: add SVG role/aria-label and semantic table for muscle frequency - BodySVG: add role="img" and aria-label listing primary muscles per view - HeatmapBodySVG: add role="img" and aria-label identifying view - Report.jsx: convert muscle frequency from div layout to with thead/tbody/th(scope)/td so screen readers can navigate by row/column Closes #74, #78 Co-Authored-By: Claude Sonnet 4.6 --- app/src/components/Report.jsx | 92 +++++++++++++++++++---------------- app/src/lib/bodymap.jsx | 4 ++ 2 files changed, 54 insertions(+), 42 deletions(-) diff --git a/app/src/components/Report.jsx b/app/src/components/Report.jsx index 0abfe01..6e74a49 100644 --- a/app/src/components/Report.jsx +++ b/app/src/components/Report.jsx @@ -387,48 +387,56 @@ export default function Report({ onShowHome, onShowLogger, onShowHistory, onShow )}
-

Muskelfrekvens

-
- MUSKEL -
- ØKT - SETT -
- {frequencyTable.map(({ id, primary, secondary }) => { - const barWidth = maxPrimaryCount > 0 ? (primary / maxPrimaryCount) * 100 : 0; - const countColor = primary > 0 - ? "var(--cds-text-primary)" - : secondary > 0 - ? "#4589ff" - : "var(--cds-text-disabled)"; - const countLabel = primary > 0 - ? String(primary) - : secondary > 0 - ? `(${secondary})` - : "—"; - return ( -
- - {muscleExercises[id]?.size > 0 ? ( - - {MUSCLES[id]?.label || id} - - ) : MUSCLES[id]?.label || id} - -
- {primary > 0 && ( -
- )} -
- - {countLabel} - - - {muscleVolume[id] > 0 ? muscleVolume[id] : "—"} - -
- ); - })} +

Muskelfrekvens

+
+ + + + + + + + + {frequencyTable.map(({ id, primary, secondary }) => { + const barWidth = maxPrimaryCount > 0 ? (primary / maxPrimaryCount) * 100 : 0; + const countColor = primary > 0 + ? "var(--cds-text-primary)" + : secondary > 0 + ? "#4589ff" + : "var(--cds-text-disabled)"; + const countLabel = primary > 0 + ? String(primary) + : secondary > 0 + ? `(${secondary})` + : "—"; + return ( + + + + + + + ); + })} + +
MUSKEL + ØKTSETT
+ {muscleExercises[id]?.size > 0 ? ( + + {MUSCLES[id]?.label || id} + + ) : MUSCLES[id]?.label || id} + +
+ {primary > 0 && ( +
+ )} +
+
+ {countLabel} + + {muscleVolume[id] > 0 ? muscleVolume[id] : "—"} +
{sessionCount > 0 && ( diff --git a/app/src/lib/bodymap.jsx b/app/src/lib/bodymap.jsx index 0ac3e66..cc8ffea 100644 --- a/app/src/lib/bodymap.jsx +++ b/app/src/lib/bodymap.jsx @@ -145,6 +145,8 @@ export function HeatmapBodySVG({ view, counts = {}, maxCount = 1, exerciseMap = return (
@@ -271,6 +273,8 @@ export function BodySVG({ view, primary, secondary, muscleMap = {} }) { return (
MUSCLES[id]?.label).filter(Boolean).join(", ") || "ingen"}.`} style={{ width: "100%", height: "auto", display: "block" }}>