- RecipeHero: render tag pills, min-h-[200px/240px], fix back link styling, remove font-[400] - IngredientList: sort by sortOrder ascending - StepList: aria-hidden on step circles - types.ts: add Tag, Ingredient, Step, RecipeDetail shared types - +page.svelte: add Edit link → /recipes/[id]/edit (desktop topbar) - Tests: tag pills, sortOrder sort, edit link, image variant, 403-as-404 documented Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
71 lines
2.1 KiB
Svelte
71 lines
2.1 KiB
Svelte
<script lang="ts">
|
|
import type { Tag } from './types';
|
|
|
|
type RecipeHeroData = {
|
|
id: string;
|
|
name: string;
|
|
serves?: number;
|
|
cookTimeMin?: number;
|
|
effort?: string;
|
|
heroImageUrl?: string;
|
|
tags: Tag[];
|
|
};
|
|
|
|
let { recipe }: { recipe: RecipeHeroData } = $props();
|
|
|
|
let hasImage = $derived(!!recipe.heroImageUrl);
|
|
|
|
let pillBase = $derived(
|
|
hasImage
|
|
? 'bg-white/20 text-[13px] font-medium font-sans px-[10px] py-[4px] rounded-full'
|
|
: 'bg-[var(--color-border)] text-[var(--color-text-muted)] text-[13px] font-medium font-sans px-[10px] py-[4px] rounded-full'
|
|
);
|
|
|
|
let cookBtnClass = $derived(
|
|
hasImage
|
|
? 'font-sans text-[13px] font-medium tracking-[0.04em] bg-white text-[var(--green-dark)] rounded-[var(--radius-md)] px-[24px] py-[12px] mt-[16px] inline-block'
|
|
: 'font-sans text-[13px] font-medium tracking-[0.04em] bg-[var(--green-dark)] text-white rounded-[var(--radius-md)] px-[24px] py-[12px] mt-[16px] inline-block'
|
|
);
|
|
</script>
|
|
|
|
<div
|
|
data-testid="recipe-hero"
|
|
class="min-h-[200px] md:min-h-[240px] {hasImage
|
|
? 'relative text-white'
|
|
: 'bg-[var(--green-tint)] text-[var(--color-text)]'} p-[24px] md:p-[32px]"
|
|
>
|
|
{#if hasImage}
|
|
<img
|
|
src={recipe.heroImageUrl}
|
|
alt={recipe.name}
|
|
class="object-cover w-full h-full absolute inset-0"
|
|
/>
|
|
<div class="absolute inset-0" style="background: rgba(0,0,0,0.5);"></div>
|
|
{/if}
|
|
|
|
<div class="relative">
|
|
<a href="/recipes" class="text-[13px] font-sans font-medium text-[var(--color-text-muted)]">← Zurück</a>
|
|
|
|
<h1 class="font-[var(--font-display)] text-[24px] md:text-[28px] mt-[8px]">
|
|
{recipe.name}
|
|
</h1>
|
|
|
|
<div class="flex gap-[8px] flex-wrap mt-[12px]">
|
|
{#if recipe.cookTimeMin != null}
|
|
<span class={pillBase}>{recipe.cookTimeMin} Min</span>
|
|
{/if}
|
|
{#if recipe.effort}
|
|
<span class={pillBase}>{recipe.effort}</span>
|
|
{/if}
|
|
{#if recipe.serves != null}
|
|
<span class={pillBase}>{recipe.serves} Port.</span>
|
|
{/if}
|
|
{#each recipe.tags as tag (tag.id)}
|
|
<span class={pillBase}>{tag.name}</span>
|
|
{/each}
|
|
</div>
|
|
|
|
<a href="/cook/{recipe.id}" class={cookBtnClass}>Jetzt kochen</a>
|
|
</div>
|
|
</div>
|