Files
mealprep/frontend/src/lib/shopping/ChecklistItem.svelte
Marcel Raddatz be43fe94b6 fix(shopping): address frontend review concerns
- ChecklistItem: use:enhance with reset:false, role=checkbox, aria-checked, focus ring
- RecipeReferencePanel: day abbreviation text-[12px] (was 11px)
- ShoppingHeader: generating pending state disables button during submit
- AddCustomItem: only collapse form on successful submission

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 19:54:25 +02:00

82 lines
2.2 KiB
Svelte

<script lang="ts">
import { enhance } from '$app/forms';
interface RecipeRef {
id?: string;
name?: string;
}
interface Props {
listId: string;
itemId: string;
name: string;
quantity: number | null;
unit: string | null;
isChecked: boolean;
sourceRecipes: RecipeRef[];
}
let { listId, itemId, name, quantity, unit, isChecked, sourceRecipes }: Props = $props();
let recipeLabel = $derived(
sourceRecipes.length > 0
? sourceRecipes
.map((r) => r.name)
.filter(Boolean)
.join(', ')
: null
);
let quantityLabel = $derived(
quantity ? `${quantity}${unit ? ` ${unit}` : ''}` : null
);
</script>
<form method="POST" action="?/check" use:enhance={() => async ({ update }) => update({ reset: false })} class="group flex items-center gap-3 py-2">
<input type="hidden" name="listId" value={listId} />
<input type="hidden" name="itemId" value={itemId} />
<input type="hidden" name="isChecked" value={!isChecked} />
<button
type="submit"
role="checkbox"
aria-checked={isChecked}
aria-label="{isChecked ? 'Abhaken rückgängig' : 'Abhaken'}: {name}"
class="flex h-5 w-5 flex-shrink-0 items-center justify-center rounded border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--green)]
{isChecked
? 'border-[var(--green)] bg-[var(--green)] text-white'
: 'border-[var(--color-border)] bg-[var(--color-surface)] hover:border-[var(--green-light)]'}"
>
{#if isChecked}
<svg class="h-3 w-3" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2">
<path d="M2 6l3 3 5-5" />
</svg>
{/if}
</button>
<div class="min-w-0 flex-1">
<p
class="font-[var(--font-sans)] text-[14px] {isChecked
? 'text-[var(--color-text-muted)] line-through'
: 'text-[var(--color-text)]'}"
>
{name}
</p>
{#if recipeLabel && !isChecked}
<p class="truncate font-[var(--font-sans)] text-[11px] text-[var(--color-text-muted)]">
Für: {recipeLabel}
</p>
{/if}
</div>
{#if quantityLabel}
<span
class="flex-shrink-0 font-[var(--font-sans)] text-[13px] {isChecked
? 'text-[var(--color-text-muted)]'
: 'text-[var(--color-text)]'}"
>
{quantityLabel}
</span>
{/if}
</form>