cookbook view refactored, minor ui fixes

This commit is contained in:
Kaibu 2021-09-13 19:28:16 +02:00
parent 0501dd9a0a
commit fd8797e2b7
12 changed files with 3956 additions and 195 deletions

View File

@ -550,7 +550,7 @@ class RecipeBookEntrySerializer(serializers.ModelSerializer):
return RecipeBookSerializer(context={'request': self.context['request']}).to_representation(obj.book) return RecipeBookSerializer(context={'request': self.context['request']}).to_representation(obj.book)
def get_recipe_content(self, obj): def get_recipe_content(self, obj):
return RecipeOverviewSerializer(context={'request': self.context['request']}).to_representation(obj.recipe) return RecipeSerializer(context={'request': self.context['request']}).to_representation(obj.recipe)
def create(self, validated_data): def create(self, validated_data):
book = validated_data['book'] book = validated_data['book']

View File

@ -25,6 +25,7 @@
"vue-multiselect": "^2.1.6", "vue-multiselect": "^2.1.6",
"vue-property-decorator": "^9.1.2", "vue-property-decorator": "^9.1.2",
"vue-template-compiler": "^2.6.14", "vue-template-compiler": "^2.6.14",
"vue2-touch-events": "^3.2.2",
"vuedraggable": "^2.24.3", "vuedraggable": "^2.24.3",
"vuex": "^3.6.0", "vuex": "^3.6.0",
"workbox-webpack-plugin": "^6.1.5" "workbox-webpack-plugin": "^6.1.5"

View File

