| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  | <template> | 
					
						
							| 
									
										
										
										
											2024-11-11 12:21:44 +01:00
										 |  |  |   <div> | 
					
						
							|  |  |  |     <v-container v-show="!isCookMode" key="recipe-page" :class="{ 'pa-0': $vuetify.breakpoint.smAndDown }"> | 
					
						
							|  |  |  |       <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> | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  |           <!-- | 
					
						
							| 
									
										
										
										
											2024-11-11 12:21:44 +01:00
										 |  |  |             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" /> | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |           <!-- | 
					
						
							| 
									
										
										
										
											2024-11-11 12:21:44 +01:00
										 |  |  |             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" | 
					
						
							|  |  |  |         class="px-1 my-4 d-print-none" | 
					
						
							|  |  |  |       /> | 
					
						
							|  |  |  |       <RecipePrintContainer :recipe="recipe" :scale="scale" /> | 
					
						
							|  |  |  |     </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 --> | 
					
						
							|  |  |  |     <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  --> | 
					
						
							|  |  |  |       <v-row  style="height: 100%;"  no-gutters class="overflow-hidden"> | 
					
						
							|  |  |  |         <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> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     </v-sheet> | 
					
						
							|  |  |  |     <v-sheet v-show="isCookMode && hasLinkedIngredients"> | 
					
						
							|  |  |  |       <div class="mt-2 px-2 px-md-4"> | 
					
						
							|  |  |  |         <RecipePageScale :recipe="recipe" :scale.sync="scale" :landscape="landscape"/> | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |       <RecipePageInstructions | 
					
						
							|  |  |  |         v-model="recipe.recipeInstructions" | 
					
						
							|  |  |  |         class="overflow-y-hidden mt-n5 px-2 px-md-4" | 
					
						
							|  |  |  |         :assets.sync="recipe.assets" | 
					
						
							|  |  |  |         :recipe="recipe" | 
					
						
							|  |  |  |         :scale="scale" | 
					
						
							|  |  |  |       /> | 
					
						
							|  |  |  |       <v-divider></v-divider> | 
					
						
							|  |  |  |       <div class="px-2 px-md-4 pb-4 "> | 
					
						
							|  |  |  |         <v-card flat> | 
					
						
							|  |  |  |           <v-card-title>{{ $t('recipe.not-linked-ingredients') }}</v-card-title> | 
					
						
							|  |  |  |             <RecipeIngredients | 
					
						
							|  |  |  |               :value="notLinkedIngredients" | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  |               :scale="scale" | 
					
						
							| 
									
										
										
										
											2024-11-11 12:21:44 +01:00
										 |  |  |               :disable-amount="recipe.settings.disableAmount" | 
					
						
							|  |  |  |               :is-cook-mode="isCookMode"> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             </RecipeIngredients> | 
					
						
							|  |  |  |         </v-card> | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |     </v-sheet> | 
					
						
							|  |  |  |     <v-btn | 
					
						
							|  |  |  |       v-if="isCookMode" | 
					
						
							|  |  |  |       fab | 
					
						
							|  |  |  |       small | 
					
						
							|  |  |  |       color="primary" | 
					
						
							|  |  |  |       style="position: fixed; right: 12px; top: 60px;" | 
					
						
							|  |  |  |       @click="toggleCookMode()" | 
					
						
							|  |  |  |       > | 
					
						
							|  |  |  |       <v-icon>mdi-close</v-icon> | 
					
						
							|  |  |  |     </v-btn> | 
					
						
							|  |  |  |   </div> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  | </template> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <script lang="ts"> | 
					
						
							| 
									
										
										
										
											2022-10-23 13:02:56 -08:00
										 |  |  | import { | 
					
						
							|  |  |  |   defineComponent, | 
					
						
							|  |  |  |   useContext, | 
					
						
							|  |  |  |   useRouter, | 
					
						
							|  |  |  |   computed, | 
					
						
							|  |  |  |   ref, | 
					
						
							|  |  |  |   onMounted, | 
					
						
							|  |  |  |   onUnmounted, | 
					
						
							| 
									
										
										
										
											2023-11-05 19:07:02 -06:00
										 |  |  | useRoute, | 
					
						
							| 
									
										
										
										
											2022-10-23 13:02:56 -08:00
										 |  |  | } from "@nuxtjs/composition-api"; | 
					
						
							| 
									
										
										
										
											2024-09-28 10:16:06 -05:00
										 |  |  | import { invoke, until } from "@vueuse/core"; | 
					
						
							| 
									
										
										
										
											2024-11-11 12:21:44 +01:00
										 |  |  | import RecipeIngredients from "../RecipeIngredients.vue"; | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  | import RecipePageEditorToolbar from "./RecipePageParts/RecipePageEditorToolbar.vue"; | 
					
						
							|  |  |  | import RecipePageFooter from "./RecipePageParts/RecipePageFooter.vue"; | 
					
						
							|  |  |  | import RecipePageHeader from "./RecipePageParts/RecipePageHeader.vue"; | 
					
						
							|  |  |  | import RecipePageIngredientEditor from "./RecipePageParts/RecipePageIngredientEditor.vue"; | 
					
						
							|  |  |  | import RecipePageIngredientToolsView from "./RecipePageParts/RecipePageIngredientToolsView.vue"; | 
					
						
							|  |  |  | import RecipePageInstructions from "./RecipePageParts/RecipePageInstructions.vue"; | 
					
						
							|  |  |  | import RecipePageOrganizers from "./RecipePageParts/RecipePageOrganizers.vue"; | 
					
						
							|  |  |  | import RecipePageScale from "./RecipePageParts/RecipePageScale.vue"; | 
					
						
							|  |  |  | import RecipePageTitleContent from "./RecipePageParts/RecipePageTitleContent.vue"; | 
					
						
							|  |  |  | import RecipePageComments from "./RecipePageParts/RecipePageComments.vue"; | 
					
						
							| 
									
										
										
										
											2023-11-05 19:07:02 -06:00
										 |  |  | import { useLoggedInState } from "~/composables/use-logged-in-state"; | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  | import RecipePrintContainer from "~/components/Domain/Recipe/RecipePrintContainer.vue"; | 
					
						
							| 
									
										
										
										
											2024-11-07 11:43:07 -06:00
										 |  |  | import { | 
					
						
							|  |  |  |   clearPageState, | 
					
						
							|  |  |  |   EditorMode, | 
					
						
							|  |  |  |   PageMode, | 
					
						
							|  |  |  |   usePageState, | 
					
						
							|  |  |  |   usePageUser, | 
					
						
							|  |  |  | } from "~/composables/recipe-page/shared-state"; | 
					
						
							| 
									
										
										
										
											2022-10-22 11:51:07 -08:00
										 |  |  | import { NoUndefinedField } from "~/lib/api/types/non-generated"; | 
					
						
							|  |  |  | import { Recipe } from "~/lib/api/types/recipe"; | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  | import { useRouteQuery } from "~/composables/use-router"; | 
					
						
							|  |  |  | import { useUserApi } from "~/composables/api"; | 
					
						
							|  |  |  | import { uuid4, deepCopy } from "~/composables/use-utils"; | 
					
						
							|  |  |  | import RecipeDialogBulkAdd from "~/components/Domain/Recipe/RecipeDialogBulkAdd.vue"; | 
					
						
							|  |  |  | import RecipeNotes from "~/components/Domain/Recipe/RecipeNotes.vue"; | 
					
						
							| 
									
										
										
										
											2024-01-06 22:18:55 +00:00
										 |  |  | import { useNavigationWarning } from "~/composables/use-navigation-warning"; | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | const EDITOR_OPTIONS = { | 
					
						
							|  |  |  |   mode: "code", | 
					
						
							|  |  |  |   search: false, | 
					
						
							|  |  |  |   mainMenuBar: false, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export default defineComponent({ | 
					
						
							|  |  |  |   components: { | 
					
						
							|  |  |  |     RecipePageHeader, | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  |     RecipePrintContainer, | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  |     RecipePageComments, | 
					
						
							|  |  |  |     RecipePageTitleContent, | 
					
						
							|  |  |  |     RecipePageEditorToolbar, | 
					
						
							|  |  |  |     RecipePageIngredientEditor, | 
					
						
							|  |  |  |     RecipePageOrganizers, | 
					
						
							|  |  |  |     RecipePageScale, | 
					
						
							|  |  |  |     RecipePageIngredientToolsView, | 
					
						
							|  |  |  |     RecipeDialogBulkAdd, | 
					
						
							|  |  |  |     RecipeNotes, | 
					
						
							|  |  |  |     RecipePageInstructions, | 
					
						
							|  |  |  |     RecipePageFooter, | 
					
						
							| 
									
										
										
										
											2024-11-11 12:21:44 +01:00
										 |  |  |     RecipeIngredients | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  |   }, | 
					
						
							|  |  |  |   props: { | 
					
						
							|  |  |  |     recipe: { | 
					
						
							|  |  |  |       type: Object as () => NoUndefinedField<Recipe>, | 
					
						
							|  |  |  |       required: true, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   setup(props) { | 
					
						
							| 
									
										
										
										
											2023-11-24 22:46:58 +01:00
										 |  |  |     const { $auth } = useContext(); | 
					
						
							| 
									
										
										
										
											2023-11-05 19:07:02 -06:00
										 |  |  |     const route = useRoute(); | 
					
						
							|  |  |  |     const groupSlug = computed(() => route.value.params.groupSlug || $auth.user?.groupSlug || ""); | 
					
						
							|  |  |  |     const { isOwnGroup } = useLoggedInState(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  |     const router = useRouter(); | 
					
						
							|  |  |  |     const api = useUserApi(); | 
					
						
							|  |  |  |     const { pageMode, editMode, setMode, isEditForm, isEditJSON, isCookMode, isEditMode, toggleCookMode } = | 
					
						
							|  |  |  |       usePageState(props.recipe.slug); | 
					
						
							| 
									
										
										
										
											2024-01-06 22:18:55 +00:00
										 |  |  |     const { deactivateNavigationWarning } = useNavigationWarning(); | 
					
						
							| 
									
										
										
										
											2024-11-11 12:21:44 +01:00
										 |  |  |     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); | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** ============================================================= | 
					
						
							|  |  |  |      * Recipe Snapshot on Mount | 
					
						
							|  |  |  |      * this is used to determine if the recipe has been changed since the last save | 
					
						
							|  |  |  |      * and prompts the user to save if they have unsaved changes. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     const originalRecipe = ref<Recipe | null>(null); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     invoke(async () => { | 
					
						
							|  |  |  |       await until(props.recipe).not.toBeNull(); | 
					
						
							|  |  |  |       originalRecipe.value = deepCopy(props.recipe); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     onUnmounted(async () => { | 
					
						
							|  |  |  |       const isSame = JSON.stringify(props.recipe) === JSON.stringify(originalRecipe.value); | 
					
						
							|  |  |  |       if (isEditMode.value && !isSame && props.recipe?.slug !== undefined) { | 
					
						
							|  |  |  |         const save = window.confirm( | 
					
						
							| 
									
										
										
										
											2023-10-26 15:26:14 +02:00
										 |  |  |           i18n.tc("general.unsaved-changes"), | 
					
						
							|  |  |  |           ); | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (save) { | 
					
						
							|  |  |  |           await api.recipes.updateOne(props.recipe.slug, props.recipe); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2024-01-06 22:18:55 +00:00
										 |  |  |       deactivateNavigationWarning(); | 
					
						
							| 
									
										
										
										
											2024-11-11 12:21:44 +01:00
										 |  |  |       toggleCookMode() | 
					
						
							| 
									
										
										
										
											2024-11-07 11:43:07 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |       clearPageState(props.recipe.slug || ""); | 
					
						
							|  |  |  |       console.debug("reset RecipePage state during unmount"); | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2024-11-11 12:21:44 +01:00
										 |  |  |     const hasLinkedIngredients = computed(() => { | 
					
						
							|  |  |  |       return props.recipe.recipeInstructions.some((step) => step.ingredientReferences && step.ingredientReferences.length > 0); | 
					
						
							|  |  |  |     }) | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  |     /** ============================================================= | 
					
						
							|  |  |  |      * Set State onMounted | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     type BooleanString = "true" | "false" | ""; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const edit = useRouteQuery<BooleanString>("edit", ""); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     onMounted(() => { | 
					
						
							|  |  |  |       if (edit.value === "true") { | 
					
						
							|  |  |  |         setMode(PageMode.EDIT); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** ============================================================= | 
					
						
							|  |  |  |      * Recipe Save Delete | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async function saveRecipe() { | 
					
						
							|  |  |  |       const { data } = await api.recipes.updateOne(props.recipe.slug, props.recipe); | 
					
						
							|  |  |  |       setMode(PageMode.VIEW); | 
					
						
							|  |  |  |       if (data?.slug) { | 
					
						
							| 
									
										
										
										
											2023-11-05 19:07:02 -06:00
										 |  |  |         router.push(`/g/${groupSlug.value}/r/` + data.slug); | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async function deleteRecipe() { | 
					
						
							|  |  |  |       const { data } = await api.recipes.deleteOne(props.recipe.slug); | 
					
						
							|  |  |  |       if (data?.slug) { | 
					
						
							| 
									
										
										
										
											2023-11-05 19:07:02 -06:00
										 |  |  |         router.push(`/g/${groupSlug.value}`); | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** ============================================================= | 
					
						
							|  |  |  |      * View Preferences | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2023-10-26 15:26:14 +02:00
										 |  |  |     const { $vuetify, i18n } = useContext(); | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const landscape = computed(() => { | 
					
						
							|  |  |  |       const preferLandscape = props.recipe.settings.landscapeView; | 
					
						
							|  |  |  |       const smallScreen = !$vuetify.breakpoint.smAndUp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (preferLandscape) { | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |       } else if (smallScreen) { | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** ============================================================= | 
					
						
							|  |  |  |      * Bulk Step Editor | 
					
						
							|  |  |  |      * TODO: Move to RecipePageInstructions component | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function addStep(steps: Array<string> | null = null) { | 
					
						
							|  |  |  |       if (!props.recipe.recipeInstructions) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (steps) { | 
					
						
							|  |  |  |         const cleanedSteps = steps.map((step) => { | 
					
						
							|  |  |  |           return { id: uuid4(), text: step, title: "", ingredientReferences: [] }; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         props.recipe.recipeInstructions.push(...cleanedSteps); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         props.recipe.recipeInstructions.push({ id: uuid4(), text: "", title: "", ingredientReferences: [] }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** ============================================================= | 
					
						
							|  |  |  |      * Meta Tags | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-08-28 20:08:33 -08:00
										 |  |  |     const { user } = usePageUser(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  |     return { | 
					
						
							| 
									
										
										
										
											2022-08-28 20:08:33 -08:00
										 |  |  |       user, | 
					
						
							| 
									
										
										
										
											2023-11-05 19:07:02 -06:00
										 |  |  |       isOwnGroup, | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  |       api, | 
					
						
							|  |  |  |       scale: ref(1), | 
					
						
							|  |  |  |       EDITOR_OPTIONS, | 
					
						
							|  |  |  |       landscape, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       pageMode, | 
					
						
							|  |  |  |       editMode, | 
					
						
							|  |  |  |       PageMode, | 
					
						
							|  |  |  |       EditorMode, | 
					
						
							|  |  |  |       isEditMode, | 
					
						
							|  |  |  |       isEditForm, | 
					
						
							|  |  |  |       isEditJSON, | 
					
						
							|  |  |  |       isCookMode, | 
					
						
							|  |  |  |       toggleCookMode, | 
					
						
							|  |  |  |       saveRecipe, | 
					
						
							|  |  |  |       deleteRecipe, | 
					
						
							|  |  |  |       addStep, | 
					
						
							| 
									
										
										
										
											2024-11-11 12:21:44 +01:00
										 |  |  |       hasLinkedIngredients, | 
					
						
							|  |  |  |       notLinkedIngredients | 
					
						
							| 
									
										
										
										
											2022-08-27 10:44:58 -08:00
										 |  |  |     }; | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   head: {}, | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | </script> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <style lang="css"> | 
					
						
							|  |  |  | .flip-list-move { | 
					
						
							|  |  |  |   transition: transform 0.5s; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | .no-move { | 
					
						
							|  |  |  |   transition: transform 0s; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | .ghost { | 
					
						
							|  |  |  |   opacity: 0.5; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | .list-group { | 
					
						
							|  |  |  |   min-height: 38px; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | .list-group-item i { | 
					
						
							|  |  |  |   cursor: pointer; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | </style> |