mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-08-05 05:25:26 +02:00
fix: Nuxt 3 Ingredient Parsing Issues and Tooltip Positions (#5829)
Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com>
This commit is contained in:
parent
eefe613aaf
commit
f9f88fb8a4
15 changed files with 91 additions and 44 deletions
|
@ -17,7 +17,7 @@
|
||||||
<RecipeFavoriteBadge v-if="loggedIn" color="info" button-style :recipe-id="recipe.id!" show-always />
|
<RecipeFavoriteBadge v-if="loggedIn" color="info" button-style :recipe-id="recipe.id!" show-always />
|
||||||
<RecipeTimelineBadge v-if="loggedIn" class="ml-1" color="info" button-style :slug="recipe.slug" :recipe-name="recipe.name!" />
|
<RecipeTimelineBadge v-if="loggedIn" class="ml-1" color="info" button-style :slug="recipe.slug" :recipe-name="recipe.name!" />
|
||||||
<div v-if="loggedIn">
|
<div v-if="loggedIn">
|
||||||
<v-tooltip v-if="canEdit" bottom color="info">
|
<v-tooltip v-if="canEdit" location="bottom" color="info">
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<v-btn
|
<v-btn
|
||||||
icon
|
icon
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<div class="ma-auto">
|
<div class="ma-auto">
|
||||||
<v-tooltip bottom>
|
<v-tooltip location="bottom">
|
||||||
<template #activator="{ props: tooltipProps }">
|
<template #activator="{ props: tooltipProps }">
|
||||||
<v-icon v-bind="tooltipProps">
|
<v-icon v-bind="tooltipProps">
|
||||||
{{ getIconDefinition(item.icon).icon }}
|
{{ getIconDefinition(item.icon).icon }}
|
||||||
|
|
|
@ -63,6 +63,22 @@
|
||||||
clearable
|
clearable
|
||||||
@keyup.enter="handleUnitEnter"
|
@keyup.enter="handleUnitEnter"
|
||||||
>
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<v-tooltip v-if="unitError" location="bottom">
|
||||||
|
<template #activator="{ props: unitTooltipProps }">
|
||||||
|
<v-icon
|
||||||
|
v-bind="unitTooltipProps"
|
||||||
|
class="ml-2 mr-n3 opacity-100"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
{{ $globals.icons.alert }}
|
||||||
|
</v-icon>
|
||||||
|
</template>
|
||||||
|
<span v-if="unitErrorTooltip">
|
||||||
|
{{ unitErrorTooltip }}
|
||||||
|
</span>
|
||||||
|
</v-tooltip>
|
||||||
|
</template>
|
||||||
<template #no-data>
|
<template #no-data>
|
||||||
<div class="caption text-center pb-2">
|
<div class="caption text-center pb-2">
|
||||||
{{ $t("recipe.press-enter-to-create") }}
|
{{ $t("recipe.press-enter-to-create") }}
|
||||||
|
@ -104,6 +120,22 @@
|
||||||
clearable
|
clearable
|
||||||
@keyup.enter="handleFoodEnter"
|
@keyup.enter="handleFoodEnter"
|
||||||
>
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<v-tooltip v-if="foodError" location="bottom">
|
||||||
|
<template #activator="{ props: foodTooltipProps }">
|
||||||
|
<v-icon
|
||||||
|
v-bind="foodTooltipProps"
|
||||||
|
class="ml-2 mr-n3 opacity-100"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
{{ $globals.icons.alert }}
|
||||||
|
</v-icon>
|
||||||
|
</template>
|
||||||
|
<span v-if="foodErrorTooltip">
|
||||||
|
{{ foodErrorTooltip }}
|
||||||
|
</span>
|
||||||
|
</v-tooltip>
|
||||||
|
</template>
|
||||||
<template #no-data>
|
<template #no-data>
|
||||||
<div class="caption text-center pb-2">
|
<div class="caption text-center pb-2">
|
||||||
{{ $t("recipe.press-enter-to-create") }}
|
{{ $t("recipe.press-enter-to-create") }}
|
||||||
|
@ -153,7 +185,6 @@
|
||||||
@toggle-original="toggleOriginalText"
|
@toggle-original="toggleOriginalText"
|
||||||
@insert-above="$emit('insert-above')"
|
@insert-above="$emit('insert-above')"
|
||||||
@insert-below="$emit('insert-below')"
|
@insert-below="$emit('insert-below')"
|
||||||
@insert-ingredient="$emit('insert-ingredient')"
|
|
||||||
@delete="$emit('delete')"
|
@delete="$emit('delete')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -184,22 +215,33 @@ import type { RecipeIngredient } from "~/lib/api/types/recipe";
|
||||||
// defineModel replaces modelValue prop
|
// defineModel replaces modelValue prop
|
||||||
const model = defineModel<RecipeIngredient>({ required: true });
|
const model = defineModel<RecipeIngredient>({ required: true });
|
||||||
|
|
||||||
const props = defineProps({
|
defineProps({
|
||||||
disableAmount: {
|
disableAmount: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
allowInsertIngredient: {
|
unitError: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
unitErrorTooltip: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
foodError: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
foodErrorTooltip: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
defineEmits([
|
defineEmits([
|
||||||
"clickIngredientField",
|
"clickIngredientField",
|
||||||
"insert-above",
|
"insert-above",
|
||||||
"insert-below",
|
"insert-below",
|
||||||
"insert-ingredient",
|
|
||||||
"delete",
|
"delete",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -228,13 +270,6 @@ const contextMenuOptions = computed(() => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
if (props.allowInsertIngredient) {
|
|
||||||
options.push({
|
|
||||||
text: i18n.t("recipe.insert-ingredient"),
|
|
||||||
event: "insert-ingredient",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (model.value.originalText) {
|
if (model.value.originalText) {
|
||||||
options.push({
|
options.push({
|
||||||
text: i18n.t("recipe.see-original-text"),
|
text: i18n.t("recipe.see-original-text"),
|
||||||
|
|
|
@ -86,7 +86,7 @@
|
||||||
<div>
|
<div>
|
||||||
<div v-if="lastMadeReady" class="d-flex justify-center flex-wrap">
|
<div v-if="lastMadeReady" class="d-flex justify-center flex-wrap">
|
||||||
<v-row no-gutters class="d-flex flex-wrap align-center" style="font-size: larger">
|
<v-row no-gutters class="d-flex flex-wrap align-center" style="font-size: larger">
|
||||||
<v-tooltip bottom>
|
<v-tooltip location="bottom">
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<v-btn
|
<v-btn
|
||||||
rounded
|
rounded
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
/>
|
/>
|
||||||
<div class="d-flex flex-wrap justify-center justify-sm-end mt-3">
|
<div class="d-flex flex-wrap justify-center justify-sm-end mt-3">
|
||||||
<v-tooltip
|
<v-tooltip
|
||||||
top
|
location="top"
|
||||||
color="accent"
|
color="accent"
|
||||||
>
|
>
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<v-tooltip
|
<v-tooltip
|
||||||
v-if="canEditScale"
|
v-if="canEditScale"
|
||||||
size="small"
|
size="small"
|
||||||
top
|
location="top"
|
||||||
color="secondary-darken-1"
|
color="secondary-darken-1"
|
||||||
>
|
>
|
||||||
<template #activator="{ props: tooltipProps }">
|
<template #activator="{ props: tooltipProps }">
|
||||||
|
@ -74,7 +74,7 @@
|
||||||
@update:model-value="recalculateScale(parseFloat($event) || 0)"
|
@update:model-value="recalculateScale(parseFloat($event) || 0)"
|
||||||
/>
|
/>
|
||||||
<v-tooltip
|
<v-tooltip
|
||||||
end
|
location="end"
|
||||||
color="secondary-darken-1"
|
color="secondary-darken-1"
|
||||||
>
|
>
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<v-tooltip
|
<v-tooltip
|
||||||
bottom
|
location="bottom"
|
||||||
nudge-right="50"
|
nudge-right="50"
|
||||||
:color="buttonStyle ? 'info' : 'secondary'"
|
:color="buttonStyle ? 'info' : 'secondary'"
|
||||||
>
|
>
|
||||||
|
|
|
@ -59,7 +59,7 @@
|
||||||
open-delay="200"
|
open-delay="200"
|
||||||
transition="slide-x-reverse-transition"
|
transition="slide-x-reverse-transition"
|
||||||
density="compact"
|
density="compact"
|
||||||
right
|
location="end"
|
||||||
content-class="text-caption"
|
content-class="text-caption"
|
||||||
>
|
>
|
||||||
<template #activator="{ props: tooltipProps }">
|
<template #activator="{ props: tooltipProps }">
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<v-tooltip
|
<v-tooltip
|
||||||
v-if="userId"
|
v-if="userId"
|
||||||
:disabled="!user || !tooltip"
|
:disabled="!user || !tooltip"
|
||||||
right
|
location="end"
|
||||||
>
|
>
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<v-avatar
|
<v-avatar
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<v-tooltip
|
<v-tooltip
|
||||||
ref="copyToolTip"
|
ref="copyToolTip"
|
||||||
v-model="show"
|
v-model="show"
|
||||||
top
|
location="top"
|
||||||
:open-on-hover="false"
|
:open-on-hover="false"
|
||||||
:open-on-click="true"
|
:open-on-click="true"
|
||||||
close-delay="500"
|
close-delay="500"
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
open-delay="200"
|
open-delay="200"
|
||||||
transition="slide-y-reverse-transition"
|
transition="slide-y-reverse-transition"
|
||||||
density="compact"
|
density="compact"
|
||||||
bottom
|
location="bottom"
|
||||||
content-class="text-caption"
|
content-class="text-caption"
|
||||||
>
|
>
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
|
|
|
@ -662,6 +662,8 @@
|
||||||
"no-unit": "No unit",
|
"no-unit": "No unit",
|
||||||
"missing-unit": "Create missing unit: {unit}",
|
"missing-unit": "Create missing unit: {unit}",
|
||||||
"missing-food": "Create missing food: {food}",
|
"missing-food": "Create missing food: {food}",
|
||||||
|
"this-unit-could-not-be-parsed-automatically": "This unit could not be parsed automatically",
|
||||||
|
"this-food-could-not-be-parsed-automatically": "This food could not be parsed automatically",
|
||||||
"no-food": "No Food"
|
"no-food": "No Food"
|
||||||
},
|
},
|
||||||
"reset-servings-count": "Reset Servings Count",
|
"reset-servings-count": "Reset Servings Count",
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
</template>
|
</template>
|
||||||
<template #[`item.actions`]="{ item }">
|
<template #[`item.actions`]="{ item }">
|
||||||
<v-tooltip
|
<v-tooltip
|
||||||
bottom
|
location="bottom"
|
||||||
:disabled="!(item && (item.households!.length > 0 || item.users!.length > 0))"
|
:disabled="!(item && (item.households!.length > 0 || item.users!.length > 0))"
|
||||||
>
|
>
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
|
|
|
@ -82,7 +82,7 @@
|
||||||
</template>
|
</template>
|
||||||
<template #[`item.actions`]="{ item }">
|
<template #[`item.actions`]="{ item }">
|
||||||
<v-tooltip
|
<v-tooltip
|
||||||
bottom
|
location="bottom"
|
||||||
:disabled="!(item && item.users!.length > 0)"
|
:disabled="!(item && item.users!.length > 0)"
|
||||||
>
|
>
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
|
|
|
@ -103,7 +103,12 @@
|
||||||
<RecipeIngredientEditor
|
<RecipeIngredientEditor
|
||||||
v-model="parsedIng[index].ingredient"
|
v-model="parsedIng[index].ingredient"
|
||||||
allow-insert-ingredient
|
allow-insert-ingredient
|
||||||
@insert-ingredient="insertIngredient(index)"
|
:unit-error="errors[index].unitError && errors[index].unitErrorMessage !== ''"
|
||||||
|
:unit-error-tooltip="$t('recipe.parser.this-unit-could-not-be-parsed-automatically')"
|
||||||
|
:food-error="errors[index].foodError && errors[index].foodErrorMessage !== ''"
|
||||||
|
:food-error-tooltip="$t('recipe.parser.this-food-could-not-be-parsed-automatically')"
|
||||||
|
@insert-above="insertIngredient(index)"
|
||||||
|
@insert-below="insertIngredient(index + 1)"
|
||||||
@delete="deleteIngredient(index)"
|
@delete="deleteIngredient(index)"
|
||||||
/>
|
/>
|
||||||
{{ ing.input }}
|
{{ ing.input }}
|
||||||
|
@ -113,7 +118,7 @@
|
||||||
v-if="errors[index].unitError && errors[index].unitErrorMessage !== ''"
|
v-if="errors[index].unitError && errors[index].unitErrorMessage !== ''"
|
||||||
color="warning"
|
color="warning"
|
||||||
size="small"
|
size="small"
|
||||||
@click="createUnit(ing.ingredient.unit!, index)"
|
@click="createUnit(errors[index].unitName, index)"
|
||||||
>
|
>
|
||||||
{{ errors[index].unitErrorMessage }}
|
{{ errors[index].unitErrorMessage }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
|
@ -121,7 +126,7 @@
|
||||||
v-if="errors[index].foodError && errors[index].foodErrorMessage !== ''"
|
v-if="errors[index].foodError && errors[index].foodErrorMessage !== ''"
|
||||||
color="warning"
|
color="warning"
|
||||||
size="small"
|
size="small"
|
||||||
@click="createFood(ing.ingredient.food!, index)"
|
@click="createFood(errors[index].foodName, index)"
|
||||||
>
|
>
|
||||||
{{ errors[index].foodErrorMessage }}
|
{{ errors[index].foodErrorMessage }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
|
@ -157,8 +162,10 @@ import type { Parser } from "~/lib/api/user/recipes/recipe";
|
||||||
|
|
||||||
interface Error {
|
interface Error {
|
||||||
ingredientIndex: number;
|
ingredientIndex: number;
|
||||||
|
unitName: string;
|
||||||
unitError: boolean;
|
unitError: boolean;
|
||||||
unitErrorMessage: string;
|
unitErrorMessage: string;
|
||||||
|
foodName: string;
|
||||||
foodError: boolean;
|
foodError: boolean;
|
||||||
foodErrorMessage: string;
|
foodErrorMessage: string;
|
||||||
}
|
}
|
||||||
|
@ -224,30 +231,33 @@ export default defineNuxtComponent({
|
||||||
const unitError = !checkForUnit(ing.ingredient.unit!);
|
const unitError = !checkForUnit(ing.ingredient.unit!);
|
||||||
const foodError = !checkForFood(ing.ingredient.food!);
|
const foodError = !checkForFood(ing.ingredient.food!);
|
||||||
|
|
||||||
|
const unit = ing.ingredient.unit?.name || i18n.t("recipe.parser.no-unit");
|
||||||
|
const food = ing.ingredient.food?.name || i18n.t("recipe.parser.no-food");
|
||||||
|
|
||||||
let unitErrorMessage = "";
|
let unitErrorMessage = "";
|
||||||
let foodErrorMessage = "";
|
let foodErrorMessage = "";
|
||||||
|
|
||||||
if (unitError || foodError) {
|
if (unitError) {
|
||||||
if (unitError) {
|
if (ing?.ingredient?.unit?.name) {
|
||||||
if (ing?.ingredient?.unit?.name) {
|
ing.ingredient.unit = undefined;
|
||||||
const unit = ing.ingredient.unit.name || i18n.t("recipe.parser.no-unit");
|
unitErrorMessage = i18n.t("recipe.parser.missing-unit", { unit }).toString();
|
||||||
unitErrorMessage = i18n.t("recipe.parser.missing-unit", { unit }).toString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (foodError) {
|
if (foodError) {
|
||||||
if (ing?.ingredient?.food?.name) {
|
if (ing?.ingredient?.food?.name) {
|
||||||
const food = ing.ingredient.food.name || i18n.t("recipe.parser.no-food");
|
ing.ingredient.food = undefined;
|
||||||
foodErrorMessage = i18n.t("recipe.parser.missing-food", { food }).toString();
|
foodErrorMessage = i18n.t("recipe.parser.missing-food", { food }).toString();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panels.value.push(index);
|
panels.value.push(index);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ingredientIndex: index,
|
ingredientIndex: index,
|
||||||
|
unitName: unit,
|
||||||
unitError,
|
unitError,
|
||||||
unitErrorMessage,
|
unitErrorMessage,
|
||||||
|
foodName: food,
|
||||||
foodError,
|
foodError,
|
||||||
foodErrorMessage,
|
foodErrorMessage,
|
||||||
} as Error;
|
} as Error;
|
||||||
|
@ -320,24 +330,24 @@ export default defineNuxtComponent({
|
||||||
return !!food?.id;
|
return !!food?.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createFood(food: CreateIngredientFood | undefined, index: number) {
|
async function createFood(foodName: string, index: number) {
|
||||||
if (!food) {
|
if (!foodName) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foodData.data.name = food.name;
|
foodData.data.name = foodName;
|
||||||
parsedIng.value[index].ingredient.food = await foodStore.actions.createOne(foodData.data) || undefined;
|
parsedIng.value[index].ingredient.food = await foodStore.actions.createOne(foodData.data) || undefined;
|
||||||
errors.value[index].foodError = false;
|
errors.value[index].foodError = false;
|
||||||
|
|
||||||
foodData.reset();
|
foodData.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createUnit(unit: CreateIngredientUnit | undefined, index: number) {
|
async function createUnit(unitName: string | undefined, index: number) {
|
||||||
if (!unit) {
|
if (!unitName) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
unitData.data.name = unit.name;
|
unitData.data.name = unitName;
|
||||||
parsedIng.value[index].ingredient.unit = await unitStore.actions.createOne(unitData.data) || undefined;
|
parsedIng.value[index].ingredient.unit = await unitStore.actions.createOne(unitData.data) || undefined;
|
||||||
errors.value[index].unitError = false;
|
errors.value[index].unitError = false;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue