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:
parent
a2a0ad1af0
commit
93cec24f26
1 changed files with 338 additions and 435 deletions
|
@ -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>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue