added loading spinner and made new view the main recipe view

This commit is contained in:
vabene1111
2021-01-13 20:59:31 +01:00
parent 948eb9be3e
commit 9e5a7b2cc0
6 changed files with 146 additions and 774 deletions

View File

@ -1,444 +1,19 @@
{% extends "base.html" %}
{% load render_bundle from webpack_loader %}
{% load static %}
{% load crispy_forms_tags %}
{% load i18n %}
{% load l10n %}
{% load custom_tags %}
{% block title %}{{ recipe.name }}{% endblock %}
{% block extra_head %}
{% include 'include/vue_base.html' %}
<script src="{% static 'js/moment-with-locales.min.js' %}"></script>
<script src="{% static 'js/frac.js' %}"></script>
<link rel="stylesheet" href="{% static 'css/pretty-checkbox.min.css' %}">
<link rel="stylesheet" href="{% static 'custom/css/markdown_blockquote.css' %}">
{% endblock %}
{% block content %}
<div class="row">
<div class="col col-md-8">
{% recipe_rating recipe request.user as rating %}
<h3>{{ recipe.name }} {{ rating|safe }}</h3>
</div>
{% if request.user.is_authenticated %}
<div class="col col-md-4 d-print-none" style="text-align: right">
<div class="dropdown">
<a class="btn shadow-none" href="#" role="button" id="dropdownMenuLink"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v"></i>
</a>
{% recipe_rating recipe request.user as rating %}
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuLink">
<a class="dropdown-item" href="{% url 'edit_recipe' recipe.pk %}"><i
class="fas fa-pencil-alt fa-fw"></i> {% trans 'Edit' %}</a>
<button class="dropdown-item" onclick="$('#bookmarkModal').modal({'show':true})">
<i class="fas fa-bookmark fa-fw"></i> {% trans 'Add to Book' %}</button>
<a class="dropdown-item" v-bind:href="shopping_url" v-if="has_ingredients">
<i class="fas fa-shopping-cart fa-fw"></i> {% trans 'Add to Shopping' %}</a>
<a class="dropdown-item" href="{% url 'new_meal_plan' %}?recipe={{ recipe.pk }}"><i
class="fas fa-calendar fa-fw"></i> {% trans 'Add to Plan' %}</a>
<button class="dropdown-item" onclick="openCookLogModal({{ recipe.pk }})"><i
class="fas fa-clipboard-list fa-fw"></i> {% trans 'Log Cooking' %}</button>
<button class="dropdown-item" onclick="window.print()"><i
class="fas fa-print fa-fw"></i> {% trans 'Print' %}</button>
<a class="dropdown-item" href="{% url 'view_export' %}?r={{ recipe.pk }}" target="_blank"
rel="noopener noreferrer"><i class="fas fa-file-export fa-fw"></i> {% trans 'Export' %}</a>
{% if recipe.internal %}
<a class="dropdown-item" href="{% url 'new_share_link' recipe.pk %}" target="_blank"
rel="noopener noreferrer"><i class="fas fa-share-alt fa-fw"></i> {% trans 'Share' %}</a>
{% endif %}
</div>
</div>
</div>
{% endif %}
<div id="app">
<recipe-view recipe_id="5"></recipe-view>
</div>
{% if recipe.storage %}
<small>{% trans 'in' %} <a
href="{% url 'edit_storage' recipe.storage.pk %}">{{ recipe.storage.name }}</a></small><br/>
{% endif %}
{% if recipe.internal %}
<small>{% trans 'by' %} {{ recipe.created_by.get_user_name }}<br/></small>
{% endif %}
{% if recipe.keywords %}
{% for x in recipe.keywords.all %}
<span class="badge badge-pill badge-light">{{ x }}</span>
{% endfor %}
<br/>
<br/>
{% endif %}
{% if recipe.working_time and recipe.working_time != 0 %}
<span class="badge badge-secondary"><i
class="fas fa-user-clock"></i> {% trans 'Preparation time ~' %} {{ recipe.working_time }} min </span>
{% endif %}
{% if recipe.waiting_time and recipe.waiting_time != 0 %}
<span
class="badge badge-secondary"><i
class="far fa-clock"></i> {% trans 'Waiting time ~' %} {{ recipe.waiting_time }} min </span>
{% endif %}
{% recipe_last recipe request.user as last_cooked %}
{% if last_cooked %}
<span class="badge badge-primary">{% trans 'Last cooked' %} {{ last_cooked|date }}</span>
{% endif %}
{% if recipe.waiting_time and recipe.waiting_time != 0 or recipe.working_time and recipe.working_time != 0 or last_cooked %}
<br/>
<br/>
{% endif %}
<div class="row">
<div class="col-md-6 order-md-1 col-sm-12 order-sm-2 col-12 order-2" v-if="recipe && has_ingredients">
<!-- TODO duplicate code remove -->
<div class="card border-primary">
<div class="card-body">
<div class="row">
<div class="col col-md-9">
<h4 class="card-title">{% trans 'Ingredients' %}</h4>
</div>
<div class="col col-md-3">
<div class="input-group d-print-none">
<input type="number" value="1" maxlength="3" class="form-control" style="min-width: 2vw"
v-model="servings"/>
<div class="input-group-append">
<span class="input-group-text"><i class="fas fa-calculator"></i></span>
</div>
</div>
</div>
</div>
<br/>
<div class="row">
<div class="col-md-12">
<table class="table table-sm">
<template v-for="s in recipe.steps">
<template v-if="s.name != '' && s.show_as_header && s.ingredients.length > 0">
<tr>
<td style="padding-top: 8px!important; ">
<b>[[s.name]]</b>
</td>
<td></td>
<td></td>
</tr>
</template>
<template v-for="i in s.ingredients">
<template v-if="i.is_header">
<tr>
<td style="padding-top: 8px!important; ">
<b>[[i.note]]</b>
</td>
<td></td>
<td></td>
</tr>
</template>
<template v-else>
<tr>
<td style="vertical-align: middle!important;">
<div class="pretty p-default p-curve">
<input type="checkbox" v-model="i.checked"/>
<div class="state p-success">
<label>
<template v-if="i.no_amount">
<span>&#x2063;</span>
</template>
<template v-if="!i.no_amount">
<span v-html="calculateAmount(i.amount)"></span>
{# Allow for amounts without units, such as "2 eggs" #}
<template v-if="i.unit">
[[i.unit.name]]
</template>
</template>
</label>
</div>
</div>
</td>
<td style="vertical-align: middle!important;">
<template v-if="i.food && i.food.recipe">
<a v-bind:href='"{% url 'view_recipe' 12345 %}".replace(/12345/, i.food.recipe)'
target="_blank" rel="noopener noreferrer">[[i.food.name]]</a>
</template>
<template v-else-if="i.food">
[[i.food.name]]
</template>
</td>
<td style="vertical-align: middle!important;">
<template v-if="i.note">
<b-button v-b-popover.hover="i.note"
class="btn btn-sm d-print-none"><i
class="fas fa-info"></i></b-button>
<div class="d-none d-print-block">
<i class="far fa-comment-alt"></i> [[i.note]]
</div>
</template>
</td>
</tr>
</template>
</template>
</template>
<!-- Bottom border -->
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
{% if recipe.image %}
<div class="col-12 order-1 col-sm-12 order-sm-1 col-md-6 order-md-2" style="text-align: center">
<img class="img img-fluid rounded" src="{{ recipe.image.url }}" style="max-height: 30vh;"
alt="{% trans 'Recipe Image' %}">
<br/>
<br/>
</div>
{% endif %}
</div>
{% if recipe.nutrition %}
<div class="row mt-5">
<div class="col-md-6 order-md-1 col-sm-12 order-sm-2 col-12 order-2">
<div class="card border-primary">
<div class="card-body">
<h4 class="card-title">{% trans 'Nutrition' %}</h4>
<table class="table table-sm">
<tr>
<td style="padding-top: 8px!important; ">
<b>{% trans 'Calories' %}</b>
</td>
<td style="text-align: right">{{ recipe.nutrition.calories|floatformat:2 }}</td>
<td>kcal</td>
</tr>
<tr>
<tr>
<td style="padding-top: 8px!important; ">
<b>{% trans 'Carbohydrates' %}</b>
</td>
<td style="text-align: right">{{ recipe.nutrition.carbohydrates|floatformat:2 }}</td>
<td>g</td>
</tr>
<tr>
<tr>
<td style="padding-top: 8px!important; ">
<b>{% trans 'Fats' %}</b>
</td>
<td style="text-align: right">{{ recipe.nutrition.fats|floatformat:2 }}</td>
<td>g</td>
</tr>
<tr>
<tr>
<td style="padding-top: 8px!important; ">
<b>{% trans 'Proteins' %}</b>
</td>
<td style="text-align: right">{{ recipe.nutrition.proteins|floatformat:2 }}</td>
<td>g</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</table>
{% if recipe.nutrition.source %}
Source: {{ recipe.nutrition.source }}
{% endif %}
</div>
</div>
</div>
</div>
{% endif %}
<div v-if="recipe !== undefined && recipe.steps.length > 0">
<hr>
<h3>{% trans 'Instructions' %}</h3>
<hr>
</div>
<div style="font-size: large;" v-if="recipe">
{% for s in recipe.steps.all %}
<div style="margin-top: 1vh" class="card">
<div class="card-body">
{% if recipe.steps.all|length > 1 %}
<div class="card-title">
<div class="row d-flex">
<div class="col-md-8 text-muted ">
{% if s.type == 'TEXT' %}
<i class="fas fa-paragraph fa-fw"></i>
{% elif s.type == 'TIME' %}
<i class="fas fa-clock fa-fw"></i>
{% endif %}
{% if s.name %}{{ s.name }}{% else %}{% trans 'Step' %}
{{ forloop.counter }}{% endif %}
{% if s.time != 0 %}
- {{ s.time }} {% trans 'Minutes' %}
{% endif %}
</div>
<div class="col-md-4 col-12 justify-content-end" v-if="has_times">
<input type="datetime-local" class="form-control"
@change="updateTimes(recipe.steps[{{ forloop.counter0 }}])"
v-model="recipe.steps[{{ forloop.counter0 }}].time_finished">
</div>
</div>
</div>
<div class="row" v-if="recipe.steps[{{ forloop.counter0 }}].ingredients.length > 0"
style="margin-top: 1vh">
<div class="col-md-6">
<table class="table table-sm">
<template v-for="i in recipe.steps[{{ forloop.counter0 }}].ingredients">
<!-- TODO duplicate code remove -->
<template v-if="i.is_header">
<tr>
<td style="padding-top: 8px!important; ">
<b>[[i.note]]</b>
</td>
<td>
</td>
<td></td>
</tr>
</template>
<template v-else>
<tr>
<td style="vertical-align: middle!important;">
<div class="pretty p-default p-curve">
<input type="checkbox" v-model="i.checked"/>
<div class="state p-success">
<label>
<template v-if="i.no_amount">
<span>&#x2063;</span>
</template>
<template v-if="!i.no_amount">
<span v-html="calculateAmount(i.amount)"></span>
{# Allow for amounts without units, such as "2 eggs" #}
<template v-if="i.unit">
[[i.unit.name]]
</template>
</template>
</label>
</div>
</div>
</td>
<td style="vertical-align: middle!important;">
<template v-if="i.food && i.food.recipe">
<a v-bind:href='"{% url 'view_recipe' 12345 %}".replace(/12345/, i.food.recipe)'
target="_blank" rel="noopener noreferrer">[[i.food.name]]</a>
</template>
<template v-else-if="i.food">
[[i.food.name]]
</template>
</td>
<td style="vertical-align: middle!important;">
<template v-if="i.note">
<b-button v-b-popover.hover="i.note"
class="btn btn-sm d-print-none"><i
class="fas fa-info"></i></b-button>
<div class="d-none d-print-block">
<i class="far fa-comment-alt"></i> [[i.note]]
</div>
</template>
</td>
</tr>
</template>
</template>
<!-- Bottom border -->
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</table>
</div>
</div>
{% endif %}
<div class="row" style="margin-top: 8px">
<div class="col-md-12">
{% if s.instruction %}
{{ s.get_instruction_render | safe }}
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
</div>
{% if recipe.storage %}
<div class="row">
{% if recipe.internal %}
<div class="col col-12" style="margin-top: 2vh">
<a href='#' onClick='openRecipe({{ recipe.id }})'
class="d-print-none">{% trans 'View external recipe' %} <i class="fas fa-external-link-alt"></i></a>
</div>
{% else %}
{% if '.pdf' in recipe.file_path %}
<div class="col col-12">
<iframe src="{% static 'pdfjs/viewer.html' %}?file={% url 'api_get_recipe_file' recipe.id %}"
width="100%"
height="700px"
style="border: none;"></iframe>
</div>
{% endif %}
{% if '.jpg' in recipe.file_path or '.png' in recipe.file_path or '.jpeg' in recipe.file_path %}
<div class="col-md-12" style="text-align: center">
<img class="img img-fluid" src="{% url 'api_get_recipe_file' recipe.id %}"
alt="{% trans 'External recipe image' %}">
</div>
{% endif %}
<div class="col col-12" style="margin-top: 1vh">
<div class="card border-info">
<div class="card-body text-info">
<h5 class="card-title">{% trans 'External recipe' %}</h5>
<p class="card-text">
{% blocktrans %}
This is an external recipe, which means you can only view it by opening the link
above.
You can convert this recipe to a fancy recipe by pressing the convert button. The
original
file
will still be accessible.
{% endblocktrans %}.
<br/>
<br/>
<a href="{% url 'edit_convert_recipe' recipe.pk %}"
class="card-link btn btn-info">{% trans 'Convert now!' %}</a>
<a href='#' onClick='openRecipe({{ recipe.id }})'
class="d-print-none btn btn-warning">{% trans 'View external recipe' %} <i
class="fas fa-external-link-alt"></i></a>
</p>
</div>
</div>
</div>
{% endif %}
</div>
{% endif %}
{% if request.user.userpreference.comments %}
<br/>
<br/>
@ -474,144 +49,27 @@
{% endif %}
{% endif %}
{% if recipe.storage %}
{% include 'include/recipe_open_modal.html' %}
{% endif %}
<!-- Bookmark Modal -->
<div class="modal fade" id="bookmarkModal" tabindex="-1" role="dialog" aria-labelledby="bookmarkModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="bookmarkModalLabel">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form method="POST" class="post-form">
<div class="modal-body">
{% csrf_token %}
{{ bookmark_form|crispy }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<input type="submit" value="{% trans 'Save' %}" class="btn btn-success">
</div>
</form>
</div>
</div>
</div>
{% include 'include/log_cooking.html' %}
{% endblock %}
{% block script %}
<script src="{% url 'javascript-catalog' %}"></script>
{% if debug %}
<script src="{% url 'js_reverse' %}"></script>
{% else %}
<script src="{% static 'django_js_reverse/js/reverse.js' %}"></script>
{% endif %}
<script type="application/javascript">
let csrftoken = Cookies.get('csrftoken');
Vue.http.headers.common['X-CSRFToken'] = csrftoken;
{% if user_servings %}
const recipe_servings = {{ user_servings|floatformat:0 }}
{% else %}
const recipe_servings = {{ recipe.servings }}
{% endif %}
let app = new Vue({
delimiters: ['[[', ']]'],
el: '#id_base_container',
data: {
recipe: undefined,
has_ingredients: false,
has_times: false,
servings: recipe_servings,
},
computed: {
ingredient_factor: function () {
return this.servings / recipe_servings
},
shopping_url: function () {
return `{% url 'view_shopping' %}?r=[${this.recipe.id},${this.servings}]`
},
},
mounted: function () {
this.loadRecipe()
},
methods: {
loadRecipe: function () {
this.$http.get("{% url 'api:recipe-detail' recipe.pk %}" {% if share %}
+ "?share={{ share }}"{% endif %}).then((response) => {
this.recipe = response.data;
this.loading = false;
for (let step of this.recipe.steps) {
if (step.ingredients.length > 0) {
this.has_ingredients = true
}
if (step.time !== 0) {
this.has_times = true
}
this.$set(step, 'time_finished', undefined);
for (let i of step.ingredients) {
this.$set(i, 'checked', false)
}
}
}).catch((err) => {
this.error = err.data;
this.loading = false;
console.log(err)
})
},
roundDecimals: function (num) {
let decimals = {% if request.user.userpreference.ingredient_decimals %}
{{ request.user.userpreference.ingredient_decimals }} {% else %} 2; {% endif %}
return +(Math.round(num + `e+${decimals}`) + `e-${decimals}`);
},
updateTimes: function (step) {
let time_diff_first = 0;
for (let s of this.recipe.steps) {
if (this.recipe.steps.indexOf(s) < this.recipe.steps.indexOf(step)) {
time_diff_first += s.time
}
}
this.recipe.steps[0].time_finished = moment(step.time_finished).subtract(time_diff_first, 'minutes').format(moment.HTML5_FMT.DATETIME_LOCAL);
let time_diff = 0;
for (let s of this.recipe.steps) {
s.time_finished = moment(this.recipe.steps[0].time_finished).add(time_diff, 'minutes').format(moment.HTML5_FMT.DATETIME_LOCAL);
time_diff += s.time
}
},
calculateAmount: function (amount) {
{% if request.user.userpreference.use_fractions %}
let return_string = ''
let fraction = frac.cont((amount * this.ingredient_factor), 9, true)
if (fraction[0] > 0) {
return_string += fraction[0]
}
if (fraction[1] > 0) {
return_string += ` <sup>${(fraction[1])}</sup>&frasl;<sub>${(fraction[2])}</sub>`
}
return return_string
{% else %}
return this.roundDecimals(amount * this.ingredient_factor)
{% endif %}
},
}
});
window.RECIPE_ID = {{recipe.pk}};
window.USER_PREF = {
'use_fractions': {% if request.user.userpreference.use_fractions %} true {% else %} false {% endif %},
'ingredient_decimals': {{ request.user.userpreference.ingredient_decimals }},
}
</script>
{% render_bundle 'chunk-vendors' %}
{% render_bundle 'recipe_view' %}
{% endblock %}

View File

@ -1,97 +0,0 @@
{% extends "base.html" %}
{% load render_bundle from webpack_loader %}
{% load static %}
{% load i18n %}
{% load l10n %}
{% load custom_tags %}
{% block title %}{{ recipe.name }}{% endblock %}
{% block content %}
{% recipe_rating recipe request.user as rating %}
<!--
<div class="row">
<div class="col-md-12">
<h3>{{ recipe.name }} {{ rating|safe }}</h3>
{% if recipe.storage %}
<small>{% trans 'in' %} <a
href="{% url 'edit_storage' recipe.storage.pk %}">{{ recipe.storage.name }}</a></small><br/>
{% endif %}
{% if recipe.internal %}
<small>{% trans 'by' %} {{ recipe.created_by.get_user_name }}<br/></small>
{% endif %}
{% if recipe.keywords %}
{% for x in recipe.keywords.all %}
<span class="badge badge-pill badge-light">{{ x }}</span>
{% endfor %}
{% endif %}
</div>
</div>
-->
<div id="app">
<recipe-view recipe_id="5"></recipe-view>
</div>
{% if request.user.userpreference.comments %}
<br/>
<br/>
<h5 {% if not comments %}class="d-print-none" {% endif %}><i class="far fa-comments"></i> {% trans 'Comments' %}
</h5>
{% for c in comments %}
<div class="card">
<div class="card-body">
<small class="card-title">{{ c.updated_at }} {% trans 'by' %} {{ c.created_by.username }}</small> <a
href="{% url 'edit_comment' c.pk %}" class="d-print-none"><i
class="fas fa-pencil-alt"></i></a><br/>
{{ c.text }}
</div>
</div>
<br/>
{% endfor %}
{% if request.user.is_authenticated %}
<div class="d-print-none">
<form method="POST" class="post-form">
{% csrf_token %}
<div class="input-group mb-3">
<textarea name="comment-text" cols="15" rows="2" class="textarea form-control" required
id="comment-id_text"></textarea>
<div class="input-group-append">
<input type="submit" value="{% trans 'Comment' %}" class="btn btn-success">
</div>
</div>
</form>
</div>
{% endif %}
{% endif %}
{% endblock %}
{% block script %}
<script src="{% url 'javascript-catalog' %}"></script>
{% if debug %}
<script src="{% url 'js_reverse' %}"></script>
{% else %}
<script src="{% static 'django_js_reverse/js/reverse.js' %}"></script>
{% endif %}
<script type="application/javascript">
window.RECIPE_ID = {{recipe.pk}};
window.USER_PREF = {
'use_fractions': {% if request.user.userpreference.use_fractions %} true {% else %} false {% endif %},
'ingredient_decimals': {{ request.user.userpreference.ingredient_decimals }},
}
</script>
{% render_bundle 'chunk-vendors' %}
{% render_bundle 'recipe_view' %}
{% endblock %}

View File

@ -153,7 +153,6 @@ def recipe_view(request, pk, share=None):
)
comment_form = CommentForm()
bookmark_form = RecipeBookEntryForm()
user_servings = None
if request.user.is_authenticated:
@ -172,18 +171,7 @@ def recipe_view(request, pk, share=None):
.exists():
ViewLog.objects.create(recipe=recipe, created_by=request.user)
return render(
request,
'recipe_view.html',
{
'recipe': recipe,
'comments': comments,
'comment_form': comment_form,
'bookmark_form': bookmark_form,
'share': share,
'user_servings': user_servings
}
)
return render(request, 'recipe_view.html', {'recipe': recipe, 'comments': comments, 'comment_form': comment_form, 'share': share, 'user_servings': user_servings})
@group_required('user')

View File

@ -1,132 +1,136 @@
<template>
<div id="app" v-if="!loading">
<div id="app">
<template v-if="loading">
<loading-spinner></loading-spinner>
</template>
<div class="row">
<div class="col-12" style="text-align: center">
<h3>{{ recipe.name }}</h3>
</div>
</div>
<div style="text-align: center">
<keywords :recipe="recipe"></keywords>
</div>
<div class="row" style="margin-top: 8px">
<div class="col-12" style="text-align: center">
<i>{{ recipe.description }}</i>
</div>
</div>
<hr/>
<div class="row">
<div class="col col-md-3">
<div class="row d-flex" style="padding-left: 16px;height: 100%">
<div class="my-auto" style="padding-right: 4px">
<i class="fas fa-user-clock fa-2x text-primary"></i>
</div>
<div class="my-auto" style="padding-right: 4px">
<span class="text-primary"><b>{{ _('Preparation') }}</b></span><br/>
{{ recipe.working_time }} {{ _('min') }}
</div>
<div v-if="!loading">
<div class="row">
<div class="col-12" style="text-align: center">
<h3>{{ recipe.name }}</h3>
</div>
</div>
<div class="col col-md-3">
<div class="row d-flex" style="height: 100%">
<div class="my-auto" style="padding-right: 4px">
<i class="far fa-clock fa-2x text-primary"></i>
</div>
<div class="my-auto" style="padding-right: 4px">
<span class="text-primary"><b>{{ _('Waiting') }}</b></span><br/>
{{ recipe.waiting_time }} {{ _('min') }}
</div>
<div style="text-align: center">
<keywords :recipe="recipe"></keywords>
</div>
<div class="row" style="margin-top: 8px">
<div class="col-12" style="text-align: center">
<i>{{ recipe.description }}</i>
</div>
</div>
<div class="col col-md-4 col-10">
<div class="row d-flex" style="padding-left: 16px;height: 100%">
<div class="my-auto" style="padding-right: 4px">
<i class="fas fa-pizza-slice fa-2x text-primary"></i>
<hr/>
<div class="row">
<div class="col col-md-3">
<div class="row d-flex" style="padding-left: 16px;height: 100%">
<div class="my-auto" style="padding-right: 4px">
<i class="fas fa-user-clock fa-2x text-primary"></i>
</div>
<div class="my-auto" style="padding-right: 4px">
<span class="text-primary"><b>{{ _('Preparation') }}</b></span><br/>
{{ recipe.working_time }} {{ _('min') }}
</div>
</div>
<div class="my-auto" style="padding-right: 4px">
<input dir="rtl"
</div>
<div class="col col-md-3">
<div class="row d-flex" style="height: 100%">
<div class="my-auto" style="padding-right: 4px">
<i class="far fa-clock fa-2x text-primary"></i>
</div>
<div class="my-auto" style="padding-right: 4px">
<span class="text-primary"><b>{{ _('Waiting') }}</b></span><br/>
{{ recipe.waiting_time }} {{ _('min') }}
</div>
</div>
</div>
<div class="col col-md-4 col-10">
<div class="row d-flex" style="padding-left: 16px;height: 100%">
<div class="my-auto" style="padding-right: 4px">
<i class="fas fa-pizza-slice fa-2x text-primary"></i>
</div>
<div class="my-auto" style="padding-right: 4px">
<input dir="rtl"
style="border-width:0px;border:none; padding:0px; padding-left: 0.5vw; padding-right: 8px; max-width: 80px"
value="1" maxlength="3"
type="number" class="form-control form-control-lg" v-model.number="servings"/>
</div>
<div class="my-auto">
<b>{{ _('Servings') }}</b>
</div>
<div class="my-auto">
<b>{{ _('Servings') }}</b>
</div>
</div>
</div>
<div class="col col-md-2 col-2 my-auto" style="text-align: right; padding-right: 1vw">
<recipe-context-menu v-bind:recipe="recipe" :servings="servings"></recipe-context-menu>
</div>
</div>
<hr/>
<div class="col col-md-2 col-2 my-auto" style="text-align: right; padding-right: 1vw">
<recipe-context-menu v-bind:recipe="recipe" :servings="servings"></recipe-context-menu>
</div>
</div>
<hr/>
<div class="row" style="margin-top: 2vh">
<div class="col-md-6 order-md-1 col-sm-12 order-sm-2 col-12 order-2" v-if="recipe && ingredient_count > 0">
<div class="card border-primary">
<div class="card-body">
<div class="row">
<div class="col col-md-8">
<h4 class="card-title"><i class="fas fa-pepper-hot"></i> {{ _('Ingredients') }}</h4>
<div class="row" style="margin-top: 2vh">
<div class="col-md-6 order-md-1 col-sm-12 order-sm-2 col-12 order-2" v-if="recipe && ingredient_count > 0"
style="margin-top: 2vh">
<div class="card border-primary">
<div class="card-body">
<div class="row">
<div class="col col-md-8">
<h4 class="card-title"><i class="fas fa-pepper-hot"></i> {{ _('Ingredients') }}</h4>
</div>
</div>
</div>
<br/>
<div class="row">
<div class="col-md-12">
<table class="table table-sm">
<!-- 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 v-bind:ingredient="i" v-bind:servings="servings" :key="i.id"
@checked-state-changed="updateIngredientCheckedState"></Ingredient>
<br/>
<div class="row">
<div class="col-md-12">
<table class="table table-sm">
<!-- 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 v-bind:ingredient="i" v-bind:servings="servings" :key="i.id"
@checked-state-changed="updateIngredientCheckedState"></Ingredient>
</template>
</template>
</template>
<!-- eslint-enable vue/no-v-for-template-key-on-child -->
</table>
<!-- eslint-enable vue/no-v-for-template-key-on-child -->
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-12 order-1 col-sm-12 order-sm-1 col-md-6 order-md-2">
<div class="row">
<div class="col-12">
<div class="col-12 order-1 col-sm-12 order-sm-1 col-md-6 order-md-2">
<div class="row">
<div class="col-12">
<img class="img img-fluid rounded" :src="recipe.image" style="max-height: 30vh;"
:alt="_( 'Recipe Image')" v-if="recipe.image !== null">
<img class="img img-fluid rounded" :src="recipe.image" style="max-height: 30vh;"
:alt="_( 'Recipe Image')" v-if="recipe.image !== null">
</div>
</div>
<div class="row" style="margin-top: 2vh">
<div class="col-12">
<Nutrition :recipe="recipe" :servings="servings"></Nutrition>
</div>
</div>
</div>
<div class="row" style="margin-top: 2vh">
<div class="col-12">
<Nutrition :recipe="recipe" :servings="servings"></Nutrition>
</div>
</div>
</div>
<div v-if="recipe.file_path.includes('.pdf')">
<PdfViewer :recipe="recipe"></PdfViewer>
</div>
<div
v-if="recipe.file_path.includes('.png') || recipe.file_path.includes('.jpg') || recipe.file_path.includes('.jpeg')">
<ImageViewer :recipe="recipe"></ImageViewer>
</div>
<div v-for="(s, index) in recipe.steps" v-bind:key="s.id" style="margin-top: 1vh">
<Step :recipe="recipe" :step="s" :servings="servings" :index="index" :start_time="start_time"
@update-start-time="updateStartTime" @checked-state-changed="updateIngredientCheckedState"></Step>
</div>
</div>
<div v-if="recipe.file_path.includes('.pdf')">
<PdfViewer :recipe="recipe"></PdfViewer>
</div>
<div
v-if="recipe.file_path.includes('.png') || recipe.file_path.includes('.jpg') || recipe.file_path.includes('.jpeg')">
<ImageViewer :recipe="recipe"></ImageViewer>
</div>
<div v-for="(s, index) in recipe.steps" v-bind:key="s.id" style="margin-top: 1vh">
<Step :recipe="recipe" :step="s" :servings="servings" :index="index" :start_time="start_time"
@update-start-time="updateStartTime" @checked-state-changed="updateIngredientCheckedState"></Step>
</div>
</div>
</template>
@ -149,6 +153,7 @@ import Nutrition from "@/components/Nutrition";
import moment from 'moment'
import Keywords from "@/components/Keywords";
import LoadingSpinner from "@/components/LoadingSpinner";
Vue.prototype.moment = moment
@ -168,6 +173,7 @@ export default {
RecipeContextMenu,
Nutrition,
Keywords,
LoadingSpinner,
},
data() {
return {
@ -191,7 +197,7 @@ export default {
this.ingredient_count += step.ingredients.length
for (let ingredient of step.ingredients) {
this.$set(ingredient, 'checked', false)
this.$set(ingredient, 'checked', false)
}
step.time_offset = total_time

View File

@ -0,0 +1,17 @@
<template>
<div class="row">
<div class="col" style="text-align: center">
<i class="fas fa-spinner fa-spin fa-10x"></i>
</div>
</div>
</template>
<script>
export default {
name: 'LoadingSpinner',
props: {
recipe: Object,
},
}
</script>

View File

@ -1 +1 @@
{"status":"done","publicPath":"http://localhost:8080/","chunks":{"chunk-vendors":[{"name":"js/chunk-vendors.js","publicPath":"http://localhost:8080/js/chunk-vendors.js","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\js\\chunk-vendors.js"}],"recipe_view":[{"name":"js/recipe_view.js","publicPath":"http://localhost:8080/js/recipe_view.js","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\js\\recipe_view.js"},{"name":"recipe_view.6a32bc3201ad26dbc898.hot-update.js","publicPath":"http://localhost:8080/recipe_view.6a32bc3201ad26dbc898.hot-update.js","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\recipe_view.6a32bc3201ad26dbc898.hot-update.js"}]},"error":"ModuleError","message":"Module Error (from ./node_modules/eslint-loader/index.js):\n\nF:\\Developement\\Django\\recipes\\vue\\src\\components\\Keywords.vue\n 3:7 error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key\n\n✖ 1 problem (1 error, 0 warnings)\n"}
{"status":"done","publicPath":"http://localhost:8080/","chunks":{"chunk-vendors":[{"name":"js/chunk-vendors.js","publicPath":"http://localhost:8080/js/chunk-vendors.js","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\js\\chunk-vendors.js"}],"recipe_view":[{"name":"js/recipe_view.js","publicPath":"http://localhost:8080/js/recipe_view.js","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\js\\recipe_view.js"},{"name":"recipe_view.cfc8fcd2004c1b08df3e.hot-update.js","publicPath":"http://localhost:8080/recipe_view.cfc8fcd2004c1b08df3e.hot-update.js","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\recipe_view.cfc8fcd2004c1b08df3e.hot-update.js"}]},"error":"ModuleError","message":"Module Error (from ./node_modules/eslint-loader/index.js):\n\nF:\\Developement\\Django\\recipes\\vue\\src\\components\\Keywords.vue\n 3:7 error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key\n\n✖ 1 problem (1 error, 0 warnings)\n"}