mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-07-09 03:04:54 -04:00
Feature/recipe viewer (#244)
* fix dialog placement * markdown support in ingredients * fix line render issue * fix tag rendering bug * change ingredients to text area * no slug error * add tag pages * remove console.logs Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
parent
30510202df
commit
049c269f6f
@ -21,7 +21,6 @@ export const metaAPI = {
|
||||
|
||||
async getIsDemo() {
|
||||
let response = await apiReq.get(debugURLs.demo);
|
||||
console.log(response);
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
|
@ -273,7 +273,6 @@ export default {
|
||||
await this.initialize();
|
||||
},
|
||||
resetPassword() {
|
||||
console.log(this.activeId);
|
||||
api.users.resetPassword(this.editedItem.id);
|
||||
},
|
||||
},
|
||||
|
@ -125,7 +125,6 @@ export default {
|
||||
|
||||
computed: {
|
||||
groupSettings() {
|
||||
console.log(this.$store.getters.getCurrentGroup);
|
||||
return this.$store.getters.getCurrentGroup;
|
||||
},
|
||||
actualStartDate() {
|
||||
|
@ -26,21 +26,16 @@
|
||||
</v-card-title>
|
||||
|
||||
<v-card-actions class="">
|
||||
<v-row dense align="center">
|
||||
<v-col>
|
||||
<v-rating
|
||||
class="mr-2"
|
||||
color="secondary"
|
||||
background-color="secondary lighten-3"
|
||||
dense
|
||||
length="5"
|
||||
size="15"
|
||||
:value="rating"
|
||||
></v-rating>
|
||||
</v-col>
|
||||
<v-col></v-col>
|
||||
<v-col align="end"> </v-col>
|
||||
</v-row>
|
||||
<v-rating
|
||||
class="mr-2"
|
||||
color="secondary"
|
||||
background-color="secondary lighten-3"
|
||||
dense
|
||||
length="5"
|
||||
size="15"
|
||||
:value="rating"
|
||||
></v-rating>
|
||||
<v-spacer></v-spacer>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-hover>
|
||||
@ -55,6 +50,7 @@ export default {
|
||||
description: String,
|
||||
rating: Number,
|
||||
image: String,
|
||||
|
||||
route: {
|
||||
default: true,
|
||||
},
|
||||
|
@ -83,14 +83,16 @@
|
||||
:key="generateKey('ingredient', index)"
|
||||
>
|
||||
<v-row align="center">
|
||||
<v-text-field
|
||||
<v-textarea
|
||||
class="mr-2"
|
||||
:label="$t('recipe.ingredient')"
|
||||
v-model="value.recipeIngredient[index]"
|
||||
append-outer-icon="mdi-menu"
|
||||
mdi-move-resize
|
||||
auto-grow
|
||||
solo
|
||||
dense
|
||||
rows="2"
|
||||
>
|
||||
<v-icon
|
||||
class="mr-n1"
|
||||
@ -100,7 +102,7 @@
|
||||
>
|
||||
mdi-delete
|
||||
</v-icon>
|
||||
</v-text-field>
|
||||
</v-textarea>
|
||||
</v-row>
|
||||
</div>
|
||||
</transition-group>
|
||||
@ -235,6 +237,7 @@
|
||||
dense
|
||||
v-model="value.recipeInstructions[index]['text']"
|
||||
:key="generateKey('instructions', index)"
|
||||
rows="4"
|
||||
>
|
||||
</v-textarea>
|
||||
</v-card-text>
|
||||
|
@ -1,27 +1,52 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2 class="mb-4">{{ $t("recipe.ingredients") }}</h2>
|
||||
<div
|
||||
v-for="(ingredient, index) in ingredients"
|
||||
<v-list-item
|
||||
dense
|
||||
v-for="(ingredient, index) in displayIngredients"
|
||||
:key="generateKey('ingredient', index)"
|
||||
@click="ingredient.checked = !ingredient.checked"
|
||||
>
|
||||
<v-checkbox
|
||||
hide-details
|
||||
class="ingredients"
|
||||
:label="ingredient"
|
||||
v-model="ingredient.checked"
|
||||
class=" pt-0 ingredients my-auto py-auto"
|
||||
color="secondary"
|
||||
>
|
||||
</v-checkbox>
|
||||
</div>
|
||||
|
||||
<v-list-item-content>
|
||||
<vue-markdown
|
||||
class="my-auto text-subtitle-1 mb-0"
|
||||
:source="ingredient.text"
|
||||
>
|
||||
</vue-markdown>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VueMarkdown from "@adapttive/vue-markdown";
|
||||
import utils from "@/utils";
|
||||
export default {
|
||||
components: {
|
||||
VueMarkdown,
|
||||
},
|
||||
props: {
|
||||
ingredients: Array,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
displayIngredients: [],
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.displayIngredients = this.ingredients.map(x => ({
|
||||
text: x,
|
||||
checked: false,
|
||||
}));
|
||||
},
|
||||
methods: {
|
||||
generateKey(item, index) {
|
||||
return utils.generateUniqueKey(item, index);
|
||||
@ -31,4 +56,11 @@ export default {
|
||||
</script>
|
||||
|
||||
<style>
|
||||
p {
|
||||
margin-bottom: auto !important;
|
||||
}
|
||||
|
||||
.my-card-text {
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
</style>
|
@ -2,12 +2,12 @@
|
||||
<div v-if="items && items.length > 0">
|
||||
<h2 class="mt-4">{{ title }}</h2>
|
||||
<v-chip
|
||||
:to="`/recipes/${getSlug(category)}`"
|
||||
label
|
||||
class="ma-1"
|
||||
color="accent"
|
||||
dark
|
||||
v-for="category in items"
|
||||
:to="`/recipes/${urlParam}/${getSlug(category)}`"
|
||||
:key="category"
|
||||
>
|
||||
{{ category }}
|
||||
@ -20,7 +20,7 @@ export default {
|
||||
props: {
|
||||
items: Array,
|
||||
title: String,
|
||||
category: {
|
||||
isCategory: {
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
@ -28,11 +28,23 @@ export default {
|
||||
allCategories() {
|
||||
return this.$store.getters.getAllCategories;
|
||||
},
|
||||
allTags() {
|
||||
return this.$store.getters.getAllTags;
|
||||
},
|
||||
urlParam() {
|
||||
return this.isCategory ? 'category' : 'tag'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getSlug(name) {
|
||||
if (this.category) {
|
||||
return this.allCategories.filter(x => x.name == name)[0].slug;
|
||||
if (!name) return;
|
||||
|
||||
if (this.isCategory) {
|
||||
const matches = this.allCategories.filter(x => x.name == name);
|
||||
if (matches.length > 0) return matches[0].slug;
|
||||
} else {
|
||||
const matches = this.allTags.filter(x => x.name == name);
|
||||
if (matches.length > 0) return matches[0].slug;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
@ -34,7 +34,11 @@
|
||||
<Ingredients :ingredients="ingredients" />
|
||||
<div v-if="medium">
|
||||
<RecipeChips :title="$t('recipe.categories')" :items="categories" />
|
||||
<RecipeChips :title="$t('recipe.tags')" :items="tags" />
|
||||
<RecipeChips
|
||||
:title="$t('recipe.tags')"
|
||||
:items="tags"
|
||||
:isCategory="false"
|
||||
/>
|
||||
<Notes :notes="notes" />
|
||||
</div>
|
||||
</v-col>
|
||||
|
@ -154,7 +154,6 @@ export default {
|
||||
return utils.getImageURL(image);
|
||||
},
|
||||
selected(slug, name) {
|
||||
console.log("Selected", slug, name);
|
||||
this.$emit("selected", slug, name);
|
||||
},
|
||||
async onFocus() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="text-center">
|
||||
<v-dialog v-model="dialog" width="600px" height="0">
|
||||
<div class="text-center ">
|
||||
<v-dialog v-model="dialog" class="search-dialog" width="600px" height="0">
|
||||
<v-card>
|
||||
<v-app-bar dark color="primary">
|
||||
<v-toolbar-title class="headline">Search a Recipe</v-toolbar-title>
|
||||
@ -49,8 +49,8 @@ export default {
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.v-dialog__content {
|
||||
<style scope>
|
||||
.search-dialog {
|
||||
margin-top: 10%;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
|
@ -36,7 +36,6 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
siteSettings() {
|
||||
console.log(this.$store.getters.getSiteSettings);
|
||||
return this.$store.getters.getSiteSettings;
|
||||
},
|
||||
recentRecipes() {
|
||||
@ -54,7 +53,6 @@ export default {
|
||||
this.siteSettings.categories.forEach(async element => {
|
||||
let recipes = await this.getRecipeByCategory(element.slug);
|
||||
if (recipes.recipes.length < 0) recipes.recipes = [];
|
||||
console.log(recipes);
|
||||
this.recipeByCategory.push(recipes);
|
||||
});
|
||||
},
|
||||
|
60
frontend/src/pages/Recipes/TagPage.vue
Normal file
60
frontend/src/pages/Recipes/TagPage.vue
Normal file
@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<v-container>
|
||||
<CategorySidebar />
|
||||
<CardSection
|
||||
:sortable="true"
|
||||
:title="title"
|
||||
:recipes="recipes"
|
||||
:card-limit="9999"
|
||||
@sort="sortAZ"
|
||||
@sort-recent="sortRecent"
|
||||
/>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { api } from "@/api";
|
||||
import CardSection from "@/components/UI/CardSection";
|
||||
import CategorySidebar from "@/components/UI/CategorySidebar";
|
||||
export default {
|
||||
components: {
|
||||
CardSection,
|
||||
CategorySidebar,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
title: "",
|
||||
recipes: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
currentTag() {
|
||||
return this.$route.params.tag;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
async currentCategory() {
|
||||
this.getRecipes();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getRecipes();
|
||||
},
|
||||
methods: {
|
||||
async getRecipes() {
|
||||
let data = await api.tags.getRecipesInTag(this.currentTag);
|
||||
this.title = data.name;
|
||||
this.recipes = data.recipes;
|
||||
},
|
||||
sortAZ() {
|
||||
this.recipes.sort((a, b) => (a.name > b.name ? 1 : -1));
|
||||
},
|
||||
sortRecent() {
|
||||
this.recipes.sort((a, b) => (a.dateAdded > b.dateAdded ? -1 : 1));
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
@ -6,6 +6,7 @@ import NewRecipe from "@/pages/Recipe/NewRecipe";
|
||||
import CustomPage from "@/pages/Recipes/CustomPage";
|
||||
import AllRecipes from "@/pages/Recipes/AllRecipes";
|
||||
import CategoryPage from "@/pages/Recipes/CategoryPage";
|
||||
import TagPage from "@/pages/Recipes/TagPage";
|
||||
import Planner from "@/pages/MealPlan/Planner";
|
||||
import Debug from "@/pages/Debug";
|
||||
import LoginPage from "@/pages/LoginPage";
|
||||
@ -33,7 +34,8 @@ export const routes = [
|
||||
{ path: "/search", component: SearchPage },
|
||||
{ path: "/recipes/all", component: AllRecipes },
|
||||
{ path: "/pages/:customPage", component: CustomPage },
|
||||
{ path: "/recipes/:category", component: CategoryPage },
|
||||
{ path: "/recipes/tag/:tag", component: TagPage },
|
||||
{ path: "/recipes/category/:category", component: CategoryPage },
|
||||
{ path: "/recipe/:recipe", component: ViewRecipe },
|
||||
{ path: "/new/", component: NewRecipe },
|
||||
{ path: "/meal-plan/planner", component: Planner },
|
||||
|
@ -2,6 +2,7 @@ from fastapi import APIRouter, Depends
|
||||
from mealie.db.database import db
|
||||
from mealie.db.db_setup import generate_session
|
||||
from mealie.routes.deps import get_current_user
|
||||
from mealie.schema.category import RecipeTagResponse
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
@ -19,7 +20,7 @@ async def get_all_recipe_tags(session: Session = Depends(generate_session)):
|
||||
return db.tags.get_all_limit_columns(session, ["slug", "name"])
|
||||
|
||||
|
||||
@router.get("/{tag}")
|
||||
@router.get("/{tag}", response_model=RecipeTagResponse)
|
||||
def get_all_recipes_by_tag(tag: str, session: Session = Depends(generate_session)):
|
||||
""" Returns a list of recipes associated with the provided tag. """
|
||||
return db.tags.get(session, tag)
|
||||
|
@ -27,5 +27,5 @@ class TagBase(CategoryBase):
|
||||
pass
|
||||
|
||||
|
||||
class RecipeTagResponse(TagBase):
|
||||
class RecipeTagResponse(RecipeCategoryResponse):
|
||||
pass
|
||||
|
Loading…
x
Reference in New Issue
Block a user