feat(suggestions): C2 — Meal suggestions (variety-aware) (#40)
feat(suggestions): implement C2 meal suggestion screen (Issue #27) Co-authored-by: Marcel Raddatz <marcel@raddatz.cloud> Co-committed-by: Marcel Raddatz <marcel@raddatz.cloud>
This commit was merged in pull request #40.
This commit is contained in:
83
frontend/src/lib/planner/SuggestionCard.svelte
Normal file
83
frontend/src/lib/planner/SuggestionCard.svelte
Normal file
@@ -0,0 +1,83 @@
|
||||
<script lang="ts">
|
||||
interface SlotRecipe {
|
||||
id?: string;
|
||||
name?: string;
|
||||
effort?: string;
|
||||
cookTimeMin?: number;
|
||||
}
|
||||
|
||||
interface Suggestion {
|
||||
recipe?: SlotRecipe;
|
||||
simulatedScore?: number;
|
||||
reasoningType?: 'good' | 'warning';
|
||||
reasoningLabel?: string;
|
||||
}
|
||||
|
||||
let {
|
||||
suggestion,
|
||||
rank,
|
||||
planId,
|
||||
slotDate,
|
||||
weekStart
|
||||
}: {
|
||||
suggestion: Suggestion;
|
||||
rank: number;
|
||||
planId: string;
|
||||
slotDate: string;
|
||||
weekStart: string;
|
||||
} = $props();
|
||||
|
||||
let metadata = $derived(
|
||||
[
|
||||
suggestion.recipe?.cookTimeMin != null ? `${suggestion.recipe.cookTimeMin} Min` : null,
|
||||
suggestion.recipe?.effort ?? null
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' · ')
|
||||
);
|
||||
</script>
|
||||
|
||||
<div class="flex items-start gap-3 rounded-[var(--radius-md)] border border-[var(--color-border)] bg-[var(--color-surface)] px-4 py-3 shadow-[var(--shadow-card)]">
|
||||
<!-- Rank number -->
|
||||
<div class="w-10 flex-shrink-0 self-start text-right">
|
||||
<span class="font-[var(--font-display)] text-[32px] font-[300] leading-none text-[var(--color-text-muted)]">{rank}</span>
|
||||
</div>
|
||||
|
||||
<!-- Card content -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="font-[var(--font-sans)] text-[15px] font-medium text-[var(--color-text)] line-clamp-2">
|
||||
{suggestion.recipe?.name ?? 'Unbekanntes Rezept'}
|
||||
</p>
|
||||
{#if metadata}
|
||||
<p class="mt-0.5 font-[var(--font-sans)] text-[12px] text-[var(--color-text-muted)]">{metadata}</p>
|
||||
{/if}
|
||||
|
||||
<!-- Reasoning badge -->
|
||||
{#if suggestion.reasoningType && suggestion.reasoningLabel}
|
||||
<div
|
||||
data-testid="reasoning-badge"
|
||||
data-type={suggestion.reasoningType}
|
||||
class="mt-2 inline-flex items-center rounded-full px-2 py-0.5 font-[var(--font-sans)] text-[11px] font-medium
|
||||
{suggestion.reasoningType === 'good'
|
||||
? 'bg-[var(--green-tint)] text-[var(--green-dark)]'
|
||||
: 'bg-[var(--yellow-tint)] text-[var(--yellow-text)]'}"
|
||||
>
|
||||
{suggestion.reasoningType === 'good' ? '✓' : '⚠'} {suggestion.reasoningLabel}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Pick action -->
|
||||
<form method="POST" action="?/pickSuggestion" class="flex-shrink-0">
|
||||
<input type="hidden" name="planId" value={planId} />
|
||||
<input type="hidden" name="recipeId" value={suggestion.recipe?.id} />
|
||||
<input type="hidden" name="slotDate" value={slotDate} />
|
||||
<input type="hidden" name="weekStart" value={weekStart} />
|
||||
<button
|
||||
type="submit"
|
||||
class="font-[var(--font-sans)] text-[13px] font-medium tracking-[0.04em] text-[var(--green-dark)] hover:underline"
|
||||
>
|
||||
Wählen
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
Reference in New Issue
Block a user