moved food and keyword to generic cards
This commit is contained in:
parent
aba2e66163
commit
d606ea8db3
@ -1 +1 @@
|
||||
.shake[data-v-153e0375]{-webkit-animation:shake-data-v-153e0375 .82s cubic-bezier(.36,.07,.19,.97) both;animation:shake-data-v-153e0375 .82s cubic-bezier(.36,.07,.19,.97) both;transform:translateZ(0);-webkit-backface-visibility:hidden;backface-visibility:hidden;perspective:1000px}@-webkit-keyframes shake-data-v-153e0375{10%,90%{transform:translate3d(-1px,0,0)}20%,80%{transform:translate3d(2px,0,0)}30%,50%,70%{transform:translate3d(-4px,0,0)}40%,60%{transform:translate3d(4px,0,0)}}@keyframes shake-data-v-153e0375{10%,90%{transform:translate3d(-1px,0,0)}20%,80%{transform:translate3d(2px,0,0)}30%,50%,70%{transform:translate3d(-4px,0,0)}40%,60%{transform:translate3d(4px,0,0)}}
|
||||
.shake[data-v-997172e4]{-webkit-animation:shake-data-v-997172e4 .82s cubic-bezier(.36,.07,.19,.97) both;animation:shake-data-v-997172e4 .82s cubic-bezier(.36,.07,.19,.97) both;transform:translateZ(0);-webkit-backface-visibility:hidden;backface-visibility:hidden;perspective:1000px}@-webkit-keyframes shake-data-v-997172e4{10%,90%{transform:translate3d(-1px,0,0)}20%,80%{transform:translate3d(2px,0,0)}30%,50%,70%{transform:translate3d(-4px,0,0)}40%,60%{transform:translate3d(4px,0,0)}}@keyframes shake-data-v-997172e4{10%,90%{transform:translate3d(-1px,0,0)}20%,80%{transform:translate3d(2px,0,0)}30%,50%,70%{transform:translate3d(-4px,0,0)}40%,60%{transform:translate3d(4px,0,0)}}
|
@ -1 +1 @@
|
||||
.shake[data-v-bb84128a]{-webkit-animation:shake-data-v-bb84128a .82s cubic-bezier(.36,.07,.19,.97) both;animation:shake-data-v-bb84128a .82s cubic-bezier(.36,.07,.19,.97) both;transform:translateZ(0);-webkit-backface-visibility:hidden;backface-visibility:hidden;perspective:1000px}@-webkit-keyframes shake-data-v-bb84128a{10%,90%{transform:translate3d(-1px,0,0)}20%,80%{transform:translate3d(2px,0,0)}30%,50%,70%{transform:translate3d(-4px,0,0)}40%,60%{transform:translate3d(4px,0,0)}}@keyframes shake-data-v-bb84128a{10%,90%{transform:translate3d(-1px,0,0)}20%,80%{transform:translate3d(2px,0,0)}30%,50%,70%{transform:translate3d(-4px,0,0)}40%,60%{transform:translate3d(4px,0,0)}}
|
||||
.shake[data-v-997172e4]{-webkit-animation:shake-data-v-997172e4 .82s cubic-bezier(.36,.07,.19,.97) both;animation:shake-data-v-997172e4 .82s cubic-bezier(.36,.07,.19,.97) both;transform:translateZ(0);-webkit-backface-visibility:hidden;backface-visibility:hidden;perspective:1000px}@-webkit-keyframes shake-data-v-997172e4{10%,90%{transform:translate3d(-1px,0,0)}20%,80%{transform:translate3d(2px,0,0)}30%,50%,70%{transform:translate3d(-4px,0,0)}40%,60%{transform:translate3d(4px,0,0)}}@keyframes shake-data-v-997172e4{10%,90%{transform:translate3d(-1px,0,0)}20%,80%{transform:translate3d(2px,0,0)}30%,50%,70%{transform:translate3d(-4px,0,0)}40%,60%{transform:translate3d(4px,0,0)}}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -12,7 +12,7 @@ from django.contrib.auth.models import User
|
||||
from django.contrib.postgres.search import TrigramSimilarity
|
||||
from django.core.exceptions import FieldError, ValidationError
|
||||
from django.core.files import File
|
||||
from django.db.models import Q
|
||||
from django.db.models import Q, Value
|
||||
from django.db.models.fields.related import ForeignObjectRel
|
||||
from django.http import FileResponse, HttpResponse, JsonResponse
|
||||
from django_scopes import scopes_disabled
|
||||
@ -114,8 +114,9 @@ class FuzzyFilterMixin(ViewSetMixin):
|
||||
)
|
||||
else:
|
||||
# TODO have this check unaccent search settings or other search preferences?
|
||||
# TODO for some querysets exact matches are sorted beyond pagesize, need to find better solution
|
||||
self.queryset = self.queryset.filter(name__istartswith=query) | self.queryset.filter(name__icontains=query)
|
||||
# for some querysets exact matches are sorted beyond pagesize, this ensures exact matches appear first
|
||||
self.queryset = self.queryset.filter(name__istartswith=query).annotate(order=Value(0)) | self.queryset.filter(name__icontains=query).annotate(order=Value(1))
|
||||
self.queryset = self.queryset.order_by('order')
|
||||
|
||||
updated_at = self.request.query_params.get('updated_at', None)
|
||||
if updated_at is not None:
|
||||
|
@ -67,32 +67,46 @@
|
||||
<!-- only show scollbars in split mode, but this doesn't interact well with infinite scroll, maybe a different componenet? -->
|
||||
<div class="row" :class="{'overflow-hidden' : show_split}" style="margin-top: 2vh">
|
||||
<div class="col col-md" :class="{'mh-100 overflow-auto' : show_split}">
|
||||
<food-card
|
||||
v-for="f in foods"
|
||||
v-bind:key="f.id"
|
||||
:food="f"
|
||||
<generic-horizontal-card v-for="f in foods" v-bind:key="f.id"
|
||||
:model=f
|
||||
model_name="Food"
|
||||
:draggable="true"
|
||||
:merge="true"
|
||||
:move="true"
|
||||
@item-action="startAction($event, 'left')"
|
||||
></food-card>
|
||||
>
|
||||
<template v-slot:upper-right>
|
||||
<b-button v-if="f.recipe" v-b-tooltip.hover :title="f.recipe.name"
|
||||
class=" btn fas fa-book-open p-0 border-0" variant="link" :href="f.recipe.url"/>
|
||||
</template>
|
||||
</generic-horizontal-card>
|
||||
<infinite-loading
|
||||
:identifier='left'
|
||||
@infinite="infiniteHandler($event, 'left')"
|
||||
spinner="waveDots">
|
||||
<template v-slot:no-more><span/></template>
|
||||
</infinite-loading>
|
||||
</div>
|
||||
<!-- right side food cards -->
|
||||
<div class="col col-md mh-100 overflow-auto " v-if="show_split">
|
||||
<food-card
|
||||
v-for="f in foods2"
|
||||
v-bind:key="f.id"
|
||||
:food="f"
|
||||
draggable="true"
|
||||
@item-action="startAction($event, 'right')"
|
||||
></food-card>
|
||||
<generic-horizontal-card v-for="f in foods" v-bind:key="f.id"
|
||||
:model=f
|
||||
model_name="Food"
|
||||
:draggable="true"
|
||||
:merge="true"
|
||||
:move="true"
|
||||
@item-action="startAction($event, 'left')"
|
||||
>
|
||||
<template v-slot:upper-right>
|
||||
<b-button v-if="f.recipe" v-b-tooltip.hover :title="f.recipe.name"
|
||||
class=" btn fas fa-book-open p-0 border-0" variant="link" :href="f.recipe.url"/>
|
||||
</template>
|
||||
</generic-horizontal-card>
|
||||
<infinite-loading
|
||||
:identifier='right'
|
||||
@infinite="infiniteHandler($event, 'right')"
|
||||
spinner="waveDots">
|
||||
<template v-slot:no-more><span/></template>
|
||||
</infinite-loading>
|
||||
</div>
|
||||
</div>
|
||||
@ -211,7 +225,8 @@ import _debounce from 'lodash/debounce'
|
||||
import {ToastMixin} from "@/utils/utils";
|
||||
|
||||
import {ApiApiFactory} from "@/utils/openapi/api.ts";
|
||||
import FoodCard from "@/components/FoodCard";
|
||||
// import FoodCard from "@/components/FoodCard";
|
||||
import GenericHorizontalCard from "@/components/GenericHorizontalCard";
|
||||
import GenericMultiselect from "@/components/GenericMultiselect";
|
||||
import InfiniteLoading from 'vue-infinite-loading';
|
||||
|
||||
@ -220,7 +235,7 @@ Vue.use(BootstrapVue)
|
||||
export default {
|
||||
name: 'FoodListView',
|
||||
mixins: [ToastMixin],
|
||||
components: {FoodCard, GenericMultiselect, InfiniteLoading},
|
||||
components: {GenericHorizontalCard, GenericMultiselect, InfiniteLoading},
|
||||
data() {
|
||||
return {
|
||||
foods: [],
|
||||
@ -282,9 +297,8 @@ export default {
|
||||
},
|
||||
// TODO should model actions be included with the context menu? the card? a seperate mixin avaible to all?
|
||||
startAction: function(e, col) {
|
||||
let target = e.target || null
|
||||
let source = e.source || null
|
||||
|
||||
let target = e?.target
|
||||
let source = e?.source
|
||||
if (e.action == 'delete') {
|
||||
this.this_item = source
|
||||
this.$bvModal.show('id_modal_food_delete')
|
||||
@ -309,13 +323,14 @@ export default {
|
||||
this.mergeFood(e.source.id, e.target.id)
|
||||
}
|
||||
} else if (e.action === 'get-children') {
|
||||
if (source.expanded) {
|
||||
Vue.set(source, 'expanded', false)
|
||||
if (source.show_children) {
|
||||
Vue.set(source, 'show_children', false)
|
||||
} else {
|
||||
this.this_item = source
|
||||
this.getChildren(col, source)
|
||||
}
|
||||
} else if (e.action === 'get-recipes') {
|
||||
|
||||
if (source.show_recipes) {
|
||||
Vue.set(source, 'show_recipes', false)
|
||||
} else {
|
||||
@ -421,7 +436,7 @@ export default {
|
||||
}
|
||||
if (parent) {
|
||||
Vue.set(parent, 'children', result.data.results)
|
||||
Vue.set(parent, 'expanded', true)
|
||||
Vue.set(parent, 'show_children', true)
|
||||
Vue.set(parent, 'show_recipes', false)
|
||||
}
|
||||
}).catch((err) => {
|
||||
@ -446,7 +461,7 @@ export default {
|
||||
if (parent) {
|
||||
Vue.set(parent, 'recipes', result.data.results)
|
||||
Vue.set(parent, 'show_recipes', true)
|
||||
Vue.set(parent, 'expanded', false)
|
||||
Vue.set(parent, 'show_children', false)
|
||||
}
|
||||
|
||||
}).catch((err) => {
|
||||
@ -467,13 +482,13 @@ export default {
|
||||
let parent2 = this.findFood(this.foods2, target.parent)
|
||||
|
||||
if (parent) {
|
||||
if (parent.expanded){
|
||||
if (parent.show_children){
|
||||
idx = parent.children.indexOf(parent.children.find(kw => kw.id === target.id))
|
||||
Vue.set(parent.children, idx, result.data)
|
||||
}
|
||||
}
|
||||
if (parent2){
|
||||
if (parent2.expanded){
|
||||
if (parent2.show_children){
|
||||
idx2 = parent2.children.indexOf(parent2.children.find(kw => kw.id === target.id))
|
||||
// deep copy to force columns to be indepedent
|
||||
Vue.set(parent2.children, idx2, JSON.parse(JSON.stringify(result.data)))
|
||||
@ -496,7 +511,7 @@ export default {
|
||||
if (food.length == 1) {
|
||||
return food[0]
|
||||
} else if (food.length == 0) {
|
||||
for (const f of food_list.filter(fd => fd.expanded == true)) {
|
||||
for (const f of food_list.filter(fd => fd.show_children == true)) {
|
||||
food = this.findFood(f.children, id)
|
||||
if (food) {
|
||||
return food
|
||||
@ -557,32 +572,32 @@ export default {
|
||||
$state.complete();
|
||||
})
|
||||
},
|
||||
destroyCard: function(id) {
|
||||
let fd = this.findFood(this.foods, id)
|
||||
let fd2 = this.findFood(this.foods2, id)
|
||||
let p_id = undefined
|
||||
p_id = fd?.parent ?? fd2.parent
|
||||
destroyCard: function(id) {
|
||||
let fd = this.findFood(this.foods, id)
|
||||
let fd2 = this.findFood(this.foods2, id)
|
||||
let p_id = undefined
|
||||
p_id = fd?.parent ?? fd2.parent
|
||||
|
||||
if (p_id) {
|
||||
let parent = this.findFood(this.foods, p_id)
|
||||
let parent2 = this.findFood(this.foods2, p_id)
|
||||
if (parent){
|
||||
Vue.set(parent, 'numchild', parent.numchild - 1)
|
||||
if (parent.expanded) {
|
||||
let idx = parent.children.indexOf(parent.children.find(kw => kw.id === id))
|
||||
Vue.delete(parent.children, idx)
|
||||
}
|
||||
}
|
||||
if (parent2){
|
||||
Vue.set(parent2, 'numchild', parent2.numchild - 1)
|
||||
if (parent2.expanded) {
|
||||
let idx = parent2.children.indexOf(parent2.children.find(kw => kw.id === id))
|
||||
Vue.delete(parent2.children, idx)
|
||||
}
|
||||
if (p_id) {
|
||||
let parent = this.findFood(this.foods, p_id)
|
||||
let parent2 = this.findFood(this.foods2, p_id)
|
||||
if (parent){
|
||||
Vue.set(parent, 'numchild', parent.numchild - 1)
|
||||
if (parent.show_children) {
|
||||
let idx = parent.children.indexOf(parent.children.find(kw => kw.id === id))
|
||||
Vue.delete(parent.children, idx)
|
||||
}
|
||||
}
|
||||
this.foods = this.foods.filter(kw => kw.id != id)
|
||||
this.foods2 = this.foods2.filter(kw => kw.id != id)
|
||||
if (parent2){
|
||||
Vue.set(parent2, 'numchild', parent2.numchild - 1)
|
||||
if (parent2.show_children) {
|
||||
let idx = parent2.children.indexOf(parent2.children.find(kw => kw.id === id))
|
||||
Vue.delete(parent2.children, idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
this.foods = this.foods.filter(kw => kw.id != id)
|
||||
this.foods2 = this.foods2.filter(kw => kw.id != id)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -68,32 +68,36 @@
|
||||
<!-- only show scollbars in split mode, but this doesn't interact well with infinite scroll, maybe a different componenet? -->
|
||||
<div class="row" :class="{'overflow-hidden' : show_split}" style="margin-top: 2vh">
|
||||
<div class="col col-md" :class="{'mh-100 overflow-auto' : show_split}">
|
||||
<keyword-card
|
||||
v-for="k in keywords"
|
||||
v-bind:key="k.id"
|
||||
:keyword="k"
|
||||
<generic-horizontal-card v-for="kw in keywords" v-bind:key="kw.id"
|
||||
:model=kw
|
||||
model_name="Keyword"
|
||||
:draggable="true"
|
||||
:merge="true"
|
||||
:move="true"
|
||||
@item-action="startAction($event, 'left')"
|
||||
></keyword-card>
|
||||
/>
|
||||
<infinite-loading
|
||||
:identifier='left'
|
||||
@infinite="infiniteHandler($event, 'left')"
|
||||
spinner="waveDots">
|
||||
<template v-slot:no-more><span/></template>
|
||||
</infinite-loading>
|
||||
</div>
|
||||
<!-- right side keyword cards -->
|
||||
<div class="col col-md mh-100 overflow-auto " v-if="show_split">
|
||||
<keyword-card
|
||||
v-for="k in keywords2"
|
||||
v-bind:key="k.id"
|
||||
:keyword="k"
|
||||
draggable="true"
|
||||
@item-action="startAction($event, 'right')"
|
||||
></keyword-card>
|
||||
<generic-horizontal-card v-for="kw in keywords2" v-bind:key="kw.id"
|
||||
:model=kw
|
||||
model_name="Keyword"
|
||||
:draggable="true"
|
||||
:merge="true"
|
||||
:move="true"
|
||||
@item-action="startAction($event, 'left')"
|
||||
/>
|
||||
<infinite-loading
|
||||
:identifier='right'
|
||||
@infinite="infiniteHandler($event, 'right')"
|
||||
spinner="waveDots">
|
||||
<template v-slot:no-more><span/></template>
|
||||
</infinite-loading>
|
||||
</div>
|
||||
</div>
|
||||
@ -197,7 +201,7 @@ import _debounce from 'lodash/debounce'
|
||||
import {ToastMixin} from "@/utils/utils";
|
||||
|
||||
import {ApiApiFactory} from "@/utils/openapi/api.ts";
|
||||
import KeywordCard from "@/components/KeywordCard";
|
||||
import GenericHorizontalCard from "@/components/GenericHorizontalCard";
|
||||
import GenericMultiselect from "@/components/GenericMultiselect";
|
||||
import InfiniteLoading from 'vue-infinite-loading';
|
||||
|
||||
@ -213,7 +217,7 @@ Vue.use(BootstrapVue)
|
||||
export default {
|
||||
name: 'KeywordListView',
|
||||
mixins: [ToastMixin],
|
||||
components: {TwemojiTextarea, KeywordCard, GenericMultiselect, InfiniteLoading},
|
||||
components: {TwemojiTextarea, GenericHorizontalCard, GenericMultiselect, InfiniteLoading},
|
||||
computed: {
|
||||
// move with generic modals
|
||||
emojiDataAll() {
|
||||
@ -309,8 +313,8 @@ export default {
|
||||
this.mergeKeyword(e.source.id, e.target.id)
|
||||
}
|
||||
} else if (e.action === 'get-children') {
|
||||
if (source.expanded) {
|
||||
Vue.set(source, 'expanded', false)
|
||||
if (source.show_children) {
|
||||
Vue.set(source, 'show_children', false)
|
||||
} else {
|
||||
this.this_item = source
|
||||
this.getChildren(col, source)
|
||||
@ -425,7 +429,7 @@ export default {
|
||||
}
|
||||
if (parent) {
|
||||
Vue.set(parent, 'children', result.data.results)
|
||||
Vue.set(parent, 'expanded', true)
|
||||
Vue.set(parent, 'show_children', true)
|
||||
Vue.set(parent, 'show_recipes', false)
|
||||
}
|
||||
|
||||
@ -453,7 +457,7 @@ export default {
|
||||
if (parent) {
|
||||
Vue.set(parent, 'recipes', result.data.results)
|
||||
Vue.set(parent, 'show_recipes', true)
|
||||
Vue.set(parent, 'expanded', false)
|
||||
Vue.set(parent, 'show_children', false)
|
||||
}
|
||||
|
||||
}).catch((err) => {
|
||||
@ -474,13 +478,13 @@ export default {
|
||||
let parent2 = this.findKeyword(this.keywords2, target.parent)
|
||||
|
||||
if (parent) {
|
||||
if (parent.expanded){
|
||||
if (parent.show_children){
|
||||
idx = parent.children.indexOf(parent.children.find(kw => kw.id === target.id))
|
||||
Vue.set(parent.children, idx, result.data)
|
||||
}
|
||||
}
|
||||
if (parent2){
|
||||
if (parent2.expanded){
|
||||
if (parent2.show_children){
|
||||
idx2 = parent2.children.indexOf(parent2.children.find(kw => kw.id === target.id))
|
||||
// deep copy to force columns to be indepedent
|
||||
Vue.set(parent2.children, idx2, JSON.parse(JSON.stringify(result.data)))
|
||||
@ -503,7 +507,7 @@ export default {
|
||||
if (keyword.length == 1) {
|
||||
return keyword[0]
|
||||
} else if (keyword.length == 0) {
|
||||
for (const k of kw_list.filter(kw => kw.expanded == true)) {
|
||||
for (const k of kw_list.filter(kw => kw.show_children == true)) {
|
||||
keyword = this.findKeyword(k.children, id)
|
||||
if (keyword) {
|
||||
return keyword
|
||||
@ -575,14 +579,14 @@ export default {
|
||||
let parent2 = this.findKeyword(this.keywords2, p_id)
|
||||
if (parent){
|
||||
Vue.set(parent, 'numchild', parent.numchild - 1)
|
||||
if (parent.expanded) {
|
||||
if (parent.show_children) {
|
||||
let idx = parent.children.indexOf(parent.children.find(kw => kw.id === id))
|
||||
Vue.delete(parent.children, idx)
|
||||
}
|
||||
}
|
||||
if (parent2){
|
||||
Vue.set(parent2, 'numchild', parent2.numchild - 1)
|
||||
if (parent2.expanded) {
|
||||
if (parent2.show_children) {
|
||||
let idx = parent2.children.indexOf(parent2.children.find(kw => kw.id === id))
|
||||
Vue.delete(parent2.children, idx)
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
<template>
|
||||
<div row>
|
||||
<b-card no-body d-flex flex-column :class="{'border border-primary' : over, 'shake': isError}"
|
||||
refs="foodCard"
|
||||
style="height: 10vh;" :style="{'cursor:grab' : draggable}"
|
||||
@dragover.prevent
|
||||
@dragenter.prevent
|
||||
@ -12,55 +11,63 @@
|
||||
@drop="handleDragDrop($event)">
|
||||
<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="food_image" v-bind:alt="$t('Recipe_Image')"></b-card-img-lazy>
|
||||
<b-card-img-lazy style="object-fit: cover; height: 10vh;" :src="model_image" v-bind:alt="text.image_alt"></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">{{ food.name }}</h5>
|
||||
<div class= "m-0 text-truncate">{{ food.description }}</div>
|
||||
<h5 class="m-0 mt-1 text-truncate">{{ model[title] }}</h5>
|
||||
<div class= "m-0 text-truncate">{{ model[subtitle] }}</div>
|
||||
<div class="mt-auto mb-1 d-flex flex-row justify-content-end">
|
||||
<div v-if="food.numchild !=0" class="mx-2 btn btn-link btn-sm"
|
||||
style="z-index: 800;" v-on:click="$emit('item-action',{'action':'get-children','source':food})">
|
||||
<div v-if="!food.expanded">{{food.numchild}} {{$t('Foods')}}</div>
|
||||
<div v-else>{{$t('Hide Foods')}}</div>
|
||||
<div v-if="model[child_count] !=0" class="mx-2 btn btn-link btn-sm"
|
||||
style="z-index: 800;" v-on:click="$emit('item-action',{'action':'get-children','source':model})">
|
||||
<div v-if="!model.show_children">{{ model[child_count] }} {{ model_name }}</div>
|
||||
<div v-else>{{ text.hide_children }}</div>
|
||||
</div>
|
||||
<div class="mx-2 btn btn-link btn-sm" style="z-index: 800;"
|
||||
v-on:click="$emit('item-action',{'action':'get-recipes','source':food})">
|
||||
<div v-if="!food.show_recipes">{{food.numrecipe}} {{$t('Recipes')}}</div>
|
||||
<div v-else>{{$t('Hide Recipes')}}</div>
|
||||
<div v-if="model[recipe_count]" class="mx-2 btn btn-link btn-sm" style="z-index: 800;"
|
||||
v-on:click="$emit('item-action',{'action':'get-recipes','source':model})">
|
||||
<div v-if="!model.show_recipes">{{ model[recipe_count] }} {{$t('Recipes')}}</div>
|
||||
<div v-else>{{$t('Hide_Recipes')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</b-card-text>
|
||||
</b-card-body>
|
||||
</b-col>
|
||||
<div class="card-img-overlay justify-content-right h-25 m-0 p-0 text-right">
|
||||
<b-button v-if="food.recipe" v-b-tooltip.hover :title="food.recipe.name"
|
||||
class=" btn fas fa-book-open p-0 border-0" variant="link" :href="food.recipe.url"/>
|
||||
<slot name="upper-right"></slot>
|
||||
|
||||
<generic-context-menu class="p-0"
|
||||
:show_merge="true"
|
||||
:show_move="true"
|
||||
@item-action="$emit('item-action', {'action': $event, 'source': food})">
|
||||
:show_merge="merge"
|
||||
:show_move="move"
|
||||
@item-action="$emit('item-action', {'action': $event, 'source': model})">
|
||||
</generic-context-menu>
|
||||
</div>
|
||||
</b-row>
|
||||
</b-card>
|
||||
<!-- recursively add child foods -->
|
||||
<div class="row" v-if="food.expanded">
|
||||
<!-- recursively add child cards -->
|
||||
<div class="row" v-if="model.show_children">
|
||||
<div class="col-md-11 offset-md-1">
|
||||
<food-card v-for="child in food.children"
|
||||
:food="child"
|
||||
v-bind:key="child.id"
|
||||
draggable="true"
|
||||
<generic-horizontal-card v-for="child in model[children]" v-bind:key="child.id"
|
||||
:draggable="draggable"
|
||||
:model="child"
|
||||
:model_name="model_name"
|
||||
:title="title"
|
||||
:subtitle="subtitle"
|
||||
:child_count="child_count"
|
||||
:children="children"
|
||||
:recipe_count="recipe_count"
|
||||
:recipes="recipes"
|
||||
:merge="merge"
|
||||
:move="move"
|
||||
@item-action="$emit('item-action', $event)">
|
||||
</food-card>
|
||||
</generic-horizontal-card>
|
||||
</div>
|
||||
</div>
|
||||
<!-- conditionally view recipes -->
|
||||
<div class="row" v-if="food.show_recipes">
|
||||
<div class="row" v-if="model.show_recipes">
|
||||
<div class="col-md-11 offset-md-1">
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));grid-gap: 1rem;">
|
||||
<recipe-card v-for="r in food.recipes"
|
||||
<recipe-card v-for="r in model[recipes]"
|
||||
v-bind:key="r.id"
|
||||
:recipe="r">
|
||||
</recipe-card>
|
||||
@ -69,11 +76,11 @@
|
||||
</div>
|
||||
<!-- this should be made a generic component, would also require mixin for functions that generate the popup and put in parent container-->
|
||||
<b-list-group ref="tooltip" variant="light" v-show="show_menu" v-on-clickaway="closeMenu" style="z-index:999; cursor:pointer">
|
||||
<b-list-group-item action v-on:click="$emit('item-action',{'action': 'move', 'target': food, 'source': source}); closeMenu()">
|
||||
{{$t('Move')}}: {{$t('move_confirmation', {'child': source.name,'parent':food.name})}}
|
||||
<b-list-group-item v-if="move" action v-on:click="$emit('item-action',{'action': 'move', 'target': model, 'source': source}); closeMenu()">
|
||||
{{$t('Move')}}: {{$t('move_confirmation', {'child': source.name,'parent':model.name})}}
|
||||
</b-list-group-item>
|
||||
<b-list-group-item action v-on:click="$emit('item-action',{'action': 'merge', 'target': food, 'source': source}); closeMenu()">
|
||||
{{$t('Merge')}}: {{ $t('merge_confirmation', {'source': source.name,'target':food.name}) }}
|
||||
<b-list-group-item v-if="merge" action v-on:click="$emit('item-action',{'action': 'merge', 'target': model, 'source': source}); closeMenu()">
|
||||
{{$t('Merge')}}: {{ $t('merge_confirmation', {'source': source.name,'target':model.name}) }}
|
||||
</b-list-group-item>
|
||||
<b-list-group-item action v-on:click="closeMenu()">
|
||||
{{$t('Cancel')}}
|
||||
@ -91,36 +98,50 @@ import { mixin as clickaway } from 'vue-clickaway';
|
||||
import { createPopper } from '@popperjs/core';
|
||||
|
||||
export default {
|
||||
name: "FoodCard",
|
||||
name: "GenericHorizontalCard",
|
||||
components: { GenericContextMenu, RecipeCard },
|
||||
mixins: [clickaway],
|
||||
props: {
|
||||
food: Object,
|
||||
draggable: {type: Boolean, default: false}
|
||||
model: Object,
|
||||
model_name: {type: String, default: 'Blank Model'}, // TODO update translations to handle plural translations
|
||||
draggable: {type: Boolean, default: false},
|
||||
title: {type: String, default: 'name'},
|
||||
subtitle: {type: String, default: 'description'},
|
||||
child_count: {type: String, default: 'numchild'},
|
||||
children: {type: String, default: 'children'},
|
||||
recipe_count: {type: String, default: 'numrecipe'},
|
||||
recipes: {type: String, default: 'recipes'},
|
||||
merge: {type: Boolean, default: false},
|
||||
move: {type: Boolean, default: false},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
food_image: '',
|
||||
model_image: '',
|
||||
over: false,
|
||||
show_menu: false,
|
||||
dragMenu: undefined,
|
||||
isError: false,
|
||||
source: {},
|
||||
target: {}
|
||||
source: {'id': undefined, 'name': undefined},
|
||||
target: {'id': undefined, 'name': undefined},
|
||||
text: {
|
||||
'image_alt': '',
|
||||
'hide_children': '',
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.food == null || this.food.image == null) {
|
||||
this.food_image = window.IMAGE_PLACEHOLDER
|
||||
} else {
|
||||
this.food_image = this.food.image
|
||||
}
|
||||
this.model_image = this.model?.image ?? window.IMAGE_PLACEHOLDER
|
||||
this.dragMenu = this.$refs.tooltip
|
||||
this.text.image_alt = this.$t(this.model_name + '_Image'),
|
||||
this.hide_children = this.$t('Hide_' + this.model_name)
|
||||
},
|
||||
methods: {
|
||||
emitAction: function(m) {
|
||||
|
||||
},
|
||||
handleDragStart: function(e) {
|
||||
this.isError = false
|
||||
e.dataTransfer.setData('source', JSON.stringify(this.food))
|
||||
e.dataTransfer.setData('source', JSON.stringify(this.model))
|
||||
},
|
||||
handleDragEnter: function(e) {
|
||||
if (!e.currentTarget.contains(e.relatedTarget) && e.relatedTarget != null) {
|
||||
@ -134,7 +155,7 @@ export default {
|
||||
},
|
||||
handleDragDrop: function(e) {
|
||||
let source = JSON.parse(e.dataTransfer.getData('source'))
|
||||
if (source.id != this.food.id){
|
||||
if (source.id != this.model.id){
|
||||
this.source = source
|
||||
let menuLocation = {getBoundingClientRect: this.generateLocation(e.clientX, e.clientY),}
|
||||
this.show_menu = true
|
||||
@ -161,7 +182,7 @@ export default {
|
||||
})
|
||||
popper.update()
|
||||
this.over = false
|
||||
this.$emit({'action': 'drop', 'target': this.food, 'source': this.source})
|
||||
this.$emit({'action': 'drop', 'target': this.model, 'source': this.source})
|
||||
} else {
|
||||
this.isError = true
|
||||
}
|
@ -66,7 +66,7 @@ export default {
|
||||
let page = 1
|
||||
let root = undefined
|
||||
let tree = undefined
|
||||
let pageSize = 10
|
||||
let pageSize = 25
|
||||
|
||||
if (query === '') {
|
||||
query = undefined
|
||||
|
@ -107,5 +107,6 @@
|
||||
"Shopping_Category": "Shopping Category",
|
||||
"Edit_Food": "Edit Food",
|
||||
"Move_Food": "Move Food",
|
||||
"New_Food": "New Food"
|
||||
"New_Food": "New Food",
|
||||
"Hide_Foods": "Hide Food"
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
// TODO make this conditional on .env DEBUG = TRUE
|
||||
config.optimization.minimize(false)
|
||||
// config.optimization.minimize(false)
|
||||
);
|
||||
|
||||
//TODO somehow remov them as they are also added to the manifest config of the service worker
|
||||
|
Loading…
Reference in New Issue
Block a user