started reworking books
This commit is contained in:
61
cookbook/static/assets/book.svg
Normal file
61
cookbook/static/assets/book.svg
Normal file
@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="200mm"
|
||||
height="155mm"
|
||||
viewBox="0 0 200 155"
|
||||
version="1.1"
|
||||
id="SVGRoot"
|
||||
sodipodi:docname="book.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<defs
|
||||
id="defs2608" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.35"
|
||||
inkscape:cx="-592.84177"
|
||||
inkscape:cy="516.62789"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:document-rotation="0"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata2611">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="m 178.43105,2.5084522 h -0.0553 c -8.32303,0.04154 -50.03147,-4.552088 -75.88885,9.0177618 -1.39985,0.732762 -3.570481,0.732762 -4.970321,0 C 71.655739,-2.0436358 29.947282,2.5499292 21.627712,2.5084522 h -0.0553 c -11.6446421,0 -21.11519213,9.1491068 -21.11519213,20.3962508 V 125.45629 c 0,10.85658 8.78272603,19.7983 19.99531613,20.35823 12.017921,0.60833 42.178527,-1.29269 62.868573,6.34943 1.82153,0.674 3.67762,1.04383 5.61666,1.04383 h 22.121021 c 1.9425,0 3.79859,-0.37329 5.62012,-1.04383 20.6935,-7.64212 50.85065,-5.7411 62.87894,-6.34943 11.20221,-0.55993 19.98493,-9.4982 19.98493,-20.35477 V 22.904703 C 199.54678,11.657559 190.0757,2.5084522 178.43105,2.5084522 Z"
|
||||
id="path835"
|
||||
style="fill:none;fill-opacity:1;stroke:#ddbf86;stroke-width:0.91445;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
sodipodi:nodetypes="sccccsssccssccscs" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.5 KiB |
@ -1,81 +1,34 @@
|
||||
{% extends "base.html" %}
|
||||
{% load custom_tags %}
|
||||
{% load render_bundle from webpack_loader %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load l10n %}
|
||||
|
||||
{% block title %}{% trans 'Recipe Books' %}{% endblock %}
|
||||
|
||||
{% block content_fluid %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col col-md-9">
|
||||
<h2>{% trans 'Recipe Books' %}</h2>
|
||||
<div id="app" >
|
||||
<cookbook-view></cookbook-view>
|
||||
</div>
|
||||
<div class="col col-md-3" style="text-align: right">
|
||||
<a href="{% url 'new_recipe_book' %}" class="btn btn-success"><i
|
||||
class="fas fa-plus-circle"></i> {% trans 'New Book' %}</a>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<br/>
|
||||
{% for b in book_list %}
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card" style="margin-top: 2px">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{% if b.book.icon %}{{ b.book.icon }} {% endif %}{{ b.book.name }}</h5>
|
||||
<h6 class="card-subtitle mb-2 text-muted">{% if b.book.created_by != request.user %}
|
||||
{% trans 'by' %} {{ b.book.created_by.get_user_name }}
|
||||
{% endif %}</h6>
|
||||
|
||||
{% if b.book.description %}
|
||||
<p class="card-text">{{ b.book.description }}</p>
|
||||
{% endif %}
|
||||
<a data-toggle="collapse" href="#collapse_{{ b.book.pk }}" role="button" aria-expanded="false"
|
||||
aria-controls="collapse_{{ b.book.pk }}" class="card-link">{% trans 'Toggle Recipes' %}</a>
|
||||
{% if b.book.created_by == request.user or request.user.is_superuser %}
|
||||
<a href="{% url 'edit_recipe_book' b.book.pk %}" class="card-link">{% trans 'Edit' %}</a>
|
||||
<a href="{% url 'delete_recipe_book' b.book.pk %}"
|
||||
class="card-link">{% trans 'Delete' %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="collapse" id="collapse_{{ b.book.pk }}">
|
||||
{% if b.recipes %}
|
||||
<ul class="list-group list-group-flush">
|
||||
{% for r in b.recipes %}
|
||||
<li class="list-group-item">
|
||||
<div class="row">
|
||||
<div class="col-10">
|
||||
{% recipe_last r.recipe request.user as last_cooked %}
|
||||
<a href="{% url 'view_recipe' r.recipe.pk %}">{{ r.recipe.name }}</a>
|
||||
{% recipe_rating r.recipe request.user as rating %}
|
||||
{{ rating|safe }}
|
||||
{% if last_cooked %}
|
||||
|
||||
<span class="badge badge-primary">{% trans 'Last cooked' %} {{ last_cooked|date }}</span>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% if b.book.created_by == request.user or request.user.is_superuser %}
|
||||
<div class="col-2" style="text-align: right">
|
||||
<a href="{% url 'delete_recipe_book_entry' r.pk %}"
|
||||
class="pull-right"><i class="fas fa-trash-alt"></i></a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<div class="card-body">
|
||||
<p>
|
||||
{% trans 'There are no recipes in this book yet.' %}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block script %}
|
||||
{% if debug %}
|
||||
<script src="{% url 'js_reverse' %}"></script>
|
||||
{% else %}
|
||||
<script src="{% static 'django_js_reverse/reverse.js' %}"></script>
|
||||
{% endif %}
|
||||
|
||||
<script type="application/javascript">
|
||||
window.IMAGE_PLACEHOLDER = "{% static 'assets/recipe_no_image.svg' %}"
|
||||
window.IMAGE_BOOK = "{% static 'assets/book.svg' %}"
|
||||
|
||||
window.CUSTOM_LOCALE = '{{ request.LANGUAGE_CODE }}'
|
||||
</script>
|
||||
|
||||
{% render_bundle 'cookbook_view' %}
|
||||
{% endblock %}
|
@ -213,20 +213,7 @@ def recipe_view(request, pk, share=None):
|
||||
|
||||
@group_required('user')
|
||||
def books(request):
|
||||
book_list = []
|
||||
|
||||
recipe_books = RecipeBook.objects.filter(Q(created_by=request.user) | Q(shared=request.user),
|
||||
space=request.space).distinct().all()
|
||||
|
||||
for b in recipe_books:
|
||||
book_list.append(
|
||||
{
|
||||
'book': b,
|
||||
'recipes': RecipeBookEntry.objects.filter(book=b).all()
|
||||
}
|
||||
)
|
||||
|
||||
return render(request, 'books.html', {'book_list': book_list})
|
||||
return render(request, 'books.html', {})
|
||||
|
||||
|
||||
@group_required('user')
|
||||
|
91
vue/src/apps/CookbookView/CookbookView.vue
Normal file
91
vue/src/apps/CookbookView/CookbookView.vue
Normal file
@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<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="row mb-3">
|
||||
<b-card class="d-flex flex-column" v-hover
|
||||
v-on:click="openBook(book.id)">
|
||||
<b-row no-gutters style="height:inherit;">
|
||||
<b-col no-gutters md="3" style="height:inherit;">
|
||||
<b-card-img-lazy style="object-fit: cover; height: 10vh;" :src="item_image"
|
||||
v-bind:alt="$t('Recipe_Image')"></b-card-img-lazy>
|
||||
</b-col>
|
||||
<b-col no-gutters md="9" 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">
|
||||
<h5 class="m-0 mt-1 text-truncate">{{ book.name }}</h5>
|
||||
<div class="m-0 text-truncate">{{ book.description }}</div>
|
||||
<div class="mt-auto mb-1 d-flex flex-row justify-content-end">
|
||||
</div>
|
||||
</b-card-text>
|
||||
</b-card-body>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-card>
|
||||
</div>
|
||||
|
||||
<cookbook-slider :recipes="recipes"></cookbook-slider>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import {BootstrapVue} from 'bootstrap-vue'
|
||||
|
||||
import 'bootstrap-vue/dist/bootstrap-vue.css'
|
||||
import {ApiApiFactory} from "../../utils/openapi/api";
|
||||
import CookbookSlider from "../../components/CookbookSlider";
|
||||
|
||||
Vue.use(BootstrapVue)
|
||||
|
||||
export default {
|
||||
name: 'CookbookView',
|
||||
mixins: [],
|
||||
components: {CookbookSlider},
|
||||
data() {
|
||||
return {
|
||||
cookbooks: [],
|
||||
book_background: window.IMAGE_BOOK,
|
||||
recipes: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.refreshData()
|
||||
this.$i18n.locale = window.CUSTOM_LOCALE
|
||||
},
|
||||
methods: {
|
||||
refreshData: function () {
|
||||
let apiClient = new ApiApiFactory()
|
||||
|
||||
apiClient.listRecipeBooks().then(result => {
|
||||
this.cookbooks = result.data
|
||||
})
|
||||
},
|
||||
openBook: function (book) {
|
||||
let apiClient = new ApiApiFactory()
|
||||
|
||||
apiClient.listRecipeBookEntrys({options: {book: book.id}}).then(result => {
|
||||
this.recipes = result.data
|
||||
})
|
||||
}
|
||||
},
|
||||
directives: {
|
||||
hover: {
|
||||
inserted: function (el) {
|
||||
el.addEventListener('mouseenter', () => {
|
||||
el.classList.add("shadow")
|
||||
});
|
||||
el.addEventListener('mouseleave', () => {
|
||||
el.classList.remove("shadow")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
|
||||
</style>
|
10
vue/src/apps/CookbookView/main.js
Normal file
10
vue/src/apps/CookbookView/main.js
Normal file
@ -0,0 +1,10 @@
|
||||
import Vue from 'vue'
|
||||
import App from './CookbookView.vue'
|
||||
import i18n from '@/i18n'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
i18n,
|
||||
render: h => h(App),
|
||||
}).$mount('#app')
|
54
vue/src/components/CookbookSlider.vue
Normal file
54
vue/src/components/CookbookSlider.vue
Normal file
@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div v-bind:style="{ backgroundImage: 'url(' + book_background + ')' }"
|
||||
style="background-repeat: no-repeat; background-size: cover; padding-top: 76%;position: relative;"
|
||||
class="pb-2 w-100">
|
||||
<div id="book_carousel" class="carousel slide row" data-ride="carousel"
|
||||
style=" position: absolute;top: 0;left: 0;bottom: 0;right: 0;">
|
||||
<div class="row m-0 w-100">
|
||||
<div class="carousel-item m-0 w-100" v-for="(i, index) in Math.ceil(recipes.length / 2)" v-bind:key="index"
|
||||
:class="{ 'active': index === 0 }">
|
||||
<div class="row m-0 w-100">
|
||||
<div class="col-6 pt-5" v-for="recipe in recipes.slice((i - 1) * 2, i * 2)" v-bind:key="recipe.id">
|
||||
<recipe-card :recipe="recipe.recipe_content" class="mt-5 ml-5 mr-5"></recipe-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-0 pl-4 pr-4 w-100">
|
||||
<div class="col-6 pull-left">
|
||||
<a class="btn btn-primary mb-3 mr-1" href="#book_carousel" role="button" data-slide="prev">
|
||||
<i class="fa fa-arrow-left"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-6 text-right">
|
||||
<a class="btn btn-primary mb-3 " href="#book_carousel" role="button" data-slide="next">
|
||||
<i class="fa fa-arrow-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import RecipeCard from "./RecipeCard";
|
||||
|
||||
export default {
|
||||
name: "CookbookSlider.vue",
|
||||
components: {RecipeCard},
|
||||
props: {
|
||||
recipes: Array
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
cookbooks: [],
|
||||
book_background: window.IMAGE_BOOK
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -29,6 +29,10 @@ const pages = {
|
||||
entry: './src/apps/ModelListView/main.js',
|
||||
chunks: ['chunk-vendors']
|
||||
},
|
||||
'cookbook_view': {
|
||||
entry: './src/apps/CookbookView/main.js',
|
||||
chunks: ['chunk-vendors']
|
||||
},
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user