mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-08-05 05:25:26 +02:00
feat(frontend): ✨ Add Meal Tags + UI Improvements (#807)
* feat: ✨ * fix colors * add additional support for settings meal tag * add defaults to recipe * use group reciep settings * fix login infinite loading * disable owner on initial load * add skeleton loader * add v-model support * formatting * fix overwriting existing values * feat(frontend): ✨ add markdown preview for steps * update black plus formatting * update help text * fix overwrite error * remove print Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
parent
d4bf81dee6
commit
912cc6d956
50 changed files with 456 additions and 246 deletions
|
@ -5,10 +5,10 @@
|
|||
:class="{ 'on-hover': hover }"
|
||||
:elevation="hover ? 12 : 2"
|
||||
:to="route ? `/recipe/${slug}` : ''"
|
||||
min-height="275"
|
||||
:min-height="imageHeight + 75"
|
||||
@click="$emit('click')"
|
||||
>
|
||||
<RecipeCardImage icon-size="200" :slug="slug" small :image-version="image">
|
||||
<RecipeCardImage :icon-size="imageHeight" :height="imageHeight" :slug="slug" small :image-version="image">
|
||||
<v-expand-transition v-if="description">
|
||||
<div v-if="hover" class="d-flex transition-fast-in-fast-out secondary v-card--reveal" style="height: 100%">
|
||||
<v-card-text class="v-card--text-show white--text">
|
||||
|
@ -23,26 +23,28 @@
|
|||
</div>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-actions>
|
||||
<RecipeFavoriteBadge v-if="loggedIn" :slug="slug" show-always />
|
||||
<RecipeRating :value="rating" :name="name" :slug="slug" :small="true" />
|
||||
<v-spacer></v-spacer>
|
||||
<RecipeChips :truncate="true" :items="tags" :title="false" :limit="2" :small="true" :is-category="false" />
|
||||
<RecipeContextMenu
|
||||
:slug="slug"
|
||||
:name="name"
|
||||
:recipe-id="recipeId"
|
||||
:use-items="{
|
||||
delete: true,
|
||||
edit: true,
|
||||
download: true,
|
||||
mealplanner: true,
|
||||
print: false,
|
||||
share: true,
|
||||
}"
|
||||
@delete="$emit('delete', slug)"
|
||||
/>
|
||||
</v-card-actions>
|
||||
<slot name="actions">
|
||||
<v-card-actions>
|
||||
<RecipeFavoriteBadge v-if="loggedIn" :slug="slug" show-always />
|
||||
<RecipeRating :value="rating" :name="name" :slug="slug" :small="true" />
|
||||
<v-spacer></v-spacer>
|
||||
<RecipeChips :truncate="true" :items="tags" :title="false" :limit="2" :small="true" :is-category="false" />
|
||||
<RecipeContextMenu
|
||||
:slug="slug"
|
||||
:name="name"
|
||||
:recipe-id="recipeId"
|
||||
:use-items="{
|
||||
delete: true,
|
||||
edit: true,
|
||||
download: true,
|
||||
mealplanner: true,
|
||||
print: false,
|
||||
share: true,
|
||||
}"
|
||||
@delete="$emit('delete', slug)"
|
||||
/>
|
||||
</v-card-actions>
|
||||
</slot>
|
||||
<slot></slot>
|
||||
</v-card>
|
||||
</v-hover>
|
||||
|
@ -92,6 +94,10 @@ export default {
|
|||
required: true,
|
||||
type: Number,
|
||||
},
|
||||
imageHeight: {
|
||||
type: Number,
|
||||
default: 200,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
</template>
|
||||
<v-date-picker v-model="newMealdate" no-title @input="pickerMenu = false"></v-date-picker>
|
||||
</v-menu>
|
||||
<v-select v-model="newMealType" :return-object="false" :items="planTypeOptions" label="Entry Type"></v-select>
|
||||
</v-card-text>
|
||||
</BaseDialog>
|
||||
<v-menu
|
||||
|
@ -77,6 +78,7 @@ import { defineComponent, reactive, ref, toRefs, useContext, useRouter } from "@
|
|||
import { useClipboard, useShare } from "@vueuse/core";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { alert } from "~/composables/use-toast";
|
||||
import { MealType, planTypeOptions } from "~/composables/use-group-mealplan";
|
||||
|
||||
export interface ContextMenuIncludes {
|
||||
delete: boolean;
|
||||
|
@ -153,6 +155,7 @@ export default defineComponent({
|
|||
loading: false,
|
||||
menuItems: [] as ContextMenuItem[],
|
||||
newMealdate: "",
|
||||
newMealType: "dinner" as MealType,
|
||||
pickerMenu: false,
|
||||
});
|
||||
|
||||
|
@ -265,7 +268,7 @@ export default defineComponent({
|
|||
async function addRecipeToPlan() {
|
||||
const { response } = await api.mealplans.createOne({
|
||||
date: state.newMealdate,
|
||||
entryType: "dinner",
|
||||
entryType: state.newMealType,
|
||||
title: "",
|
||||
text: "",
|
||||
recipeId: props.recipeId,
|
||||
|
@ -310,6 +313,7 @@ export default defineComponent({
|
|||
domConfirmDelete,
|
||||
domMealplanDialog,
|
||||
icon,
|
||||
planTypeOptions,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<div class="mr-auto">
|
||||
{{ $t("search.results") }}
|
||||
</div>
|
||||
<router-link to="/search"> {{ $t("search.advanced-search") }} </router-link>
|
||||
<router-link to="/search?advanced=true"> {{ $t("search.advanced-search") }} </router-link>
|
||||
</v-card-actions>
|
||||
|
||||
<RecipeCardMobile
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div v-if="value && value.length > 0">
|
||||
<div class="d-flex justify-start">
|
||||
<h2 class="mb-4 mt-1">{{ $t("recipe.ingredients") }}</h2>
|
||||
<AppButtonCopy btn-class="ml-auto" :copy-text="ingredientCopyText" />
|
||||
<AppButtonCopy btn-class="ml-auto" :copy-text="ingredientCopyText" />
|
||||
</div>
|
||||
<div>
|
||||
<div v-for="(ingredient, index) in value" :key="'ingredient' + index">
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<section @keyup.ctrl.90="undoMerge">
|
||||
<!-- Ingredient Link Editor -->
|
||||
<v-dialog v-model="dialog" width="600">
|
||||
<v-card>
|
||||
<v-card :ripple="false">
|
||||
<v-app-bar dark color="primary" class="mt-n1 mb-3">
|
||||
<v-icon large left>
|
||||
{{ $globals.icons.link }}
|
||||
|
@ -127,8 +127,7 @@
|
|||
</v-fade-transition>
|
||||
</v-card-title>
|
||||
<v-card-text v-if="edit">
|
||||
<v-textarea :key="'instructions' + index" v-model="value[index]['text']" auto-grow dense rows="4">
|
||||
</v-textarea>
|
||||
<MarkdownEditor v-model="value[index]['text']" />
|
||||
<div
|
||||
v-for="ing in step.ingredientReferences"
|
||||
:key="ing.referenceId"
|
||||
|
@ -417,4 +416,9 @@ export default defineComponent({
|
|||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.v-card--link:before {
|
||||
background: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
67
frontend/components/global/MarkdownEditor.vue
Normal file
67
frontend/components/global/MarkdownEditor.vue
Normal file
|
@ -0,0 +1,67 @@
|
|||
<template>
|
||||
<div>
|
||||
<v-tabs v-model="tab" height="30px" class="my-1">
|
||||
<v-tab>
|
||||
<v-icon small left> {{ $globals.icons.edit }}</v-icon>
|
||||
Edit
|
||||
</v-tab>
|
||||
<v-tab>
|
||||
<v-icon small left> {{ $globals.icons.eye }}</v-icon>
|
||||
Preview
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
<v-textarea
|
||||
v-if="tab == 0"
|
||||
v-model="inputVal"
|
||||
:class="label == '' ? '' : 'mt-5'"
|
||||
:label="label"
|
||||
auto-grow
|
||||
dense
|
||||
rows="4"
|
||||
></v-textarea>
|
||||
<VueMarkdown v-else :source="value"> </VueMarkdown>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
// @ts-ignore
|
||||
import VueMarkdown from "@adapttive/vue-markdown";
|
||||
|
||||
import { defineComponent, reactive, toRefs, computed } from "@nuxtjs/composition-api";
|
||||
|
||||
export default defineComponent({
|
||||
name: "MarkdownEditor",
|
||||
components: {
|
||||
VueMarkdown,
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
setup(props, context) {
|
||||
const state = reactive({
|
||||
tab: 0,
|
||||
});
|
||||
|
||||
const inputVal = computed({
|
||||
get: () => {
|
||||
return props.value;
|
||||
},
|
||||
set: (val) => {
|
||||
context.emit("input", val);
|
||||
},
|
||||
});
|
||||
return {
|
||||
inputVal,
|
||||
...toRefs(state),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
@ -8,16 +8,26 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent } from "@nuxtjs/composition-api";
|
||||
import { useToggle } from "@vueuse/shared";
|
||||
import { watch } from "vue-demi";
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
tag: {
|
||||
type: String,
|
||||
default: "div",
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
setup(_, context) {
|
||||
const [state, toggle] = useToggle();
|
||||
|
||||
watch(state, () => {
|
||||
context.emit("input", state);
|
||||
});
|
||||
|
||||
return {
|
||||
state,
|
||||
toggle,
|
||||
|
|
|
@ -4,6 +4,15 @@ import { useAsyncKey } from "./use-utils";
|
|||
import { useUserApi } from "~/composables/api";
|
||||
import { CreateMealPlan, UpdateMealPlan } from "~/api/class-interfaces/group-mealplan";
|
||||
|
||||
export type MealType = "breakfast" | "lunch" | "dinner" | "snack";
|
||||
|
||||
export const planTypeOptions = [
|
||||
{ text: "Breakfast", value: "breakfast" },
|
||||
{ text: "Lunch", value: "lunch" },
|
||||
{ text: "Dinner", value: "dinner" },
|
||||
{ text: "Snack", value: "snack" },
|
||||
];
|
||||
|
||||
export const useMealplans = function () {
|
||||
const api = useUserApi();
|
||||
const loading = ref(false);
|
||||
|
@ -72,9 +81,14 @@ export const useMealplans = function () {
|
|||
this.refreshAll();
|
||||
}
|
||||
},
|
||||
|
||||
async setType(payload: UpdateMealPlan, typ: MealType) {
|
||||
payload.entryType = typ;
|
||||
await this.updateOne(payload);
|
||||
},
|
||||
};
|
||||
|
||||
const mealplans = actions.getAll();
|
||||
|
||||
return { mealplans, actions, validForm };
|
||||
return { mealplans, actions, validForm, loading };
|
||||
};
|
||||
|
|
|
@ -223,7 +223,7 @@ export default {
|
|||
background: "#202021",
|
||||
},
|
||||
light: {
|
||||
primary: process.env.THEME_LIGHT_PRIMARY || "#007A99",
|
||||
primary: process.env.THEME_LIGHT_PRIMARY || "#E58325",
|
||||
accent: process.env.THEME_LIGHT_ACCENT || "#007A99",
|
||||
secondary: process.env.THEME_DARK_SECONDARY || "#973542",
|
||||
success: process.env.THEME_DARK_SUCCESS || "#43A047",
|
||||
|
@ -237,7 +237,6 @@ export default {
|
|||
privateRuntimeConfig: {},
|
||||
|
||||
proxy: {
|
||||
// "http://localhost:9000/*/api",
|
||||
// See Proxy section
|
||||
[`${process.env.SUB_PATH || ""}api`]: {
|
||||
pathRewrite: {
|
||||
|
|
|
@ -193,6 +193,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, useContext, computed, reactive } from "@nuxtjs/composition-api";
|
||||
import { alert } from "~/composables/use-toast";
|
||||
export default defineComponent({
|
||||
layout: "basic",
|
||||
|
||||
|
@ -215,7 +216,16 @@ export default defineComponent({
|
|||
formData.append("username", form.email);
|
||||
formData.append("password", form.password);
|
||||
|
||||
await $auth.loginWith("local", { data: formData });
|
||||
try {
|
||||
await $auth.loginWith("local", { data: formData });
|
||||
} catch (error) {
|
||||
if (error.response.status === 401) {
|
||||
alert.error("Invalid Credentials");
|
||||
}
|
||||
else {
|
||||
alert.error("Something Went Wrong!")
|
||||
}
|
||||
}
|
||||
loggingIn.value = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,9 @@
|
|||
<v-date-picker v-model="newMeal.date" no-title @input="pickerMenu = false"></v-date-picker>
|
||||
</v-menu>
|
||||
<v-card-text>
|
||||
<v-select v-model="newMeal.entryType" :return-object="false" :items="planTypeOptions" label="Entry Type">
|
||||
</v-select>
|
||||
|
||||
<v-autocomplete
|
||||
v-if="!dialog.note"
|
||||
v-model="newMeal.recipeId"
|
||||
|
@ -68,7 +71,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<v-switch v-model="edit" label="Editor"></v-switch>
|
||||
<v-row class="mt-2">
|
||||
<v-row class="">
|
||||
<v-col
|
||||
v-for="(plan, index) in mealsByDate"
|
||||
:key="index"
|
||||
|
@ -79,68 +82,120 @@
|
|||
xl="2"
|
||||
class="col-borders my-1 d-flex flex-column"
|
||||
>
|
||||
<p class="h5 text-center">
|
||||
{{ $d(plan.date, "short") }}
|
||||
</p>
|
||||
<draggable
|
||||
tag="div"
|
||||
:value="plan.meals"
|
||||
group="meals"
|
||||
:data-index="index"
|
||||
:data-box="plan.date"
|
||||
style="min-height: 150px"
|
||||
@end="onMoveCallback"
|
||||
>
|
||||
<v-card v-for="mealplan in plan.meals" :key="mealplan.id" v-model="hover[mealplan.id]" class="my-1">
|
||||
<v-list-item :to="edit ? null : `/recipe/${mealplan.recipe.slug}`">
|
||||
<v-list-item-avatar :rounded="false">
|
||||
<RecipeCardImage v-if="mealplan.recipe" tiny icon-size="25" :slug="mealplan.recipe.slug" />
|
||||
<v-icon v-else>
|
||||
{{ $globals.icons.primary }}
|
||||
</v-icon>
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="mb-1">
|
||||
{{ mealplan.recipe ? mealplan.recipe.name : mealplan.title }}
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle>
|
||||
{{ mealplan.recipe ? mealplan.recipe.description : mealplan.text }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-divider v-if="edit" class="mx-2"></v-divider>
|
||||
<v-card-actions v-if="edit">
|
||||
<v-btn color="error" icon @click="actions.deleteOne(mealplan.id)">
|
||||
<v-icon>{{ $globals.icons.delete }}</v-icon>
|
||||
</v-btn>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn
|
||||
v-if="mealplan.recipe"
|
||||
color="info"
|
||||
icon
|
||||
nuxt
|
||||
target="_blank"
|
||||
:to="`/recipe/${mealplan.recipe.slug}`"
|
||||
>
|
||||
<v-icon>{{ $globals.icons.openInNew }}</v-icon>
|
||||
</v-btn>
|
||||
<v-sheet class="mb-2 bottom-color-border">
|
||||
<p class="headline text-center mb-1">
|
||||
{{ $d(plan.date, "short") }}
|
||||
</p>
|
||||
</v-sheet>
|
||||
|
||||
<!-- Day Column Recipes -->
|
||||
<template v-if="edit">
|
||||
<draggable
|
||||
tag="div"
|
||||
:value="plan.meals"
|
||||
group="meals"
|
||||
:data-index="index"
|
||||
:data-box="plan.date"
|
||||
style="min-height: 150px"
|
||||
@end="onMoveCallback"
|
||||
>
|
||||
<v-card v-for="mealplan in plan.meals" :key="mealplan.id" v-model="hover[mealplan.id]" class="my-1">
|
||||
<v-list-item :to="edit || !mealplan.recipe ? null : `/recipe/${mealplan.recipe.slug}`">
|
||||
<v-list-item-avatar :rounded="false">
|
||||
<RecipeCardImage
|
||||
v-if="mealplan.recipe"
|
||||
tiny
|
||||
icon-size="25"
|
||||
:slug="mealplan.recipe ? mealplan.recipe.slug : ''"
|
||||
/>
|
||||
<v-icon v-else>
|
||||
{{ $globals.icons.primary }}
|
||||
</v-icon>
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="mb-1">
|
||||
{{ mealplan.recipe ? mealplan.recipe.name : mealplan.title }}
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle style="min-height: 16px">
|
||||
{{ mealplan.recipe ? mealplan.recipe.description + " " : mealplan.text }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-divider class="mx-2"></v-divider>
|
||||
<div class="py-2 px-2 d-flex">
|
||||
<v-menu offset-y>
|
||||
<template #activator="{ on, attrs }">
|
||||
<v-chip v-bind="attrs" label small color="accent" v-on="on" @click.prevent>
|
||||
<v-icon left>
|
||||
{{ $globals.icons.tags }}
|
||||
</v-icon>
|
||||
{{ mealplan.entryType }}
|
||||
</v-chip>
|
||||
</template>
|
||||
<v-list>
|
||||
<v-list-item
|
||||
v-for="mealType in planTypeOptions"
|
||||
:key="mealType.value"
|
||||
@click="actions.setType(mealplan, mealType.value)"
|
||||
>
|
||||
<v-list-item-title> {{ mealType.text }} </v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="info" class="mr-2" small icon>
|
||||
<v-icon>{{ $globals.icons.cartCheck }}</v-icon>
|
||||
</v-btn>
|
||||
<v-btn color="error" small icon @click="actions.deleteOne(mealplan.id)">
|
||||
<v-icon>{{ $globals.icons.delete }}</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-card>
|
||||
</draggable>
|
||||
|
||||
<!-- Day Column Actions -->
|
||||
<v-card outlined class="mt-auto">
|
||||
<v-card-actions class="d-flex">
|
||||
<div style="width: 50%">
|
||||
<v-btn block text @click="randomMeal(plan.date)">
|
||||
<v-icon large>{{ $globals.icons.diceMultiple }}</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
<div style="width: 50%">
|
||||
<v-btn block text @click="openDialog(plan.date)">
|
||||
<v-icon large>{{ $globals.icons.createAlt }}</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</draggable>
|
||||
<v-card v-if="edit" outlined class="mt-auto">
|
||||
<v-card-actions class="d-flex">
|
||||
<div style="width: 50%">
|
||||
<v-btn block text @click="randomMeal(plan.date)">
|
||||
<v-icon large>{{ $globals.icons.diceMultiple }}</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
<div style="width: 50%">
|
||||
<v-btn block text @click="openDialog(plan.date)">
|
||||
<v-icon large>{{ $globals.icons.createAlt }}</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</template>
|
||||
<template v-else-if="plan.meals">
|
||||
<RecipeCard
|
||||
v-for="mealplan in plan.meals"
|
||||
:key="mealplan.id"
|
||||
:recipe-id="0"
|
||||
:image-height="125"
|
||||
class="mb-2"
|
||||
:route="mealplan.recipe ? true : false"
|
||||
:slug="mealplan.recipe ? mealplan.recipe.slug : mealplan.title"
|
||||
:description="mealplan.recipe ? mealplan.recipe.description : mealplan.text"
|
||||
:name="mealplan.recipe ? mealplan.recipe.name : mealplan.title"
|
||||
>
|
||||
<template #actions>
|
||||
<v-divider class="mb-0 mt-2 mx-2"></v-divider>
|
||||
<v-card-actions class="justify-end mt-1">
|
||||
<v-chip label small color="accent">
|
||||
<v-icon left>
|
||||
{{ $globals.icons.tags }}
|
||||
</v-icon>
|
||||
{{ mealplan.entryType }}
|
||||
</v-chip>
|
||||
</v-card-actions>
|
||||
</template>
|
||||
</RecipeCard>
|
||||
</template>
|
||||
|
||||
<v-skeleton-loader v-else elevation="2" type="image, list-item-two-line"></v-skeleton-loader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
|
@ -151,17 +206,19 @@ import { computed, defineComponent, reactive, ref, toRefs, watch } from "@nuxtjs
|
|||
import { isSameDay, addDays, subDays, parseISO, format } from "date-fns";
|
||||
import { SortableEvent } from "sortablejs"; // eslint-disable-line
|
||||
import draggable from "vuedraggable";
|
||||
import { useMealplans } from "~/composables/use-group-mealplan";
|
||||
import { useMealplans, planTypeOptions } from "~/composables/use-group-mealplan";
|
||||
import { useRecipes, allRecipes } from "~/composables/recipes";
|
||||
import RecipeCardImage from "~/components/Domain/Recipe/RecipeCardImage.vue";
|
||||
import RecipeCard from "~/components/Domain/Recipe/RecipeCard.vue";
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
draggable,
|
||||
RecipeCardImage,
|
||||
RecipeCard,
|
||||
},
|
||||
setup() {
|
||||
const { mealplans, actions } = useMealplans();
|
||||
const { mealplans, actions, loading } = useMealplans();
|
||||
|
||||
useRecipes(true, true);
|
||||
const state = reactive({
|
||||
|
@ -242,6 +299,7 @@ export default defineComponent({
|
|||
|
||||
// =====================================================
|
||||
// New Meal Dialog
|
||||
|
||||
const domMealDialog = ref(null);
|
||||
const dialog = reactive({
|
||||
loading: false,
|
||||
|
@ -256,11 +314,13 @@ export default defineComponent({
|
|||
newMeal.title = "";
|
||||
newMeal.text = "";
|
||||
});
|
||||
|
||||
const newMeal = reactive({
|
||||
date: "",
|
||||
title: "",
|
||||
text: "",
|
||||
recipeId: null,
|
||||
recipeId: null as Number | null,
|
||||
entryType: "dinner",
|
||||
});
|
||||
|
||||
function openDialog(date: Date) {
|
||||
|
@ -273,40 +333,45 @@ export default defineComponent({
|
|||
newMeal.date = "";
|
||||
newMeal.title = "";
|
||||
newMeal.text = "";
|
||||
newMeal.entryType = "dinner";
|
||||
newMeal.recipeId = null;
|
||||
}
|
||||
|
||||
function randomMeal(date: Date) {
|
||||
async function randomMeal(date: Date) {
|
||||
// TODO: Refactor to use API call to get random recipe
|
||||
// @ts-ignore
|
||||
const randomRecipe = allRecipes.value[Math.floor(Math.random() * allRecipes.value.length)];
|
||||
|
||||
newMeal.date = format(date, "yyyy-MM-dd");
|
||||
// @ts-ignore
|
||||
newMeal.recipeId = randomRecipe.id;
|
||||
|
||||
newMeal.recipeId = randomRecipe.id || null;
|
||||
|
||||
console.log(newMeal.recipeId, randomRecipe.id);
|
||||
|
||||
// @ts-ignore
|
||||
actions.createOne(newMeal);
|
||||
await actions.createOne({ ...newMeal });
|
||||
resetDialog();
|
||||
}
|
||||
|
||||
return {
|
||||
resetDialog,
|
||||
randomMeal,
|
||||
...toRefs(state),
|
||||
actions,
|
||||
allRecipes,
|
||||
backOneWeek,
|
||||
days,
|
||||
dialog,
|
||||
domMealDialog,
|
||||
openDialog,
|
||||
mealplans,
|
||||
actions,
|
||||
newMeal,
|
||||
allRecipes,
|
||||
...toRefs(state),
|
||||
mealsByDate,
|
||||
onMoveCallback,
|
||||
backOneWeek,
|
||||
forwardOneWeek,
|
||||
loading,
|
||||
mealplans,
|
||||
mealsByDate,
|
||||
newMeal,
|
||||
onMoveCallback,
|
||||
openDialog,
|
||||
planTypeOptions,
|
||||
randomMeal,
|
||||
resetDialog,
|
||||
weekRange,
|
||||
days,
|
||||
};
|
||||
},
|
||||
head() {
|
||||
|
@ -318,8 +383,16 @@ export default defineComponent({
|
|||
</script>
|
||||
|
||||
<style lang="css">
|
||||
.col-borders {
|
||||
/* .col-borders {
|
||||
border-top: 1px solid #e0e0e0;
|
||||
} */
|
||||
|
||||
.left-color-border {
|
||||
border-left: 5px solid var(--v-primary-base) !important;
|
||||
}
|
||||
|
||||
.bottom-color-border {
|
||||
border-bottom: 2px solid var(--v-primary-base) !important;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -110,7 +110,7 @@
|
|||
<!-- Advanced Editor -->
|
||||
<div v-if="form">
|
||||
<h2 class="mb-4">{{ $t("recipe.ingredients") }}</h2>
|
||||
<draggable v-model="recipe.recipeIngredient" handle=".handle">
|
||||
<draggable v-if="recipe.recipeIngredient.length > 0" v-model="recipe.recipeIngredient" handle=".handle">
|
||||
<RecipeIngredientEditor
|
||||
v-for="(ingredient, index) in recipe.recipeIngredient"
|
||||
:key="ingredient.referenceId"
|
||||
|
@ -119,6 +119,7 @@
|
|||
@delete="recipe.recipeIngredient.splice(index, 1)"
|
||||
/>
|
||||
</draggable>
|
||||
<v-skeleton-loader v-else boilerplate elevation="2" type="list-item"> </v-skeleton-loader>
|
||||
<div class="d-flex justify-end mt-2">
|
||||
<v-tooltip top color="accent">
|
||||
<template #activator="{ on, attrs }">
|
||||
|
|
|
@ -126,7 +126,7 @@ export default defineComponent({
|
|||
|
||||
const headers = reactive({
|
||||
id: false,
|
||||
owner: true,
|
||||
owner: false,
|
||||
tags: true,
|
||||
categories: true,
|
||||
recipeYield: false,
|
||||
|
|
|
@ -4,7 +4,7 @@ ALLOW_SIGNUP=true
|
|||
|
||||
# =====================================
|
||||
# Light Mode Config
|
||||
THEME_LIGHT_PRIMARY=#007A99
|
||||
THEME_LIGHT_PRIMARY=#E58325
|
||||
THEME_LIGHT_ACCENT=#007A99
|
||||
THEME_LIGHT_SECONDARY=#973542
|
||||
THEME_LIGHT_SUCCESS=#43A047
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue