recipes: view transitions for recipe detail navigation

Image morphs between CompactCard thumbnail and hero, title block
slides up from bottom, header persists across transitions. Only
activates for recipe detail navigations, not between list pages.
This commit is contained in:
2026-02-17 18:59:18 +01:00
parent 433ad43ead
commit 912e2b3fd5
5 changed files with 59 additions and 5 deletions
+1
View File
@@ -99,6 +99,7 @@ nav{
box-shadow: 0 1em 1rem 0rem rgba(0,0,0,0.4);
height: var(--header-h);
padding-left: 0.5rem;
view-transition-name: site-header;
}
.nav-toggle{
display: none;
+10 -1
View File
@@ -23,6 +23,11 @@
const img_color = $derived(recipe.images?.[0]?.color || '');
const isInSeason = $derived(icon_override || recipe.season?.includes(current_month));
function activateTransitions(event) {
const img = event.currentTarget.querySelector('.img-wrap img');
if (img) img.style.viewTransitionName = `recipe-${recipe.short_name}-img`;
}
</script>
<style>
.compact-card {
@@ -63,6 +68,7 @@
height: 100%;
object-fit: cover;
transition: transform 0.4s ease;
border-radius: var(--radius-card) var(--radius-card) 0 0;
}
.info {
position: relative;
@@ -157,7 +163,9 @@
}
</style>
<div class="compact-card">
<!-- svelte-ignore a11y_click_events_have_key_events -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div class="compact-card" onclick={activateTransitions}>
<a href="{routePrefix}/{recipe.short_name}" class="card-link" aria-label={recipe.name}></a>
{#if showFavoriteIndicator && isFavorite}
<span class="favorite">❤️</span>
@@ -167,6 +175,7 @@
src="https://bocken.org/static/rezepte/thumb/{img_name}"
alt={img_alt}
loading={loading_strat}
data-recipe={recipe.short_name}
/>
</div>
<div class="info">
@@ -1,7 +1,7 @@
<script>
import { onMount } from "svelte";
let { src, color = '', alt = "", children } = $props();
let { src, color = '', alt = "", transitionName = '', children } = $props();
let isredirected = $state(false);
@@ -145,7 +145,7 @@ dialog button{
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div class:zoom-in={!isredirected} onclick={show_dialog_img}>
<div class="image-wrap" style:background-color={color}>
<img class="image" {src} {alt}/>
<img class="image" {src} {alt} style:view-transition-name={transitionName || null}/>
</div>
<noscript>
<div class="image-wrap" style:background-color={color}>