save WIP
This commit is contained in:
@ -22,9 +22,13 @@
|
|||||||
<script src="{% static 'django_js_reverse/js/reverse.js' %}"></script>
|
<script src="{% static 'django_js_reverse/js/reverse.js' %}"></script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<script type="application/javascript">
|
|
||||||
window.RECIPE_ID = 5;
|
|
||||||
|
|
||||||
|
<script type="application/javascript">
|
||||||
|
window.RECIPE_ID = 6;
|
||||||
|
window.USER_PREF = {
|
||||||
|
'use_fractions': {% if request.user.userpreference.use_fractions %} true {% else %} false {% endif %},
|
||||||
|
'ingredient_decimals': {{ request.user.userpreference.ingredient_decimals }},
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% render_bundle 'chunk-vendors' %}
|
{% render_bundle 'chunk-vendors' %}
|
||||||
|
@ -24,9 +24,7 @@ SECRET_KEY = os.getenv('SECRET_KEY') if os.getenv('SECRET_KEY') else 'INSECURE_S
|
|||||||
|
|
||||||
DEBUG = bool(int(os.getenv('DEBUG', True)))
|
DEBUG = bool(int(os.getenv('DEBUG', True)))
|
||||||
|
|
||||||
INTERNAL_IPS = [
|
INTERNAL_IPS = os.getenv('INTERNAL_IPS').split(',') if os.getenv('INTERNAL_IPS') else ['127.0.0.1']
|
||||||
'127.0.0.1',
|
|
||||||
]
|
|
||||||
|
|
||||||
# allow djangos wsgi server to server mediafiles
|
# allow djangos wsgi server to server mediafiles
|
||||||
GUNICORN_MEDIA = bool(int(os.getenv('GUNICORN_MEDIA', True)))
|
GUNICORN_MEDIA = bool(int(os.getenv('GUNICORN_MEDIA', True)))
|
||||||
|
@ -23,10 +23,36 @@
|
|||||||
|
|
||||||
|
|
||||||
<div class="row">
|
<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">
|
<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 v-for="s in recipe.steps" v-bind:key="s.id">
|
|
||||||
<div v-for="i in s.ingredients" v-bind:key="i.id">
|
<div class="card border-primary">
|
||||||
<Ingredient v-bind:ingredient="i"></Ingredient>
|
<div class="card-body">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col col-md-9">
|
||||||
|
<h4 class="card-title">{{ _('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">
|
||||||
|
<div v-for="s in recipe.steps" v-bind:key="s.id">
|
||||||
|
<div v-for="i in s.ingredients" v-bind:key="i.id">
|
||||||
|
<Ingredient v-bind:ingredient="i" v-bind:servings="servings"></Ingredient>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -34,13 +60,16 @@
|
|||||||
<div class="col-12 order-1 col-sm-12 order-sm-1 col-md-6 order-md-2" style="text-align: center">
|
<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" style="max-height: 30vh;"
|
<img class="img img-fluid rounded" :src="recipe.image" style="max-height: 30vh;"
|
||||||
:alt="_( 'Recipe Image')">
|
:alt="_( 'Recipe Image')">
|
||||||
<br/>
|
|
||||||
<br/>
|
<div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-for="s in recipe.steps" v-bind:key="s.id">
|
<div v-for="(s, index) in recipe.steps" v-bind:key="s.id" style="margin-top: 1vh">
|
||||||
<Step v-bind:step="s" v-bind:servings="servings"></Step>
|
<Step v-bind:step="s" v-bind:servings="servings" v-bind:index="index"></Step>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -77,7 +106,7 @@ export default {
|
|||||||
loading: true,
|
loading: true,
|
||||||
recipe_id: window.RECIPE_ID,
|
recipe_id: window.RECIPE_ID,
|
||||||
recipe: undefined,
|
recipe: undefined,
|
||||||
has_ingredients: false,
|
ingredient_count: 0,
|
||||||
servings: 1,
|
servings: 1,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -91,9 +120,8 @@ export default {
|
|||||||
this.loading = false
|
this.loading = false
|
||||||
|
|
||||||
for (let step of this.recipe.steps) {
|
for (let step of this.recipe.steps) {
|
||||||
if (step.ingredients.length > 0) {
|
this.ingredient_count += step.ingredients.length
|
||||||
this.has_ingredients = true
|
|
||||||
}
|
|
||||||
if (step.time !== 0) {
|
if (step.time !== 0) {
|
||||||
this.has_times = true
|
this.has_times = true
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,52 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<input type="checkbox">
|
<tr>
|
||||||
{{ingredient.amount}}
|
<td>
|
||||||
{{ingredient.unit}}
|
<input type="checkbox">
|
||||||
{{ingredient.food}}
|
</td>
|
||||||
{{ingredient.note}}
|
<td>
|
||||||
|
<span v-if="ingredient.amount !== 0">{{ calculateAmount(ingredient.amount) }}</span>
|
||||||
|
</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>
|
||||||
|
<div v-if="ingredient.note">
|
||||||
|
<span v-b-popover.hover="ingredient.note"
|
||||||
|
class="d-print-none"> <i class="far fa-comment"></i>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="d-none d-print-block">
|
||||||
|
<i class="far fa-comment-alt"></i> {{ ingredient.note }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
import {calculateAmount} from "@/utils/utils";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Ingredient',
|
name: 'Ingredient',
|
||||||
props: {
|
props: {
|
||||||
ingredient: Object,
|
ingredient: Object,
|
||||||
servings: Number
|
servings: {
|
||||||
|
type: Number,
|
||||||
|
default: 1,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
calculateAmount: function (x) {
|
||||||
|
return calculateAmount(x, this.servings)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,18 +1,32 @@
|
|||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<div v-for="i in step.ingredients" v-bind:key="i.id">
|
<h5 class="text-secondary">
|
||||||
<Ingredient v-bind:ingredient="i" v-bind:servings="servings"></Ingredient>
|
<template v-if="step.name">{{ step.name }}</template>
|
||||||
|
<template v-else>{{ _('Step') }} {{index + 1}}</template>
|
||||||
|
</h5>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-md-3">
|
||||||
|
<i class="fa fa-stopwatch"></i> {{ step.time }}
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<div v-for="i in step.ingredients" v-bind:key="i.id">
|
||||||
|
<Ingredient v-bind:ingredient="i" v-bind:servings="servings"></Ingredient>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-9">
|
||||||
|
<i class="fas fa-paragraph text-secondary"></i>
|
||||||
|
{{ step.instruction }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
Servings Step: {{servings}}
|
|
||||||
|
|
||||||
{{ step.instruction }}
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
@ -20,15 +34,20 @@
|
|||||||
<script>
|
<script>
|
||||||
|
|
||||||
import Ingredient from "@/components/Ingredient";
|
import Ingredient from "@/components/Ingredient";
|
||||||
|
import {GettextMixin} from "@/utils/utils";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Step',
|
name: 'Step',
|
||||||
|
mixins: [
|
||||||
|
GettextMixin,
|
||||||
|
],
|
||||||
components: {
|
components: {
|
||||||
Ingredient
|
Ingredient,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
step: Object,
|
step: Object,
|
||||||
servings: Number,
|
servings: Number,
|
||||||
|
index: Number,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
63
vue/src/utils/fractions.js
Normal file
63
vue/src/utils/fractions.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/* frac.js (C) 2012-present SheetJS -- http://sheetjs.com */
|
||||||
|
|
||||||
|
/*https://developer.aliyun.com/mirror/npm/package/frac/v/0.3.0 Apache license*/
|
||||||
|
export function frac(x, D, mixed) {
|
||||||
|
var n1 = Math.floor(x), d1 = 1;
|
||||||
|
var n2 = n1 + 1, d2 = 1;
|
||||||
|
if (x !== n1) while (d1 <= D && d2 <= D) {
|
||||||
|
var m = (n1 + n2) / (d1 + d2);
|
||||||
|
if (x === m) {
|
||||||
|
if (d1 + d2 <= D) {
|
||||||
|
d1 += d2;
|
||||||
|
n1 += n2;
|
||||||
|
d2 = D + 1;
|
||||||
|
} else if (d1 > d2) d2 = D + 1;
|
||||||
|
else d1 = D + 1;
|
||||||
|
break;
|
||||||
|
} else if (x < m) {
|
||||||
|
n2 = n1 + n2;
|
||||||
|
d2 = d1 + d2;
|
||||||
|
} else {
|
||||||
|
n1 = n1 + n2;
|
||||||
|
d1 = d1 + d2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (d1 > D) {
|
||||||
|
d1 = d2;
|
||||||
|
n1 = n2;
|
||||||
|
}
|
||||||
|
if (!mixed) return [0, n1, d1];
|
||||||
|
var q = Math.floor(n1 / d1);
|
||||||
|
return [q, n1 - q * d1, d1];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cont(x, D, mixed) {
|
||||||
|
var sgn = x < 0 ? -1 : 1;
|
||||||
|
var B = x * sgn;
|
||||||
|
var P_2 = 0, P_1 = 1, P = 0;
|
||||||
|
var Q_2 = 1, Q_1 = 0, Q = 0;
|
||||||
|
var A = Math.floor(B);
|
||||||
|
while (Q_1 < D) {
|
||||||
|
A = Math.floor(B);
|
||||||
|
P = A * P_1 + P_2;
|
||||||
|
Q = A * Q_1 + Q_2;
|
||||||
|
if ((B - A) < 0.00000005) break;
|
||||||
|
B = 1 / (B - A);
|
||||||
|
P_2 = P_1;
|
||||||
|
P_1 = P;
|
||||||
|
Q_2 = Q_1;
|
||||||
|
Q_1 = Q;
|
||||||
|
}
|
||||||
|
if (Q > D) {
|
||||||
|
if (Q_1 > D) {
|
||||||
|
Q = Q_2;
|
||||||
|
P = P_2;
|
||||||
|
} else {
|
||||||
|
Q = Q_1;
|
||||||
|
P = P_1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!mixed) return [0, sgn * P, Q];
|
||||||
|
var q = Math.floor(sgn * P / Q);
|
||||||
|
return [q, sgn * P - q * Q, Q];
|
||||||
|
}
|
@ -62,3 +62,37 @@ export const ResolveUrlMixin = {
|
|||||||
export function resolveDjangoUrl(url, params) {
|
export function resolveDjangoUrl(url, params) {
|
||||||
return window.Urls[url](params)
|
return window.Urls[url](params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* other utilities
|
||||||
|
* */
|
||||||
|
|
||||||
|
export function getUserPreference(pref) {
|
||||||
|
return window.USER_PREF[pref]
|
||||||
|
}
|
||||||
|
|
||||||
|
import {frac} from "@/utils/fractions";
|
||||||
|
|
||||||
|
export function calculateAmount(amount, factor) {
|
||||||
|
if (getUserPreference('user_fractions')) {
|
||||||
|
let return_string = ''
|
||||||
|
let fraction = frac.cont((amount * factor), 9, true)
|
||||||
|
|
||||||
|
if (fraction[0] > 0) {
|
||||||
|
return_string += fraction[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fraction[1] > 0) {
|
||||||
|
return_string += ` <sup>${(fraction[1])}</sup>⁄<sub>${(fraction[2])}</sub>`
|
||||||
|
}
|
||||||
|
|
||||||
|
return return_string
|
||||||
|
} else {
|
||||||
|
return roundDecimals(amount * factor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function roundDecimals(num) {
|
||||||
|
let decimals = ((getUserPreference('user_fractions')) ? getUserPreference('user_fractions') : 2);
|
||||||
|
return +(Math.round(num + `e+${decimals}`) + `e-${decimals}`);
|
||||||
|
}
|
||||||
|
@ -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.7d030f252e9720efc1eb.hot-update.js","publicPath":"http://localhost:8080/recipe_view.7d030f252e9720efc1eb.hot-update.js","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\recipe_view.7d030f252e9720efc1eb.hot-update.js"}]},"error":"ModuleBuildError","message":"Module build failed (from ./node_modules/eslint-loader/index.js):\nError: ENOENT: no such file or directory, open 'F:\\Developement\\Django\\recipes\\vue\\src\\apps\\RecipeView\\main.js'"}
|
{"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.e165d99965cf62182119.hot-update.js","publicPath":"http://localhost:8080/recipe_view.e165d99965cf62182119.hot-update.js","path":"F:\\Developement\\Django\\recipes\\cookbook\\static\\vue\\recipe_view.e165d99965cf62182119.hot-update.js"}]},"error":"ModuleError","message":"Module Error (from ./node_modules/eslint-loader/index.js):\n\nF:\\Developement\\Django\\recipes\\vue\\src\\components\\Step.vue\n 22:37 error Parsing error: duplicate-attribute vue/no-parsing-error\n 22:37 error Duplicate attribute 'class' vue/no-duplicate-attributes\n\n✖ 2 problems (2 errors, 0 warnings)\n"}
|
Reference in New Issue
Block a user