1
0
Fork 0
mirror of https://github.com/mealie-recipes/mealie.git synced 2025-07-23 15:19:41 +02:00

fix: delete recipe instructions after nuxt 3 upgrade (#5560)

This commit is contained in:
Kuchenpirat 2025-06-22 22:34:25 +02:00 committed by GitHub
parent a2a0ad1af0
commit 93cec24f26
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -356,8 +356,9 @@
</section> </section>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { VueDraggable } from "vue-draggable-plus"; import { VueDraggable } from "vue-draggable-plus";
import { computed, nextTick, onMounted, ref, watch } from "vue";
import RecipeIngredientHtml from "../../RecipeIngredientHtml.vue"; import RecipeIngredientHtml from "../../RecipeIngredientHtml.vue";
import type { RecipeStep, IngredientReferences, RecipeIngredient, RecipeAsset, Recipe } from "~/lib/api/types/recipe"; import type { RecipeStep, IngredientReferences, RecipeIngredient, RecipeAsset, Recipe } from "~/lib/api/types/recipe";
import { parseIngredientText } from "~/composables/recipes"; import { parseIngredientText } from "~/composables/recipes";
@ -376,64 +377,33 @@ interface MergerHistory {
sourceText: string; sourceText: string;
} }
export default defineNuxtComponent({ const instructionList = defineModel<RecipeStep[]>("modelValue", { required: true, default: () => [] });
components: { const assets = defineModel<RecipeAsset[]>("assets", { required: true, default: () => [] });
VueDraggable,
RecipeIngredientHtml, const props = defineProps({
DropZone,
RecipeIngredients,
},
props: {
modelValue: {
type: Array as () => RecipeStep[],
required: false,
default: () => [],
},
recipe: { recipe: {
type: Object as () => NoUndefinedField<Recipe>, type: Object as () => NoUndefinedField<Recipe>,
required: true, required: true,
}, },
assets: {
type: Array as () => RecipeAsset[],
required: true,
},
scale: { scale: {
type: Number, type: Number,
default: 1, default: 1,
}, },
}, });
emits: ["update:modelValue", "click-instruction-field", "update:assets"],
const emit = defineEmits(["click-instruction-field", "update:assets"]);
setup(props, context) {
const i18n = useI18n();
const BASE_URL = useRequestURL().origin; const BASE_URL = useRequestURL().origin;
const { isCookMode, toggleCookMode, isEditForm } = usePageState(props.recipe.slug); const { isCookMode, toggleCookMode, isEditForm } = usePageState(props.recipe.slug);
const state = reactive({ const dialog = ref(false);
dialog: false, const disabledSteps = ref<number[]>([]);
disabledSteps: [] as number[], const unusedIngredients = ref<RecipeIngredient[]>([]);
unusedIngredients: [] as RecipeIngredient[], const usedIngredients = ref<RecipeIngredient[]>([]);
usedIngredients: [] as RecipeIngredient[],
});
const showTitleEditor = ref<{ [key: string]: boolean }>({}); const showTitleEditor = ref<{ [key: string]: boolean }>({});
const actionEvents = [
{
text: i18n.t("recipe.toggle-section") as string,
event: "toggle-section",
},
{
text: i18n.t("recipe.link-ingredients") as string,
event: "link-ingredients",
},
{
text: i18n.t("recipe.merge-above") as string,
event: "merge-above",
},
];
// =============================================================== // ===============================================================
// UI State Helpers // UI State Helpers
@ -441,51 +411,53 @@ export default defineNuxtComponent({
return !(title === null || title === "" || title === undefined); return !(title === null || title === "" || title === undefined);
} }
watch(props.modelValue, (v) => { watch(instructionList, (v) => {
state.disabledSteps = []; disabledSteps.value = [];
v.forEach((element: RecipeStep) => { v.forEach((element: RecipeStep) => {
if (element.id !== undefined) { if (element.id !== undefined) {
showTitleEditor.value[element.id!] = hasSectionTitle(element.title!); showTitleEditor.value[element.id!] = hasSectionTitle(element.title!);
} }
}); });
}); }, { deep: true });
const showCookMode = ref(false); const showCookMode = ref(false);
// Eliminate state with an eager call to watcher?
onMounted(() => { onMounted(() => {
props.modelValue.forEach((element: RecipeStep) => { instructionList.value.forEach((element: RecipeStep) => {
if (element.id !== undefined) { if (element.id !== undefined) {
showTitleEditor.value[element.id!] = hasSectionTitle(element.title!); showTitleEditor.value[element.id!] = hasSectionTitle(element.title!);
} }
// showCookMode.value = false;
if (showCookMode.value === false && element.ingredientReferences && element.ingredientReferences.length > 0) { if (showCookMode.value === false && element.ingredientReferences && element.ingredientReferences.length > 0) {
showCookMode.value = true; showCookMode.value = true;
} }
showTitleEditor.value = { ...showTitleEditor.value }; showTitleEditor.value = { ...showTitleEditor.value };
}); });
if (assets.value === undefined) {
emit("update:assets", []);
}
}); });
function toggleDisabled(stepIndex: number) { function toggleDisabled(stepIndex: number) {
if (isEditForm.value) { if (isEditForm.value) {
return; return;
} }
if (state.disabledSteps.includes(stepIndex)) { if (disabledSteps.value.includes(stepIndex)) {
const index = state.disabledSteps.indexOf(stepIndex); const index = disabledSteps.value.indexOf(stepIndex);
if (index !== -1) { if (index !== -1) {
state.disabledSteps.splice(index, 1); disabledSteps.value.splice(index, 1);
} }
} }
else { else {
state.disabledSteps.push(stepIndex); disabledSteps.value.push(stepIndex);
} }
} }
function isChecked(stepIndex: number) { function isChecked(stepIndex: number) {
if (state.disabledSteps.includes(stepIndex) && !isEditForm.value) { if (disabledSteps.value.includes(stepIndex) && !isEditForm.value) {
return "disabled-card"; return "disabled-card";
} }
} }
@ -501,18 +473,7 @@ export default defineNuxtComponent({
showTitleEditor.value = temp; showTitleEditor.value = temp;
} }
const instructionList = ref<RecipeStep[]>([...props.modelValue]);
watch(
() => props.modelValue,
(newVal) => {
instructionList.value = [...newVal];
},
{ deep: true },
);
function onDragEnd() { function onDragEnd() {
context.emit("update:modelValue", [...instructionList.value]);
drag.value = false; drag.value = false;
} }
@ -525,20 +486,20 @@ export default defineNuxtComponent({
function openDialog(idx: number, text: string, refs?: IngredientReferences[]) { function openDialog(idx: number, text: string, refs?: IngredientReferences[]) {
if (!refs) { if (!refs) {
instructionList.value[idx].ingredientReferences = []; instructionList.value[idx].ingredientReferences = [];
refs = props.modelValue[idx].ingredientReferences as IngredientReferences[]; refs = instructionList.value[idx].ingredientReferences as IngredientReferences[];
} }
setUsedIngredients(); setUsedIngredients();
activeText.value = text; activeText.value = text;
activeIndex.value = idx; activeIndex.value = idx;
state.dialog = true; dialog.value = true;
activeRefs.value = refs.map(ref => ref.referenceId ?? ""); activeRefs.value = refs.map(ref => ref.referenceId ?? "");
} }
const availableNextStep = computed(() => activeIndex.value < props.modelValue.length - 1); const availableNextStep = computed(() => activeIndex.value < instructionList.value.length - 1);
function setIngredientIds() { function setIngredientIds() {
const instruction = props.modelValue[activeIndex.value]; const instruction = instructionList.value[activeIndex.value];
instruction.ingredientReferences = activeRefs.value.map((ref) => { instruction.ingredientReferences = activeRefs.value.map((ref) => {
return { return {
referenceId: ref, referenceId: ref,
@ -547,12 +508,12 @@ export default defineNuxtComponent({
// Update the visibility of the cook mode button // Update the visibility of the cook mode button
showCookMode.value = false; showCookMode.value = false;
props.modelValue.forEach((element) => { instructionList.value.forEach((element) => {
if (showCookMode.value === false && element.ingredientReferences && element.ingredientReferences.length > 0) { if (showCookMode.value === false && element.ingredientReferences && element.ingredientReferences.length > 0) {
showCookMode.value = true; showCookMode.value = true;
} }
}); });
state.dialog = false; dialog.value = false;
} }
function saveAndOpenNextLinkIngredients() { function saveAndOpenNextLinkIngredients() {
@ -563,7 +524,7 @@ export default defineNuxtComponent({
} }
setIngredientIds(); setIngredientIds();
const nextStep = props.modelValue[currentStepIndex + 1]; const nextStep = instructionList.value[currentStepIndex + 1];
// close dialog before opening to reset the scroll position // close dialog before opening to reset the scroll position
nextTick(() => openDialog(currentStepIndex + 1, nextStep.text, nextStep.ingredientReferences)); nextTick(() => openDialog(currentStepIndex + 1, nextStep.text, nextStep.ingredientReferences));
} }
@ -571,7 +532,7 @@ export default defineNuxtComponent({
function setUsedIngredients() { function setUsedIngredients() {
const usedRefs: { [key: string]: boolean } = {}; const usedRefs: { [key: string]: boolean } = {};
props.modelValue.forEach((element) => { instructionList.value.forEach((element) => {
element.ingredientReferences?.forEach((ref) => { element.ingredientReferences?.forEach((ref) => {
if (ref.referenceId !== undefined) { if (ref.referenceId !== undefined) {
usedRefs[ref.referenceId!] = true; usedRefs[ref.referenceId!] = true;
@ -579,11 +540,11 @@ export default defineNuxtComponent({
}); });
}); });
state.usedIngredients = props.recipe.recipeIngredient.filter((ing) => { usedIngredients.value = props.recipe.recipeIngredient.filter((ing) => {
return ing.referenceId !== undefined && ing.referenceId in usedRefs; return ing.referenceId !== undefined && ing.referenceId in usedRefs;
}); });
state.unusedIngredients = props.recipe.recipeIngredient.filter((ing) => { unusedIngredients.value = props.recipe.recipeIngredient.filter((ing) => {
return !(ing.referenceId !== undefined && ing.referenceId in usedRefs); return !(ing.referenceId !== undefined && ing.referenceId in usedRefs);
}); });
} }
@ -630,11 +591,11 @@ export default defineNuxtComponent({
mergeHistory.value.push({ mergeHistory.value.push({
target, target,
source, source,
targetText: props.modelValue[target].text, targetText: instructionList.value[target].text,
sourceText: props.modelValue[source].text, sourceText: instructionList.value[source].text,
}); });
instructionList.value[target].text += " " + props.modelValue[source].text; instructionList.value[target].text += " " + instructionList.value[source].text;
instructionList.value.splice(source, 1); instructionList.value.splice(source, 1);
} }
@ -692,13 +653,13 @@ export default defineNuxtComponent({
} }
} }
const allCollapsed = sectionSteps.every(idx => state.disabledSteps.includes(idx)); const allCollapsed = sectionSteps.every(idx => disabledSteps.value.includes(idx));
if (allCollapsed) { if (allCollapsed) {
state.disabledSteps = state.disabledSteps.filter(idx => !sectionSteps.includes(idx)); disabledSteps.value = disabledSteps.value.filter(idx => !sectionSteps.includes(idx));
} }
else { else {
state.disabledSteps = [...state.disabledSteps, ...sectionSteps]; disabledSteps.value = [...disabledSteps.value, ...sectionSteps];
} }
} }
@ -709,19 +670,6 @@ export default defineNuxtComponent({
const api = useUserApi(); const api = useUserApi();
const { recipeAssetPath } = useStaticRoutes(); const { recipeAssetPath } = useStaticRoutes();
const imageUploadMode = ref(false);
function toggleDragMode() {
console.log("Toggling Drag Mode");
imageUploadMode.value = !imageUploadMode.value;
}
onMounted(() => {
if (props.assets === undefined) {
context.emit("update:assets", []);
}
});
const loadingStates = ref<{ [key: number]: boolean }>({}); const loadingStates = ref<{ [key: number]: boolean }>({});
async function handleImageDrop(index: number, files: File[]) { async function handleImageDrop(index: number, files: File[]) {
@ -750,7 +698,7 @@ export default defineNuxtComponent({
return; // TODO: Handle error return; // TODO: Handle error
} }
context.emit("update:assets", [...props.assets, data]); emit("update:assets", [...assets.value, data]);
const assetUrl = BASE_URL + recipeAssetPath(props.recipe.id, data.fileName as string); const assetUrl = BASE_URL + recipeAssetPath(props.recipe.id, data.fileName as string);
const text = `<img src="${assetUrl}" height="100%" width="100%"/>`; const text = `<img src="${assetUrl}" height="100%" width="100%"/>`;
instructionList.value[index].text += text; instructionList.value[index].text += text;
@ -768,51 +716,6 @@ export default defineNuxtComponent({
}; };
input.click(); input.click();
} }
const breakpoint = useDisplay();
return {
// Image Uploader
toggleDragMode,
handleImageDrop,
imageUploadMode,
openImageUpload,
loadingStates,
// Rest
onDragEnd,
drag,
togglePreviewState,
toggleCollapseSection,
previewStates,
...toRefs(state),
actionEvents,
activeRefs,
activeText,
getIngredientByRefId,
showTitleEditor,
mergeAbove,
moveTo,
openDialog,
setIngredientIds,
availableNextStep,
saveAndOpenNextLinkIngredients,
undoMerge,
toggleDisabled,
isChecked,
toggleShowTitle,
instructionList,
autoSetReferences,
parseIngredientText,
toggleCookMode,
showCookMode,
isCookMode,
isEditForm,
insert,
breakpoint,
};
},
});
</script> </script>
<style lang="css" scoped> <style lang="css" scoped>