feat: group recipe ingredients by section titles (#5864)

Co-authored-by: Michael Genson <71845777+michael-genson@users.noreply.github.com>
This commit is contained in:
Felix Schneider
2025-08-29 23:25:25 +02:00
committed by GitHub
parent 6d2936cab6
commit 18f7e8d935
3 changed files with 99 additions and 15 deletions

View File

@@ -29,32 +29,49 @@
{{ activeText }}
</p>
<v-divider class="mb-4" />
<v-checkbox-btn
v-for="ing in unusedIngredients"
:key="ing.referenceId"
v-model="activeRefs"
:value="ing.referenceId"
>
<template #label>
<RecipeIngredientHtml :markup="parseIngredientText(ing)" />
</template>
</v-checkbox-btn>
<template v-if="usedIngredients.length > 0">
<template v-if="Object.keys(groupedUnusedIngredients).length > 0">
<h4 class="py-3 ml-1">
{{ $t("recipe.linked-to-other-step") }}
{{ $t("recipe.unlinked") }}
</h4>
<template v-for="(ingredients, title) in groupedUnusedIngredients" :key="title">
<h4 v-if="title" class="py-3 ml-1 pl-4">
{{ title }}
</h4>
<v-checkbox-btn
v-for="ing in usedIngredients"
v-for="ing in ingredients"
:key="ing.referenceId"
v-model="activeRefs"
:value="ing.referenceId"
class="ml-4"
>
<template #label>
<RecipeIngredientHtml :markup="parseIngredientText(ing)" />
</template>
</v-checkbox-btn>
</template>
</template>
<template v-if="Object.keys(groupedUsedIngredients).length > 0">
<h4 class="py-3 ml-1">
{{ $t("recipe.linked-to-other-step") }}
</h4>
<template v-for="(ingredients, title) in groupedUsedIngredients" :key="title">
<h4 v-if="title" class="py-3 ml-1 pl-4">
{{ title }}
</h4>
<v-checkbox-btn
v-for="ing in ingredients"
:key="ing.referenceId"
v-model="activeRefs"
:value="ing.referenceId"
class="ml-4"
>
<template #label>
<RecipeIngredientHtml :markup="parseIngredientText(ing)" />
</template>
</v-checkbox-btn>
</template>
</template>
</v-card-text>
<v-divider />
@@ -563,6 +580,71 @@ const ingredientLookup = computed(() => {
}, results);
});
// Map each ingredient's referenceId to its section title
const ingredientSectionTitles = computed(() => {
const titleMap: { [key: string]: string } = {};
let currentTitle = "";
// Go through all ingredients in order
props.recipe.recipeIngredient.forEach((ingredient) => {
if (ingredient.referenceId === undefined) {
return;
}
// If this ingredient has a title, update the current title
if (ingredient.title) {
currentTitle = ingredient.title;
}
// Assign the current title to this ingredient
titleMap[ingredient.referenceId] = currentTitle;
});
return titleMap;
});
const groupedUnusedIngredients = computed(() => {
const groups: { [key: string]: RecipeIngredient[] } = {};
// Group ingredients by section title
unusedIngredients.value.forEach((ingredient) => {
if (ingredient.referenceId === undefined) {
return;
}
// Use the section title from the mapping, or fallback to the ingredient's own title
const title = ingredientSectionTitles.value[ingredient.referenceId] || ingredient.title || "";
if (!groups[title]) {
groups[title] = [];
}
groups[title].push(ingredient);
});
return groups;
});
const groupedUsedIngredients = computed(() => {
const groups: { [key: string]: RecipeIngredient[] } = {};
// Group ingredients by section title
usedIngredients.value.forEach((ingredient) => {
if (ingredient.referenceId === undefined) {
return;
}
// Use the section title from the mapping, or fallback to the ingredient's own title
const title = ingredientSectionTitles.value[ingredient.referenceId] || ingredient.title || "";
if (!groups[title]) {
groups[title] = [];
}
groups[title].push(ingredient);
});
return groups;
});
function getIngredientByRefId(refId: string | undefined) {
if (refId === undefined) {
return "";