fix: mobile layout fixes, i18n coverage, and recipe share link

Mobile:
- Recipes search bar full-width on mobile instead of capped narrow
- Cook mode ingredients panel stacks above the step instead of
  squeezing it into a narrow column
- Version history Compare/Restore buttons wrap onto their own row
- Recipe edit ingredient fields wrap instead of forcing horizontal
  scroll on narrow viewports

i18n: translates remaining hardcoded strings across recipes
filter/sort, adapt-recipe and AI variations dialogs, the full
settings section (sidebar + 6 sub-pages + BYOK/model-prefs/
API-keys/webhooks managers), explore tab, collections (new/fork/
share dialogs), meal planning (planner, AI generation phases, new
shopping list, shared-plan view), photo import, recipe bulk-select
toolbar, and recipe action-button tooltips. Also fixes the recipes
page subtitle, which wasn't just unworded but missing its {count}
interpolation entirely — it always rendered as the bare word
"results" regardless of how many recipes existed.

Feature: adds a ShareRecipeButton that copies the public /r/{id}
link to the clipboard, with a notice when the recipe isn't Public
yet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Arnaud
2026-07-02 15:13:51 +02:00
parent b07bada291
commit eb424d8c04
44 changed files with 932 additions and 376 deletions
+5 -5
View File
@@ -341,31 +341,31 @@ 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 gap-2 items-start">
<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-16 shrink-0"
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-24 shrink-0"
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"
className="flex-1 min-w-[100px]"
/>
<Input
value={ing.note}
onChange={(e) => updateIngredient(i, { note: e.target.value })}
placeholder={t("note")}
className="w-48 shrink-0"
className="w-full sm:w-48 sm:shrink-0"
/>
<button
type="button"