fix: prevent hero image flash by aligning server/client random seed
All checks were successful
CI / update (push) Successful in 1m28s

Generate heroIndex on the server and pass it to the client so SSR and
hydration pick the same hero recipe, eliminating the image swap on
first interaction.
This commit is contained in:
2026-02-16 14:43:15 +01:00
parent c855cdd25c
commit 7922563c4d
3 changed files with 5 additions and 3 deletions

View File

@@ -19,6 +19,7 @@ export const load: PageServerLoad = async ({ fetch, locals, params }) => {
return { return {
season: addFavoriteStatusToRecipes(item_season, userFavorites), season: addFavoriteStatusToRecipes(item_season, userFavorites),
all_brief: addFavoriteStatusToRecipes(item_all_brief, userFavorites), all_brief: addFavoriteStatusToRecipes(item_all_brief, userFavorites),
session session,
heroIndex: Math.random()
}; };
}; };

View File

@@ -26,8 +26,8 @@
// Only recipes with hashed images (e.g. myrecipe.a1b2c3d4.webp) // Only recipes with hashed images (e.g. myrecipe.a1b2c3d4.webp)
const hasHashedImage = (r) => r.images?.length > 0 && /\.\w+\.\w+$/.test(r.images[0].mediapath); const hasHashedImage = (r) => r.images?.length > 0 && /\.\w+\.\w+$/.test(r.images[0].mediapath);
// Pick once on mount — not reactive, so image and link always match // Server-generated random index ensures SSR and client pick the same hero
const heroIndex = Math.random(); const heroIndex = data.heroIndex;
const heroRecipe = $derived.by(() => { const heroRecipe = $derived.by(() => {
const seasonPool = data.season.filter(hasHashedImage); const seasonPool = data.season.filter(hasHashedImage);
const pool = seasonPool.length > 0 ? seasonPool : data.all_brief.filter(hasHashedImage); const pool = seasonPool.length > 0 ? seasonPool : data.all_brief.filter(hasHashedImage);

View File

@@ -34,6 +34,7 @@ export async function load({ data }) {
...data, ...data,
all_brief: rand_array(allBrief), all_brief: rand_array(allBrief),
season: rand_array(seasonRecipes), season: rand_array(seasonRecipes),
heroIndex: Math.random(),
isOffline: true isOffline: true
}; };
} }