This commit is contained in:
smilerz 2021-11-29 13:13:01 -06:00
parent cae3773d5a
commit 0693d31550
7 changed files with 292 additions and 201 deletions

View File

@ -79,8 +79,7 @@ def is_object_shared(user, obj):
# share checks for relevant objects # share checks for relevant objects
if not user.is_authenticated: if not user.is_authenticated:
return False return False
else: return user in obj.get_shared()
return user in obj.get_shared()
def share_link_valid(recipe, share): def share_link_valid(recipe, share):

View File

@ -62,7 +62,7 @@ class ExtendedRecipeMixin(serializers.ModelSerializer):
# probably not a tree # probably not a tree
pass pass
if recipes.count() != 0: if recipes.count() != 0:
return recipes.order_by('?')[:1][0].image.url return random.choice(recipes).image.url
else: else:
return None return None
@ -96,7 +96,7 @@ class CustomDecimalField(serializers.Field):
class SpaceFilterSerializer(serializers.ListSerializer): class SpaceFilterSerializer(serializers.ListSerializer):
def to_representation(self, data): def to_representation(self, data):
if (type(data) == QuerySet and data.query.is_sliced): if (type(data) == QuerySet and data.query.is_sliced) or not self.context.get('request', None):
# if query is sliced it came from api request not nested serializer # if query is sliced it came from api request not nested serializer
return super().to_representation(data) return super().to_representation(data)
if self.child.Meta.model == User: if self.child.Meta.model == User:

View File

@ -675,7 +675,6 @@ class RecipeViewSet(viewsets.ModelViewSet):
return Response(self.serializer_class(qs, many=True).data) return Response(self.serializer_class(qs, many=True).data)
# TODO deprecate
class ShoppingListRecipeViewSet(viewsets.ModelViewSet): class ShoppingListRecipeViewSet(viewsets.ModelViewSet):
queryset = ShoppingListRecipe.objects queryset = ShoppingListRecipe.objects
serializer_class = ShoppingListRecipeSerializer serializer_class = ShoppingListRecipeSerializer

View File

