MealReviewCard
The card shell around a "confirm/edit this logged meal" screen — a name field, an optional quantity hint, and slots for the portion/gram + macro stepper controls (yemek's own NumberStepper), used before an AI recognition result or a search-picked product is actually saved.
Playground
Werte überprüfen
1 Portion ≈ 350g
Click "Als verzehrt markieren" — a checkmark pulses immediately, then the button shows a spinner (simulating a ~1.2s save call) before returning to normal. Toggle off the quantity slot to see the search-picked-product variant (no portion baseline). The steppers here are the real NumberStepper component, not placeholders — try nudging a value.
vue
<script setup>
import { MealReviewCard, NumberStepper } from 'yemek'
const confirmName = ref('...')
const saving = ref(false)
async function saveMeal() {
saving.value = true
await supabase.from('meals').insert({ /* ... */ })
saving.value = false
}
</script>
<template>
<MealReviewCard
title="Werte überprüfen"
v-model:name="confirmName"
name-label="Bezeichnung"
:quantity-hint="`1 Portion ≈ ${basePortionGrams}g`"
confirm-label="Als verzehrt markieren"
:saving="saving"
@confirm="saveMeal"
>
<template #quantity>
<div class="grid-2">
<NumberStepper v-model="portionCount" :min="0.25" :max="20" :step="0.5" @update:model-value="updateFromPortions" />
<NumberStepper v-model="gramsAmount" :step-percent="0.1" :min="0" :max="9999" @update:model-value="updateFromGrams" />
</div>
</template>
<template #macros>
<div class="grid-2">
<NumberStepper v-model="confirmCalories" accent-color="var(--yemek-nutrient-calories)" :min="0" :max="4000" />
<NumberStepper v-model="confirmProtein" accent-color="var(--yemek-nutrient-protein)" :min="0" :max="300" />
<NumberStepper v-model="confirmCarbs" accent-color="var(--yemek-nutrient-carbs)" :min="0" :max="500" />
<NumberStepper v-model="confirmFat" accent-color="var(--yemek-nutrient-fat)" :min="0" :max="300" />
</div>
</template>
</MealReviewCard>
</template>Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Card heading. |
name | string | — | Meal name (v-model). |
nameLabel | string | — | Already-localized label above the name field. |
quantityHint | string | undefined | Already-formatted, e.g. "1 Portion ≈ 350g". Omit for a search-picked product with no portion baseline — the #quantity slot section then also doesn't render. |
confirmLabel | string | — | Confirm button label. |
saving | boolean | false | Disables the button and shows a spinner while the consumer's save call is in flight. |
Slots
| Slot | Description |
|---|---|
quantity | The portion/gram stepper controls (only rendered — including the quantityHint line — when this slot has content). Typically yemek's own NumberStepper. |
macros | The calorie/protein/carbs/fat stepper controls. Rendered with display: contents, so the consumer's own grid wrapper fully controls layout. |
Events
| Event | Payload | Fired when |
|---|---|---|
update:name | string | The name field changes (standard v-model). |
confirm | — | The confirm button is clicked (not fired while saving is true). |
Behavior notes
- No portion/gram scaling math and no macro clamping live in the component — those stay the consumer's domain logic (in meal-tracker's case,
app/lib/portions.ts/mealLimits.ts). The slots hold the actual stepper controls — yemek's ownNumberStepper, or any other input the consumer prefers. - Clicking confirm triggers an immediate checkmark-pulse micro-interaction (500ms) before
saving's spinner (if the consumer sets it) takes over — feedback that the click registered, replacing a plain button with zero click feedback. prefers-reduced-motion: reducedisables the checkmark-pulse/pop animations and slows the spinner's rotation instead of stopping it entirely (it's a loading indicator, not decorative).- The quantity panel's background is derived relative to the card's own surface (
color-mix(in srgb, var(--yemek-color-text) 5%, var(--yemek-color-surface))), not the separate-insettoken — same lesson as ChoicePicker's #39 fix, guarantees the panel reads as visibly distinct regardless of how close a host theme's-surface/-insetpair happen to be. - The confirm button uses
--yemek-radius-sm(sharper), not-md— flagged as reading too rounded/pill-like next to the rest of the framework's more angular buttons.