mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-22 14:33:33 -07:00
ui improvements + mealplanner search
This commit is contained in:
parent
12a53ed6fe
commit
4493894162
11 changed files with 93 additions and 42 deletions
|
@ -150,4 +150,5 @@ export default {
|
|||
*::-webkit-scrollbar-thumb {
|
||||
background: grey;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -8,13 +8,14 @@ const prefix = baseURL + "recipes/";
|
|||
|
||||
const recipeURLs = {
|
||||
allRecipes: baseURL + "recipes",
|
||||
allRecipesByCategory: prefix + "category",
|
||||
create: prefix + "create",
|
||||
createByURL: prefix + "create-url",
|
||||
recipe: (slug) => prefix + slug,
|
||||
update: (slug) => prefix + slug,
|
||||
delete: (slug) => prefix + slug,
|
||||
recipeImage: (slug) => `${prefix}${slug}/image`,
|
||||
updateImage: (slug) => `${prefix}${slug}/image`,
|
||||
recipe: slug => prefix + slug,
|
||||
update: slug => prefix + slug,
|
||||
delete: slug => prefix + slug,
|
||||
recipeImage: slug => `${prefix}${slug}/image`,
|
||||
updateImage: slug => `${prefix}${slug}/image`,
|
||||
};
|
||||
|
||||
export default {
|
||||
|
@ -27,6 +28,14 @@ export default {
|
|||
return response;
|
||||
},
|
||||
|
||||
async getAllByCategory(categories) {
|
||||
let response = await apiReq.post(
|
||||
recipeURLs.allRecipesByCategory,
|
||||
categories
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
async create(recipeData) {
|
||||
let response = await apiReq.post(recipeURLs.create, recipeData);
|
||||
return response.data;
|
||||
|
@ -67,7 +76,7 @@ export default {
|
|||
keys: recipeKeys,
|
||||
num: num,
|
||||
},
|
||||
paramsSerializer: (params) => {
|
||||
paramsSerializer: params => {
|
||||
return qs.stringify(params, { arrayFormat: "repeat" });
|
||||
},
|
||||
});
|
||||
|
|
|
@ -96,6 +96,7 @@ export default {
|
|||
return {
|
||||
isLoading: false,
|
||||
meals: [],
|
||||
items: [],
|
||||
|
||||
// Dates
|
||||
startDate: null,
|
||||
|
@ -117,11 +118,13 @@ export default {
|
|||
}
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
let settings = await api.settings.requestAll();
|
||||
console.log(settings);
|
||||
this.items = await api.recipes.getAllByCategory(settings.planCategories);
|
||||
},
|
||||
|
||||
computed: {
|
||||
items() {
|
||||
return this.$store.getters.getRecentRecipes;
|
||||
},
|
||||
actualStartDate() {
|
||||
return Date.parse(this.startDate);
|
||||
},
|
||||
|
|
|
@ -6,7 +6,19 @@
|
|||
:to="route ? `/recipe/${slug}` : ''"
|
||||
@click="$emit('click')"
|
||||
>
|
||||
<v-img height="200" :src="getImage(image)"></v-img>
|
||||
<v-img height="200" :src="getImage(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">
|
||||
{{ description }}
|
||||
</v-card-text>
|
||||
</div>
|
||||
</v-expand-transition>
|
||||
</v-img>
|
||||
<v-card-title class="my-n3 mb-n6">{{ name | truncate(30) }}</v-card-title>
|
||||
|
||||
<v-card-actions class="">
|
||||
|
@ -23,16 +35,7 @@
|
|||
></v-rating>
|
||||
</v-col>
|
||||
<v-col></v-col>
|
||||
<v-col align="end">
|
||||
<v-tooltip top color="secondary" max-width="400" open-delay="50">
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn color="secondary" v-on="on" v-bind="attrs" text>{{
|
||||
$t("recipe.description")
|
||||
}}</v-btn>
|
||||
</template>
|
||||
<span>{{ description }}</span>
|
||||
</v-tooltip>
|
||||
</v-col>
|
||||
<v-col align="end"> </v-col>
|
||||
</v-row>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
|
@ -61,4 +64,15 @@ export default {
|
|||
</script>
|
||||
|
||||
<style>
|
||||
.v-card--reveal {
|
||||
align-items: center;
|
||||
bottom: 0;
|
||||
justify-content: center;
|
||||
opacity: 0.8;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
.v-card--text-show {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
</style>
|
|
@ -57,6 +57,7 @@ export default {
|
|||
return {
|
||||
searchSlug: "",
|
||||
search: " ",
|
||||
data: [],
|
||||
result: [],
|
||||
autoResults: [],
|
||||
isDark: false,
|
||||
|
@ -67,27 +68,31 @@ export default {
|
|||
distance: 100,
|
||||
maxPatternLength: 32,
|
||||
minMatchCharLength: 1,
|
||||
keys: ["name", "slug"],
|
||||
keys: ["name", "slug", "description"],
|
||||
},
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.isDark = this.$store.getters.getIsDark;
|
||||
this.data = this.$store.getters.getRecentRecipes;
|
||||
},
|
||||
computed: {
|
||||
data() {
|
||||
return this.$store.getters.getRecentRecipes;
|
||||
},
|
||||
fuse() {
|
||||
return new Fuse(this.data, this.options);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
search() {
|
||||
if (this.search.trim() === "") this.result = this.list;
|
||||
else this.result = this.fuse.search(this.search.trim());
|
||||
|
||||
try {
|
||||
this.result = this.fuse.search(this.search.trim());
|
||||
} catch {
|
||||
this.result = this.data
|
||||
.map(x => ({ item: x }))
|
||||
.sort((a, b) => (a.name > b.name ? 1 : -1));
|
||||
}
|
||||
console.log(this.result);
|
||||
this.$emit("results", this.result);
|
||||
|
||||
if (this.showResults === true) {
|
||||
this.autoResults = this.result;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="text-center">
|
||||
<v-dialog v-model="dialog" min-height="700" max-width="1000">
|
||||
<v-dialog v-model="dialog" height="100%" max-width="1200">
|
||||
<v-card min-height="725" height="100%">
|
||||
<v-card-text>
|
||||
<v-card-title></v-card-title>
|
||||
|
@ -22,7 +22,7 @@
|
|||
:md="6"
|
||||
:lg="4"
|
||||
:xl="3"
|
||||
v-for="item in searchResults.slice(0, 10)"
|
||||
v-for="item in searchResults.slice(0, 24)"
|
||||
:key="item.item.name"
|
||||
>
|
||||
<RecipeCard
|
||||
|
@ -58,6 +58,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
updateResults(results) {
|
||||
console.log(results);
|
||||
this.searchResults = results;
|
||||
},
|
||||
emitSelect(name, slug) {
|
||||
|
|
|
@ -15,7 +15,7 @@ const mutations = {
|
|||
state.showLimit = payload;
|
||||
},
|
||||
setCategories(state, payload) {
|
||||
state.categories = payload;
|
||||
state.categories = payload.sort((a, b) => (a.name > b.name ? 1 : -1));
|
||||
},
|
||||
setHomeCategories(state, payload) {
|
||||
state.homeCategories = payload;
|
||||
|
|
|
@ -47,7 +47,6 @@ const store = new Vuex.Store({
|
|||
},
|
||||
|
||||
setMealPlanCategories(state, payload) {
|
||||
console.log(payload);
|
||||
state.mealPlanCategories = payload;
|
||||
},
|
||||
},
|
||||
|
|
|
@ -100,11 +100,17 @@ class BaseDocument:
|
|||
match_key = self.primary_key
|
||||
|
||||
result = (
|
||||
session.query(self.sql_model).filter_by(**{match_key: match_value}).one()
|
||||
session.query(self.sql_model)
|
||||
.filter_by(**{match_key: match_value})
|
||||
.limit(limit)
|
||||
.all()
|
||||
)
|
||||
db_entry = result.dict()
|
||||
db_entries = [x.dict() for x in result]
|
||||
|
||||
return db_entry
|
||||
if limit == 1:
|
||||
return db_entries[0]
|
||||
|
||||
return db_entries
|
||||
|
||||
def create(self, session: Session, document: dict) -> dict:
|
||||
"""Creates a new database entry for the given SQL Alchemy Model.
|
||||
|
|
|
@ -4,6 +4,7 @@ from db.database import db
|
|||
from db.db_setup import generate_session
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from models.recipe_models import AllRecipeRequest
|
||||
from slugify import slugify
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
router = APIRouter(tags=["Query All Recipes"])
|
||||
|
@ -71,13 +72,23 @@ def get_all_recipes_post(
|
|||
return db.recipes.get_all_limit_columns(session, body.properties, body.limit)
|
||||
|
||||
|
||||
@router.post("/api/category")
|
||||
async def filter_by_category(
|
||||
categories: list, session: Session = Depends(generate_session)
|
||||
):
|
||||
@router.post("/api/recipes/category")
|
||||
def filter_by_category(categories: list, session: Session = Depends(generate_session)):
|
||||
""" pass a list of categories and get a list of recipes associated with those categories """
|
||||
#! This should be refactored into a single database call, but I couldn't figure it out
|
||||
in_category = [db.categories.get(session, cat) for cat in categories]
|
||||
#! This should be refactored into a single database call, but I couldn't figure it out
|
||||
in_category = [
|
||||
db.categories.get(session, slugify(cat), limit=1) for cat in categories
|
||||
]
|
||||
in_category = [cat.get("recipes") for cat in in_category]
|
||||
in_category = [item for sublist in in_category for item in sublist]
|
||||
return in_category
|
||||
|
||||
|
||||
@router.post("/api/recipes/tag")
|
||||
async def filter_by_tags(tags: list, session: Session = Depends(generate_session)):
|
||||
""" pass a list of tags and get a list of recipes associated with those tags"""
|
||||
#! This should be refactored into a single database call, but I couldn't figure it out
|
||||
in_tags = [db.tags.get(session, slugify(tag), limit=1) for tag in tags]
|
||||
in_tags = [tag.get("recipes") for tag in in_tags]
|
||||
in_tags = [item for sublist in in_tags for item in sublist]
|
||||
return in_tags
|
||||
|
|
|
@ -69,8 +69,10 @@ def delete_recipe(recipe_slug: str, db: Session = Depends(generate_session)):
|
|||
async def get_recipe_img(recipe_slug: str):
|
||||
""" Takes in a recipe slug, returns the static image """
|
||||
recipe_image = read_image(recipe_slug)
|
||||
|
||||
return FileResponse(recipe_image)
|
||||
if recipe_image:
|
||||
return FileResponse(recipe_image)
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
@router.put("/{recipe_slug}/image")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue