feat: private accounts, explore/people merge, meal-plan fixes, i18n and theme cleanup

- Private accounts: users.isPrivate hides a user from search and their
  recipes from search/trending/for-you discovery surfaces (follow-aware
  where the route already has session context, blanket exclusion where it
  doesn't); existing followers and direct links are unaffected, no
  follow-request approval flow was built (explicit scope limit)
- Merged /people into the Explore tab (tab=people query param); the old
  standalone route now redirects there
- "Get Ideas" vs "Surprise Me" were doing the same empty-prompt call;
  Surprise Me now injects a real random constraint (5-ingredient, one-pot,
  etc.), matching the existing pattern in the AI recipe-generate dialog
- Meal-plan day cells now link to their recipe (was dead text) and gained
  a one-click "mark as cooked" action
- Theme toggle is now a real three-way light/dark/system control instead
  of a binary flip
- Nutrition goals form had zero i18n wiring; fully localized now

New migration 0027 (users.is_private) generated, left unapplied like the
others. Verified with typecheck, lint, and a clean --no-cache docker build.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Arnaud
2026-07-10 09:26:03 +02:00
parent 36e7698096
commit 9c545a5bb3
20 changed files with 4804 additions and 82 deletions
+24 -4
View File
@@ -19,7 +19,8 @@
"notifications": "Notifications",
"viewProfile": "View profile",
"lightMode": "Light mode",
"darkMode": "Dark mode"
"darkMode": "Dark mode",
"systemMode": "System"
},
"notifications": {
"title": "Notifications",
@@ -305,7 +306,19 @@
"nutritionGoals": {
"title": "Daily Nutrition Goals",
"description": "Set your daily targets. These are shown as progress bars on your meal plan.",
"viewDiaryCta": "View nutrition diary"
"viewDiaryCta": "View nutrition diary",
"caloriesLabel": "Calories (kcal/day)",
"proteinLabel": "Protein (g/day)",
"carbsLabel": "Carbs (g/day)",
"fatLabel": "Fat (g/day)",
"caloriesPlaceholder": "e.g. 2000",
"proteinPlaceholder": "e.g. 50",
"carbsPlaceholder": "e.g. 250",
"fatPlaceholder": "e.g. 70",
"saveButton": "Save goals",
"saving": "Saving...",
"saveSuccess": "Nutrition goals saved",
"saveError": "Failed to save nutrition goals"
},
"webhooksPage": {
"title": "Webhooks",
@@ -423,6 +436,8 @@
},
"explore": {
"title": "Explore",
"tabRecipes": "Recipes",
"tabPeople": "People",
"searchPlaceholder": "Search public recipes…",
"maxMinutes": "Max minutes",
"aiSearchPlaceholder": "e.g. quick weeknight dinners, Italian comfort food…",
@@ -689,7 +704,10 @@
"listCreate": "Create",
"pickRecipe": "Pick recipe",
"addEntry": "+ Add",
"removeEntry": "Remove meal"
"removeEntry": "Remove meal",
"markCooked": "Mark as cooked",
"markCookedSuccess": "Marked as cooked",
"markCookedFailed": "Failed to mark as cooked"
},
"pantry": {
"title": "Pantry",
@@ -1026,7 +1044,9 @@
"publicBioPlaceholder": "Tell other cooks about yourself…",
"privateBio": "AI context (private)",
"privateBioDescription": "Never shown publicly. Injected into AI prompts to personalise suggestions — add your dietary preferences, kitchen equipment, cooking skill level, allergies, etc.",
"privateBioPlaceholder": "e.g. I'm vegetarian, have a stand mixer and an air fryer, intermediate cook, allergic to tree nuts, prefer Mediterranean flavours…"
"privateBioPlaceholder": "e.g. I'm vegetarian, have a stand mixer and an air fryer, intermediate cook, allergic to tree nuts, prefer Mediterranean flavours…",
"privateAccount": "Private account",
"privateAccountDescription": "When on, your profile and recipes won't appear in search or discovery (Explore, Trending, For You). People who already follow you keep seeing your recipes."
},
"profilePage": {
"tabRecipes": "Recipes",
+24 -4
View File
@@ -19,7 +19,8 @@
"notifications": "Notifications",
"viewProfile": "Voir le profil",
"lightMode": "Mode clair",
"darkMode": "Mode sombre"
"darkMode": "Mode sombre",
"systemMode": "Système"
},
"notifications": {
"title": "Notifications",
@@ -305,7 +306,19 @@
"nutritionGoals": {
"title": "Objectifs nutritionnels quotidiens",
"description": "Définissez vos objectifs quotidiens. Ils apparaissent sous forme de barres de progression dans votre planning repas.",
"viewDiaryCta": "Voir le journal nutritionnel"
"viewDiaryCta": "Voir le journal nutritionnel",
"caloriesLabel": "Calories (kcal/jour)",
"proteinLabel": "Protéines (g/jour)",
"carbsLabel": "Glucides (g/jour)",
"fatLabel": "Lipides (g/jour)",
"caloriesPlaceholder": "ex. 2000",
"proteinPlaceholder": "ex. 50",
"carbsPlaceholder": "ex. 250",
"fatPlaceholder": "ex. 70",
"saveButton": "Enregistrer les objectifs",
"saving": "Enregistrement...",
"saveSuccess": "Objectifs nutritionnels enregistrés",
"saveError": "Impossible d'enregistrer les objectifs nutritionnels"
},
"webhooksPage": {
"title": "Webhooks",
@@ -423,6 +436,8 @@
},
"explore": {
"title": "Explorer",
"tabRecipes": "Recettes",
"tabPeople": "Personnes",
"searchPlaceholder": "Rechercher des recettes publiques…",
"maxMinutes": "Minutes max",
"aiSearchPlaceholder": "ex. dîners rapides en semaine, cuisine réconfortante italienne…",
@@ -677,7 +692,10 @@
"listCreate": "Créer",
"pickRecipe": "Choisir une recette",
"addEntry": "+ Ajouter",
"removeEntry": "Retirer le repas"
"removeEntry": "Retirer le repas",
"markCooked": "Marquer comme cuisiné",
"markCookedSuccess": "Marqué comme cuisiné",
"markCookedFailed": "Échec du marquage comme cuisiné"
},
"pantry": {
"title": "Garde-manger",
@@ -1014,7 +1032,9 @@
"publicBioPlaceholder": "Parlez de vous aux autres cuisiniers…",
"privateBio": "Contexte IA (privé)",
"privateBioDescription": "Jamais visible publiquement. Injecté dans les prompts IA pour personnaliser les suggestions — ajoutez vos préférences alimentaires, équipements, niveau de cuisine, allergies, etc.",
"privateBioPlaceholder": "ex. Je suis végétarien, j'ai un robot pâtissier et une friteuse à air, niveau intermédiaire, allergique aux fruits à coque, je préfère les saveurs méditerranéennes…"
"privateBioPlaceholder": "ex. Je suis végétarien, j'ai un robot pâtissier et une friteuse à air, niveau intermédiaire, allergique aux fruits à coque, je préfère les saveurs méditerranéennes…",
"privateAccount": "Compte privé",
"privateAccountDescription": "Une fois activé, votre profil et vos recettes n'apparaîtront plus dans la recherche ni dans les découvertes (Explorer, Tendances, Pour vous). Les personnes qui vous suivent déjà continueront de voir vos recettes."
},
"profilePage": {
"tabRecipes": "Recettes",