refactor(shopping): extract ShoppingChecklist.svelte to eliminate mobile/desktop duplication
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
92
frontend/src/lib/shopping/ShoppingChecklist.svelte
Normal file
92
frontend/src/lib/shopping/ShoppingChecklist.svelte
Normal file
@@ -0,0 +1,92 @@
|
||||
<script lang="ts">
|
||||
import ChecklistItem from '$lib/shopping/ChecklistItem.svelte';
|
||||
import AddCustomItem from '$lib/shopping/AddCustomItem.svelte';
|
||||
|
||||
interface RecipeRef {
|
||||
id?: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
interface Item {
|
||||
id?: string;
|
||||
name?: string;
|
||||
quantity?: number;
|
||||
unit?: string;
|
||||
isChecked?: boolean;
|
||||
sourceRecipes?: RecipeRef[];
|
||||
}
|
||||
|
||||
interface Props {
|
||||
listId: string;
|
||||
uncheckedItems: Item[];
|
||||
checkedItems: Item[];
|
||||
totalItems: number;
|
||||
filteredStaplesCount?: number;
|
||||
showFilteredStaples?: boolean;
|
||||
}
|
||||
|
||||
let {
|
||||
listId,
|
||||
uncheckedItems,
|
||||
checkedItems,
|
||||
totalItems,
|
||||
filteredStaplesCount = 0,
|
||||
showFilteredStaples = false
|
||||
}: Props = $props();
|
||||
|
||||
let checkedCount = $derived(checkedItems.length);
|
||||
</script>
|
||||
|
||||
{#if uncheckedItems.length > 0}
|
||||
<div class="divide-y divide-[var(--color-border)]">
|
||||
{#each uncheckedItems as item (item.id)}
|
||||
<ChecklistItem
|
||||
{listId}
|
||||
itemId={item.id ?? ''}
|
||||
name={item.name ?? ''}
|
||||
quantity={item.quantity ?? null}
|
||||
unit={item.unit ?? null}
|
||||
isChecked={false}
|
||||
sourceRecipes={item.sourceRecipes ?? []}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{:else if totalItems > 0}
|
||||
<p class="py-4 text-center font-[var(--font-sans)] text-[14px] text-[var(--color-text-muted)]">
|
||||
Alles erledigt!
|
||||
</p>
|
||||
{/if}
|
||||
|
||||
<div class="mt-3">
|
||||
<AddCustomItem {listId} />
|
||||
</div>
|
||||
|
||||
{#if showFilteredStaples && filteredStaplesCount > 0}
|
||||
<div class="mt-3 rounded-[var(--radius-md)] border border-[var(--color-border)] bg-[var(--color-surface)] px-3 py-2">
|
||||
<p class="font-[var(--font-sans)] text-[12px] text-[var(--color-text-muted)]">
|
||||
{filteredStaplesCount} Grundzutaten ausgeblendet ·
|
||||
<a href="/pantry" class="font-medium text-[var(--green-dark)] hover:underline">Vorrat bearbeiten</a>
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if checkedItems.length > 0}
|
||||
<div class="mt-4">
|
||||
<p class="mb-1 font-[var(--font-sans)] text-[12px] font-medium uppercase tracking-wide text-[var(--color-text-muted)]">
|
||||
Abgehakt ({checkedCount})
|
||||
</p>
|
||||
<div class="divide-y divide-[var(--color-border)]">
|
||||
{#each checkedItems as item (item.id)}
|
||||
<ChecklistItem
|
||||
{listId}
|
||||
itemId={item.id ?? ''}
|
||||
name={item.name ?? ''}
|
||||
quantity={item.quantity ?? null}
|
||||
unit={item.unit ?? null}
|
||||
isChecked={true}
|
||||
sourceRecipes={item.sourceRecipes ?? []}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import ShoppingHeader from '$lib/shopping/ShoppingHeader.svelte';
|
||||
import ChecklistItem from '$lib/shopping/ChecklistItem.svelte';
|
||||
import AddCustomItem from '$lib/shopping/AddCustomItem.svelte';
|
||||
import ShoppingChecklist from '$lib/shopping/ShoppingChecklist.svelte';
|
||||
import RecipeReferencePanel from '$lib/shopping/RecipeReferencePanel.svelte';
|
||||
|
||||
let { data } = $props();
|
||||
@@ -65,63 +64,14 @@
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<!-- Unchecked items -->
|
||||
{#if uncheckedItems.length > 0}
|
||||
<div class="divide-y divide-[var(--color-border)]">
|
||||
{#each uncheckedItems as item (item.id)}
|
||||
<ChecklistItem
|
||||
{listId}
|
||||
itemId={item.id ?? ''}
|
||||
name={item.name ?? ''}
|
||||
quantity={item.quantity ?? null}
|
||||
unit={item.unit ?? null}
|
||||
isChecked={false}
|
||||
sourceRecipes={item.sourceRecipes ?? []}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{:else if totalItems > 0}
|
||||
<p class="py-4 text-center font-[var(--font-sans)] text-[14px] text-[var(--color-text-muted)]">
|
||||
Alles erledigt!
|
||||
</p>
|
||||
{/if}
|
||||
|
||||
<!-- Add custom item -->
|
||||
<div class="mt-3">
|
||||
<AddCustomItem {listId} />
|
||||
</div>
|
||||
|
||||
<!-- Filtered staples info (mobile) -->
|
||||
{#if filteredStaplesCount > 0}
|
||||
<div class="mt-3 rounded-[var(--radius-md)] border border-[var(--color-border)] bg-[var(--color-surface)] px-3 py-2">
|
||||
<p class="font-[var(--font-sans)] text-[12px] text-[var(--color-text-muted)]">
|
||||
{filteredStaplesCount} Grundzutaten ausgeblendet ·
|
||||
<a href="/pantry" class="font-medium text-[var(--green-dark)] hover:underline">Vorrat bearbeiten</a>
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Checked items -->
|
||||
{#if checkedItems.length > 0}
|
||||
<div class="mt-4">
|
||||
<p class="mb-1 font-[var(--font-sans)] text-[12px] font-medium uppercase tracking-wide text-[var(--color-text-muted)]">
|
||||
Abgehakt ({checkedCount})
|
||||
</p>
|
||||
<div class="divide-y divide-[var(--color-border)]">
|
||||
{#each checkedItems as item (item.id)}
|
||||
<ChecklistItem
|
||||
{listId}
|
||||
itemId={item.id ?? ''}
|
||||
name={item.name ?? ''}
|
||||
quantity={item.quantity ?? null}
|
||||
unit={item.unit ?? null}
|
||||
isChecked={true}
|
||||
sourceRecipes={item.sourceRecipes ?? []}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<ShoppingChecklist
|
||||
{listId}
|
||||
{uncheckedItems}
|
||||
{checkedItems}
|
||||
{totalItems}
|
||||
{filteredStaplesCount}
|
||||
showFilteredStaples={true}
|
||||
/>
|
||||
{/if}
|
||||
</main>
|
||||
</div>
|
||||
@@ -170,53 +120,12 @@
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<!-- Unchecked items -->
|
||||
{#if uncheckedItems.length > 0}
|
||||
<div class="divide-y divide-[var(--color-border)]">
|
||||
{#each uncheckedItems as item (item.id)}
|
||||
<ChecklistItem
|
||||
{listId}
|
||||
itemId={item.id ?? ''}
|
||||
name={item.name ?? ''}
|
||||
quantity={item.quantity ?? null}
|
||||
unit={item.unit ?? null}
|
||||
isChecked={false}
|
||||
sourceRecipes={item.sourceRecipes ?? []}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{:else if totalItems > 0}
|
||||
<p class="py-4 text-center font-[var(--font-sans)] text-[14px] text-[var(--color-text-muted)]">
|
||||
Alles erledigt!
|
||||
</p>
|
||||
{/if}
|
||||
|
||||
<!-- Add custom item -->
|
||||
<div class="mt-4">
|
||||
<AddCustomItem {listId} />
|
||||
</div>
|
||||
|
||||
<!-- Checked items -->
|
||||
{#if checkedItems.length > 0}
|
||||
<div class="mt-6 border-t border-[var(--color-border)] pt-4">
|
||||
<p class="mb-1 font-[var(--font-sans)] text-[12px] font-medium uppercase tracking-wide text-[var(--color-text-muted)]">
|
||||
Abgehakt ({checkedCount})
|
||||
</p>
|
||||
<div class="divide-y divide-[var(--color-border)]">
|
||||
{#each checkedItems as item (item.id)}
|
||||
<ChecklistItem
|
||||
{listId}
|
||||
itemId={item.id ?? ''}
|
||||
name={item.name ?? ''}
|
||||
quantity={item.quantity ?? null}
|
||||
unit={item.unit ?? null}
|
||||
isChecked={true}
|
||||
sourceRecipes={item.sourceRecipes ?? []}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<ShoppingChecklist
|
||||
{listId}
|
||||
{uncheckedItems}
|
||||
{checkedItems}
|
||||
{totalItems}
|
||||
/>
|
||||
{/if}
|
||||
</main>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user