@ -1,18 +1,18 @@
<template> <template>
<div id="app" class="col-12 col-xl-8 col-lg-10 offset-xl-2 offset-lg-1 offset"> <div id="app" class="col-12 col-xl-8 col-lg-10 offset-xl-2 offset-lg-1 offset">
<div class="mb-3" v-for="book in cookbooks" v-bind:key="book.id"> <div class="mb-3" v-for="book in cookbooks" v-bind:key="book.id">
<div class="row mb-3"> <div class="row">
<b-card class="d-flex flex-column" v-hover <div class="col-md-12">
<b-card class="d-flex flex-column" v-hover
v-on:click="openBook(book.id)"> v-on:click="openBook(book.id)">
<b-row no-gutters style="height:inherit;"> <b-row no-gutters style="height:inherit;">
<b-col no-gutters md="3" style="height:inherit;"> <b-col no-gutters md="2" style="height:inherit;">
<b-card-img-lazy style="object-fit: cover; height: 10vh;" :src="item_image" <h3>{{book.icon}}</h3>
v-bind:alt="$t('Recipe_Image')"></b-card-img-lazy>
</b-col> </b-col>
<b-col no-gutters md="9" style="height:inherit;"> <b-col no-gutters md="10" style="height:inherit;">
<b-card-body class="m-0 py-0" style="height:inherit;"> <b-card-body class="m-0 py-0" style="height:inherit;">
<b-card-text class=" h-100 my-0 d-flex flex-column" style="text-overflow: ellipsis"> <b-card-text class="h-100 my-0 d-flex flex-column" style="text-overflow: ellipsis">
<h5 class="m-0 mt-1 text-truncate">{{ book.name }}</h5> <h5 class="m-0 mt-1 text-truncate">{{ book.name }} <span class="float-right"><i class="fa fa-book"></i></span> </h5>
<div class="m-0 text-truncate">{{ book.description }}</div> <div class="m-0 text-truncate">{{ book.description }}</div>
<div class="mt-auto mb-1 d-flex flex-row justify-content-end"> <div class="mt-auto mb-1 d-flex flex-row justify-content-end">
</div> </div>
@ -21,10 +21,12 @@
</b-col> </b-col>
</b-row> </b-row>
</b-card> </b-card>
</div>
</div> </div>
<loading-spinner v-if="current_book === book.id && loading" ></loading-spinner>
<transition name="slide-fade"> <transition name="slide-fade">
<cookbook-slider :recipes="recipes" :book="book" v-if="current_book === book.id"></cookbook-slider> <cookbook-slider :recipes="recipes" :book="book" v-if="current_book === book.id && !loading"></cookbook-slider>
</transition> </transition>
</div> </div>
</div> </div>
@ -37,19 +39,21 @@ import {BootstrapVue} from 'bootstrap-vue'
import 'bootstrap-vue/dist/bootstrap-vue.css' import 'bootstrap-vue/dist/bootstrap-vue.css'
import {ApiApiFactory} from "../../utils/openapi/api"; import {ApiApiFactory} from "../../utils/openapi/api";
import CookbookSlider from "../../components/CookbookSlider"; import CookbookSlider from "../../components/CookbookSlider";
import LoadingSpinner from "../../components/LoadingSpinner";
Vue.use(BootstrapVue) Vue.use(BootstrapVue)
export default { export default {
name: 'CookbookView', name: 'CookbookView',
mixins: [], mixins: [],
components: {CookbookSlider}, components: {LoadingSpinner, CookbookSlider},
data() { data() {
return { return {
cookbooks: [], cookbooks: [],
book_background: window.IMAGE_BOOK, book_background: window.IMAGE_BOOK,
recipes: [], recipes: [],
current_book: undefined current_book: undefined,
loading: false,
} }
}, },
mounted() { mounted() {
@ -65,12 +69,18 @@ export default {
}) })
}, },
openBook: function (book) { openBook: function (book) {
if(book === this.current_book) {
this.current_book = undefined
this.recipes = []
return
}
this.loading = true
let apiClient = new ApiApiFactory() let apiClient = new ApiApiFactory()
this.current_book = book this.current_book = book
console.log(this.current_book) apiClient.listRecipeBookEntrys({query: {book: book}}).then(result => {
apiClient.listRecipeBookEntrys({options: {book: book.id}}).then(result => {
this.recipes = result.data this.recipes = result.data
this.loading = false
}) })
} }
}, },
@ -95,10 +105,6 @@ export default {
transition: all .6s ease; transition: all .6s ease;
} }
.slide-fade-leave-active {
transition: all .5s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.slide-fade-enter, .slide-fade-leave-to .slide-fade-enter, .slide-fade-leave-to
/* .slide-fade-leave-active below version 2.1.8 */ /* .slide-fade-leave-active below version 2.1.8 */
{ {

View File

@ -0,0 +1,107 @@
<template>
<b-card no-body v-hover>
<b-card-header class="p-4">
<h5>{{ book_copy.icon }}&nbsp;{{ book_copy.name }}
<span class="float-right" @click="editOrSave"><i
class="fa" v-bind:class="{ 'fa-pen': !editing, 'fa-save': editing }"
aria-hidden="true"></i></span></h5>
</b-card-header>
<b-card-body class="p-4">
<div class="form-group" v-if="editing">
<label for="inputName1">{{ $t('Name') }}</label>
<input class="form-control" id="inputName1"
placeholder="Name" v-model="book_copy.name">
</div>
<div class="form-group" v-if="editing">
<label for="inputIcon1">{{ $t('Icon') }}</label>
<input class="form-control" id="inputIcon1"
placeholder="Name" v-model="book_copy.icon">
<emoji-input :field="'icon'" :label="'icon'" :value="book_copy.icon"></emoji-input>
</div>
<div class="form-group" v-if="editing">
<label for="inputDesc1">{{ $t('Description') }}</label>
<textarea class="form-control" id="inputDesc1" rows="3" v-model="book_copy.description">
</textarea>
</div>
<b-card-text style="text-overflow: ellipsis;" v-if="!editing">
{{ book_copy.description }}
</b-card-text>
</b-card-body>
</b-card>
</template>
<script>
import {ApiApiFactory} from "../utils/openapi/api";
import {StandardToasts} from "../utils/utils";
import EmojiInput from "./Modals/EmojiInput";
export default {
name: "CookbookEditCard",
components: {EmojiInput},
props: {
book: Object
},
data() {
return {
editing: false,
book_copy: {},
users: []
}
},
mounted() {
this.book_copy = this.book
this.$root.$on('change', this.updateEmoji);
},
directives: {
hover: {
inserted: function (el) {
el.addEventListener('mouseenter', () => {
el.classList.add("shadow")
});
el.addEventListener('mouseleave', () => {
el.classList.remove("shadow")
});
}
}
},
methods: {
editOrSave: function () {
if (!this.editing) {
this.editing = true
this.$emit("editing", true)
} else {
this.editing = false
this.saveData()
this.$emit("editing", false)
}
},
updateEmoji: function (item, value) {
if (item === 'icon') {
this.book_copy.icon = value
}
},
saveData: function () {
let apiClient = new ApiApiFactory()
apiClient.updateRecipeBook(this.book_copy.id, this.book_copy).then(result => {
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_UPDATE)
}).catch(error => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE)
})
},
refreshData: function () {
let apiClient = new ApiApiFactory()
apiClient.listUsers().then(result => {
this.users = result.data
})
},
}
}
</script>
<style scoped>
</style>

