feat(planner): add RecipePickerDrawer slide-in drawer
Wraps RecipePicker in a fixed right-side drawer with backdrop. Slide-in/out transition, backdrop click closes, purely presentational (open + onclose props from parent). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
77
frontend/src/lib/planner/RecipePickerDrawer.svelte
Normal file
77
frontend/src/lib/planner/RecipePickerDrawer.svelte
Normal file
@@ -0,0 +1,77 @@
|
||||
<script lang="ts">
|
||||
import type { Recipe, Suggestion } from '$lib/planner/types';
|
||||
import RecipePicker from './RecipePicker.svelte';
|
||||
|
||||
let {
|
||||
open,
|
||||
slotDate,
|
||||
planId,
|
||||
suggestions,
|
||||
allRecipes,
|
||||
isLoading,
|
||||
onpick,
|
||||
onclose,
|
||||
excludeRecipeId,
|
||||
replacingRecipe
|
||||
}: {
|
||||
open: boolean;
|
||||
slotDate: string;
|
||||
planId: string;
|
||||
suggestions: Suggestion[];
|
||||
allRecipes: Recipe[];
|
||||
isLoading: boolean;
|
||||
onpick: (recipeId: string, recipeName: string) => void;
|
||||
onclose: () => void;
|
||||
excludeRecipeId?: string;
|
||||
replacingRecipe?: { name: string; meta?: string };
|
||||
} = $props();
|
||||
|
||||
let drawerTransform = $derived(open ? 'translateX(0)' : 'translateX(100%)');
|
||||
let backdropVisibility = $derived(open ? 'visible' : 'hidden');
|
||||
let backdropOpacity = $derived(open ? '1' : '0');
|
||||
</script>
|
||||
|
||||
<!-- Backdrop -->
|
||||
<div
|
||||
data-testid="drawer-backdrop"
|
||||
aria-hidden="true"
|
||||
onclick={onclose}
|
||||
style="position: fixed; inset: 0; background: rgba(0,0,0,0.3); z-index: 40; visibility: {backdropVisibility}; opacity: {backdropOpacity}; transition: opacity 0.2s, visibility 0.2s;"
|
||||
></div>
|
||||
|
||||
<!-- Drawer panel -->
|
||||
<div
|
||||
data-testid="recipe-picker-drawer"
|
||||
aria-hidden={!open}
|
||||
style="position: fixed; right: 0; top: 0; height: 100%; width: min(480px, 90vw); background: var(--color-page); border-left: 1px solid var(--color-border); z-index: 50; transform: {drawerTransform}; transition: transform 0.25s ease; display: flex; flex-direction: column;"
|
||||
>
|
||||
<!-- Header -->
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; border-bottom: 1px solid var(--color-border); flex-shrink: 0;">
|
||||
<p style="margin: 0; font-family: var(--font-display); font-size: 15px; font-weight: 500; color: var(--color-text);">
|
||||
Rezept wählen
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Schließen"
|
||||
onclick={onclose}
|
||||
style="background: none; border: none; cursor: pointer; font-size: 20px; line-height: 1; color: var(--color-text-muted); padding: 4px 8px;"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- RecipePicker content -->
|
||||
<div style="overflow-y: auto; flex: 1;">
|
||||
<RecipePicker
|
||||
{planId}
|
||||
date={slotDate}
|
||||
dateLabel={slotDate}
|
||||
{suggestions}
|
||||
{allRecipes}
|
||||
{isLoading}
|
||||
{onpick}
|
||||
{excludeRecipeId}
|
||||
{replacingRecipe}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user