From 4a3e85bcf763d127b9934eb3e6c1c9efbb969829 Mon Sep 17 00:00:00 2001 From: Alexander Bocken Date: Wed, 8 Apr 2026 16:14:53 +0200 Subject: [PATCH] feat: add info popover tooltips to calorie balance and adherence cards Clicking the (i) icon on the calorie balance or adherence card now shows a floating popover explaining how each metric is calculated, with EN/DE translations. --- package.json | 2 +- .../fitness/[stats=fitnessStats]/+page.svelte | 69 ++++++++++++++++++- 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 3b603412..692f1c48 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homepage", - "version": "1.13.0", + "version": "1.13.1", "private": true, "type": "module", "scripts": { diff --git a/src/routes/fitness/[stats=fitnessStats]/+page.svelte b/src/routes/fitness/[stats=fitnessStats]/+page.svelte index 5498d81e..5ed5e122 100644 --- a/src/routes/fitness/[stats=fitnessStats]/+page.svelte +++ b/src/routes/fitness/[stats=fitnessStats]/+page.svelte @@ -3,7 +3,7 @@ import { page } from '$app/stores'; import FitnessChart from '$lib/components/fitness/FitnessChart.svelte'; import MuscleHeatmap from '$lib/components/fitness/MuscleHeatmap.svelte'; - import { Dumbbell, Route, Flame, Weight, Beef, Scale, Target } from '@lucide/svelte'; + import { Dumbbell, Route, Flame, Weight, Beef, Scale, Target, Info } from '@lucide/svelte'; import FitnessStreakAura from '$lib/components/fitness/FitnessStreakAura.svelte'; import { onMount } from 'svelte'; import { detectFitnessLang, fitnessSlugs, t } from '$lib/js/fitnessI18n'; @@ -38,6 +38,8 @@ let goalStreak = $derived(data.goal?.streak ?? 0); let goalWeekly = $derived(data.goal?.weeklyWorkouts ?? null); + let showBalanceInfo = $state(false); + let showAdherenceInfo = $state(false); let goalEditing = $state(false); let goalInput = $state(4); let goalSaving = $state(false); @@ -293,7 +295,17 @@ {:else}
{/if} -
{t('calorie_balance', lang)}
+
+ {t('calorie_balance', lang)} + + {#if showBalanceInfo} +
+ {lang === 'en' + ? 'Average daily calories eaten minus your calorie goal over the last 7 days. Negative = deficit, positive = surplus.' + : 'Durchschnittlich gegessene Kalorien minus dein Kalorienziel der letzten 7 Tage. Negativ = Defizit, positiv = Überschuss.'} +
+ {/if} +
{#if ns.avgCalorieBalance != null} {t('seven_day_avg', lang)} @@ -310,7 +322,17 @@ {:else}
{/if} -
{t('diet_adherence', lang)}
+
+ {t('diet_adherence', lang)} + + {#if showAdherenceInfo} +
+ {lang === 'en' + ? 'Percentage of days where calories eaten were within ±10% of your goal. Days without tracking count as misses.' + : 'Prozent der Tage, an denen die gegessenen Kalorien innerhalb von ±10 % deines Ziels lagen. Nicht erfasste Tage zählen als verfehlt.'} +
+ {/if} +
{#if ns.adherencePercent != null} {t('since_start', lang)} ({ns.adherenceDays} {t('days', lang)}) @@ -713,6 +735,47 @@ text-align: center; font-size: 0.7rem; } + .card-label-info { + position: relative; + } + .card-info-trigger { + display: inline-flex; + align-items: center; + vertical-align: middle; + opacity: 0.4; + cursor: pointer; + margin-left: 0.15rem; + background: none; + border: none; + padding: 0; + color: inherit; + } + .card-info-trigger:hover { + opacity: 0.8; + } + .card-info-tooltip { + position: absolute; + bottom: 100%; + left: 50%; + transform: translateX(-50%); + margin-bottom: 0.4rem; + background: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: 8px; + padding: 0.5rem 0.65rem; + font-size: 0.7rem; + font-weight: 400; + line-height: 1.5; + color: var(--color-text-secondary); + text-transform: none; + letter-spacing: normal; + white-space: normal; + max-width: 240px; + width: max-content; + text-align: center; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); + z-index: 20; + } .card-value.positive { color: var(--nord14); } .card-value.negative { color: var(--nord11); } .card-value-na {