View File

@ -1,53 +1,43 @@
<template> <template>
<div v-bind:style="{ backgroundImage: 'url(' + book_background + ')' }" <div v-bind:class="{ bounceright: bounce_right, bounceleft: bounce_left }">
style="background-repeat: no-repeat; background-size: cover; padding-top: 76%;position: relative;" <div class="row">
class="pb-2 w-100"> <div class="col col-md-12 text-center pt-2 pb-4">
<div id="book_carousel" class="carousel slide" data-interval="0" <b-pagination pills
style=" position: absolute;top: 0;left: 0;bottom: 0;right: 0;"> v-model="current_page"
<div class="row m-0 pl-4 pr-4 pt-5 w-100" style="height: 15vh"> :total-rows="page_count_pagination"
<a class="mb-3 col-6 pull-left" href="#book_carousel" role="button" data-slide="prev"> :per-page="per_page_count"
</a> @change="pageChange"
<a class="mb-3 col-6 text-right" href="#book_carousel" role="button" data-slide="next"> first-text="📖"
</a> align="fill">
</b-pagination>
</div> </div>
<div class="row m-0 w-100 pt-2"> </div>
<div class="carousel-item w-100 active"> <div class="row" v-touch:swipe.left="swipeLeft" v-touch:swipe.right="swipeRight">
<div class="row m-0 w-100"> <div class="col-md-1" @click="swipeRight" style="cursor: pointer;">
<div class="col-6"> </div>
<b-card no-body v-hover class="ml-5 mr-5"> <div class="col-md-5">
<b-card-header class="p-4"> <transition name="flip" mode="out-in">
<h5>{{ book.name }} <span class="pull-right">{{ book.icon }}</span></h5> <cookbook-edit-card :book="book" v-if="current_page === 1"
</b-card-header> v-on:editing="cookbook_editing = $event"></cookbook-edit-card>
<b-card-body class="p-4"> </transition>
<b-card-text style="text-overflow: ellipsis;"> <transition name="flip" mode="out-in">
{{ book.description }} <recipe-card :recipe="display_recipes[0].recipe_content"
</b-card-text> v-if="current_page > 1" :key="display_recipes[0]"></recipe-card>
</b-card-body> </transition>
</b-card> </div>
</div> <div class="col-md-5">
<div class="col-6"> <transition name="flip" mode="out-in">
<b-card no-body v-hover class="ml-5 mr-5"> <cookbook-toc :recipes="recipes" v-if="current_page === 1"
<b-card-header class="p-4"> v-on:switchRecipe="switchRecipe($event)"></cookbook-toc>
<h5>{{ $t('TableOfContents') }}</h5> </transition>
</b-card-header> <transition name="flip">
<b-card-body class="p-4"> <recipe-card :recipe="display_recipes[1].recipe_content"
<ol> v-if="current_page > 1 && display_recipes.length === 2" :key="display_recipes[1]"></recipe-card>
<li v-for="recipe in recipes" v-bind:key="recipe.name"> </transition>
{{ recipe.recipe_content.name }} </div>
</li> <div class="col-md-1" @click="swipeLeft" style="cursor: pointer;">
</ol>
</b-card-body>
</b-card>
</div>
</div>
</div>
<div class="carousel-item w-100" v-for="(i, index) in Math.ceil(recipes.length / 2)" v-bind:key="index">
<div class="row m-0 w-100">
<div class="col-6" v-for="recipe in recipes.slice((i - 1) * 2, i * 2)" v-bind:key="recipe.id">
<recipe-card :recipe="recipe.recipe_content" class="ml-5 mr-5"></recipe-card>
</div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -56,18 +46,67 @@
<script> <script>
import RecipeCard from "./RecipeCard"; import RecipeCard from "./RecipeCard";
import CookbookEditCard from "./CookbookEditCard";
import CookbookToc from "./CookbookToc";
import Vue2TouchEvents from "vue2-touch-events"
import Vue from "vue";
Vue.use(Vue2TouchEvents)
export default { export default {
name: "CookbookSlider.vue", name: "CookbookSlider.vue",
components: {RecipeCard}, components: {CookbookToc, CookbookEditCard, RecipeCard},
props: { props: {
recipes: Array, recipes: Array,
book: Object book: Object
}, },
computed: {
page_count_pagination: function () {
return this.recipes.length + 2
},
page_count: function () {
return Math.ceil(this.page_count_pagination / this.per_page_count)
}
},
data() { data() {
return { return {
cookbooks: [], display_recipes: [],
book_background: window.IMAGE_BOOK current_page: 1,
per_page_count: 2,
bounce_left: false,
bounce_right: false,
cookbook_editing: false
}
},
methods: {
pageChange: function (page) {
this.current_page = page
this.display_recipes = this.recipes.slice(((this.current_page - 1) - 1) * 2, (this.current_page - 1) * 2)
},
swipeLeft: function () {
if (this.cookbook_editing) {
return
}
if (this.current_page < this.page_count) {
this.pageChange(this.current_page + 1)
} else {
this.bounce_left = true
setTimeout(() => this.bounce_left = false, 500);
}
},
swipeRight: function () {
if (this.cookbook_editing) {
return
}
if (this.current_page > 1) {
this.pageChange(this.current_page - 1)
} else {
this.bounce_right = true
setTimeout(() => this.bounce_right = false, 500);
}
},
switchRecipe: function (index) {
this.pageChange(Math.ceil((index + 1) / this.per_page_count) + 1)
} }
}, },
directives: { directives: {
@ -86,5 +125,96 @@ export default {
</script> </script>
<style scoped> <style scoped>
.flip-enter-active {
-webkit-animation-name: bounceUp;
animation-name: bounceUp;
-webkit-animation-duration: .5s;
animation-duration: .5s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
-webkit-animation-timing-function: linear;
animation-timing-function: linear;
animation-iteration-count: infinite;
-webkit-animation-iteration-count: infinite;
}
.bounceleft {
-webkit-animation-name: bounceLeft;
animation-name: bounceLeft;
-webkit-animation-duration: .5s;
animation-duration: .5s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
-webkit-animation-timing-function: linear;
animation-timing-function: linear;
animation-iteration-count: 1;
-webkit-animation-iteration-count: 1;
}
.bounceright {
-webkit-animation-name: bounceRight;
animation-name: bounceRight;
-webkit-animation-duration: .5s;
animation-duration: .5s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
-webkit-animation-timing-function: linear;
animation-timing-function: linear;
animation-iteration-count: 1;
-webkit-animation-iteration-count: 1;
}
@-webkit-keyframes bounceUp {
0%, 100% {
-webkit-transform: translateY(0);
}
50% {
-webkit-transform: translateY(-7px);
}
}
@keyframes bounceUp {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-7px);
}
}
@-webkit-keyframes bounceLeft {
0%, 100% {
-webkit-transform: translateY(0);
}
50% {
-webkit-transform: translateX(-10px);
}
}
@keyframes bounceLeft {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateX(-10px);
}
}
@-webkit-keyframes bounceRight {
0%, 100% {
-webkit-transform: translateY(0);
}
50% {
-webkit-transform: translateX(10px);
}
}
@keyframes bounceRight {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateX(10px);
}
}
</style> </style>

View File

@ -0,0 +1,44 @@
<template>
<b-card no-body v-hover>
<b-card-header class="p-4">
<h5>{{ $t('TableOfContents') }}</h5>
</b-card-header>
<b-card-body class="p-4">
<ol style="max-height: 60vh;overflow-y:auto;-webkit-overflow-scrolling: touch;" class="mb-1">
<li v-for="(recipe, index) in recipes" v-bind:key="index" v-on:click="$emit('switchRecipe', index)">
<a href="#">{{ recipe.recipe_content.name }} <recipe-rating :recipe="recipe"></recipe-rating> </a>
</li>
</ol>
<b-card-text v-if="recipes.length === 0">
{{ $t('Empty')}}
</b-card-text>
</b-card-body>
</b-card>
</template>
<script>
import RecipeRating from "./RecipeRating";
export default {
name: "CookbookToc",
components: {RecipeRating},
props: {
recipes: Array
},
directives: {
hover: {
inserted: function (el) {
el.addEventListener('mouseenter', () => {
el.classList.add("shadow")
});
el.addEventListener('mouseleave', () => {
el.classList.remove("shadow")
});
}
}
}
}
</script>
<style scoped>
</style>

View File

@ -2,41 +2,41 @@
<tr @click="$emit('checked-state-changed', ingredient)"> <tr @click="$emit('checked-state-changed', ingredient)">
<template v-if="ingredient.is_header"> <template v-if="ingredient.is_header">
<td colspan="5"> <td colspan="5">
<b>{{ ingredient.note }}</b> <b>{{ ingredient.note }}</b>
</td> </td>
</template> </template>
<template v-else> <template v-else>
<td class="d-print-none"> <td class="d-print-non" v-if="detailed">
<i class="far fa-check-circle text-success" v-if="ingredient.checked"></i> <i class="far fa-check-circle text-success" v-if="ingredient.checked"></i>
<i class="far fa-check-circle text-primary" v-if="!ingredient.checked"></i> <i class="far fa-check-circle text-primary" v-if="!ingredient.checked"></i>
</td> </td>
<td> <td>
<span v-if="ingredient.amount !== 0" v-html="calculateAmount(ingredient.amount)"></span> <span v-if="ingredient.amount !== 0" v-html="calculateAmount(ingredient.amount)"></span>
</td> </td>
<td> <td>
<span v-if="ingredient.unit !== null && !ingredient.no_amount">{{ ingredient.unit.name }}</span> <span v-if="ingredient.unit !== null && !ingredient.no_amount">{{ ingredient.unit.name }}</span>
</td> </td>
<td> <td>
<template v-if="ingredient.food !== null"> <template v-if="ingredient.food !== null">
<a :href="resolveDjangoUrl('view_recipe', ingredient.food.recipe)" v-if="ingredient.food.recipe !== null" <a :href="resolveDjangoUrl('view_recipe', ingredient.food.recipe)" v-if="ingredient.food.recipe !== null"
target="_blank" rel="noopener noreferrer">{{ ingredient.food.name }}</a> target="_blank" rel="noopener noreferrer">{{ ingredient.food.name }}</a>
<span v-if="ingredient.food.recipe === null">{{ ingredient.food.name }}</span> <span v-if="ingredient.food.recipe === null">{{ ingredient.food.name }}</span>
</template> </template>
</td> </td>
<td> <td v-if="detailed">
<div v-if="ingredient.note"> <div v-if="ingredient.note">
<span v-b-popover.hover="ingredient.note" <span v-b-popover.hover="ingredient.note"
class="d-print-none"> <i class="far fa-comment"></i> class="d-print-none"> <i class="far fa-comment"></i>
</span> </span>
<div class="d-none d-print-block"> <div class="d-none d-print-block">
<i class="far fa-comment-alt d-print-none"></i> {{ ingredient.note }} <i class="far fa-comment-alt d-print-none"></i> {{ ingredient.note }}
</div>
</div> </div>
</td> </div>
</td>
</template> </template>
</tr> </tr>
</template> </template>
@ -51,6 +51,10 @@ export default {
ingredient_factor: { ingredient_factor: {
type: Number, type: Number,
default: 1, default: 1,
},
detailed: {
type: Boolean,
default: true
} }
}, },
mixins: [ mixins: [

View File

@ -1,7 +1,7 @@
<template> <template>
<div v-if="recipe.keywords.length > 0"> <div v-if="recipe.keywords.length > 0">
<span :key="k.id" v-for="k in recipe.keywords" style="padding: 2px"> <span :key="k.id" v-for="k in recipe.keywords" class="pl-1">
<b-badge pill variant="light">{{k.label}}</b-badge> <b-badge pill variant="light" class="font-weight-normal">{{k.label}}</b-badge>
</span> </span>
</div> </div>
</template> </template>

View File

@ -1,6 +1,6 @@
<template> <template>
<span> <span class="pl-1">
<b-badge pill variant="primary" v-if="recipe.last_cooked !== null"><i class="fas fa-utensils"></i> {{ <b-badge pill variant="primary" v-if="recipe.last_cooked !== null" class="font-weight-normal"><i class="fas fa-utensils"></i> {{
formatDate(recipe.last_cooked) formatDate(recipe.last_cooked)
}}</b-badge> }}</b-badge>
</span> </span>

View File

@ -6,12 +6,20 @@
<b-card-img-lazy style="height: 15vh; object-fit: cover" class="" :src=recipe_image <b-card-img-lazy style="height: 15vh; object-fit: cover" class="" :src=recipe_image
v-bind:alt="$t('Recipe_Image')" v-bind:alt="$t('Recipe_Image')"
top></b-card-img-lazy> top></b-card-img-lazy>
<div class="card-img-overlay h-100 d-flex flex-column justify-content-right" <div class="card-img-overlay h-100 d-flex flex-column justify-content-right float-right text-right pt-2 pr-1">
style="float:right; text-align: right; padding-top: 10px; padding-right: 5px">
<a> <a>
<recipe-context-menu :recipe="recipe" style="float:right" v-if="recipe !== null"></recipe-context-menu> <recipe-context-menu :recipe="recipe" class="float-right" v-if="recipe !== null"></recipe-context-menu>
</a> </a>
</div> </div>
<div class="card-img-overlay w-50 d-flex flex-column justify-content-left float-left text-left pt-2"
v-if="recipe.waiting_time !== 0">
<b-badge pill variant="light" class="mt-1 font-weight-normal"><i class="fa fa-clock"></i>
{{ recipe.working_time }} {{ $t('min') }}
</b-badge>
<b-badge pill variant="secondary" class="mt-1 font-weight-normal"><i class="fa fa-pause"></i>
{{ recipe.waiting_time }} {{ $t('min') }}
</b-badge>
</div>
</a> </a>
@ -25,18 +33,31 @@
<template v-if="recipe !== null"> <template v-if="recipe !== null">
<recipe-rating :recipe="recipe"></recipe-rating> <recipe-rating :recipe="recipe"></recipe-rating>
<template v-if="recipe.description !== null"> <template v-if="recipe.description !== null">
<span v-if="recipe.description.length > 120"> <span v-if="recipe.description.length > text_length">
{{ recipe.description.substr(0, 120) + "\u2026" }} {{ recipe.description.substr(0, text_length) + "\u2026" }}
</span> </span>
<span v-if="recipe.description.length <= 120"> <span v-if="recipe.description.length <= text_length">
{{ recipe.description }} {{ recipe.description }}
</span> </span>
</template> </template>
<p class="mt-1">
<br/> <!-- TODO UGLY! --> <last-cooked :recipe="recipe"></last-cooked>
<last-cooked :recipe="recipe"></last-cooked> <keywords :recipe="recipe" style="margin-top: 4px"></keywords>
<keywords :recipe="recipe" style="margin-top: 4px"></keywords> </p>
<div class="row mt-3" v-if="detailed">
<div class="col-md-12">
<h6 class="card-title"><i class="fas fa-pepper-hot"></i> {{ $t('Ingredients') }}</h6>
<table class="table table-sm text-wrap">
<!-- eslint-disable vue/no-v-for-template-key-on-child -->
<template v-for="s in recipe.steps">
<template v-for="i in s.ingredients">
<Ingredient :detailed="false" :ingredient="i" :ingredient_factor="1" :key="i.id"></Ingredient>
</template>
</template>
<!-- eslint-enable vue/no-v-for-template-key-on-child -->
</table>
</div>
</div>
<b-badge pill variant="info" v-if="!recipe.internal">{{ $t('External') }}</b-badge> <b-badge pill variant="info" v-if="!recipe.internal">{{ $t('External') }}</b-badge>
<!-- <b-badge pill variant="success" <!-- <b-badge pill variant="success"
@ -65,6 +86,7 @@ import RecipeRating from "@/components/RecipeRating";
import moment from "moment/moment"; import moment from "moment/moment";
import Vue from "vue"; import Vue from "vue";
import LastCooked from "@/components/LastCooked"; import LastCooked from "@/components/LastCooked";
import Ingredient from "./Ingredient";
Vue.prototype.moment = moment Vue.prototype.moment = moment
@ -73,18 +95,30 @@ export default {
mixins: [ mixins: [
ResolveUrlMixin, ResolveUrlMixin,
], ],
components: {LastCooked, RecipeRating, Keywords, RecipeContextMenu}, components: {LastCooked, RecipeRating, Keywords, RecipeContextMenu, Ingredient},
props: { props: {
recipe: Object, recipe: Object,
meal_plan: Object, meal_plan: Object,
footer_text: String, footer_text: String,
footer_icon: String, footer_icon: String
}, },
data() { data() {
return { return {
recipe_image: '', recipe_image: '',
} }
}, },
computed: {
detailed: function () {
return this.recipe.steps !== undefined;
},
text_length: function () {
if (this.detailed) {
return 200
} else {
return 120
}
}
},
mounted() { mounted() {
if (this.recipe == null || this.recipe.image === null) { if (this.recipe == null || this.recipe.image === null) {

View File

@ -124,6 +124,9 @@ export function resolveDjangoUrl(url, params = null) {
* */ * */
export function getUserPreference(pref) { export function getUserPreference(pref) {
if(window.USER_PREF === undefined) {
return undefined;
}
return window.USER_PREF[pref] return window.USER_PREF[pref]
} }

File diff suppressed because it is too large Load Diff