@ -84,12 +84,7 @@
<h5> <h5>
{{ meal_type.icon }} {{ meal_type.name {{ meal_type.icon }} {{ meal_type.name
}}<span class="float-right text-primary" }}<span class="float-right text-primary"
><i ><i class="fa" v-bind:class="{ 'fa-pen': !meal_type.editing, 'fa-save': meal_type.editing }" @click="editOrSaveMealType(index)" aria-hidden="true"></i
class="fa"
v-bind:class="{ 'fa-pen': !meal_type.editing, 'fa-save': meal_type.editing }"
@click="editOrSaveMealType(index)"
aria-hidden="true"
></i
></span> ></span>
</h5> </h5>
</div> </div>
@ -132,7 +127,7 @@
openEntryEdit(contextData.originalItem.entry) openEntryEdit(contextData.originalItem.entry)
" "
> >
<a class="dropdown-item p-2" href="#"><i class="fas fa-pen"></i> {{ $t("Edit") }}</a> <a class="dropdown-item p-2" href="javascript:void(0)"><i class="fas fa-pen"></i> {{ $t("Edit") }}</a>
</ContextMenuItem> </ContextMenuItem>
<ContextMenuItem <ContextMenuItem
@click=" @click="
@ -140,7 +135,7 @@
moveEntryLeft(contextData) moveEntryLeft(contextData)
" "
> >
<a class="dropdown-item p-2" href="#"><i class="fas fa-arrow-left"></i> {{ $t("Move") }}</a> <a class="dropdown-item p-2" href="javascript:void(0)"><i class="fas fa-arrow-left"></i> {{ $t("Move") }}</a>
</ContextMenuItem> </ContextMenuItem>
<ContextMenuItem <ContextMenuItem
@click=" @click="
@ -148,7 +143,7 @@
moveEntryRight(contextData) moveEntryRight(contextData)
" "
> >
<a class="dropdown-item p-2" href="#"><i class="fas fa-arrow-right"></i> {{ $t("Move") }}</a> <a class="dropdown-item p-2" href="javascript:void(0)"><i class="fas fa-arrow-right"></i> {{ $t("Move") }}</a>
</ContextMenuItem> </ContextMenuItem>
<ContextMenuItem <ContextMenuItem
@click=" @click="
@ -156,7 +151,7 @@
createEntry(contextData.originalItem.entry) createEntry(contextData.originalItem.entry)
" "
> >
<a class="dropdown-item p-2" href="#"><i class="fas fa-copy"></i> {{ $t("Clone") }}</a> <a class="dropdown-item p-2" href="javascript:void(0)"><i class="fas fa-copy"></i> {{ $t("Clone") }}</a>
</ContextMenuItem> </ContextMenuItem>
<ContextMenuItem <ContextMenuItem
@click=" @click="
@ -164,7 +159,7 @@
addToShopping(contextData) addToShopping(contextData)
" "
> >
<a class="dropdown-item p-2" href="#"><i class="fas fa-shopping-cart"></i> {{ $t("Add_to_Shopping") }}</a> <a class="dropdown-item p-2" href="javascript:void(0)"><i class="fas fa-shopping-cart"></i> {{ $t("Add_to_Shopping") }}</a>
</ContextMenuItem> </ContextMenuItem>
<ContextMenuItem <ContextMenuItem
@click=" @click="
@ -172,7 +167,7 @@
deleteEntry(contextData) deleteEntry(contextData)
" "
> >
<a class="dropdown-item p-2 text-danger" href="#"><i class="fas fa-trash"></i> {{ $t("Delete") }}</a> <a class="dropdown-item p-2 text-danger" href="javascript:void(0)"><i class="fas fa-trash"></i> {{ $t("Delete") }}</a>
</ContextMenuItem> </ContextMenuItem>
</template> </template>
</ContextMenu> </ContextMenu>
@ -210,61 +205,7 @@
</b-button-group> </b-button-group>
</div> </div>
</div> </div>
<b-form-checkbox </b-sidebar>
id="checkbox-1"
v-model="meal_type.default"
name="default_checkbox"
class="mb-2">
{{ $t('Default') }}
</b-form-checkbox>
<button class="btn btn-danger" @click="deleteMealType(index)">{{ $t('Delete') }}</button>
<button class="btn btn-primary float-right" @click="editOrSaveMealType(index)">{{
$t('Save')
}}
</button>
</b-card-body>
</b-card>
</draggable>
<button class="btn btn-success float-right mt-1" @click="newMealType"><i class="fas fa-plus"></i>
{{ $t('New_Meal_Type') }}
</button>
</div>
</div>
</div>
</b-tab>
</b-tabs>
<ContextMenu ref="menu">
<template #menu="{ contextData }">
<ContextMenuItem @click="$refs.menu.close();openEntryEdit(contextData.originalItem.entry)">
<a class="dropdown-item p-2" href="javascript:void(0)"><i class="fas fa-pen"></i> {{ $t("Edit") }}</a>
</ContextMenuItem>
<ContextMenuItem @click="$refs.menu.close();moveEntryLeft(contextData)">
<a class="dropdown-item p-2" href="javascript:void(0)"><i class="fas fa-arrow-left"></i> {{ $t("Move") }}</a>
</ContextMenuItem>
<ContextMenuItem @click="$refs.menu.close();moveEntryRight(contextData)">
<a class="dropdown-item p-2" href="javascript:void(0)"><i class="fas fa-arrow-right"></i> {{ $t("Move") }}</a>
</ContextMenuItem>
<ContextMenuItem @click="$refs.menu.close();createEntry(contextData.originalItem.entry)">
<a class="dropdown-item p-2" href="javascript:void(0)"><i class="fas fa-copy"></i> {{ $t("Clone") }}</a>
</ContextMenuItem>
<ContextMenuItem @click="$refs.menu.close();addToShopping(contextData)">
<a class="dropdown-item p-2" href="javascript:void(0)"><i class="fas fa-shopping-cart"></i> {{ $t("Add_to_Shopping") }}</a>
</ContextMenuItem>
<ContextMenuItem @click="$refs.menu.close();deleteEntry(contextData)">
<a class="dropdown-item p-2 text-danger" href="javascript:void(0)"><i class="fas fa-trash"></i> {{ $t("Delete") }}</a>
</ContextMenuItem>
</template>
</ContextMenu>
<meal-plan-edit-modal :entry="entryEditing" :entryEditing_initial_recipe="entryEditing_initial_recipe"
:entry-editing_initial_meal_type="entryEditing_initial_meal_type" :modal_title="modal_title"
:edit_modal_show="edit_modal_show" @save-entry="editEntry"
@delete-entry="deleteEntry" @reload-meal-types="refreshMealTypes"></meal-plan-edit-modal>
<template>
<div>
<b-sidebar id="sidebar-shopping" :title="$t('Shopping_list')" backdrop right shadow="sm">
<div class="row p-1 no-gutters">
<div class="col-12 mt-1" v-if="shopping_list.length === 0">
<p class="p-3">{{ $t("Shopping_List_Empty") }}</p>
</div> </div>
</template> </template>
<transition name="slide-fade"> <transition name="slide-fade">
@ -315,7 +256,7 @@ import "bootstrap-vue/dist/bootstrap-vue.css"
import ContextMenu from "@/components/ContextMenu/ContextMenu" import ContextMenu from "@/components/ContextMenu/ContextMenu"
import ContextMenuItem from "@/components/ContextMenu/ContextMenuItem" import ContextMenuItem from "@/components/ContextMenu/ContextMenuItem"
import MealPlanCard from "@/components/MealPlanCard" import MealPlanCard from "@/components/MealPlanCard"
import MealPlanEditModal from "@/components/Modals/MealPlanEditModal" import MealPlanEditModal from "@/components/MealPlanEditModal"
import MealPlanCalenderHeader from "@/components/MealPlanCalenderHeader" import MealPlanCalenderHeader from "@/components/MealPlanCalenderHeader"
import EmojiInput from "@/components/Modals/EmojiInput" import EmojiInput from "@/components/Modals/EmojiInput"
@ -458,124 +399,280 @@ export default {
this.settings = Object.assign({}, this.settings, this.$cookies.get(SETTINGS_COOKIE_NAME)) this.settings = Object.assign({}, this.settings, this.$cookies.get(SETTINGS_COOKIE_NAME))
} }
}) })
} else { this.$root.$on("change", this.updateEmoji)
this.createEntry(edit_entry) this.$i18n.locale = window.CUSTOM_LOCALE
}
}, },
setShowDate(d) { watch: {
this.showDate = d; settings: {
handler() {
this.$cookies.set(SETTINGS_COOKIE_NAME, this.settings, "360d")
},
deep: true,
},
}, },
createEntryClick(data) { methods: {
this.entryEditing = this.options.entryEditing addToShopping(entry) {
this.entryEditing.date = moment(data).format('YYYY-MM-DD') if (entry.originalItem.entry.recipe !== null) {
this.$bvModal.show(`edit-modal`) this.shopping_list.push(entry.originalItem.entry)
}, makeToast(this.$t("Success"), this.$t("Added_To_Shopping_List"), "success")
findEntry(id) { } else {
return this.plan_entries.filter(entry => { makeToast(this.$t("Failure"), this.$t("Cannot_Add_Notes_To_Shopping"), "danger")
return entry.id === id }
})[0] },
}, saveShoppingList() {
moveEntry(null_object, target_date, drag_event) { let url = window.SHOPPING_URL
this.plan_entries.forEach((entry) => { let first = true
if (entry.id === this.dragged_item.id) { for (let se of this.shopping_list) {
if (drag_event.ctrlKey) { if (first) {
let new_entry = Object.assign({}, entry) url += `?r=[${se.recipe.id},${se.servings}]`
new_entry.date = target_date first = false
this.createEntry(new_entry) } else {
} else { url += `&r=[${se.recipe.id},${se.servings}]`
entry.date = target_date }
this.saveEntry(entry) }
} window.open(url)
} },
}) setStartingDay(days) {
}, if (this.settings.startingDayOfWeek + days < 0) {
moveEntryLeft(data) { this.settings.startingDayOfWeek = 6
this.plan_entries.forEach((entry) => { } else if (this.settings.startingDayOfWeek + days > 6) {
if (entry.id === data.id) { this.settings.startingDayOfWeek = 0
entry.date = moment(entry.date).subtract(1, 'd') } else {
this.saveEntry(entry) this.settings.startingDayOfWeek = this.settings.startingDayOfWeek + days
} }
}) },
}, newMealType() {
moveEntryRight(data) { let apiClient = new ApiApiFactory()
this.plan_entries.forEach((entry) => {
if (entry.id === data.id) {
entry.date = moment(entry.date).add(1, 'd')
this.saveEntry(entry)
}
})
},
deleteEntry(data) {
this.plan_entries.forEach((entry, index, list) => {
if (entry.id === data.id) {
let apiClient = new ApiApiFactory()
apiClient.destroyMealPlan(entry.id).then(e => { apiClient
list.splice(index, 1) .createMealType({ name: this.$t("Meal_Type") })
}).catch(error => { .then((e) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) this.periodChangedCallback(this.current_period)
}) })
} .catch((error) => {
}) StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE)
}, })
entryClick(data) {
let entry = this.findEntry(data.id)
this.openEntryEdit(entry)
},
openContextMenu($event, value) {
this.$refs.menu.open($event, value)
},
openEntryEdit(entry) {
this.$bvModal.show(`edit-modal`)
this.entryEditing = entry
this.entryEditing.date = moment(entry.date).format('YYYY-MM-DD')
if (this.entryEditing.recipe != null) {
this.entryEditing.title_placeholder = this.entryEditing.recipe.name
}
},
periodChangedCallback(date) {
this.current_period = date
let apiClient = new ApiApiFactory()
apiClient.listMealPlans({ this.refreshMealTypes()
query: { },
from_date: moment(date.periodStart).format('YYYY-MM-DD'), sortMealTypes() {
to_date: moment(date.periodEnd).format('YYYY-MM-DD') this.meal_types.forEach(function (element, index) {
} element.order = index
}).then(result => { })
this.plan_entries = result.data let updated = 0
}) this.meal_types.forEach((meal_type) => {
this.refreshMealTypes() let apiClient = new ApiApiFactory()
apiClient
.updateMealType(meal_type.id, meal_type)
.then((e) => {
if (updated === this.meal_types.length - 1) {
this.periodChangedCallback(this.current_period)
} else {
updated++
}
})
.catch((error) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE)
})
})
},
editOrSaveMealType(index) {
let meal_type = this.meal_types[index]
if (meal_type.editing) {
this.$set(this.meal_types[index], "editing", false)
let apiClient = new ApiApiFactory()
apiClient
.updateMealType(this.meal_types[index].id, this.meal_types[index])
.then((e) => {
this.periodChangedCallback(this.current_period)
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_UPDATE)
})
.catch((error) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE)
})
} else {
this.$set(this.meal_types[index], "editing", true)
}
},
deleteMealType(index) {
let apiClient = new ApiApiFactory()
apiClient
.destroyMealType(this.meal_types[index].id)
.then((e) => {
this.periodChangedCallback(this.current_period)
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_DELETE)
})
.catch((error) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_DELETE)
})
},
updateEmoji: function (field, value) {
this.meal_types.forEach((meal_type) => {
if (meal_type.editing) {
meal_type.icon = value
}
})
},
editEntry(edit_entry) {
if (edit_entry.id !== -1) {
this.plan_entries.forEach((entry, index) => {
if (entry.id === edit_entry.id) {
this.$set(this.plan_entries, index, edit_entry)
this.saveEntry(this.plan_entries[index])
}
})
} else {
this.createEntry(edit_entry)
}
},
setShowDate(d) {
this.showDate = d
},
createEntryClick(data) {
this.entryEditing = this.options.entryEditing
this.entryEditing.date = moment(data).format("YYYY-MM-DD")
this.$bvModal.show(`edit-modal`)
},
findEntry(id) {
return this.plan_entries.filter((entry) => {
return entry.id === id
})[0]
},
moveEntry(null_object, target_date, drag_event) {
this.plan_entries.forEach((entry) => {
if (entry.id === this.dragged_item.id) {
if (drag_event.ctrlKey) {
let new_entry = Object.assign({}, entry)
new_entry.date = target_date
this.createEntry(new_entry)
} else {
entry.date = target_date
this.saveEntry(entry)
}
}
})
},
moveEntryLeft(data) {
this.plan_entries.forEach((entry) => {
if (entry.id === data.id) {
entry.date = moment(entry.date).subtract(1, "d")
this.saveEntry(entry)
}
})
},
moveEntryRight(data) {
this.plan_entries.forEach((entry) => {
if (entry.id === data.id) {
entry.date = moment(entry.date).add(1, "d")
this.saveEntry(entry)
}
})
},
deleteEntry(data) {
this.plan_entries.forEach((entry, index, list) => {
if (entry.id === data.id) {
let apiClient = new ApiApiFactory()
apiClient
.destroyMealPlan(entry.id)
.then((e) => {
list.splice(index, 1)
})
.catch((error) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE)
})
}
})
},
entryClick(data) {
let entry = this.findEntry(data.id)
this.openEntryEdit(entry)
},
openContextMenu($event, value) {
this.$refs.menu.open($event, value)
},
openEntryEdit(entry) {
this.$bvModal.show(`edit-modal`)
this.entryEditing = entry
this.entryEditing.date = moment(entry.date).format("YYYY-MM-DD")
if (this.entryEditing.recipe != null) {
this.entryEditing.title_placeholder = this.entryEditing.recipe.name
}
},
periodChangedCallback(date) {
this.current_period = date
let apiClient = new ApiApiFactory()
apiClient
.listMealPlans({
query: {
from_date: moment(date.periodStart).format("YYYY-MM-DD"),
to_date: moment(date.periodEnd).format("YYYY-MM-DD"),
},
})
.then((result) => {
this.plan_entries = result.data
})
this.refreshMealTypes()
},
refreshMealTypes() {
let apiClient = new ApiApiFactory()
apiClient.listMealTypes().then((result) => {
result.data.forEach((meal_type) => {
meal_type.editing = false
})
this.meal_types = result.data
})
},
saveEntry(entry) {
entry.date = moment(entry.date).format("YYYY-MM-DD")
let apiClient = new ApiApiFactory()
apiClient.updateMealPlan(entry.id, entry).catch((error) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE)
})
},
createEntry(entry) {
entry.date = moment(entry.date).format("YYYY-MM-DD")
let apiClient = new ApiApiFactory()
apiClient
.createMealPlan(entry)
.catch((error) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE)
})
.then((entry_result) => {
this.plan_entries.push(entry_result.data)
})
},
buildItem(plan_entry) {
//dirty hack to order items within a day
let date = moment(plan_entry.date).add(plan_entry.meal_type.order, "m")
return {
id: plan_entry.id,
startDate: date,
endDate: date,
entry: plan_entry,
}
},
}, },
refreshMealTypes() { directives: {
let apiClient = new ApiApiFactory() hover: {
inserted: function (el) {
apiClient.listMealTypes().then(result => { el.addEventListener("mouseenter", () => {
result.data.forEach((meal_type) => { el.classList.add("shadow")
meal_type.editing = false })
}) el.addEventListener("mouseleave", () => {
this.meal_types = result.data el.classList.remove("shadow")
}) })
}, },
saveEntry(entry) { },
entry.date = moment(entry.date).format("YYYY-MM-DD")
let apiClient = new ApiApiFactory()
apiClient.updateMealPlan(entry.id, entry).catch(error => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE)
})
},
createEntry(entry) {
entry.date = moment(entry.date).format("YYYY-MM-DD")
let apiClient = new ApiApiFactory()
apiClient.createMealPlan(entry).catch(error => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE)
}).then((entry_result) => {
this.plan_entries.push(entry_result.data)
})
}, },
} }
</script> </script>

