From 0da3b130e44ae0fab1bebb88b81dd92d2edb1167 Mon Sep 17 00:00:00 2001 From: Alexander Bocken Date: Thu, 23 Apr 2026 15:30:05 +0200 Subject: [PATCH] fix(fitness/stats): wrap streamed muscle heatmap in {#await} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The $state + $effect pattern I used for the muscle heatmap in bb0895c didn't propagate the streamed promise into the component's internal $derived(data.totals) chain — the hover counts stayed at zero even after the data arrived. Switch just the heatmap to an {#await} block so it mounts once with the fully-resolved object. The nutrition card shells, periods, and shared periods keep their $state pattern because the card templates read individual fields directly (which gracefully fall through to the "—" branches while pending) and re-rendering once the value arrives is fine. Also drops the two reverted commits for the set-subfield projection (4d1fed6, fe8d036); those are replaced later with a safer narrowing that keeps whole set objects. --- package.json | 2 +- .../fitness/[stats=fitnessStats]/+page.svelte | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 5f1e4dfc..f636211f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homepage", - "version": "1.46.19", + "version": "1.46.20", "private": true, "type": "module", "scripts": { diff --git a/src/routes/fitness/[stats=fitnessStats]/+page.svelte b/src/routes/fitness/[stats=fitnessStats]/+page.svelte index 5a3e35d1..1de683d6 100644 --- a/src/routes/fitness/[stats=fitnessStats]/+page.svelte +++ b/src/routes/fitness/[stats=fitnessStats]/+page.svelte @@ -120,20 +120,17 @@ }] }); - // Streamed panels: render empty shells on SSR/initial hydrate, then fill - // in once the server-sent promise resolves. Defaults match the previous - // error-fallback shapes so the existing `!= null` checks cascade to the - // "—" branches while the data is in flight. + // Streamed panels. nutrition / periods resolve through $state so the card + // shells render immediately with "—" placeholders; muscle heatmap is + // wrapped in {#await} below instead because its internal $derived chain + // needs the full resolved object in one shot to render correctly. /** @type {any} */ let ns = $state({}); - /** @type {{ weeks: any[]; totals: any; muscleGroups: any[] }} */ - let muscleHeatmapData = $state({ weeks: [], totals: {}, muscleGroups: [] }); /** @type {any[]} */ let periodsData = $state([]); /** @type {any[]} */ let sharedPeriodsData = $state([]); $effect(() => { Promise.resolve(data.nutritionStats).then(v => { ns = v ?? {}; }); }); - $effect(() => { Promise.resolve(data.muscleHeatmap).then(v => { muscleHeatmapData = v ?? { weeks: [], totals: {}, muscleGroups: [] }; }); }); $effect(() => { Promise.resolve(data.periods).then(v => { periodsData = v ?? []; }); }); $effect(() => { Promise.resolve(data.sharedPeriods).then(v => { sharedPeriodsData = v ?? []; }); }); @@ -500,7 +497,9 @@

{t('muscle_balance', lang)}

- + {#await data.muscleHeatmap then muscleHeatmap} + + {/await}