mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-02 12:49:02 -05:00
recipe view as model chain and ingredient checkbox
This commit is contained in:
@@ -37,7 +37,7 @@ const target = ref({} as Food)
|
||||
|
||||
function mergeModel() {
|
||||
let api = new ApiApi()
|
||||
if (target != null) {
|
||||
if (target.value != null) {
|
||||
loading.value = true
|
||||
api.apiFoodMergeUpdate({id: props.sourceId!, food: {} as Food, target: target.value.id!}).then(r => {
|
||||
useMessageStore().addPreparedMessage(PreparedMessage.UPDATE_SUCCESS)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<v-table density="compact" v-if="props.ingredients.length > 0">
|
||||
<v-table density="compact" v-if="ingredients.length > 0">
|
||||
|
||||
<tbody>
|
||||
<ingredients-table-row v-for="i in props.ingredients" :ingredient="i" :key="i.id" :show-notes="props.showNotes"
|
||||
<ingredients-table-row v-for="(ing, i) in ingredients" v-model="ingredients[i]" :key="ing.id" :show-notes="props.showNotes"
|
||||
:ingredient-factor="ingredientFactor"></ingredients-table-row>
|
||||
</tbody>
|
||||
|
||||
@@ -15,11 +15,9 @@ import {Ingredient} from "@/openapi";
|
||||
import IngredientsTableRow from "@/components/display/IngredientsTableRow.vue";
|
||||
import draggable from 'vuedraggable'
|
||||
|
||||
const ingredients = defineModel<Ingredient[]>({required: true})
|
||||
|
||||
const props = defineProps({
|
||||
ingredients: {
|
||||
type: Array as PropType<Array<Ingredient>>,
|
||||
default: [],
|
||||
},
|
||||
showNotes: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
@@ -33,7 +31,7 @@ const props = defineProps({
|
||||
const mutable_ingredients = ref([] as Ingredient[])
|
||||
|
||||
onMounted(() => {
|
||||
mutable_ingredients.value = props.ingredients
|
||||
mutable_ingredients.value = ingredients.value
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
<template>
|
||||
<tr>
|
||||
<template v-if="props.ingredient.isHeader">
|
||||
<td colspan="4"><b>{{ props.ingredient.note }}</b></td>
|
||||
<template v-if="ingredient.isHeader">
|
||||
<td colspan="4"><b>{{ ingredient.note }}</b></td>
|
||||
</template>
|
||||
<template v-else>
|
||||
<td>{{ props.ingredient.amount * props.ingredientFactor }}</td>
|
||||
<td><span v-if="props.ingredient.unit != null">{{ props.ingredient.unit.name }}</span></td>
|
||||
<td><span v-if="props.ingredient.food != null">{{ props.ingredient.food.name }}</span></td>
|
||||
<td><v-checkbox-btn v-model="ingredient.checked" color="success"></v-checkbox-btn></td>
|
||||
<td>{{ ingredient.amount * props.ingredientFactor }}</td>
|
||||
<td><span v-if="ingredient.unit != null">{{ ingredient.unit.name }}</span></td>
|
||||
<td><span v-if="ingredient.food != null">{{ ingredient.food.name }}</span></td>
|
||||
<td v-if="props.showNotes">
|
||||
<v-icon class="far fa-comment float-right" v-if="props.ingredient.note != '' && props.ingredient.note != undefined" @click="showTooltip = !showTooltip">
|
||||
<v-tooltip v-model="showTooltip" activator="parent" location="start">{{ props.ingredient.note }}</v-tooltip>
|
||||
<v-icon class="far fa-comment float-right" v-if="ingredient.note != '' && ingredient.note != undefined" @click="showTooltip = !showTooltip">
|
||||
<v-tooltip v-model="showTooltip" activator="parent" location="start">{{ ingredient.note }}</v-tooltip>
|
||||
</v-icon>
|
||||
</td>
|
||||
</template>
|
||||
@@ -21,11 +22,9 @@
|
||||
import {PropType, ref} from 'vue'
|
||||
import {Ingredient} from "@/openapi";
|
||||
|
||||
const ingredient = defineModel<Ingredient>({required: true})
|
||||
|
||||
const props = defineProps({
|
||||
ingredient: {
|
||||
type: {} as PropType<Ingredient>,
|
||||
required: true
|
||||
},
|
||||
showNotes: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<template v-if="props.recipe.name == undefined">
|
||||
<template v-if="recipe.name == undefined">
|
||||
<v-skeleton-loader type="card" class="mt-md-4 rounded-0"></v-skeleton-loader>
|
||||
<v-skeleton-loader type="article" class="mt-2"></v-skeleton-loader>
|
||||
<v-skeleton-loader type="article" class="mt-2"></v-skeleton-loader>
|
||||
@@ -8,17 +8,17 @@
|
||||
<v-skeleton-loader type="list-item-avatar-three-line"></v-skeleton-loader>
|
||||
</template>
|
||||
|
||||
<template v-if="props.recipe.name != undefined">
|
||||
<template v-if="recipe.name != undefined">
|
||||
|
||||
<v-card class="mt-md-4 rounded-0">
|
||||
<recipe-image
|
||||
max-height="25vh"
|
||||
:recipe="props.recipe"
|
||||
:recipe="recipe"
|
||||
v-if="recipe.internal"
|
||||
>
|
||||
<template #overlay>
|
||||
<v-chip class="ms-2" color="primary" variant="flat" size="x-small">by {{ props.recipe.createdBy.displayName }}</v-chip>
|
||||
<keywords-component variant="flat" class="ms-1 mb-2" :keywords="props.recipe.keywords"></keywords-component>
|
||||
<v-chip class="ms-2" color="primary" variant="flat" size="x-small">by {{ recipe.createdBy.displayName }}</v-chip>
|
||||
<keywords-component variant="flat" class="ms-1 mb-2" :keywords="recipe.keywords"></keywords-component>
|
||||
</template>
|
||||
</recipe-image>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<v-card>
|
||||
<v-sheet class="d-flex align-center">
|
||||
<span class="ps-2 text-h5 flex-grow-1 pa-1" :class="{'text-truncate': !showFullRecipeName}" @click="showFullRecipeName = !showFullRecipeName">
|
||||
{{ props.recipe.name }}
|
||||
{{ recipe.name }}
|
||||
</span>
|
||||
<recipe-context-menu :recipe="recipe"></recipe-context-menu>
|
||||
</v-sheet>
|
||||
@@ -42,18 +42,18 @@
|
||||
<v-container>
|
||||
<v-row class="text-center text-body-2">
|
||||
<v-col class="pt-1 pb-1">
|
||||
<i class="fas fa-cogs fa-fw mr-1"></i> {{ props.recipe.workingTime }} min<br/>
|
||||
<i class="fas fa-cogs fa-fw mr-1"></i> {{ recipe.workingTime }} min<br/>
|
||||
<div class="text-grey">{{ $t('WorkingTime') }}</div>
|
||||
</v-col>
|
||||
<v-col class="pt-1 pb-1">
|
||||
<div><i class="fas fa-hourglass-half fa-fw mr-1"></i> {{ props.recipe.waitingTime }} min</div>
|
||||
<div><i class="fas fa-hourglass-half fa-fw mr-1"></i> {{ recipe.waitingTime }} min</div>
|
||||
<div class="text-grey">{{ $t('WaitingTime') }}</div>
|
||||
</v-col>
|
||||
<v-col class="pt-1 pb-1">
|
||||
|
||||
<div class="cursor-pointer">
|
||||
<i class="fas fa-sort-numeric-up fa-fw mr-1"></i> {{ servings }} <br/>
|
||||
<div class="text-grey"><span v-if="props.recipe?.servingsText">{{ props.recipe.servingsText }}</span><span v-else>{{ $t('Servings') }}</span></div>
|
||||
<div class="text-grey"><span v-if="recipe.servingsText">{{ recipe.servingsText }}</span><span v-else>{{ $t('Servings') }}</span></div>
|
||||
<number-scaler-dialog :number="servings" @confirm="(s: number) => {servings = s}" title="Servings">
|
||||
</number-scaler-dialog>
|
||||
</div>
|
||||
@@ -64,12 +64,12 @@
|
||||
</v-container>
|
||||
</v-card>
|
||||
|
||||
<v-card class="mt-1" v-if="props.recipe.steps.length > 1">
|
||||
<steps-overview :steps="props.recipe.steps" :ingredient-factor="ingredientFactor"></steps-overview>
|
||||
<v-card class="mt-1" v-if="recipe.steps.length > 1">
|
||||
<steps-overview :steps="recipe.steps" :ingredient-factor="ingredientFactor"></steps-overview>
|
||||
</v-card>
|
||||
|
||||
<v-card class="mt-1" v-for="(step, index) in props.recipe.steps" :key="step.id">
|
||||
<step :step="step" :step-number="index+1" :ingredientFactor="ingredientFactor"></step>
|
||||
<v-card class="mt-1" v-for="(step, index) in recipe.steps" :key="step.id">
|
||||
<step v-model="recipe.steps[index]" :step-number="index+1" :ingredientFactor="ingredientFactor"></step>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
@@ -94,23 +94,22 @@ import PdfViewer from "../../../../vue/src/components/PdfViewer.vue";
|
||||
import ImageViewer from "../../../../vue/src/components/ImageViewer.vue";
|
||||
import ExternalRecipeViewer from "@/components/display/ExternalRecipeViewer.vue";
|
||||
|
||||
const recipe = defineModel<Recipe>({required: true})
|
||||
|
||||
const props = defineProps({
|
||||
recipe: {
|
||||
type: Object as PropType<Recipe>,
|
||||
required: true
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
const servings = ref(1)
|
||||
const showFullRecipeName = ref(false)
|
||||
|
||||
const ingredientFactor = computed(() => {
|
||||
return servings.value / ((props.recipe.servings != undefined) ? props.recipe.servings : 1)
|
||||
return servings.value / ((recipe.value.servings != undefined) ? recipe.value.servings : 1)
|
||||
})
|
||||
|
||||
watch(() => props.recipe.servings, () => {
|
||||
if (props.recipe.servings) {
|
||||
servings.value = props.recipe.servings
|
||||
watch(() => recipe.value.servings, () => {
|
||||
if (recipe.value.servings) {
|
||||
servings.value = recipe.value.servings
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
<v-row>
|
||||
<v-col><span v-if="props.step.name">{{ props.step.name }}</span><span v-else>{{ $t('Step') }} {{ props.stepNumber }}</span></v-col>
|
||||
<v-col><span v-if="step.name">{{ step.name }}</span><span v-else>{{ $t('Step') }} {{ props.stepNumber }}</span></v-col>
|
||||
<v-col class="text-right">
|
||||
<v-btn-group density="compact" variant="tonal">
|
||||
<v-btn size="small" color="info" v-if="props.step.time != undefined && props.step.time > 0" @click="timerRunning = true"><i
|
||||
class="fas fa-stopwatch mr-1 fa-fw"></i> {{ props.step.time }}
|
||||
<v-btn size="small" color="info" v-if="step.time != undefined && step.time > 0" @click="timerRunning = true"><i
|
||||
class="fas fa-stopwatch mr-1 fa-fw"></i> {{ step.time }}
|
||||
</v-btn>
|
||||
<v-btn size="small" color="success" v-if="hasDetails" @click="stepChecked = !stepChecked"><i class="fas fa-fw"
|
||||
:class="{'fa-check': !stepChecked, 'fa-times': stepChecked}"></i>
|
||||
@@ -16,14 +16,14 @@
|
||||
</v-row>
|
||||
</v-card-title>
|
||||
<template v-if="!stepChecked">
|
||||
<timer :seconds="props.step.time != undefined ? props.step.time*60 : 0" @stop="timerRunning = false" v-if="timerRunning"></timer>
|
||||
<timer :seconds="step.time != undefined ? step.time*60 : 0" @stop="timerRunning = false" v-if="timerRunning"></timer>
|
||||
<v-card-text>
|
||||
<v-row>
|
||||
<v-col cols="12" md="6" v-if="props.step?.ingredients.length > 0">
|
||||
<ingredients-table :ingredients="props.step.ingredients" :ingredient-factor="ingredientFactor"></ingredients-table>
|
||||
<v-col cols="12" md="6" v-if="step.ingredients.length > 0">
|
||||
<ingredients-table v-model="step.ingredients" :ingredient-factor="ingredientFactor"></ingredients-table>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<instructions :instructions_html="props.step.instructionsMarkdown" :ingredient_factor="ingredientFactor"></instructions>
|
||||
<instructions :instructions_html="step.instructionsMarkdown" :ingredient_factor="ingredientFactor"></instructions>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
@@ -41,11 +41,9 @@ import {Step} from "@/openapi";
|
||||
import Instructions from "@/components/display/Instructions.vue";
|
||||
import Timer from "@/components/display/Timer.vue";
|
||||
|
||||
const step = defineModel<Step>({required: true})
|
||||
|
||||
const props = defineProps({
|
||||
step: {
|
||||
type: {} as PropType<Step>,
|
||||
required: true,
|
||||
},
|
||||
stepNumber: {
|
||||
type: Number,
|
||||
required: false,
|
||||
@@ -61,7 +59,7 @@ const timerRunning = ref(false)
|
||||
const stepChecked = ref(false)
|
||||
|
||||
const hasDetails = computed(() => {
|
||||
return props.step.ingredients.length > 0 || (props.step.instruction != undefined && props.step.instruction.length > 0) || props.step.stepRecipeData != undefined || props.step.file != undefined
|
||||
return step.value.ingredients.length > 0 || (step.value.instruction != undefined && step.value.instruction.length > 0) || step.value.stepRecipeData != undefined || step.value.file != undefined
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<v-expansion-panels>
|
||||
<v-expansion-panel>
|
||||
<v-expansion-panel-title><i class="far fa-list-alt fa-fw me-2"></i> Steps Overview</v-expansion-panel-title>
|
||||
<v-expansion-panel-title><i class="far fa-list-alt fa-fw me-2"></i> {{$t('StepsOverview')}}</v-expansion-panel-title>
|
||||
<v-expansion-panel-text>
|
||||
<v-container>
|
||||
<v-row v-for="(s, i) in props.steps">
|
||||
<v-col class="pa-1">
|
||||
<b v-if="s.showAsHeader">{{ i + 1 }}. {{ s.name }} </b>
|
||||
<ingredients-table :ingredients="s.ingredients" :ingredient-factor="props.ingredientFactor"></ingredients-table>
|
||||
<ingredients-table v-model="s.ingredients" :ingredient-factor="props.ingredientFactor"></ingredients-table>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<v-progress-linear :model-value="timerProgress" color="primary" height="5"></v-progress-linear>
|
||||
<v-alert :color="timerColor" class="rounded-0" variant="tonal">
|
||||
<v-alert-title><i class="fas fa-stopwatch mr-1"></i> {{ Duration.fromMillis(durationSeconds * 1000).toFormat('hh:mm:ss') }}</v-alert-title>
|
||||
Finished at {{ DateTime.now().plus({'seconds': durationSeconds}).toLocaleString(DateTime.TIME_SIMPLE) }}
|
||||
{{$t('FinishedAt')}} {{ DateTime.now().plus({'seconds': durationSeconds}).toLocaleString(DateTime.TIME_SIMPLE) }}
|
||||
<template #close>
|
||||
<v-btn-group divided>
|
||||
<v-btn width="40" @click="changeTimer(-60)"><i class="fas fa-minus"></i>1</v-btn>
|
||||
|
||||
Reference in New Issue
Block a user