View File

@ -140,7 +140,7 @@ import "bootstrap-vue/dist/bootstrap-vue.css"
import { apiLoadRecipe } from "@/utils/api" import { apiLoadRecipe } from "@/utils/api"
import StepComponent from "@/components/StepComponent" import StepComponent from "@/components/StepComponent"
import RecipeContextMenu from "@/components/ContextMenu/RecipeContextMenu" import RecipeContextMenu from "@/components/RecipeContextMenu"
import { ResolveUrlMixin, ToastMixin } from "@/utils/utils" import { ResolveUrlMixin, ToastMixin } from "@/utils/utils"
import PdfViewer from "@/components/PdfViewer" import PdfViewer from "@/components/PdfViewer"

View File

@ -8,12 +8,8 @@
</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.working_time !== 0 || recipe.waiting_time !== 0"> <div class="card-img-overlay w-50 d-flex flex-column justify-content-left float-left text-left pt-2" v-if="recipe.working_time !== 0 || recipe.waiting_time !== 0">
<b-badge pill variant="light" class="mt-1 font-weight-normal" v-if="recipe.working_time !== 0" <b-badge pill variant="light" class="mt-1 font-weight-normal" v-if="recipe.working_time !== 0"><i class="fa fa-clock"></i> {{ recipe.working_time }} {{ $t("min") }} </b-badge>
><i class="fa fa-clock"></i> {{ recipe.working_time }} {{ $t("min") }} <b-badge pill variant="secondary" class="mt-1 font-weight-normal" v-if="recipe.waiting_time !== 0"><i class="fa fa-pause"></i> {{ recipe.waiting_time }} {{ $t("min") }} </b-badge>
</b-badge>
<b-badge pill variant="secondary" class="mt-1 font-weight-normal" v-if="recipe.waiting_time !== 0"
><i class="fa fa-pause"></i> {{ recipe.waiting_time }} {{ $t("min") }}
</b-badge>
</div> </div>
</a> </a>
@ -25,7 +21,7 @@
</a> </a>
</h6> </h6>
<b-card-text style="text-overflow: ellipsis;"> <b-card-text style="text-overflow: ellipsis">
<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">
@ -61,7 +57,7 @@
</template> </template>
<script> <script>
import RecipeContextMenu from "@/components/ContextMenu/RecipeContextMenu" import RecipeContextMenu from "@/components/RecipeContextMenu"
import KeywordsComponent from "@/components/KeywordsComponent" import KeywordsComponent from "@/components/KeywordsComponent"
import { resolveDjangoUrl, ResolveUrlMixin } from "@/utils/utils" import { resolveDjangoUrl, ResolveUrlMixin } from "@/utils/utils"
import RecipeRating from "@/components/RecipeRating" import RecipeRating from "@/components/RecipeRating"
@ -86,17 +82,17 @@ export default {
console.log(this.recipe) console.log(this.recipe)
}, },
computed: { computed: {
detailed: function() { detailed: function () {
return this.recipe?.steps !== undefined return this.recipe?.steps !== undefined
}, },
text_length: function() { text_length: function () {
if (this.detailed) { if (this.detailed) {
return 200 return 200
} else { } else {
return 120 return 120
} }
}, },
recipe_image: function() { recipe_image: function () {
if (this.recipe == null || this.recipe.image === null) { if (this.recipe == null || this.recipe.image === null) {
return window.IMAGE_PLACEHOLDER return window.IMAGE_PLACEHOLDER
} else { } else {
@ -106,7 +102,7 @@ export default {
}, },
methods: { methods: {
// TODO: convert this to genericAPI // TODO: convert this to genericAPI
clickUrl: function() { clickUrl: function () {
if (this.recipe !== null) { if (this.recipe !== null) {
return resolveDjangoUrl("view_recipe", this.recipe.id) return resolveDjangoUrl("view_recipe", this.recipe.id)
} else { } else {
@ -116,7 +112,7 @@ export default {
}, },
directives: { directives: {
hover: { hover: {
inserted: function(el) { inserted: function (el) {
el.addEventListener("mouseenter", () => { el.addEventListener("mouseenter", () => {
el.classList.add("shadow") el.classList.add("shadow")
}) })

View File

@ -107,7 +107,7 @@ import { makeToast, resolveDjangoUrl, ResolveUrlMixin, StandardToasts } from "@/
import CookLog from "@/components/CookLog" import CookLog from "@/components/CookLog"
import axios from "axios" import axios from "axios"
import AddRecipeToBook from "@/components/Modals/AddRecipeToBook" import AddRecipeToBook from "@/components/Modals/AddRecipeToBook"
import MealPlanEditModal from "@/components/Modals/MealPlanEditModal" import MealPlanEditModal from "@/components/MealPlanEditModal"
import ShoppingModal from "@/components/Modals/ShoppingModal" import ShoppingModal from "@/components/Modals/ShoppingModal"
import moment from "moment" import moment from "moment"
import Vue from "vue" import Vue from "vue"