| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  | <!-- eslint-disable vue/no-v-html --> | 
					
						
							| 
									
										
										
										
											2021-05-14 21:10:03 -08:00
										 |  |  | <template> | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  |   <div :class="dense ? 'wrapper' : 'wrapper pa-3'"> | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  |     <section> | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  |       <v-container class="ma-0 pa-0"> | 
					
						
							|  |  |  |         <v-row> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           <v-col v-if="preferences.imagePosition && preferences.imagePosition != ImagePosition.hidden"
 | 
					
						
							|  |  |  |                  :order="preferences.imagePosition == ImagePosition.left ? -1 : 1" | 
					
						
							|  |  |  |                  cols="4" | 
					
						
							|  |  |  |                  align-self="center" | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  |           > | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |             <img :key="imageKey" | 
					
						
							|  |  |  |                  :src="recipeImageUrl" | 
					
						
							|  |  |  |                  style="min-height: 50; max-width: 100%;" | 
					
						
							|  |  |  |             > | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  |           </v-col> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           <v-col order="0"> | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  |             <v-card-title class="headline pl-0"> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |               <v-icon start | 
					
						
							|  |  |  |                       color="primary" | 
					
						
							|  |  |  |               > | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  |                 {{ $globals.icons.primary }} | 
					
						
							|  |  |  |               </v-icon> | 
					
						
							|  |  |  |               {{ recipe.name }} | 
					
						
							|  |  |  |             </v-card-title> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |             <div v-if="recipeYield"
 | 
					
						
							|  |  |  |                  class="d-flex justify-space-between align-center px-4 pb-2" | 
					
						
							|  |  |  |             > | 
					
						
							|  |  |  |               <v-chip :size="$vuetify.display.smAndDown ? 'small' : undefined" | 
					
						
							|  |  |  |                       label | 
					
						
							| 
									
										
										
										
											2024-11-20 08:46:27 -06:00
										 |  |  |               > | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |                 <v-icon start> | 
					
						
							| 
									
										
										
										
											2024-11-20 08:46:27 -06:00
										 |  |  |                   {{ $globals.icons.potSteam }} | 
					
						
							|  |  |  |                 </v-icon> | 
					
						
							|  |  |  |                 <!-- eslint-disable-next-line vue/no-v-html --> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |                 <span v-html="recipeYield" /> | 
					
						
							| 
									
										
										
										
											2024-11-20 08:46:27 -06:00
										 |  |  |               </v-chip> | 
					
						
							|  |  |  |             </div> | 
					
						
							| 
									
										
										
										
											2025-02-26 17:07:12 +01:00
										 |  |  |             <v-row class="d-flex justify-start"> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |               <RecipeTimeCard :prep-time="recipe.prepTime" | 
					
						
							|  |  |  |                               :total-time="recipe.totalTime" | 
					
						
							|  |  |  |                               :perform-time="recipe.performTime" | 
					
						
							|  |  |  |                               small | 
					
						
							|  |  |  |                               color="white" | 
					
						
							|  |  |  |                               class="ml-4" | 
					
						
							| 
									
										
										
										
											2025-02-26 17:07:12 +01:00
										 |  |  |               /> | 
					
						
							|  |  |  |             </v-row> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |             <v-card-text v-if="preferences.showDescription"
 | 
					
						
							|  |  |  |                          class="px-0" | 
					
						
							|  |  |  |             > | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  |               <SafeMarkdown :source="recipe.description" /> | 
					
						
							|  |  |  |             </v-card-text> | 
					
						
							|  |  |  |           </v-col> | 
					
						
							|  |  |  |         </v-row> | 
					
						
							|  |  |  |       </v-container> | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  |     </section> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-10 19:48:07 -05:00
										 |  |  |     <!-- Ingredients --> | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  |     <section> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |       <v-card-title class="headline pl-0"> | 
					
						
							|  |  |  |         {{ $t("recipe.ingredients") }} | 
					
						
							|  |  |  |       </v-card-title> | 
					
						
							|  |  |  |       <div v-for="(ingredientSection, sectionIndex) in ingredientSections"
 | 
					
						
							|  |  |  |            :key="`ingredient-section-${sectionIndex}`" | 
					
						
							|  |  |  |            class="print-section" | 
					
						
							| 
									
										
										
										
											2022-06-12 19:43:09 -05:00
										 |  |  |       > | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |         <h4 v-if="ingredientSection.ingredients[0].title"
 | 
					
						
							|  |  |  |             class="ingredient-title mt-2" | 
					
						
							|  |  |  |         > | 
					
						
							| 
									
										
										
										
											2022-10-22 11:51:07 -08:00
										 |  |  |           {{ ingredientSection.ingredients[0].title }} | 
					
						
							| 
									
										
										
										
											2022-08-20 02:01:55 -05:00
										 |  |  |         </h4> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |         <div class="ingredient-grid" | 
					
						
							|  |  |  |              :style="{ gridTemplateRows: `repeat(${Math.ceil(ingredientSection.ingredients.length / 2)}, min-content)` }" | 
					
						
							| 
									
										
										
										
											2022-10-22 11:51:07 -08:00
										 |  |  |         > | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |           <template v-for="(ingredient, ingredientIndex) in ingredientSection.ingredients"
 | 
					
						
							|  |  |  |                     :key="`ingredient-${ingredientIndex}`" | 
					
						
							|  |  |  |           > | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  |             <!-- eslint-disable-next-line vue/no-v-html --> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |             <p class="ingredient-body" | 
					
						
							|  |  |  |                v-html="parseText(ingredient)" | 
					
						
							|  |  |  |             /> | 
					
						
							| 
									
										
										
										
											2022-06-12 19:43:09 -05:00
										 |  |  |           </template> | 
					
						
							|  |  |  |         </div> | 
					
						
							| 
									
										
										
										
											2021-11-04 18:15:23 -08:00
										 |  |  |       </div> | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  |     </section> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-12 19:43:09 -05:00
										 |  |  |     <!-- Instructions --> | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  |     <section> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |       <div v-for="(instructionSection, sectionIndex) in instructionSections"
 | 
					
						
							|  |  |  |            :key="`instruction-section-${sectionIndex}`" | 
					
						
							|  |  |  |            :class="{ 'print-section': instructionSection.sectionName }" | 
					
						
							| 
									
										
										
										
											2022-06-12 19:43:09 -05:00
										 |  |  |       > | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |         <v-card-title v-if="!sectionIndex"
 | 
					
						
							|  |  |  |                       class="headline pl-0" | 
					
						
							|  |  |  |         > | 
					
						
							|  |  |  |           {{ $t("recipe.instructions") }} | 
					
						
							|  |  |  |         </v-card-title> | 
					
						
							|  |  |  |         <div v-for="(step, stepIndex) in instructionSection.instructions"
 | 
					
						
							|  |  |  |              :key="`instruction-${stepIndex}`" | 
					
						
							|  |  |  |         > | 
					
						
							| 
									
										
										
										
											2022-06-12 19:43:09 -05:00
										 |  |  |           <div class="print-section"> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |             <h4 v-if="step.title"
 | 
					
						
							|  |  |  |                 :key="`instruction-title-${stepIndex}`" | 
					
						
							|  |  |  |                 class="instruction-title mb-2" | 
					
						
							|  |  |  |             > | 
					
						
							| 
									
										
										
										
											2022-06-12 19:43:09 -05:00
										 |  |  |               {{ step.title }} | 
					
						
							|  |  |  |             </h4> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |             <h5> | 
					
						
							|  |  |  |               {{ step.summary ? step.summary : $t("recipe.step-index", { | 
					
						
							|  |  |  |                 step: stepIndex | 
					
						
							|  |  |  |                   + instructionSection.stepOffset | 
					
						
							|  |  |  |                   + 1, | 
					
						
							|  |  |  |               }) }} | 
					
						
							|  |  |  |             </h5> | 
					
						
							|  |  |  |             <SafeMarkdown :source="step.text" | 
					
						
							|  |  |  |                           class="recipe-step-body" | 
					
						
							|  |  |  |             /> | 
					
						
							| 
									
										
										
										
											2022-06-12 19:43:09 -05:00
										 |  |  |           </div> | 
					
						
							| 
									
										
										
										
											2021-11-04 18:15:23 -08:00
										 |  |  |         </div> | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  |       </div> | 
					
						
							|  |  |  |     </section> | 
					
						
							| 
									
										
										
										
											2021-05-14 21:10:03 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-12 19:43:09 -05:00
										 |  |  |     <!-- Notes --> | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  |     <div v-if="preferences.showNotes"> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |       <v-divider v-if="hasNotes"
 | 
					
						
							|  |  |  |                  class="grey my-4" | 
					
						
							|  |  |  |       /> | 
					
						
							| 
									
										
										
										
											2021-05-14 21:10:03 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  |       <section> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |         <div v-for="(note, index) in recipe.notes"
 | 
					
						
							|  |  |  |              :key="index + 'note'" | 
					
						
							|  |  |  |         > | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  |           <div class="print-section"> | 
					
						
							|  |  |  |             <h4>{{ note.title }}</h4> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |             <SafeMarkdown :source="note.text" | 
					
						
							|  |  |  |                           class="note-body" | 
					
						
							|  |  |  |             /> | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  |           </div> | 
					
						
							| 
									
										
										
										
											2022-06-12 19:43:09 -05:00
										 |  |  |         </div> | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  |       </section> | 
					
						
							|  |  |  |     </div> | 
					
						
							| 
									
										
										
										
											2024-06-18 11:08:22 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     <!-- Nutrition --> | 
					
						
							|  |  |  |     <div v-if="preferences.showNutrition"> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |       <v-card-title class="headline pl-0"> | 
					
						
							|  |  |  |         {{ $t("recipe.nutrition") }} | 
					
						
							|  |  |  |       </v-card-title> | 
					
						
							| 
									
										
										
										
											2024-06-18 11:08:22 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       <section> | 
					
						
							|  |  |  |         <div class="print-section"> | 
					
						
							|  |  |  |           <table class="nutrition-table"> | 
					
						
							|  |  |  |             <tbody> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |               <tr v-for="(value, key) in recipe.nutrition"
 | 
					
						
							|  |  |  |                   :key="key" | 
					
						
							|  |  |  |               > | 
					
						
							| 
									
										
										
										
											2024-06-18 11:08:22 +02:00
										 |  |  |                 <template v-if="value"> | 
					
						
							|  |  |  |                   <td>{{ labels[key].label }}</td> | 
					
						
							| 
									
										
										
										
											2024-11-01 15:12:25 -07:00
										 |  |  |                   <td>{{ value ? (labels[key].suffix ? `${value} ${labels[key].suffix}` : value) : '-' }}</td> | 
					
						
							| 
									
										
										
										
											2024-06-18 11:08:22 +02:00
										 |  |  |                 </template> | 
					
						
							|  |  |  |               </tr> | 
					
						
							|  |  |  |             </tbody> | 
					
						
							|  |  |  |           </table> | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |         </div> | 
					
						
							|  |  |  |       </section> | 
					
						
							| 
									
										
										
										
											2024-06-18 11:08:22 +02:00
										 |  |  |     </div> | 
					
						
							| 
									
										
										
										
											2021-05-14 21:10:03 -08:00
										 |  |  |   </div> | 
					
						
							|  |  |  | </template> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-04 18:15:23 -08:00
										 |  |  | <script lang="ts"> | 
					
						
							| 
									
										
										
										
											2024-11-20 08:46:27 -06:00
										 |  |  | import DOMPurify from "dompurify"; | 
					
						
							| 
									
										
										
										
											2021-11-04 18:15:23 -08:00
										 |  |  | import RecipeTimeCard from "~/components/Domain/Recipe/RecipeTimeCard.vue"; | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  | import { useStaticRoutes } from "~/composables/api"; | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  | import type { Recipe, RecipeIngredient, RecipeStep } from "~/lib/api/types/recipe"; | 
					
						
							|  |  |  | import type { NoUndefinedField } from "~/lib/api/types/non-generated"; | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  | import { ImagePosition, useUserPrintPreferences } from "~/composables/use-users/preferences"; | 
					
						
							| 
									
										
										
										
											2024-06-18 11:08:22 +02:00
										 |  |  | import { parseIngredientText, useNutritionLabels } from "~/composables/recipes"; | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  | import { usePageState } from "~/composables/recipe-page/shared-state"; | 
					
						
							| 
									
										
										
										
											2024-11-20 08:46:27 -06:00
										 |  |  | import { useScaledAmount } from "~/composables/recipes/use-scaled-amount"; | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-12 19:43:09 -05:00
										 |  |  | type IngredientSection = { | 
					
						
							|  |  |  |   sectionName: string; | 
					
						
							|  |  |  |   ingredients: RecipeIngredient[]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type InstructionSection = { | 
					
						
							|  |  |  |   sectionName: string; | 
					
						
							|  |  |  |   stepOffset: number; | 
					
						
							|  |  |  |   instructions: RecipeStep[]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  | export default defineNuxtComponent({ | 
					
						
							| 
									
										
										
										
											2021-05-14 21:10:03 -08:00
										 |  |  |   components: { | 
					
						
							|  |  |  |     RecipeTimeCard, | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   props: { | 
					
						
							| 
									
										
										
										
											2021-08-07 16:49:55 -08:00
										 |  |  |     recipe: { | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  |       type: Object as () => NoUndefinedField<Recipe>, | 
					
						
							| 
									
										
										
										
											2021-08-07 16:49:55 -08:00
										 |  |  |       required: true, | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2022-12-30 16:47:35 -06:00
										 |  |  |     scale: { | 
					
						
							|  |  |  |       type: Number, | 
					
						
							|  |  |  |       default: 1, | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  |     dense: { | 
					
						
							|  |  |  |       type: Boolean, | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |       default: false, | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2021-05-14 21:10:03 -08:00
										 |  |  |   }, | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  |   setup(props) { | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |     const i18n = useI18n(); | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  |     const preferences = useUserPrintPreferences(); | 
					
						
							|  |  |  |     const { recipeImage } = useStaticRoutes(); | 
					
						
							|  |  |  |     const { imageKey } = usePageState(props.recipe.slug); | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |     const { labels } = useNutritionLabels(); | 
					
						
							| 
									
										
										
										
											2024-06-18 11:08:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-20 08:46:27 -06:00
										 |  |  |     function sanitizeHTML(rawHtml: string) { | 
					
						
							|  |  |  |       return DOMPurify.sanitize(rawHtml, { | 
					
						
							|  |  |  |         USE_PROFILES: { html: true }, | 
					
						
							|  |  |  |         ALLOWED_TAGS: ["strong", "sup"], | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-06-18 11:08:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-20 08:46:27 -06:00
										 |  |  |     const servingsDisplay = computed(() => { | 
					
						
							|  |  |  |       const { scaledAmountDisplay } = useScaledAmount(props.recipe.recipeYieldQuantity, props.scale); | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |       return scaledAmountDisplay | 
					
						
							|  |  |  |         ? i18n.t("recipe.yields-amount-with-text", { | 
					
						
							|  |  |  |           amount: scaledAmountDisplay, | 
					
						
							|  |  |  |           text: props.recipe.recipeYield, | 
					
						
							|  |  |  |         }) as string | 
					
						
							|  |  |  |         : ""; | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2024-11-20 08:46:27 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const yieldDisplay = computed(() => { | 
					
						
							|  |  |  |       const { scaledAmountDisplay } = useScaledAmount(props.recipe.recipeServings, props.scale); | 
					
						
							|  |  |  |       return scaledAmountDisplay ? i18n.t("recipe.serves-amount", { amount: scaledAmountDisplay }) as string : ""; | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2024-06-18 11:08:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-20 08:46:27 -06:00
										 |  |  |     const recipeYield = computed(() => { | 
					
						
							|  |  |  |       if (servingsDisplay.value && yieldDisplay.value) { | 
					
						
							|  |  |  |         return sanitizeHTML(`${yieldDisplay.value}; ${servingsDisplay.value}`); | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							| 
									
										
										
										
											2024-11-20 08:46:27 -06:00
										 |  |  |         return sanitizeHTML(yieldDisplay.value || servingsDisplay.value); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const recipeImageUrl = computed(() => { | 
					
						
							|  |  |  |       return recipeImage(props.recipe.id, props.recipe.image, imageKey.value); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-12 19:43:09 -05:00
										 |  |  |     // Group ingredients by section so we can style them independently
 | 
					
						
							|  |  |  |     const ingredientSections = computed<IngredientSection[]>(() => { | 
					
						
							|  |  |  |       if (!props.recipe.recipeIngredient) { | 
					
						
							|  |  |  |         return []; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return props.recipe.recipeIngredient.reduce((sections, ingredient) => { | 
					
						
							|  |  |  |         // if title append new section to the end of the array
 | 
					
						
							|  |  |  |         if (ingredient.title) { | 
					
						
							|  |  |  |           sections.push({ | 
					
						
							|  |  |  |             sectionName: ingredient.title, | 
					
						
							|  |  |  |             ingredients: [ingredient], | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           return sections; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // append new section if first
 | 
					
						
							|  |  |  |         if (sections.length === 0) { | 
					
						
							|  |  |  |           sections.push({ | 
					
						
							|  |  |  |             sectionName: "", | 
					
						
							|  |  |  |             ingredients: [ingredient], | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           return sections; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // otherwise add ingredient to last section in the array
 | 
					
						
							|  |  |  |         sections[sections.length - 1].ingredients.push(ingredient); | 
					
						
							|  |  |  |         return sections; | 
					
						
							|  |  |  |       }, [] as IngredientSection[]); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Group instructions by section so we can style them independently
 | 
					
						
							|  |  |  |     const instructionSections = computed<InstructionSection[]>(() => { | 
					
						
							|  |  |  |       if (!props.recipe.recipeInstructions) { | 
					
						
							|  |  |  |         return []; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return props.recipe.recipeInstructions.reduce((sections, step) => { | 
					
						
							|  |  |  |         const offset = (() => { | 
					
						
							|  |  |  |           if (sections.length === 0) { | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           const lastOffset = sections[sections.length - 1].stepOffset; | 
					
						
							|  |  |  |           const lastNumSteps = sections[sections.length - 1].instructions.length; | 
					
						
							|  |  |  |           return lastOffset + lastNumSteps; | 
					
						
							|  |  |  |         })(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // if title append new section to the end of the array
 | 
					
						
							|  |  |  |         if (step.title) { | 
					
						
							|  |  |  |           sections.push({ | 
					
						
							|  |  |  |             sectionName: step.title, | 
					
						
							|  |  |  |             stepOffset: offset, | 
					
						
							|  |  |  |             instructions: [step], | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           return sections; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // append if first element
 | 
					
						
							|  |  |  |         if (sections.length === 0) { | 
					
						
							|  |  |  |           sections.push({ | 
					
						
							|  |  |  |             sectionName: "", | 
					
						
							|  |  |  |             stepOffset: offset, | 
					
						
							|  |  |  |             instructions: [step], | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           return sections; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // otherwise add step to last section in the array
 | 
					
						
							|  |  |  |         sections[sections.length - 1].instructions.push(step); | 
					
						
							|  |  |  |         return sections; | 
					
						
							|  |  |  |       }, [] as InstructionSection[]); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  |     const hasNotes = computed(() => { | 
					
						
							|  |  |  |       return props.recipe.notes && props.recipe.notes.length > 0; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-10 19:48:07 -05:00
										 |  |  |     function parseText(ingredient: RecipeIngredient) { | 
					
						
							| 
									
										
										
										
											2022-12-30 16:47:35 -06:00
										 |  |  |       return parseIngredientText(ingredient, props.recipe.settings?.disableAmount || false, props.scale); | 
					
						
							| 
									
										
										
										
											2022-06-10 19:48:07 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  |     return { | 
					
						
							| 
									
										
										
										
											2024-06-18 11:08:22 +02:00
										 |  |  |       labels, | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  |       hasNotes, | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  |       imageKey, | 
					
						
							|  |  |  |       ImagePosition, | 
					
						
							| 
									
										
										
										
											2022-06-10 19:48:07 -05:00
										 |  |  |       parseText, | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  |       parseIngredientText, | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  |       preferences, | 
					
						
							|  |  |  |       recipeImageUrl, | 
					
						
							| 
									
										
										
										
											2024-11-20 08:46:27 -06:00
										 |  |  |       recipeYield, | 
					
						
							| 
									
										
										
										
											2022-06-12 19:43:09 -05:00
										 |  |  |       ingredientSections, | 
					
						
							|  |  |  |       instructionSections, | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  |     }; | 
					
						
							|  |  |  |   }, | 
					
						
							| 
									
										
										
										
											2021-11-04 18:15:23 -08:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2021-05-14 21:10:03 -08:00
										 |  |  | </script> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  | <style scoped> | 
					
						
							| 
									
										
										
										
											2022-06-12 19:43:09 -05:00
										 |  |  | /* Makes all text solid black */ | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  | .wrapper { | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  |   background-color: white; | 
					
						
							| 
									
										
										
										
											2022-06-10 19:48:07 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-19 18:37:18 -06:00
										 |  |  | .wrapper, | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  | .wrapper :deep(*) { | 
					
						
							| 
									
										
										
										
											2022-06-10 19:48:07 -05:00
										 |  |  |   opacity: 1 !important; | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  |   color: black !important; | 
					
						
							| 
									
										
										
										
											2021-05-14 21:10:03 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-12 19:43:09 -05:00
										 |  |  | /* Prevents sections from being broken up between pages */ | 
					
						
							|  |  |  | .print-section { | 
					
						
							|  |  |  |   page-break-inside: avoid; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-14 21:10:03 -08:00
										 |  |  | p { | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  |   padding-bottom: 0 !important; | 
					
						
							|  |  |  |   margin-bottom: 0 !important; | 
					
						
							| 
									
										
										
										
											2021-05-14 21:10:03 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  | .v-card__text { | 
					
						
							|  |  |  |   padding-bottom: 0; | 
					
						
							|  |  |  |   margin-bottom: 0; | 
					
						
							| 
									
										
										
										
											2021-05-14 21:10:03 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  | .ingredient-grid { | 
					
						
							|  |  |  |   display: grid; | 
					
						
							| 
									
										
										
										
											2022-08-19 14:42:06 -05:00
										 |  |  |   grid-auto-flow: column; | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  |   grid-template-columns: 1fr 1fr; | 
					
						
							| 
									
										
										
										
											2022-06-10 19:48:07 -05:00
										 |  |  |   grid-gap: 0.5rem; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-12 19:43:09 -05:00
										 |  |  | .ingredient-title, | 
					
						
							|  |  |  | .instruction-title { | 
					
						
							| 
									
										
										
										
											2022-06-10 19:48:07 -05:00
										 |  |  |   grid-column: 1 / span 2; | 
					
						
							| 
									
										
										
										
											2022-06-12 19:43:09 -05:00
										 |  |  |   text-decoration: underline; | 
					
						
							|  |  |  |   text-underline-offset: 4px; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .ingredient-body, | 
					
						
							|  |  |  | .recipe-step-body, | 
					
						
							|  |  |  | .note-body { | 
					
						
							|  |  |  |   font-size: 14px; | 
					
						
							| 
									
										
										
										
											2021-05-14 21:10:03 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  | ul { | 
					
						
							|  |  |  |   padding-left: 1rem; | 
					
						
							| 
									
										
										
										
											2021-05-14 21:10:03 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  | li { | 
					
						
							|  |  |  |   list-style-type: none; | 
					
						
							|  |  |  |   margin-bottom: 0.25rem; | 
					
						
							| 
									
										
										
										
											2021-05-14 21:10:03 -08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2024-06-18 11:08:22 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | .nutrition-table { | 
					
						
							| 
									
										
										
										
											2024-11-01 15:12:25 -07:00
										 |  |  |   max-width: 80%; | 
					
						
							| 
									
										
										
										
											2024-06-18 11:08:22 +02:00
										 |  |  |   border-collapse: collapse; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-01 15:12:25 -07:00
										 |  |  | .nutrition-table th, | 
					
						
							|  |  |  | .nutrition-table td { | 
					
						
							|  |  |  |   padding: 6px 10px; | 
					
						
							|  |  |  |   text-align: left; | 
					
						
							|  |  |  |   vertical-align: top; | 
					
						
							|  |  |  |   font-size: 14px; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .nutrition-table th { | 
					
						
							|  |  |  |   font-weight: bold; | 
					
						
							|  |  |  |   padding-bottom: 10px; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .nutrition-table td:first-child { | 
					
						
							|  |  |  |   width: 70%; | 
					
						
							|  |  |  |   font-weight: bold; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .nutrition-table td:last-child { | 
					
						
							|  |  |  |   width: 30%; | 
					
						
							|  |  |  |   text-align: right; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-06-20 00:09:12 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-18 11:08:22 +02:00
										 |  |  | .nutrition-table td { | 
					
						
							|  |  |  |   padding: 2px; | 
					
						
							|  |  |  |   text-align: left; | 
					
						
							|  |  |  |   font-size: 14px; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-05-28 17:00:37 -08:00
										 |  |  | </style> |