mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-22 06:23:34 -07:00
mealplan redesign
This commit is contained in:
parent
14769006e2
commit
15b44eb8a3
7 changed files with 150 additions and 174 deletions
|
@ -1,10 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<v-row>
|
<v-row>
|
||||||
<MealSelect
|
<SearchDialog ref="mealselect" @select="setSlug" />
|
||||||
:forceDialog="dialog"
|
|
||||||
@close="dialog = false"
|
|
||||||
@select="setSlug($event)"
|
|
||||||
/>
|
|
||||||
<v-col
|
<v-col
|
||||||
cols="12"
|
cols="12"
|
||||||
sm="12"
|
sm="12"
|
||||||
|
@ -19,10 +15,10 @@
|
||||||
<v-img
|
<v-img
|
||||||
height="200"
|
height="200"
|
||||||
:src="getImage(meal.slug)"
|
:src="getImage(meal.slug)"
|
||||||
@click="selectRecipe(index)"
|
@click="openSearch(index)"
|
||||||
></v-img>
|
></v-img>
|
||||||
<v-card-title class="my-n3 mb-n6">{{ meal.dateText }}</v-card-title>
|
<v-card-title class="my-n3 mb-n6">{{ meal.dateText }}</v-card-title>
|
||||||
<v-card-subtitle> {{ meal.slug }}</v-card-subtitle>
|
<v-card-subtitle> {{ meal.name }}</v-card-subtitle>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-hover>
|
</v-hover>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
@ -31,10 +27,10 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import utils from "../../utils";
|
import utils from "../../utils";
|
||||||
import MealSelect from "./MealSelect";
|
import SearchDialog from "../UI/SearchDialog";
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
MealSelect,
|
SearchDialog,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
value: Array,
|
value: Array,
|
||||||
|
@ -44,7 +40,6 @@ export default {
|
||||||
recipeData: [],
|
recipeData: [],
|
||||||
cardData: [],
|
cardData: [],
|
||||||
activeIndex: 0,
|
activeIndex: 0,
|
||||||
dialog: false,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -53,20 +48,14 @@ export default {
|
||||||
return utils.getImageURL(slug);
|
return utils.getImageURL(slug);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setSlug(slug) {
|
setSlug(name, slug) {
|
||||||
let index = this.activeIndex;
|
let index = this.activeIndex;
|
||||||
this.value[index]["slug"] = slug;
|
this.value[index]["slug"] = slug;
|
||||||
|
this.value[index]["name"] = name;
|
||||||
},
|
},
|
||||||
selectRecipe(index) {
|
openSearch(index) {
|
||||||
this.activeIndex = index;
|
this.activeIndex = index;
|
||||||
this.dialog = true;
|
this.$refs.mealselect.open();
|
||||||
},
|
|
||||||
getProperty(index, property) {
|
|
||||||
try {
|
|
||||||
return this.recipeData[index][property];
|
|
||||||
} catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
<template>
|
|
||||||
<v-row justify="center">
|
|
||||||
<v-dialog v-model="dialog" persistent max-width="800">
|
|
||||||
<v-card>
|
|
||||||
<v-card-title class="headline"> {{$t('meal-plan.choose-a-recipe')}} </v-card-title>
|
|
||||||
<v-card-text>
|
|
||||||
<v-autocomplete
|
|
||||||
:items="availableRecipes"
|
|
||||||
v-model="selected"
|
|
||||||
clearable
|
|
||||||
return
|
|
||||||
dense
|
|
||||||
hide-details
|
|
||||||
hide-selected
|
|
||||||
item-text="slug"
|
|
||||||
:label="$t('search.search-for-a-recipe')"
|
|
||||||
single-line
|
|
||||||
>
|
|
||||||
<template v-slot:no-data>
|
|
||||||
<v-list-item>
|
|
||||||
<v-list-item-title :v-html="$t('search.search-for-your-favorite-recipe')">
|
|
||||||
</v-list-item-title>
|
|
||||||
</v-list-item>
|
|
||||||
</template>
|
|
||||||
<template v-slot:item="{ item }">
|
|
||||||
<v-row align="center" @click="dialog = false">
|
|
||||||
<v-col sm="2">
|
|
||||||
<v-img
|
|
||||||
max-height="100"
|
|
||||||
max-width="100"
|
|
||||||
:src="getImage(item.image)"
|
|
||||||
></v-img>
|
|
||||||
</v-col>
|
|
||||||
<v-col sm="10">
|
|
||||||
<h3>
|
|
||||||
{{ item.name }}
|
|
||||||
</h3>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</template>
|
|
||||||
</v-autocomplete>
|
|
||||||
</v-card-text>
|
|
||||||
<v-card-actions>
|
|
||||||
<v-spacer></v-spacer>
|
|
||||||
<v-btn color="secondary" text @click="dialog = false"> {{$t('general.close')}} </v-btn>
|
|
||||||
<v-btn color="secondary" text @click="dialog = false"> {{$t('general.select')}} </v-btn>
|
|
||||||
</v-card-actions>
|
|
||||||
</v-card>
|
|
||||||
</v-dialog>
|
|
||||||
</v-row>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import utils from "../../utils";
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
forceDialog: Boolean,
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
dialog: false,
|
|
||||||
selected: "",
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
forceDialog() {
|
|
||||||
this.dialog = this.forceDialog;
|
|
||||||
},
|
|
||||||
selected() {
|
|
||||||
if (this.selected) {
|
|
||||||
this.$emit("select", this.selected);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dialog() {
|
|
||||||
if (this.dialog === false) {
|
|
||||||
this.$emit("close");
|
|
||||||
} else {
|
|
||||||
this.selected = "";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
availableRecipes() {
|
|
||||||
return this.$store.getters.getRecentRecipes;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
getImage(slug) {
|
|
||||||
return utils.getImageURL(slug);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
</style>
|
|
|
@ -25,9 +25,9 @@
|
||||||
<v-col align="end">
|
<v-col align="end">
|
||||||
<v-tooltip top color="secondary" max-width="400" open-delay="50">
|
<v-tooltip top color="secondary" max-width="400" open-delay="50">
|
||||||
<template v-slot:activator="{ on, attrs }">
|
<template v-slot:activator="{ on, attrs }">
|
||||||
<v-btn color="secondary" v-on="on" v-bind="attrs" text
|
<v-btn color="secondary" v-on="on" v-bind="attrs" text>{{
|
||||||
>{{$t('recipe.description')}}</v-btn
|
$t("recipe.description")
|
||||||
>
|
}}</v-btn>
|
||||||
</template>
|
</template>
|
||||||
<span>{{ description }}</span>
|
<span>{{ description }}</span>
|
||||||
</v-tooltip>
|
</v-tooltip>
|
||||||
|
@ -47,10 +47,15 @@ export default {
|
||||||
description: String,
|
description: String,
|
||||||
rating: Number,
|
rating: Number,
|
||||||
image: String,
|
image: String,
|
||||||
|
route: {
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
moreInfo(recipeSlug) {
|
moreInfo(recipeSlug) {
|
||||||
this.$router.push(`/recipe/${recipeSlug}`);
|
if (this.route) {
|
||||||
|
this.$router.push(`/recipe/${recipeSlug}`);
|
||||||
|
} else this.$emit("click");
|
||||||
},
|
},
|
||||||
getImage(image) {
|
getImage(image) {
|
||||||
return utils.getImageURL(image);
|
return utils.getImageURL(image);
|
||||||
|
|
76
frontend/src/components/UI/SearchDialog.vue
Normal file
76
frontend/src/components/UI/SearchDialog.vue
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
<template>
|
||||||
|
<div class="text-center">
|
||||||
|
<v-dialog v-model="dialog" min-height="700" max-width="1000">
|
||||||
|
<v-card min-height="725" height="100%">
|
||||||
|
<v-card-text>
|
||||||
|
<v-card-title></v-card-title>
|
||||||
|
<v-row justify="center">
|
||||||
|
<v-col cols="1"> </v-col>
|
||||||
|
<v-col>
|
||||||
|
<SearchBar @results="updateResults" :show-results="false" />
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="2">
|
||||||
|
<v-btn icon>
|
||||||
|
<v-icon large> mdi-filter </v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
<v-row v-if="searchResults">
|
||||||
|
<v-col
|
||||||
|
:sm="6"
|
||||||
|
:md="6"
|
||||||
|
:lg="4"
|
||||||
|
:xl="3"
|
||||||
|
v-for="item in searchResults.slice(0, 10)"
|
||||||
|
:key="item.item.name"
|
||||||
|
>
|
||||||
|
<RecipeCard
|
||||||
|
:route="false"
|
||||||
|
:name="item.item.name"
|
||||||
|
:description="item.item.description"
|
||||||
|
:slug="item.item.slug"
|
||||||
|
:rating="item.item.rating"
|
||||||
|
:image="item.item.image"
|
||||||
|
@click="emitSelect(item.item.name, item.item.slug)"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SearchBar from "../UI/SearchBar";
|
||||||
|
import RecipeCard from "../UI/RecipeCard";
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
SearchBar,
|
||||||
|
RecipeCard,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
searchResults: null,
|
||||||
|
dialog: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateResults(results) {
|
||||||
|
this.searchResults = results;
|
||||||
|
},
|
||||||
|
emitSelect(name, slug) {
|
||||||
|
console.log(name, slug);
|
||||||
|
this.$emit("select", name, slug);
|
||||||
|
this.dialog = false;
|
||||||
|
},
|
||||||
|
open() {
|
||||||
|
this.dialog = true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
|
@ -5,66 +5,71 @@
|
||||||
:meal-plan="editMealPlan"
|
:meal-plan="editMealPlan"
|
||||||
@updated="planUpdated"
|
@updated="planUpdated"
|
||||||
/>
|
/>
|
||||||
<NewMeal v-else @created="requestMeals" />
|
<NewMeal v-else @created="requestMeals" class="mb-5" />
|
||||||
|
|
||||||
<v-card class="my-1">
|
<v-card class="my-2">
|
||||||
<v-card-title class="headline"> {{$t('meal-plan.meal-plans')}} </v-card-title>
|
<v-card-title class="headline">
|
||||||
|
{{ $t("meal-plan.meal-plans") }}
|
||||||
|
</v-card-title>
|
||||||
<v-divider></v-divider>
|
<v-divider></v-divider>
|
||||||
|
|
||||||
<v-timeline align-top :dense="$vuetify.breakpoint.smAndDown">
|
<v-row no-gutters>
|
||||||
<v-timeline-item
|
<v-col
|
||||||
class="mx-4"
|
:sm="6"
|
||||||
|
:md="6"
|
||||||
|
:lg="4"
|
||||||
|
:xl="3"
|
||||||
v-for="(mealplan, i) in plannedMeals"
|
v-for="(mealplan, i) in plannedMeals"
|
||||||
:key="i"
|
:key="i"
|
||||||
color="accent lighten-2"
|
|
||||||
icon="mdi-silverware-variant"
|
|
||||||
fill-dot
|
|
||||||
>
|
>
|
||||||
<v-card>
|
<v-card class="ml-2 mt-2 mr-0">
|
||||||
<v-card-title class="white--text secondary lighten-1">
|
<v-card-title>
|
||||||
{{ formatDate(mealplan.startDate) }} -
|
{{ formatDate(mealplan.startDate) }} -
|
||||||
{{ formatDate(mealplan.endDate) }}
|
{{ formatDate(mealplan.endDate) }}
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
|
<v-list nav>
|
||||||
<v-card-text>
|
<v-list-item-group color="primary">
|
||||||
<v-row dense align="center">
|
<v-list-item
|
||||||
<v-col></v-col>
|
|
||||||
<v-col
|
|
||||||
v-for="(meal, index) in mealplan.meals"
|
v-for="(meal, index) in mealplan.meals"
|
||||||
:key="generateKey(meal.slug, index)"
|
:key="generateKey(meal.slug, index)"
|
||||||
|
@click="$router.push(`/recipe/${meal.slug}`)"
|
||||||
>
|
>
|
||||||
<v-img
|
<v-list-item-avatar
|
||||||
class="rounded-lg info"
|
color="primary"
|
||||||
:src="getImage(meal.image)"
|
class="headline font-weight-light white--text"
|
||||||
height="80"
|
|
||||||
width="80"
|
|
||||||
>
|
>
|
||||||
</v-img>
|
<v-img :src="getImage(meal.image)"></v-img>
|
||||||
</v-col>
|
</v-list-item-avatar>
|
||||||
<v-col></v-col>
|
<v-list-item-content>
|
||||||
</v-row>
|
<v-list-item-title v-text="meal.name"></v-list-item-title>
|
||||||
<v-row class="mt-2 ml-1">
|
<v-list-item-subtitle v-text="meal.dateText">
|
||||||
<v-btn
|
</v-list-item-subtitle>
|
||||||
color="accent lighten-2"
|
</v-list-item-content>
|
||||||
class="mx-0"
|
</v-list-item>
|
||||||
text
|
</v-list-item-group>
|
||||||
@click="editPlan(mealplan.uid)"
|
</v-list>
|
||||||
>
|
<v-card-actions class="mt-n5">
|
||||||
{{$t('general.edit')}}
|
<v-spacer></v-spacer>
|
||||||
</v-btn>
|
<v-btn
|
||||||
<v-btn
|
color="accent lighten-2"
|
||||||
color="error lighten-2"
|
class="mx-0"
|
||||||
class="mx-2"
|
text
|
||||||
text
|
@click="editPlan(mealplan.uid)"
|
||||||
@click="deletePlan(mealplan.uid)"
|
>
|
||||||
>
|
{{ $t("general.edit") }}
|
||||||
{{$t('general.delete')}}
|
</v-btn>
|
||||||
</v-btn>
|
<v-btn
|
||||||
</v-row>
|
color="error lighten-2"
|
||||||
</v-card-text>
|
class="mx-2"
|
||||||
|
text
|
||||||
|
@click="deletePlan(mealplan.uid)"
|
||||||
|
>
|
||||||
|
{{ $t("general.delete") }}
|
||||||
|
</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-timeline-item>
|
</v-col>
|
||||||
</v-timeline>
|
</v-row>
|
||||||
</v-card>
|
</v-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -53,17 +53,17 @@ export default {
|
||||||
const dow = days[dateObject.getUTCDay()];
|
const dow = days[dateObject.getUTCDay()];
|
||||||
const month = months[dateObject.getUTCMonth()];
|
const month = months[dateObject.getUTCMonth()];
|
||||||
const day = dateObject.getUTCDate();
|
const day = dateObject.getUTCDate();
|
||||||
const year = dateObject.getFullYear();
|
// const year = dateObject.getFullYear();
|
||||||
|
|
||||||
return `${dow}, ${month} ${day}, ${year}`;
|
return `${dow}, ${month} ${day}`;
|
||||||
},
|
},
|
||||||
getDateAsTextAlt(dateObject) {
|
getDateAsTextAlt(dateObject) {
|
||||||
const dow = days[dateObject.getUTCDay()];
|
const dow = days[dateObject.getUTCDay()];
|
||||||
const month = monthsShort[dateObject.getUTCMonth()];
|
const month = monthsShort[dateObject.getUTCMonth()];
|
||||||
const day = dateObject.getUTCDate();
|
const day = dateObject.getUTCDate();
|
||||||
const year = dateObject.getFullYear();
|
// const year = dateObject.getFullYear();
|
||||||
|
|
||||||
return `${dow}, ${month} ${day}, ${year}`;
|
return `${dow}, ${month} ${day}`;
|
||||||
},
|
},
|
||||||
getDateAsPythonDate(dateObject) {
|
getDateAsPythonDate(dateObject) {
|
||||||
const month = dateObject.getMonth() + 1;
|
const month = dateObject.getMonth() + 1;
|
||||||
|
|
|
@ -32,6 +32,7 @@ class Meal(BaseModel):
|
||||||
|
|
||||||
|
|
||||||
class MealData(BaseModel):
|
class MealData(BaseModel):
|
||||||
|
name: Optional[str]
|
||||||
slug: str
|
slug: str
|
||||||
dateText: str
|
dateText: str
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue