diff --git a/app/src/components/BodyPanel.jsx b/app/src/components/BodyPanel.jsx
index f481b5b..adffad0 100644
--- a/app/src/components/BodyPanel.jsx
+++ b/app/src/components/BodyPanel.jsx
@@ -4,7 +4,7 @@ import { BodySVG, useIsMobile } from "../lib/bodymap.jsx";
// Renders a front+back body map pair: side-by-side on desktop, toggled on mobile.
// Manages its own mobile view state so parents don't need to.
-export default function BodyPanel({ primary, secondary, muscleMap, marginBottom = 16 }) {
+export default function BodyPanel({ primary, secondary, muscleMap, marginBottom = 16, onHover, hovered }) {
const isMobile = useIsMobile();
const [mobileView, setMobileView] = useState("front");
@@ -20,7 +20,7 @@ export default function BodyPanel({ primary, secondary, muscleMap, marginBottom
))}
-
+
);
@@ -30,7 +30,7 @@ export default function BodyPanel({ primary, secondary, muscleMap, marginBottom
{["front", "back"].map(view => (
-
+
))}
diff --git a/app/src/components/History.jsx b/app/src/components/History.jsx
index 56b1db0..ce30449 100644
--- a/app/src/components/History.jsx
+++ b/app/src/components/History.jsx
@@ -156,6 +156,7 @@ export default function History({ onShowHome, onShowLogger, onShowHistory, onSho
const [analyzeError, setAnalyzeError] = useState(null);
const [libraryExercises, setLibraryExercises] = useState([]);
const [newExerciseIds, setNewExerciseIds] = useState(new Set());
+ const [hoveredMuscle, setHoveredMuscle] = useState(null);
const fileRef = useRef();
useEffect(() => {
@@ -193,7 +194,8 @@ export default function History({ onShowHome, onShowLogger, onShowHistory, onSho
const toggleExpand = (id) => {
setExpandedIds(prev => {
const next = new Set(prev);
- next.has(id) ? next.delete(id) : next.add(id);
+ if (next.has(id)) { next.delete(id); setHoveredMuscle(null); }
+ else next.add(id);
return next;
});
};
@@ -227,6 +229,7 @@ export default function History({ onShowHome, onShowLogger, onShowHistory, onSho
setSelectedDate(new Date(dateStr + "T12:00:00"));
setEditMode(false);
setSelectedSession(null);
+ setHoveredMuscle(null);
loadSession(dateStr);
};
@@ -498,8 +501,38 @@ export default function History({ onShowHome, onShowLogger, onShowHistory, onSho
primary={sessionMuscles.primary}
secondary={sessionMuscles.secondary}
muscleMap={sessionMuscleMap}
+ onHover={setHoveredMuscle}
+ hovered={hoveredMuscle}
+ marginBottom={0}
/>
+
+ {hoveredMuscle ? (
+
+
+ {MUSCLES[hoveredMuscle]?.label}
+
+
+
+
+ {(sessionMuscleMap[hoveredMuscle] || []).length}
+
+
+ {(sessionMuscleMap[hoveredMuscle] || []).length === 1 ? "ØVELSE" : "ØVELSER"}
+
+
+
+ {(sessionMuscleMap[hoveredMuscle] || []).join(" · ")}
+
+
+
+ ) : (
+
+ Hold musepeker over kroppen for detaljer
+
+ )}
+
+
Primær ({sessionMuscles.primary.length})
Sekundær ({sessionMuscles.secondary.length})
diff --git a/app/src/components/Home.jsx b/app/src/components/Home.jsx
index cfc281d..1491163 100644
--- a/app/src/components/Home.jsx
+++ b/app/src/components/Home.jsx
@@ -3,7 +3,7 @@ import { format, parseISO, startOfISOWeek, addDays } from "date-fns";
import { nb } from "date-fns/locale";
import { InlineLoading } from "@carbon/react";
import { Camera } from "@carbon/icons-react";
-import { BodySVG, MUSCLES } from "../lib/bodymap.jsx";
+import { BodySVG } from "../lib/bodymap.jsx";
import { fetchLastSession, fetchThisWeekSessions } from "../lib/db";
import { extractMuscles } from "../lib/utils";
import PageShell, { SectionLabel, PageHeading } from "./PageShell";
@@ -76,12 +76,6 @@ export default function Home({
const muscles = lastSession ? extractMuscles(lastSession) : null;
const isToday = lastSession?.session_date === format(today, "yyyy-MM-dd");
- const muscleMap = muscles
- ? Object.fromEntries(
- [...muscles.primary, ...muscles.secondary].map(id => [id, [MUSCLES[id]?.label ?? id]])
- )
- : {};
-
const weekStart = startOfISOWeek(today);
const weekDays = DAY_LABELS.map((label, i) => {
const date = format(addDays(weekStart, i), "yyyy-MM-dd");
@@ -171,13 +165,13 @@ export default function Home({
{/* Body figures + exercise list side by side */}
- {/* Body figures — hover shows muscle name */}
+ {/* Body figures */}
@@ -261,11 +255,7 @@ export default function Home({
maxWidth: 200,
}}>
{tooltip.names.map((name, i) => (
-
0 ? "4px 0 0" : 0,
- }}>
+
0 ? "4px 0 0" : 0 }}>
{name}
))}
diff --git a/app/src/components/Report.jsx b/app/src/components/Report.jsx
index cd5e708..5f011cf 100644
--- a/app/src/components/Report.jsx
+++ b/app/src/components/Report.jsx
@@ -322,9 +322,9 @@ export default function Report({ onShowHome, onShowLogger, onShowHistory, onShow
))}
-
+
{hoveredMuscle ? (
-
+
{MUSCLES[hoveredMuscle]?.label}
diff --git a/app/src/lib/bodymap.jsx b/app/src/lib/bodymap.jsx
index cc8ffea..c6fe681 100644
--- a/app/src/lib/bodymap.jsx
+++ b/app/src/lib/bodymap.jsx
@@ -252,23 +252,28 @@ export function HeatmapBodySVG({ view, counts = {}, maxCount = 1, exerciseMap =
);
}
-export function BodySVG({ view, primary, secondary, muscleMap = {} }) {
+export function BodySVG({ view, primary, secondary, muscleMap = {}, onHover, hovered }) {
const pSet = new Set(primary);
const sSet = new Set(secondary);
const [tooltip, setTooltip] = React.useState(null);
const wrapRef = React.useRef();
const handleEnter = (id, e) => {
+ if (onHover) { onHover(id); return; }
const rect = wrapRef.current?.getBoundingClientRect();
if (!rect) return;
setTooltip({ id, x: e.clientX - rect.left, y: e.clientY - rect.top });
};
const handleMove = (id, e) => {
+ if (onHover) return;
const rect = wrapRef.current?.getBoundingClientRect();
if (!rect) return;
setTooltip({ id, x: e.clientX - rect.left, y: e.clientY - rect.top });
};
- const handleLeave = () => setTooltip(null);
+ const handleLeave = () => {
+ if (onHover) { onHover(null); return; }
+ setTooltip(null);
+ };
return (
@@ -295,7 +300,7 @@ export function BodySVG({ view, primary, secondary, muscleMap = {} }) {
const isPrimary = pSet.has(id);
const isSec = sSet.has(id);
if (!isPrimary && !isSec) return null;
- const isHovered = tooltip?.id === id;
+ const isHovered = onHover ? id === hovered : tooltip?.id === id;
const fill = isPrimary
? (isHovered ? PRIMARY_HOVER : PRIMARY_FILL)
: `url(#sec-stripe-${view})`;
@@ -321,7 +326,7 @@ export function BodySVG({ view, primary, secondary, muscleMap = {} }) {
- {tooltip && muscleMap[tooltip.id]?.length > 0 && (
+ {!onHover && tooltip && muscleMap[tooltip.id]?.length > 0 && (