fix: cramped ingredient/step rows on mobile in recipe editor
Both rows packed 4+ inline fields (grip handle, quantity, unit, name, note for ingredients; step number, textarea, timer, delete for steps) into a single flex row with no mobile-aware wrap plan — flex-wrap on ingredients caused the delete button to float disconnected from its row, and steps had no wrap at all, squeezing the textarea down to a sliver. Both now split into two grouped rows below sm: breakpoint (core fields, then secondary field + delete) and collapse back to one row on larger screens. Not visually verified in a browser — this sandbox has no DB/dev server running (Docker unavailable), so this is typecheck+lint verified only. v0.46.2
This commit is contained in:
@@ -691,40 +691,44 @@ export function RecipeForm({ recipeId, defaultValues }: RecipeFormProps) {
|
||||
<Label>{t("ingredients")}</Label>
|
||||
<div className="space-y-2">
|
||||
{ingredients.map((ing, i) => (
|
||||
<div key={ing.id} className="flex flex-wrap gap-2 items-start">
|
||||
<GripVertical className="h-4 w-4 text-muted-foreground mt-2 cursor-grab shrink-0" />
|
||||
<Input
|
||||
value={ing.quantity}
|
||||
onChange={(e) => updateIngredient(i, { quantity: e.target.value })}
|
||||
placeholder={t("amount")}
|
||||
className="w-14 sm:w-16 shrink-0"
|
||||
/>
|
||||
<Input
|
||||
value={ing.unit}
|
||||
onChange={(e) => updateIngredient(i, { unit: e.target.value })}
|
||||
placeholder={t("unit")}
|
||||
className="w-16 sm:w-24 shrink-0"
|
||||
/>
|
||||
<Input
|
||||
value={ing.rawName}
|
||||
onChange={(e) => updateIngredient(i, { rawName: e.target.value })}
|
||||
placeholder={t("ingredient")}
|
||||
className="flex-1 min-w-[100px]"
|
||||
/>
|
||||
<Input
|
||||
value={ing.note}
|
||||
onChange={(e) => updateIngredient(i, { note: e.target.value })}
|
||||
placeholder={t("note")}
|
||||
className="w-full sm:w-48 sm:shrink-0"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => removeIngredient(i)}
|
||||
disabled={ingredients.length === 1}
|
||||
className="mt-1.5 text-muted-foreground hover:text-destructive transition-colors disabled:opacity-30"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</button>
|
||||
<div key={ing.id} className="flex flex-col sm:flex-row gap-2 sm:items-start">
|
||||
<div className="flex gap-2 items-start">
|
||||
<GripVertical className="h-4 w-4 text-muted-foreground mt-2 cursor-grab shrink-0" />
|
||||
<Input
|
||||
value={ing.quantity}
|
||||
onChange={(e) => updateIngredient(i, { quantity: e.target.value })}
|
||||
placeholder={t("amount")}
|
||||
className="w-16 shrink-0"
|
||||
/>
|
||||
<Input
|
||||
value={ing.unit}
|
||||
onChange={(e) => updateIngredient(i, { unit: e.target.value })}
|
||||
placeholder={t("unit")}
|
||||
className="w-16 sm:w-24 shrink-0"
|
||||
/>
|
||||
<Input
|
||||
value={ing.rawName}
|
||||
onChange={(e) => updateIngredient(i, { rawName: e.target.value })}
|
||||
placeholder={t("ingredient")}
|
||||
className="flex-1 min-w-0"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-2 items-start pl-6 sm:pl-0">
|
||||
<Input
|
||||
value={ing.note}
|
||||
onChange={(e) => updateIngredient(i, { note: e.target.value })}
|
||||
placeholder={t("note")}
|
||||
className="flex-1 sm:w-48 sm:shrink-0"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => removeIngredient(i)}
|
||||
disabled={ingredients.length === 1}
|
||||
className="mt-2 text-muted-foreground hover:text-destructive transition-colors disabled:opacity-30 shrink-0"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -835,33 +839,37 @@ export function RecipeForm({ recipeId, defaultValues }: RecipeFormProps) {
|
||||
<div className="space-y-3">
|
||||
{steps.map((step, i) => (
|
||||
<div key={step.id} className="space-y-1.5">
|
||||
<div className="flex gap-3 items-start">
|
||||
<div className="mt-2.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-muted text-xs font-bold text-muted-foreground">
|
||||
{i + 1}
|
||||
<div className="flex flex-col sm:flex-row gap-2 sm:gap-3">
|
||||
<div className="flex gap-3 flex-1 min-w-0">
|
||||
<div className="mt-2.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-muted text-xs font-bold text-muted-foreground">
|
||||
{i + 1}
|
||||
</div>
|
||||
<Textarea
|
||||
value={step.instruction}
|
||||
onChange={(e) => updateStep(i, { instruction: e.target.value })}
|
||||
placeholder={t("stepPlaceholder", { n: i + 1 })}
|
||||
rows={2}
|
||||
className="flex-1 min-w-0"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-2 items-start pl-9 sm:pl-0">
|
||||
<Input
|
||||
value={step.timerSeconds}
|
||||
onChange={(e) => updateStep(i, { timerSeconds: e.target.value })}
|
||||
placeholder={t("timerSeconds")}
|
||||
type="number"
|
||||
min={0}
|
||||
className="w-28 shrink-0"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => removeStep(i)}
|
||||
disabled={steps.length === 1}
|
||||
className="mt-2 text-muted-foreground hover:text-destructive transition-colors disabled:opacity-30 shrink-0"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
<Textarea
|
||||
value={step.instruction}
|
||||
onChange={(e) => updateStep(i, { instruction: e.target.value })}
|
||||
placeholder={t("stepPlaceholder", { n: i + 1 })}
|
||||
rows={2}
|
||||
className="flex-1 min-w-0"
|
||||
/>
|
||||
<Input
|
||||
value={step.timerSeconds}
|
||||
onChange={(e) => updateStep(i, { timerSeconds: e.target.value })}
|
||||
placeholder={t("timerSeconds")}
|
||||
type="number"
|
||||
min={0}
|
||||
className="w-28 shrink-0"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => removeStep(i)}
|
||||
disabled={steps.length === 1}
|
||||
className="mt-2.5 text-muted-foreground hover:text-destructive transition-colors disabled:opacity-30"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
{isBatchCook && dishes.some((d) => d.name.trim()) && (
|
||||
<div className="flex flex-wrap gap-1.5 pl-9">
|
||||
|
||||
Reference in New Issue
Block a user