feat: recipe type (dish/drink) for better cocktail handling (v0.31.0)
Add recipes.recipeType enum (dish|drink, default dish). Recipe form now shows a Type selector and hides food-only fields for drinks (prep/cook time, difficulty, batch-cook toggle) instead of forcing every cocktail through meal-oriented UI. Detail page skips the meal/drink pairing suggestion buttons on drink recipes (pairing a drink with a drink doesn't make sense). Recipes list gains a Type filter facet alongside difficulty/batch-cook. Scoped deliberately narrow per investigation: no ABV/glass-type/ garnish structured fields, no meal-plan schema changes, and the existing AI drink-pairing-suggestion feature (ephemeral, never saved as a recipe) is left as-is rather than wired into recipe creation — those suggestions are wine/beer/spirit recommendations without ingredients/steps, not really recipes to save. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -71,6 +71,12 @@ const BATCH_COOK_KEYS: Record<string, string> = {
|
||||
"0": "batchCookExclude",
|
||||
};
|
||||
|
||||
const RECIPE_TYPE_KEYS: Record<string, string> = {
|
||||
"": "all",
|
||||
dish: "dish",
|
||||
drink: "drink",
|
||||
};
|
||||
|
||||
export function RecipesHeader({
|
||||
count,
|
||||
initialQuery = "",
|
||||
@@ -79,6 +85,7 @@ export function RecipesHeader({
|
||||
initialDifficulty = "",
|
||||
initialTag = "",
|
||||
initialBatchCook = "",
|
||||
initialRecipeType = "",
|
||||
}: {
|
||||
count: number;
|
||||
initialQuery?: string;
|
||||
@@ -87,6 +94,7 @@ export function RecipesHeader({
|
||||
initialDifficulty?: string;
|
||||
initialTag?: string;
|
||||
initialBatchCook?: string;
|
||||
initialRecipeType?: string;
|
||||
}) {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
@@ -106,6 +114,7 @@ export function RecipesHeader({
|
||||
difficulty: initialDifficulty,
|
||||
tag: initialTag,
|
||||
batchCook: initialBatchCook,
|
||||
recipeType: initialRecipeType,
|
||||
...overrides,
|
||||
};
|
||||
if (current.q?.trim()) params.set("q", current.q.trim());
|
||||
@@ -114,6 +123,7 @@ export function RecipesHeader({
|
||||
if (current.difficulty) params.set("difficulty", current.difficulty);
|
||||
if (current.tag?.trim()) params.set("tag", current.tag.trim());
|
||||
if (current.batchCook) params.set("batchCook", current.batchCook);
|
||||
if (current.recipeType) params.set("recipeType", current.recipeType);
|
||||
startTransition(() => router.push(`${pathname}?${params.toString()}`));
|
||||
}
|
||||
|
||||
@@ -122,7 +132,7 @@ export function RecipesHeader({
|
||||
pushParams({ q: value });
|
||||
}
|
||||
|
||||
const activeFilterCount = [initialVisibility, initialDifficulty, initialTag, initialBatchCook].filter(Boolean).length;
|
||||
const activeFilterCount = [initialVisibility, initialDifficulty, initialTag, initialBatchCook, initialRecipeType].filter(Boolean).length;
|
||||
const sortChanged = initialSort !== "updated_desc";
|
||||
|
||||
return (
|
||||
@@ -270,12 +280,26 @@ export function RecipesHeader({
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>{t("recipeTypeLabel")}</DropdownMenuLabel>
|
||||
{Object.entries(RECIPE_TYPE_KEYS).map(([value, key]) => (
|
||||
<DropdownMenuItem
|
||||
key={value}
|
||||
closeOnClick={false}
|
||||
onClick={() => pushParams({ recipeType: value })}
|
||||
className={cn(initialRecipeType === value && "font-medium text-primary")}
|
||||
>
|
||||
{value === "" ? t(key) : tRecipe(`recipeType.${key}`)}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuGroup>
|
||||
{activeFilterCount > 0 && (
|
||||
<>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem
|
||||
onClick={() => pushParams({ visibility: "", difficulty: "", tag: "", batchCook: "" })}
|
||||
onClick={() => pushParams({ visibility: "", difficulty: "", tag: "", batchCook: "", recipeType: "" })}
|
||||
className="text-muted-foreground"
|
||||
>
|
||||
<X className="h-3 w-3 mr-1.5" /> {t("clearFilters")}
|
||||
|
||||
Reference in New Issue
Block a user