mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-07-30 18:49:41 +02:00
feat: Added a dedicated cookmode dialog that allows for individual scrolling (#4464)
This commit is contained in:
parent
65c35adc9d
commit
d419acd61e
6 changed files with 190 additions and 87 deletions
|
@ -1,14 +1,16 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="value && value.length > 0">
|
<div v-if="value && value.length > 0">
|
||||||
<div class="d-flex justify-start">
|
<div v-if="!isCookMode" class="d-flex justify-start" >
|
||||||
<h2 class="mb-2 mt-1">{{ $t("recipe.ingredients") }}</h2>
|
<h2 class="mb-2 mt-1">{{ $t("recipe.ingredients") }}</h2>
|
||||||
<AppButtonCopy btn-class="ml-auto" :copy-text="ingredientCopyText" />
|
<AppButtonCopy btn-class="ml-auto" :copy-text="ingredientCopyText" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div v-for="(ingredient, index) in value" :key="'ingredient' + index">
|
<div v-for="(ingredient, index) in value" :key="'ingredient' + index">
|
||||||
<h3 v-if="showTitleEditor[index]" class="mt-2">{{ ingredient.title }}</h3>
|
<template v-if="!isCookMode">
|
||||||
<v-divider v-if="showTitleEditor[index]"></v-divider>
|
<h3 v-if="showTitleEditor[index]" class="mt-2">{{ ingredient.title }}</h3>
|
||||||
<v-list-item dense @click="toggleChecked(index)">
|
<v-divider v-if="showTitleEditor[index]"></v-divider>
|
||||||
|
</template>
|
||||||
|
<v-list-item dense @click.stop="toggleChecked(index)">
|
||||||
<v-checkbox hide-details :value="checked[index]" class="pt-0 my-auto py-auto" color="secondary" />
|
<v-checkbox hide-details :value="checked[index]" class="pt-0 my-auto py-auto" color="secondary" />
|
||||||
<v-list-item-content :key="ingredient.quantity">
|
<v-list-item-content :key="ingredient.quantity">
|
||||||
<RecipeIngredientListItem :ingredient="ingredient" :disable-amount="disableAmount" :scale="scale" />
|
<RecipeIngredientListItem :ingredient="ingredient" :disable-amount="disableAmount" :scale="scale" />
|
||||||
|
@ -40,6 +42,10 @@ export default defineComponent({
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 1,
|
default: 1,
|
||||||
},
|
},
|
||||||
|
isCookMode: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
function validateTitle(title?: string) {
|
function validateTitle(title?: string) {
|
||||||
|
|
|
@ -1,75 +1,135 @@
|
||||||
<template>
|
<template>
|
||||||
<v-container :class="{ 'pa-0': $vuetify.breakpoint.smAndDown }">
|
<div>
|
||||||
<v-card :flat="$vuetify.breakpoint.smAndDown" class="d-print-none">
|
<v-container v-show="!isCookMode" key="recipe-page" :class="{ 'pa-0': $vuetify.breakpoint.smAndDown }">
|
||||||
<RecipePageHeader
|
<v-card :flat="$vuetify.breakpoint.smAndDown" class="d-print-none">
|
||||||
|
<RecipePageHeader
|
||||||
|
:recipe="recipe"
|
||||||
|
:recipe-scale="scale"
|
||||||
|
:landscape="landscape"
|
||||||
|
@save="saveRecipe"
|
||||||
|
@delete="deleteRecipe"
|
||||||
|
/>
|
||||||
|
<LazyRecipeJsonEditor v-if="isEditJSON" v-model="recipe" class="mt-10" :options="EDITOR_OPTIONS" />
|
||||||
|
<v-card-text v-else>
|
||||||
|
<!--
|
||||||
|
This is where most of the main content is rendered. Some components include state for both Edit and View modes
|
||||||
|
which is why some have explicit v-if statements and others use the composition API to determine and manage
|
||||||
|
the shared state internally.
|
||||||
|
|
||||||
|
The global recipe object is shared down the tree of components and _is_ mutated by child components. This is
|
||||||
|
some-what of a hack of the system and goes against the principles of Vue, but it _does_ seem to work and streamline
|
||||||
|
a significant amount of prop management. When we move to Vue 3 and have access to some of the newer API's the plan to update this
|
||||||
|
data management and mutation system we're using.
|
||||||
|
-->
|
||||||
|
<RecipePageEditorToolbar v-if="isEditForm" :recipe="recipe" />
|
||||||
|
<RecipePageTitleContent :recipe="recipe" :landscape="landscape" />
|
||||||
|
<RecipePageIngredientEditor v-if="isEditForm" :recipe="recipe" />
|
||||||
|
<RecipePageScale :recipe="recipe" :scale.sync="scale" :landscape="landscape" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
This section contains the 2 column layout for the recipe steps and other content.
|
||||||
|
-->
|
||||||
|
<v-row>
|
||||||
|
<!--
|
||||||
|
The left column is conditionally rendered based on cook mode.
|
||||||
|
-->
|
||||||
|
<v-col v-if="!isCookMode || isEditForm" cols="12" sm="12" md="4" lg="4">
|
||||||
|
<RecipePageIngredientToolsView v-if="!isEditForm" :recipe="recipe" :scale="scale" />
|
||||||
|
<RecipePageOrganizers v-if="$vuetify.breakpoint.mdAndUp" :recipe="recipe" />
|
||||||
|
</v-col>
|
||||||
|
<v-divider v-if="$vuetify.breakpoint.mdAndUp && !isCookMode" class="my-divider" :vertical="true" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
the right column is always rendered, but it's layout width is determined by where the left column is
|
||||||
|
rendered.
|
||||||
|
-->
|
||||||
|
<v-col cols="12" sm="12" :md="8 + (isCookMode ? 1 : 0) * 4" :lg="8 + (isCookMode ? 1 : 0) * 4">
|
||||||
|
<RecipePageInstructions
|
||||||
|
v-model="recipe.recipeInstructions"
|
||||||
|
:assets.sync="recipe.assets"
|
||||||
|
:recipe="recipe"
|
||||||
|
:scale="scale"
|
||||||
|
/>
|
||||||
|
<div v-if="isEditForm" class="d-flex">
|
||||||
|
<RecipeDialogBulkAdd class="ml-auto my-2 mr-1" @bulk-data="addStep" />
|
||||||
|
<BaseButton class="my-2" @click="addStep()"> {{ $t("general.add") }}</BaseButton>
|
||||||
|
</div>
|
||||||
|
<div v-if="!$vuetify.breakpoint.mdAndUp">
|
||||||
|
<RecipePageOrganizers :recipe="recipe" />
|
||||||
|
</div>
|
||||||
|
<RecipeNotes v-model="recipe.notes" :edit="isEditForm" />
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
<RecipePageFooter :recipe="recipe" />
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
<WakelockSwitch/>
|
||||||
|
<RecipePageComments
|
||||||
|
v-if="!recipe.settings.disableComments && !isEditForm && !isCookMode"
|
||||||
:recipe="recipe"
|
:recipe="recipe"
|
||||||
:recipe-scale="scale"
|
class="px-1 my-4 d-print-none"
|
||||||
:landscape="landscape"
|
|
||||||
@save="saveRecipe"
|
|
||||||
@delete="deleteRecipe"
|
|
||||||
/>
|
/>
|
||||||
<LazyRecipeJsonEditor v-if="isEditJSON" v-model="recipe" class="mt-10" :options="EDITOR_OPTIONS" />
|
<RecipePrintContainer :recipe="recipe" :scale="scale" />
|
||||||
<v-card-text v-else>
|
</v-container>
|
||||||
<!--
|
<!-- Cook mode displayes two columns with ingredients and instructions side by side, each being scrolled individually, allowing to view both at the same timer -->
|
||||||
This is where most of the main content is rendered. Some components include state for both Edit and View modes
|
<v-sheet v-show="isCookMode && !hasLinkedIngredients" key="cookmode" :style="{height: $vuetify.breakpoint.smAndUp ? 'calc(100vh - 48px)' : ''}"> <!-- the calc is to account for the toolbar a more dynamic solution could be needed -->
|
||||||
which is why some have explicit v-if statements and others use the composition API to determine and manage
|
<v-row style="height: 100%;" no-gutters class="overflow-hidden">
|
||||||
the shared state internally.
|
<v-col cols="12" sm="5" class="overflow-y-auto pl-4 pr-3 py-2" style="height: 100%;">
|
||||||
|
<div class="d-flex align-center">
|
||||||
|
<RecipePageScale :recipe="recipe" :scale.sync="scale" :landscape="landscape" />
|
||||||
|
</div>
|
||||||
|
<RecipePageIngredientToolsView v-if="!isEditForm" :recipe="recipe" :scale="scale" :is-cook-mode="isCookMode" />
|
||||||
|
<v-divider></v-divider>
|
||||||
|
</v-col>
|
||||||
|
<v-col class="overflow-y-auto py-2" style="height: 100%;" cols="12" sm="7">
|
||||||
|
<RecipePageInstructions
|
||||||
|
v-model="recipe.recipeInstructions"
|
||||||
|
class="overflow-y-hidden px-4"
|
||||||
|
:assets.sync="recipe.assets"
|
||||||
|
:recipe="recipe"
|
||||||
|
:scale="scale"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
The global recipe object is shared down the tree of components and _is_ mutated by child components. This is
|
</v-sheet>
|
||||||
some-what of a hack of the system and goes against the principles of Vue, but it _does_ seem to work and streamline
|
<v-sheet v-show="isCookMode && hasLinkedIngredients">
|
||||||
a significant amount of prop management. When we move to Vue 3 and have access to some of the newer API's the plan to update this
|
<div class="mt-2 px-2 px-md-4">
|
||||||
data management and mutation system we're using.
|
<RecipePageScale :recipe="recipe" :scale.sync="scale" :landscape="landscape"/>
|
||||||
-->
|
</div>
|
||||||
<RecipePageEditorToolbar v-if="isEditForm" :recipe="recipe" />
|
<RecipePageInstructions
|
||||||
<RecipePageTitleContent :recipe="recipe" :landscape="landscape" />
|
v-model="recipe.recipeInstructions"
|
||||||
<RecipePageIngredientEditor v-if="isEditForm" :recipe="recipe" />
|
class="overflow-y-hidden mt-n5 px-2 px-md-4"
|
||||||
<RecipePageScale :recipe="recipe" :scale.sync="scale" :landscape="landscape" />
|
:assets.sync="recipe.assets"
|
||||||
|
:recipe="recipe"
|
||||||
<!--
|
:scale="scale"
|
||||||
This section contains the 2 column layout for the recipe steps and other content.
|
/>
|
||||||
-->
|
<v-divider></v-divider>
|
||||||
<v-row>
|
<div class="px-2 px-md-4 pb-4 ">
|
||||||
<!--
|
<v-card flat>
|
||||||
The left column is conditionally rendered based on cook mode.
|
<v-card-title>{{ $t('recipe.not-linked-ingredients') }}</v-card-title>
|
||||||
-->
|
<RecipeIngredients
|
||||||
<v-col v-if="!isCookMode || isEditForm" cols="12" sm="12" md="4" lg="4">
|
:value="notLinkedIngredients"
|
||||||
<RecipePageIngredientToolsView v-if="!isEditForm" :recipe="recipe" :scale="scale" />
|
|
||||||
<RecipePageOrganizers v-if="$vuetify.breakpoint.mdAndUp" :recipe="recipe" />
|
|
||||||
</v-col>
|
|
||||||
<v-divider v-if="$vuetify.breakpoint.mdAndUp && !isCookMode" class="my-divider" :vertical="true" />
|
|
||||||
|
|
||||||
<!--
|
|
||||||
the right column is always rendered, but it's layout width is determined by where the left column is
|
|
||||||
rendered.
|
|
||||||
-->
|
|
||||||
<v-col cols="12" sm="12" :md="8 + (isCookMode ? 1 : 0) * 4" :lg="8 + (isCookMode ? 1 : 0) * 4">
|
|
||||||
<RecipePageInstructions
|
|
||||||
v-model="recipe.recipeInstructions"
|
|
||||||
:assets.sync="recipe.assets"
|
|
||||||
:recipe="recipe"
|
|
||||||
:scale="scale"
|
:scale="scale"
|
||||||
/>
|
:disable-amount="recipe.settings.disableAmount"
|
||||||
<div v-if="isEditForm" class="d-flex">
|
:is-cook-mode="isCookMode">
|
||||||
<RecipeDialogBulkAdd class="ml-auto my-2 mr-1" @bulk-data="addStep" />
|
|
||||||
<BaseButton class="my-2" @click="addStep()"> {{ $t("general.add") }}</BaseButton>
|
</RecipeIngredients>
|
||||||
</div>
|
</v-card>
|
||||||
<div v-if="!$vuetify.breakpoint.mdAndUp">
|
</div>
|
||||||
<RecipePageOrganizers :recipe="recipe" />
|
</v-sheet>
|
||||||
</div>
|
<v-btn
|
||||||
<RecipeNotes v-model="recipe.notes" :edit="isEditForm" />
|
v-if="isCookMode"
|
||||||
</v-col>
|
fab
|
||||||
</v-row>
|
small
|
||||||
<RecipePageFooter :recipe="recipe" />
|
color="primary"
|
||||||
</v-card-text>
|
style="position: fixed; right: 12px; top: 60px;"
|
||||||
</v-card>
|
@click="toggleCookMode()"
|
||||||
<WakelockSwitch/>
|
>
|
||||||
<RecipePageComments
|
<v-icon>mdi-close</v-icon>
|
||||||
v-if="!recipe.settings.disableComments && !isEditForm && !isCookMode"
|
</v-btn>
|
||||||
:recipe="recipe"
|
</div>
|
||||||
class="px-1 my-4 d-print-none"
|
|
||||||
/>
|
|
||||||
<RecipePrintContainer :recipe="recipe" :scale="scale" />
|
|
||||||
</v-container>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -84,6 +144,7 @@ import {
|
||||||
useRoute,
|
useRoute,
|
||||||
} from "@nuxtjs/composition-api";
|
} from "@nuxtjs/composition-api";
|
||||||
import { invoke, until } from "@vueuse/core";
|
import { invoke, until } from "@vueuse/core";
|
||||||
|
import RecipeIngredients from "../RecipeIngredients.vue";
|
||||||
import RecipePageEditorToolbar from "./RecipePageParts/RecipePageEditorToolbar.vue";
|
import RecipePageEditorToolbar from "./RecipePageParts/RecipePageEditorToolbar.vue";
|
||||||
import RecipePageFooter from "./RecipePageParts/RecipePageFooter.vue";
|
import RecipePageFooter from "./RecipePageParts/RecipePageFooter.vue";
|
||||||
import RecipePageHeader from "./RecipePageParts/RecipePageHeader.vue";
|
import RecipePageHeader from "./RecipePageParts/RecipePageHeader.vue";
|
||||||
|
@ -133,6 +194,7 @@ export default defineComponent({
|
||||||
RecipeNotes,
|
RecipeNotes,
|
||||||
RecipePageInstructions,
|
RecipePageInstructions,
|
||||||
RecipePageFooter,
|
RecipePageFooter,
|
||||||
|
RecipeIngredients
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
recipe: {
|
recipe: {
|
||||||
|
@ -151,6 +213,13 @@ export default defineComponent({
|
||||||
const { pageMode, editMode, setMode, isEditForm, isEditJSON, isCookMode, isEditMode, toggleCookMode } =
|
const { pageMode, editMode, setMode, isEditForm, isEditJSON, isCookMode, isEditMode, toggleCookMode } =
|
||||||
usePageState(props.recipe.slug);
|
usePageState(props.recipe.slug);
|
||||||
const { deactivateNavigationWarning } = useNavigationWarning();
|
const { deactivateNavigationWarning } = useNavigationWarning();
|
||||||
|
const notLinkedIngredients = computed(() => {
|
||||||
|
console.log("inst",props.recipe.recipeInstruction);
|
||||||
|
return props.recipe.recipeIngredient.filter((ingredient) => {
|
||||||
|
return !props.recipe.recipeInstructions.some((step) => step.ingredientReferences?.map((ref) => ref.referenceId).includes(ingredient.referenceId));
|
||||||
|
})
|
||||||
|
})
|
||||||
|
console.log(notLinkedIngredients);
|
||||||
|
|
||||||
/** =============================================================
|
/** =============================================================
|
||||||
* Recipe Snapshot on Mount
|
* Recipe Snapshot on Mount
|
||||||
|
@ -176,11 +245,14 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deactivateNavigationWarning();
|
deactivateNavigationWarning();
|
||||||
|
toggleCookMode()
|
||||||
|
|
||||||
clearPageState(props.recipe.slug || "");
|
clearPageState(props.recipe.slug || "");
|
||||||
console.debug("reset RecipePage state during unmount");
|
console.debug("reset RecipePage state during unmount");
|
||||||
});
|
});
|
||||||
|
const hasLinkedIngredients = computed(() => {
|
||||||
|
return props.recipe.recipeInstructions.some((step) => step.ingredientReferences && step.ingredientReferences.length > 0);
|
||||||
|
})
|
||||||
/** =============================================================
|
/** =============================================================
|
||||||
* Set State onMounted
|
* Set State onMounted
|
||||||
*/
|
*/
|
||||||
|
@ -278,6 +350,8 @@ export default defineComponent({
|
||||||
saveRecipe,
|
saveRecipe,
|
||||||
deleteRecipe,
|
deleteRecipe,
|
||||||
addStep,
|
addStep,
|
||||||
|
hasLinkedIngredients,
|
||||||
|
notLinkedIngredients
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
head: {},
|
head: {},
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
:value="recipe.recipeIngredient"
|
:value="recipe.recipeIngredient"
|
||||||
:scale="scale"
|
:scale="scale"
|
||||||
:disable-amount="recipe.settings.disableAmount"
|
:disable-amount="recipe.settings.disableAmount"
|
||||||
|
:is-cook-mode="isCookMode"
|
||||||
/>
|
/>
|
||||||
<div v-if="!isEditMode && recipe.tools && recipe.tools.length > 0">
|
<div v-if="!isEditMode && recipe.tools && recipe.tools.length > 0">
|
||||||
<h2 class="mb-2 mt-4">{{ $t('tool.required-tools') }}</h2>
|
<h2 class="mb-2 mt-4">{{ $t('tool.required-tools') }}</h2>
|
||||||
|
@ -46,6 +47,10 @@ export default defineComponent({
|
||||||
type: Number,
|
type: Number,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
isCookMode: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const { isOwnGroup } = useLoggedInState();
|
const { isOwnGroup } = useLoggedInState();
|
||||||
|
|
|
@ -65,8 +65,8 @@
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
<div class="d-flex justify-space-between justify-start">
|
<div class="d-flex justify-space-between justify-start">
|
||||||
<h2 class="mb-4 mt-1">{{ $t("recipe.instructions") }}</h2>
|
<h2 v-if="!isCookMode" class="mb-4 mt-1">{{ $t("recipe.instructions") }}</h2>
|
||||||
<BaseButton v-if="!isEditForm && showCookMode" minor cancel color="primary" @click="toggleCookMode()">
|
<BaseButton v-if="!isEditForm && !isCookMode" minor cancel color="primary" @click="toggleCookMode()">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
{{ $globals.icons.primary }}
|
{{ $globals.icons.primary }}
|
||||||
</template>
|
</template>
|
||||||
|
@ -243,16 +243,31 @@
|
||||||
</DropZone>
|
</DropZone>
|
||||||
<v-expand-transition>
|
<v-expand-transition>
|
||||||
<div v-show="!isChecked(index) && !isEditForm" class="m-0 p-0">
|
<div v-show="!isChecked(index) && !isEditForm" class="m-0 p-0">
|
||||||
|
|
||||||
<v-card-text class="markdown">
|
<v-card-text class="markdown">
|
||||||
<SafeMarkdown class="markdown" :source="step.text" />
|
<v-row>
|
||||||
<div v-if="isCookMode && step.ingredientReferences && step.ingredientReferences.length > 0">
|
<v-col
|
||||||
<v-divider class="mb-2"></v-divider>
|
v-if="isCookMode && step.ingredientReferences && step.ingredientReferences.length > 0"
|
||||||
<RecipeIngredientHtml
|
cols="12"
|
||||||
v-for="ing in step.ingredientReferences"
|
sm="5"
|
||||||
:key="ing.referenceId"
|
>
|
||||||
:markup="getIngredientByRefId(ing.referenceId)"
|
<div class="ml-n4">
|
||||||
/>
|
<RecipeIngredients
|
||||||
</div>
|
:value="recipe.recipeIngredient.filter((ing) => {
|
||||||
|
if(!step.ingredientReferences) return false
|
||||||
|
return step.ingredientReferences.map((ref) => ref.referenceId).includes(ing.referenceId || '')
|
||||||
|
})"
|
||||||
|
:scale="scale"
|
||||||
|
:disable-amount="recipe.settings.disableAmount"
|
||||||
|
:is-cook-mode="isCookMode"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</v-col>
|
||||||
|
<v-divider v-if="isCookMode && step.ingredientReferences && step.ingredientReferences.length > 0 && $vuetify.breakpoint.smAndUp" vertical ></v-divider>
|
||||||
|
<v-col>
|
||||||
|
<SafeMarkdown class="markdown" :source="step.text" />
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</div>
|
</div>
|
||||||
</v-expand-transition>
|
</v-expand-transition>
|
||||||
|
@ -261,7 +276,7 @@
|
||||||
</div>
|
</div>
|
||||||
</TransitionGroup>
|
</TransitionGroup>
|
||||||
</draggable>
|
</draggable>
|
||||||
<v-divider class="mt-10 d-flex d-md-none"/>
|
<v-divider v-if="!isCookMode" class="mt-10 d-flex d-md-none"/>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -287,7 +302,7 @@ import { usePageState } from "~/composables/recipe-page/shared-state";
|
||||||
import { useExtractIngredientReferences } from "~/composables/recipe-page/use-extract-ingredient-references";
|
import { useExtractIngredientReferences } from "~/composables/recipe-page/use-extract-ingredient-references";
|
||||||
import { NoUndefinedField } from "~/lib/api/types/non-generated";
|
import { NoUndefinedField } from "~/lib/api/types/non-generated";
|
||||||
import DropZone from "~/components/global/DropZone.vue";
|
import DropZone from "~/components/global/DropZone.vue";
|
||||||
|
import RecipeIngredients from "~/components/Domain/Recipe/RecipeIngredients.vue";
|
||||||
interface MergerHistory {
|
interface MergerHistory {
|
||||||
target: number;
|
target: number;
|
||||||
source: number;
|
source: number;
|
||||||
|
@ -300,6 +315,7 @@ export default defineComponent({
|
||||||
draggable,
|
draggable,
|
||||||
RecipeIngredientHtml,
|
RecipeIngredientHtml,
|
||||||
DropZone,
|
DropZone,
|
||||||
|
RecipeIngredients
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
|
@ -322,7 +338,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
|
|
||||||
setup(props, context) {
|
setup(props, context) {
|
||||||
const { i18n, req } = useContext();
|
const { i18n, req, $vuetify } = useContext();
|
||||||
const BASE_URL = detectServerBaseUrl(req);
|
const BASE_URL = detectServerBaseUrl(req);
|
||||||
|
|
||||||
const { isCookMode, toggleCookMode, isEditForm } = usePageState(props.recipe.slug);
|
const { isCookMode, toggleCookMode, isEditForm } = usePageState(props.recipe.slug);
|
||||||
|
|
|
@ -662,7 +662,8 @@
|
||||||
"missing-food": "Create missing food: {food}",
|
"missing-food": "Create missing food: {food}",
|
||||||
"no-food": "No Food"
|
"no-food": "No Food"
|
||||||
},
|
},
|
||||||
"reset-servings-count": "Reset Servings Count"
|
"reset-servings-count": "Reset Servings Count",
|
||||||
|
"not-linked-ingredients": "Additional Ingredients"
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"advanced-search": "Advanced Search",
|
"advanced-search": "Advanced Search",
|
||||||
|
|
|
@ -268,6 +268,7 @@ export interface RecipeStep {
|
||||||
title?: string | null;
|
title?: string | null;
|
||||||
text: string;
|
text: string;
|
||||||
ingredientReferences?: IngredientReferences[];
|
ingredientReferences?: IngredientReferences[];
|
||||||
|
summary?: string | null;
|
||||||
}
|
}
|
||||||
export interface RecipeAsset {
|
export interface RecipeAsset {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue