mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-10-31 02:03:35 -04:00 
			
		
		
		
	feat: Structured Yields (#4489)
Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com>
This commit is contained in:
		| @@ -1,16 +1,13 @@ | ||||
| <template> | ||||
|   <div> | ||||
|   <div v-if="yieldDisplay"> | ||||
|     <div class="text-center d-flex align-center"> | ||||
|       <div> | ||||
|         <v-menu v-model="menu" :disabled="!editScale" offset-y top nudge-top="6" :close-on-content-click="false"> | ||||
|         <v-menu v-model="menu" :disabled="!canEditScale" offset-y top nudge-top="6" :close-on-content-click="false"> | ||||
|           <template #activator="{ on, attrs }"> | ||||
|             <v-card class="pa-1 px-2" dark color="secondary darken-1" small v-bind="attrs" v-on="on"> | ||||
|               <span v-if="!recipeYield"> x {{ scale }} </span> | ||||
|               <div v-else-if="!numberParsed && recipeYield"> | ||||
|                 <span v-if="numerator === 1"> {{ recipeYield }} </span> | ||||
|                 <span v-else> {{ numerator }}x {{ scaledYield }} </span> | ||||
|               </div> | ||||
|               <span v-else> {{ scaledYield }} </span> | ||||
|               <v-icon small class="mr-2">{{ $globals.icons.edit }}</v-icon> | ||||
|               <!-- eslint-disable-next-line vue/no-v-html --> | ||||
|               <span v-html="yieldDisplay"></span> | ||||
|  | ||||
|             </v-card> | ||||
|           </template> | ||||
| @@ -20,7 +17,7 @@ | ||||
|             </v-card-title> | ||||
|             <v-card-text class="mt-n5"> | ||||
|               <div class="mt-4 d-flex align-center"> | ||||
|                 <v-text-field v-model="numerator" type="number" :min="0" hide-spin-buttons /> | ||||
|                 <v-text-field v-model="yieldQuantityEditorValue" type="number" :min="0" hide-spin-buttons @input="recalculateScale(yieldQuantityEditorValue)" /> | ||||
|                 <v-tooltip right color="secondary darken-1"> | ||||
|                   <template #activator="{ on, attrs }"> | ||||
|                     <v-btn v-bind="attrs" icon class="mx-1" small v-on="on" @click="scale = 1"> | ||||
| @@ -37,7 +34,7 @@ | ||||
|         </v-menu> | ||||
|       </div> | ||||
|       <BaseButtonGroup | ||||
|         v-if="editScale" | ||||
|         v-if="canEditScale" | ||||
|         class="pl-2" | ||||
|         :large="false" | ||||
|         :buttons="[ | ||||
| @@ -53,41 +50,36 @@ | ||||
|             event: 'increment', | ||||
|           }, | ||||
|         ]" | ||||
|         @decrement="numerator--" | ||||
|         @increment="numerator++" | ||||
|         @decrement="recalculateScale(yieldQuantity - 1)" | ||||
|         @increment="recalculateScale(yieldQuantity + 1)" | ||||
|       /> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| import { defineComponent, ref, computed, watch  } from "@nuxtjs/composition-api"; | ||||
| import { computed, defineComponent, ref, useContext, watch } from "@nuxtjs/composition-api"; | ||||
| import { useScaledAmount } from "~/composables/recipes/use-scaled-amount"; | ||||
|  | ||||
| export default defineComponent({ | ||||
|   props: { | ||||
|     recipeYield: { | ||||
|       type: String, | ||||
|       default: null, | ||||
|     }, | ||||
|     scaledYield: { | ||||
|       type: String, | ||||
|       default: null, | ||||
|     }, | ||||
|     basicYieldNum: { | ||||
|     value: { | ||||
|       type: Number, | ||||
|       default: null, | ||||
|       required: true, | ||||
|     }, | ||||
|     recipeServings: { | ||||
|       type: Number, | ||||
|       default: 0, | ||||
|     }, | ||||
|     editScale: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|     value: { | ||||
|       type: Number, | ||||
|       required: true, | ||||
|     }, | ||||
|   }, | ||||
|   setup(props, { emit }) { | ||||
|     const { i18n } = useContext(); | ||||
|     const menu = ref<boolean>(false); | ||||
|     const canEditScale = computed(() => props.editScale && props.recipeServings > 0); | ||||
|  | ||||
|     const scale = computed({ | ||||
|       get: () => props.value, | ||||
| @@ -97,24 +89,54 @@ export default defineComponent({ | ||||
|       }, | ||||
|     }); | ||||
|  | ||||
|     const numerator = ref<number>(props.basicYieldNum != null ? parseFloat(props.basicYieldNum.toFixed(3)) : 1); | ||||
|     const denominator = props.basicYieldNum != null ? parseFloat(props.basicYieldNum.toFixed(32)) : 1; | ||||
|     const numberParsed = !!props.basicYieldNum; | ||||
|     function recalculateScale(newYield: number) { | ||||
|       if (isNaN(newYield) || newYield <= 0) { | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|     watch(() => numerator.value, () => { | ||||
|       scale.value = parseFloat((numerator.value / denominator).toFixed(32)); | ||||
|       if (props.recipeServings <= 0) { | ||||
|         scale.value = 1; | ||||
|       } else { | ||||
|         scale.value = newYield / props.recipeServings; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     const recipeYieldAmount = computed(() => { | ||||
|       return useScaledAmount(props.recipeServings, scale.value); | ||||
|     }); | ||||
|     const yieldQuantity = computed(() => recipeYieldAmount.value.scaledAmount); | ||||
|     const yieldDisplay = computed(() => { | ||||
|       return yieldQuantity.value ? i18n.t( | ||||
|         "recipe.serves-amount", { amount: recipeYieldAmount.value.scaledAmountDisplay } | ||||
|       ) as string : ""; | ||||
|     }); | ||||
|  | ||||
|     // only update yield quantity when the menu opens, so we don't override the user's input | ||||
|     const yieldQuantityEditorValue = ref(recipeYieldAmount.value.scaledAmount); | ||||
|     watch( | ||||
|       () => menu.value, | ||||
|       () => { | ||||
|         if (!menu.value) { | ||||
|           return; | ||||
|         } | ||||
|  | ||||
|         yieldQuantityEditorValue.value = recipeYieldAmount.value.scaledAmount; | ||||
|       } | ||||
|     ) | ||||
|  | ||||
|     const disableDecrement = computed(() => { | ||||
|       return numerator.value <= 1; | ||||
|       return recipeYieldAmount.value.scaledAmount <= 1; | ||||
|     }); | ||||
|  | ||||
|  | ||||
|     return { | ||||
|       menu, | ||||
|       canEditScale, | ||||
|       scale, | ||||
|       numerator, | ||||
|       recalculateScale, | ||||
|       yieldDisplay, | ||||
|       yieldQuantity, | ||||
|       yieldQuantityEditorValue, | ||||
|       disableDecrement, | ||||
|       numberParsed, | ||||
|     }; | ||||
|   }, | ||||
| }); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user