mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-07-09 03:04:54 -04:00
feat: Show nutrition on recipe print (#3740)
Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com>
This commit is contained in:
parent
598b0f3707
commit
b220cd6431
@ -31,6 +31,13 @@
|
||||
<v-switch v-model="preferences.showNotes" hide-details :label="$tc('recipe.notes')" />
|
||||
</v-row>
|
||||
</v-col>
|
||||
<v-col cols="auto" align-self="start">
|
||||
<v-row no-gutters>
|
||||
<v-switch v-model="preferences.showNutrition" hide-details :label="$tc('recipe.nutrition')" />
|
||||
</v-row>
|
||||
<v-row no-gutters>
|
||||
</v-row>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
<v-card
|
||||
|
@ -8,14 +8,8 @@
|
||||
<v-card-text v-if="edit">
|
||||
<div v-for="(item, key, index) in value" :key="index">
|
||||
<v-text-field
|
||||
dense
|
||||
:value="value[key]"
|
||||
:label="labels[key].label"
|
||||
:suffix="labels[key].suffix"
|
||||
type="number"
|
||||
autocomplete="off"
|
||||
@input="updateValue(key, $event)"
|
||||
></v-text-field>
|
||||
dense :value="value[key]" :label="labels[key].label" :suffix="labels[key].suffix" type="number"
|
||||
autocomplete="off" @input="updateValue(key, $event)"></v-text-field>
|
||||
</div>
|
||||
</v-card-text>
|
||||
<v-list v-if="showViewer" dense class="mt-0 pt-0">
|
||||
@ -34,17 +28,10 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, useContext } from "@nuxtjs/composition-api";
|
||||
import { computed, defineComponent } from "@nuxtjs/composition-api";
|
||||
import { useNutritionLabels } from "~/composables/recipes";
|
||||
import { Nutrition } from "~/lib/api/types/recipe";
|
||||
|
||||
type NutritionLabelType = {
|
||||
[key: string]: {
|
||||
label: string;
|
||||
suffix: string;
|
||||
value?: string;
|
||||
};
|
||||
};
|
||||
|
||||
import { NutritionLabelType } from "~/composables/recipes/use-recipe-nutrition";
|
||||
export default defineComponent({
|
||||
props: {
|
||||
value: {
|
||||
@ -57,37 +44,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props, context) {
|
||||
const { i18n } = useContext();
|
||||
const labels = <NutritionLabelType>{
|
||||
calories: {
|
||||
label: i18n.tc("recipe.calories"),
|
||||
suffix: i18n.tc("recipe.calories-suffix"),
|
||||
},
|
||||
fatContent: {
|
||||
label: i18n.tc("recipe.fat-content"),
|
||||
suffix: i18n.tc("recipe.grams"),
|
||||
},
|
||||
fiberContent: {
|
||||
label: i18n.tc("recipe.fiber-content"),
|
||||
suffix: i18n.tc("recipe.grams"),
|
||||
},
|
||||
proteinContent: {
|
||||
label: i18n.tc("recipe.protein-content"),
|
||||
suffix: i18n.tc("recipe.grams"),
|
||||
},
|
||||
sodiumContent: {
|
||||
label: i18n.tc("recipe.sodium-content"),
|
||||
suffix: i18n.tc("recipe.milligrams"),
|
||||
},
|
||||
sugarContent: {
|
||||
label: i18n.tc("recipe.sugar-content"),
|
||||
suffix: i18n.tc("recipe.grams"),
|
||||
},
|
||||
carbohydrateContent: {
|
||||
label: i18n.tc("recipe.carbohydrate-content"),
|
||||
suffix: i18n.tc("recipe.grams"),
|
||||
},
|
||||
};
|
||||
const { labels } = useNutritionLabels();
|
||||
const valueNotNull = computed(() => {
|
||||
let key: keyof Nutrition;
|
||||
for (key in props.value) {
|
||||
|
@ -83,19 +83,42 @@
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- Nutrition -->
|
||||
<div v-if="preferences.showNutrition">
|
||||
<v-card-title class="headline pl-0"> {{ $t("recipe.nutrition") }} </v-card-title>
|
||||
|
||||
|
||||
<section>
|
||||
<div class="print-section">
|
||||
<table class="nutrition-table">
|
||||
<tbody>
|
||||
<tr v-for="(value, key) in recipe.nutrition" :key="key">
|
||||
<template v-if="value">
|
||||
<td>{{ labels[key].label }}</td>
|
||||
<td>{{ value || '-' }}</td>
|
||||
</template>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed } from "@nuxtjs/composition-api";
|
||||
import { computed, defineComponent } from "@nuxtjs/composition-api";
|
||||
import RecipeTimeCard from "~/components/Domain/Recipe/RecipeTimeCard.vue";
|
||||
import { useStaticRoutes } from "~/composables/api";
|
||||
import { Recipe, RecipeIngredient, RecipeStep } from "~/lib/api/types/recipe";
|
||||
import { Recipe, RecipeIngredient, RecipeStep} from "~/lib/api/types/recipe";
|
||||
import { NoUndefinedField } from "~/lib/api/types/non-generated";
|
||||
import { ImagePosition, useUserPrintPreferences } from "~/composables/use-users/preferences";
|
||||
import { parseIngredientText } from "~/composables/recipes";
|
||||
import { parseIngredientText, useNutritionLabels } from "~/composables/recipes";
|
||||
import { usePageState } from "~/composables/recipe-page/shared-state";
|
||||
|
||||
|
||||
type IngredientSection = {
|
||||
sectionName: string;
|
||||
ingredients: RecipeIngredient[];
|
||||
@ -129,6 +152,10 @@ export default defineComponent({
|
||||
const preferences = useUserPrintPreferences();
|
||||
const { recipeImage } = useStaticRoutes();
|
||||
const { imageKey } = usePageState(props.recipe.slug);
|
||||
const {labels} = useNutritionLabels();
|
||||
|
||||
|
||||
|
||||
|
||||
const recipeImageUrl = computed(() => {
|
||||
return recipeImage(props.recipe.id, props.recipe.image, imageKey.value);
|
||||
@ -221,6 +248,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
return {
|
||||
labels,
|
||||
hasNotes,
|
||||
imageKey,
|
||||
ImagePosition,
|
||||
@ -290,4 +318,16 @@ li {
|
||||
list-style-type: none;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.nutrition-table {
|
||||
width: 25%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.nutrition-table td {
|
||||
padding: 2px;
|
||||
text-align: left;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
@ -2,4 +2,5 @@ export { useFraction } from "./use-fraction";
|
||||
export { useRecipe } from "./use-recipe";
|
||||
export { useRecipes, recentRecipes, allRecipes, useLazyRecipes } from "./use-recipes";
|
||||
export { parseIngredientText, useParsedIngredientText } from "./use-recipe-ingredients";
|
||||
export { useNutritionLabels } from "./use-recipe-nutrition";
|
||||
export { useTools } from "./use-recipe-tools";
|
||||
|
47
frontend/composables/recipes/use-recipe-nutrition.ts
Normal file
47
frontend/composables/recipes/use-recipe-nutrition.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { useContext } from "@nuxtjs/composition-api";
|
||||
|
||||
|
||||
export interface NutritionLabelType {
|
||||
[key: string]: {
|
||||
label: string;
|
||||
suffix: string;
|
||||
value?: string;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
export function useNutritionLabels() {
|
||||
const { i18n } = useContext();
|
||||
const labels = <NutritionLabelType>{
|
||||
calories: {
|
||||
label: i18n.tc("recipe.calories"),
|
||||
suffix: i18n.tc("recipe.calories-suffix"),
|
||||
},
|
||||
fatContent: {
|
||||
label: i18n.tc("recipe.fat-content"),
|
||||
suffix: i18n.tc("recipe.grams"),
|
||||
},
|
||||
fiberContent: {
|
||||
label: i18n.tc("recipe.fiber-content"),
|
||||
suffix: i18n.tc("recipe.grams"),
|
||||
},
|
||||
proteinContent: {
|
||||
label: i18n.tc("recipe.protein-content"),
|
||||
suffix: i18n.tc("recipe.grams"),
|
||||
},
|
||||
sodiumContent: {
|
||||
label: i18n.tc("recipe.sodium-content"),
|
||||
suffix: i18n.tc("recipe.milligrams"),
|
||||
},
|
||||
sugarContent: {
|
||||
label: i18n.tc("recipe.sugar-content"),
|
||||
suffix: i18n.tc("recipe.grams"),
|
||||
},
|
||||
carbohydrateContent: {
|
||||
label: i18n.tc("recipe.carbohydrate-content"),
|
||||
suffix: i18n.tc("recipe.grams"),
|
||||
},
|
||||
};
|
||||
|
||||
return { labels }
|
||||
}
|
@ -6,6 +6,7 @@ export interface UserPrintPreferences {
|
||||
imagePosition: string;
|
||||
showDescription: boolean;
|
||||
showNotes: boolean;
|
||||
showNutrition: boolean;
|
||||
}
|
||||
|
||||
export interface UserSearchQuery {
|
||||
|
Loading…
x
Reference in New Issue
Block a user