Button only renders when onremove callback is provided, keeping the component usable in read-only contexts without the destructive action. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
123 lines
4.2 KiB
Svelte
123 lines
4.2 KiB
Svelte
<script lang="ts">
|
|
interface SlotRecipe {
|
|
id: string;
|
|
name: string;
|
|
effort?: string;
|
|
cookTimeMin?: number;
|
|
}
|
|
|
|
interface Slot {
|
|
id?: string;
|
|
slotDate?: string;
|
|
recipe: SlotRecipe | null;
|
|
}
|
|
|
|
interface Props {
|
|
open: boolean;
|
|
slot: Slot;
|
|
onswap: () => void;
|
|
oncancel: () => void;
|
|
onremove?: () => void;
|
|
}
|
|
|
|
let { open, slot, onswap, oncancel, onremove }: Props = $props();
|
|
|
|
const meta = $derived.by(() => {
|
|
const parts: string[] = [];
|
|
if (slot.recipe?.cookTimeMin != null) parts.push(`${slot.recipe.cookTimeMin} min`);
|
|
if (slot.recipe?.effort) parts.push(slot.recipe.effort);
|
|
return parts.join(' · ');
|
|
});
|
|
|
|
$effect(() => {
|
|
if (!open) return;
|
|
|
|
function handleKeydown(e: KeyboardEvent) {
|
|
if (e.key === 'Escape') oncancel();
|
|
}
|
|
|
|
window.addEventListener('keydown', handleKeydown);
|
|
return () => window.removeEventListener('keydown', handleKeydown);
|
|
});
|
|
</script>
|
|
|
|
{#if open}
|
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
<div
|
|
role="presentation"
|
|
data-testid="sheet-backdrop"
|
|
style="position:fixed;inset:0;z-index:50;background:rgba(28,28,24,0.4)"
|
|
onclick={oncancel}
|
|
>
|
|
<div
|
|
role="dialog"
|
|
aria-modal="true"
|
|
tabindex="-1"
|
|
style="position:absolute;bottom:0;left:0;right:0;background:var(--color-page);border-radius:var(--radius-xl) var(--radius-xl) 0 0;box-shadow:var(--shadow-overlay)"
|
|
onclick={(e) => e.stopPropagation()}
|
|
>
|
|
<!-- Drag handle -->
|
|
<div style="display:flex;justify-content:center;margin-top:12px">
|
|
<div style="width:32px;height:4px;background:var(--color-border);border-radius:9999px"></div>
|
|
</div>
|
|
|
|
<!-- Meal title -->
|
|
<p style="font-family:var(--font-display);font-size:15px;font-weight:500;color:var(--color-text);padding:0 16px;margin:12px 0 4px">
|
|
{slot.recipe?.name ?? ''}
|
|
</p>
|
|
|
|
<!-- Metadata -->
|
|
{#if meta}
|
|
<p style="font-family:var(--font-sans);font-size:11px;color:var(--color-text-muted);padding:0 16px 12px;margin:0">
|
|
{meta}
|
|
</p>
|
|
{/if}
|
|
|
|
<!-- Actions -->
|
|
<div style="padding:0 16px 16px;display:flex;flex-direction:column;gap:6px">
|
|
<button
|
|
type="button"
|
|
style="width:100%;background:var(--orange-tint);border:1px solid #FBCDA4;color:var(--orange-dark);font-family:var(--font-sans);font-size:13px;font-weight:500;border-radius:var(--radius-lg);padding:12px;text-align:center;cursor:pointer"
|
|
onclick={onswap}
|
|
>
|
|
↻ Gericht tauschen
|
|
</button>
|
|
|
|
{#if onremove}
|
|
<button
|
|
type="button"
|
|
style="width:100%;background:var(--color-error, #d9534f);border:1px solid var(--color-error, #d9534f);color:#fff;font-family:var(--font-sans);font-size:13px;font-weight:500;border-radius:var(--radius-lg);padding:12px;text-align:center;cursor:pointer"
|
|
onclick={onremove}
|
|
>
|
|
✕ Gericht entfernen
|
|
</button>
|
|
{/if}
|
|
|
|
{#if slot.recipe}
|
|
<a
|
|
href="/recipes/{slot.recipe.id}/cook"
|
|
style="display:block;width:100%;background:var(--green-tint);border:1px solid var(--green-light);color:var(--green-dark);font-family:var(--font-sans);font-size:13px;font-weight:500;border-radius:var(--radius-lg);padding:12px;text-align:center;box-sizing:border-box;text-decoration:none"
|
|
>
|
|
🍳 Jetzt kochen
|
|
</a>
|
|
|
|
<a
|
|
href="/recipes/{slot.recipe.id}"
|
|
style="display:block;width:100%;background:var(--color-subtle);border:1px solid var(--color-border);color:var(--color-text-muted);font-family:var(--font-sans);font-size:13px;font-weight:500;border-radius:var(--radius-lg);padding:12px;text-align:center;box-sizing:border-box;text-decoration:none"
|
|
>
|
|
👁 Rezept ansehen
|
|
</a>
|
|
{/if}
|
|
|
|
<button
|
|
type="button"
|
|
style="width:100%;background:none;border:none;color:var(--color-text-muted);font-family:var(--font-sans);font-size:13px;text-align:center;cursor:pointer;padding:12px"
|
|
onclick={oncancel}
|
|
>
|
|
Abbrechen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{/if}
|