mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-22 22:43:34 -07:00
add toolbars tools to recipe sections
This commit is contained in:
parent
1018ed28fd
commit
697fa16010
17 changed files with 132 additions and 46 deletions
|
@ -1,7 +1,7 @@
|
||||||
const baseURL = "/api/";
|
const baseURL = "/api/";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { store } from "../store";
|
import { store } from "../store";
|
||||||
import utils from "@/utils";
|
import { utils } from "@/utils";
|
||||||
|
|
||||||
axios.defaults.headers.common["Authorization"] = `Bearer ${store.getters.getToken}`;
|
axios.defaults.headers.common["Authorization"] = `Bearer ${store.getters.getToken}`;
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { api } from "@/api";
|
import { api } from "@/api";
|
||||||
import utils from "@/utils";
|
import { utils } from "@/utils";
|
||||||
import MealPlanCard from "./MealPlanCard";
|
import MealPlanCard from "./MealPlanCard";
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -82,7 +82,7 @@
|
||||||
const CREATE_EVENT = "created";
|
const CREATE_EVENT = "created";
|
||||||
import DatePicker from "@/components/FormHelpers/DatePicker";
|
import DatePicker from "@/components/FormHelpers/DatePicker";
|
||||||
import { api } from "@/api";
|
import { api } from "@/api";
|
||||||
import utils from "@/utils";
|
import { utils } from "@/utils";
|
||||||
import MealPlanCard from "./MealPlanCard";
|
import MealPlanCard from "./MealPlanCard";
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
import BulkAdd from "@/components/Recipe/Parts/Helpers/BulkAdd";
|
import BulkAdd from "@/components/Recipe/Parts/Helpers/BulkAdd";
|
||||||
import VueMarkdown from "@adapttive/vue-markdown";
|
import VueMarkdown from "@adapttive/vue-markdown";
|
||||||
import draggable from "vuedraggable";
|
import draggable from "vuedraggable";
|
||||||
import utils from "@/utils";
|
import { utils } from "@/utils";
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
BulkAdd,
|
BulkAdd,
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import VueMarkdown from "@adapttive/vue-markdown";
|
import VueMarkdown from "@adapttive/vue-markdown";
|
||||||
import utils from "@/utils";
|
import { utils } from "@/utils";
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
VueMarkdown,
|
VueMarkdown,
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import VueMarkdown from "@adapttive/vue-markdown";
|
import VueMarkdown from "@adapttive/vue-markdown";
|
||||||
import utils from "@/utils";
|
import { utils } from "@/utils";
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
VueMarkdown,
|
VueMarkdown,
|
||||||
|
|
|
@ -124,7 +124,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import utils from "@/utils";
|
import { utils } from "@/utils";
|
||||||
import { api } from "@/api";
|
import { api } from "@/api";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
|
@ -88,7 +88,7 @@
|
||||||
<script>
|
<script>
|
||||||
import Nutrition from "@/components/Recipe/Parts/Nutrition";
|
import Nutrition from "@/components/Recipe/Parts/Nutrition";
|
||||||
import VueMarkdown from "@adapttive/vue-markdown";
|
import VueMarkdown from "@adapttive/vue-markdown";
|
||||||
import utils from "@/utils";
|
import { utils } from "@/utils";
|
||||||
import RecipeChips from "./RecipeChips";
|
import RecipeChips from "./RecipeChips";
|
||||||
import Rating from "@/components/Recipe/Parts/Rating";
|
import Rating from "@/components/Recipe/Parts/Rating";
|
||||||
import Notes from "@/components/Recipe/Parts/Notes";
|
import Notes from "@/components/Recipe/Parts/Notes";
|
||||||
|
|
|
@ -6,21 +6,28 @@
|
||||||
</v-icon>
|
</v-icon>
|
||||||
<v-toolbar-title class="headline"> {{ title }} </v-toolbar-title>
|
<v-toolbar-title class="headline"> {{ title }} </v-toolbar-title>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer></v-spacer>
|
||||||
<v-menu offset-y v-if="$listeners.sortRecent || $listeners.sort">
|
<v-btn text @click="navigateRandom">
|
||||||
|
Random
|
||||||
|
</v-btn>
|
||||||
|
<v-menu offset-y v-if="$listeners.sort">
|
||||||
<template v-slot:activator="{ on, attrs }">
|
<template v-slot:activator="{ on, attrs }">
|
||||||
<v-btn-toggle group>
|
<v-btn text v-bind="attrs" v-on="on">
|
||||||
<v-btn text v-bind="attrs" v-on="on">
|
{{ $t("general.sort") }}
|
||||||
{{ $t("general.sort") }}
|
</v-btn>
|
||||||
</v-btn>
|
|
||||||
</v-btn-toggle>
|
|
||||||
</template>
|
</template>
|
||||||
<v-list>
|
<v-list>
|
||||||
<v-list-item @click="$emit('sortRecent')">
|
<v-list-item @click="sortRecipes(EVENTS.az)">
|
||||||
<v-list-item-title>{{ $t("general.recent") }}</v-list-item-title>
|
|
||||||
</v-list-item>
|
|
||||||
<v-list-item @click="$emit('sort')">
|
|
||||||
<v-list-item-title>{{ $t("general.sort-alphabetically") }}</v-list-item-title>
|
<v-list-item-title>{{ $t("general.sort-alphabetically") }}</v-list-item-title>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
<v-list-item @click="sortRecipes(EVENTS.rating)">
|
||||||
|
<v-list-item-title>{{ $t("general.rating") }}</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item @click="sortRecipes(EVENTS.updated)">
|
||||||
|
<v-list-item-title>{{ $t("general.updated") }}</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item @click="sortRecipes(EVENTS.created)">
|
||||||
|
<v-list-item-title>{{ $t("general.created") }}</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
</v-menu>
|
</v-menu>
|
||||||
</v-app-bar>
|
</v-app-bar>
|
||||||
|
@ -76,6 +83,9 @@
|
||||||
<script>
|
<script>
|
||||||
import RecipeCard from "../Recipe/RecipeCard";
|
import RecipeCard from "../Recipe/RecipeCard";
|
||||||
import MobileRecipeCard from "@/components/Recipe/MobileRecipeCard";
|
import MobileRecipeCard from "@/components/Recipe/MobileRecipeCard";
|
||||||
|
import { utils } from "@/utils";
|
||||||
|
const SORT_EVENT = "sort";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
RecipeCard,
|
RecipeCard,
|
||||||
|
@ -106,6 +116,12 @@ export default {
|
||||||
return {
|
return {
|
||||||
cardLimit: 30,
|
cardLimit: 30,
|
||||||
loading: false,
|
loading: false,
|
||||||
|
EVENTS: {
|
||||||
|
az: "az",
|
||||||
|
rating: "rating",
|
||||||
|
created: "created",
|
||||||
|
updated: "updated",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -144,6 +160,31 @@ export default {
|
||||||
await new Promise(r => setTimeout(r, 1000));
|
await new Promise(r => setTimeout(r, 1000));
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
},
|
},
|
||||||
|
navigateRandom() {
|
||||||
|
const recipe = utils.recipe.randomRecipe(this.recipes);
|
||||||
|
this.$router.push(`/recipe/${recipe.slug}`);
|
||||||
|
},
|
||||||
|
sortRecipes(sortType) {
|
||||||
|
let sortTarget = [...this.recipes];
|
||||||
|
switch (sortType) {
|
||||||
|
case this.EVENTS.az:
|
||||||
|
utils.recipe.sortAToZ(sortTarget);
|
||||||
|
break;
|
||||||
|
case this.EVENTS.rating:
|
||||||
|
utils.recipe.sortByRating(sortTarget);
|
||||||
|
break;
|
||||||
|
case this.EVENTS.created:
|
||||||
|
utils.recipe.sortByCreated(sortTarget);
|
||||||
|
break;
|
||||||
|
case this.EVENTS.updated:
|
||||||
|
utils.recipe.sortByUpdated(sortTarget);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.log("Unknown Event", sortType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$emit(SORT_EVENT, sortTarget);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
"confirm": "Confirm",
|
"confirm": "Confirm",
|
||||||
"create": "Create",
|
"create": "Create",
|
||||||
|
"created": "Created",
|
||||||
"current-parenthesis": "(Current)",
|
"current-parenthesis": "(Current)",
|
||||||
"dashboard": "Dashboard",
|
"dashboard": "Dashboard",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
|
@ -63,6 +64,7 @@
|
||||||
"no": "No",
|
"no": "No",
|
||||||
"ok": "OK",
|
"ok": "OK",
|
||||||
"options": "Options:",
|
"options": "Options:",
|
||||||
|
"rating": "Rating",
|
||||||
"random": "Random",
|
"random": "Random",
|
||||||
"recent": "Recent",
|
"recent": "Recent",
|
||||||
"recipes": "Recipes",
|
"recipes": "Recipes",
|
||||||
|
@ -83,6 +85,7 @@
|
||||||
"token": "Token",
|
"token": "Token",
|
||||||
"tuesday": "Tuesday",
|
"tuesday": "Tuesday",
|
||||||
"update": "Update",
|
"update": "Update",
|
||||||
|
"updated": "Updated",
|
||||||
"upload": "Upload",
|
"upload": "Upload",
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
"users": "Users",
|
"users": "Users",
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { api } from "@/api";
|
import { api } from "@/api";
|
||||||
import utils from "@/utils";
|
import { utils } from "@/utils";
|
||||||
import NewMeal from "@/components/MealPlan/MealPlanNew";
|
import NewMeal from "@/components/MealPlan/MealPlanNew";
|
||||||
import EditPlan from "@/components/MealPlan/MealPlanEditor";
|
import EditPlan from "@/components/MealPlan/MealPlanEditor";
|
||||||
import ShoppingListDialog from "@/components/MealPlan/ShoppingListDialog";
|
import ShoppingListDialog from "@/components/MealPlan/ShoppingListDialog";
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { api } from "@/api";
|
import { api } from "@/api";
|
||||||
import utils from "@/utils";
|
import { utils } from "@/utils";
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -5,9 +5,8 @@
|
||||||
title-icon=""
|
title-icon=""
|
||||||
:sortable="true"
|
:sortable="true"
|
||||||
:title="$t('page.all-recipes')"
|
:title="$t('page.all-recipes')"
|
||||||
:recipes="allRecipes"
|
:recipes="shownRecipes"
|
||||||
@sort="sortAZ"
|
@sort="assignSorted"
|
||||||
@sort-recent="sortRecent"
|
|
||||||
/>
|
/>
|
||||||
</v-container>
|
</v-container>
|
||||||
</template>
|
</template>
|
||||||
|
@ -22,6 +21,7 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
loading: false,
|
loading: false,
|
||||||
|
sortedResults: [],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
|
@ -35,13 +35,17 @@ export default {
|
||||||
allRecipes() {
|
allRecipes() {
|
||||||
return this.$store.getters.getAllRecipes;
|
return this.$store.getters.getAllRecipes;
|
||||||
},
|
},
|
||||||
|
shownRecipes() {
|
||||||
|
if (this.sortedResults.length > 0) {
|
||||||
|
return this.sortedResults;
|
||||||
|
} else {
|
||||||
|
return this.allRecipes;
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
sortAZ() {
|
assignSorted(val) {
|
||||||
this.allRecipes.sort((a, b) => (a.name > b.name ? 1 : -1));
|
this.sortedResults = val;
|
||||||
},
|
|
||||||
sortRecent() {
|
|
||||||
this.allRecipes.sort((a, b) => (a.dateAdded > b.dateAdded ? -1 : 1));
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -47,31 +47,20 @@
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
<v-row v-if="fuzzyRecipes">
|
<CardSection title-icon="mdi-mag" :recipes="showRecipes" :hardLimit="maxResults" @sort="assignFuzzy" />
|
||||||
<v-col :sm="6" :md="6" :lg="4" :xl="3" v-for="item in fuzzyRecipes.slice(0, maxResults)" :key="item.name">
|
|
||||||
<RecipeCard
|
|
||||||
:name="item.item.name"
|
|
||||||
:description="item.item.description"
|
|
||||||
:slug="item.item.slug"
|
|
||||||
:rating="item.item.rating"
|
|
||||||
:image="item.item.image"
|
|
||||||
:tags="item.item.tags"
|
|
||||||
/>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-container>
|
</v-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Fuse from "fuse.js";
|
import Fuse from "fuse.js";
|
||||||
import RecipeCard from "@/components/Recipe/RecipeCard";
|
|
||||||
import CategoryTagSelector from "@/components/FormHelpers/CategoryTagSelector";
|
import CategoryTagSelector from "@/components/FormHelpers/CategoryTagSelector";
|
||||||
|
import CardSection from "@/components/UI/CardSection";
|
||||||
import FilterSelector from "./FilterSelector.vue";
|
import FilterSelector from "./FilterSelector.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
RecipeCard,
|
CardSection,
|
||||||
CategoryTagSelector,
|
CategoryTagSelector,
|
||||||
FilterSelector,
|
FilterSelector,
|
||||||
},
|
},
|
||||||
|
@ -88,6 +77,7 @@ export default {
|
||||||
exclude: false,
|
exclude: false,
|
||||||
matchAny: false,
|
matchAny: false,
|
||||||
},
|
},
|
||||||
|
sortedResults: [],
|
||||||
includeCategories: [],
|
includeCategories: [],
|
||||||
includeTags: [],
|
includeTags: [],
|
||||||
options: {
|
options: {
|
||||||
|
@ -126,16 +116,31 @@ export default {
|
||||||
},
|
},
|
||||||
fuzzyRecipes() {
|
fuzzyRecipes() {
|
||||||
if (this.searchString.trim() === "") {
|
if (this.searchString.trim() === "") {
|
||||||
return this.filteredRecipes.map(x => ({ item: x }));
|
return this.filteredRecipes;
|
||||||
}
|
}
|
||||||
const result = this.fuse.search(this.searchString.trim());
|
const result = this.fuse.search(this.searchString.trim());
|
||||||
return result;
|
return result.map(x => x.item);
|
||||||
},
|
},
|
||||||
isSearching() {
|
isSearching() {
|
||||||
return this.searchString && this.searchString.length > 0;
|
return this.searchString && this.searchString.length > 0;
|
||||||
},
|
},
|
||||||
|
showRecipes() {
|
||||||
|
if (this.sortedResults.length > 0) {
|
||||||
|
return this.sortedResults;
|
||||||
|
} else {
|
||||||
|
return this.fuzzyRecipes;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
showRecipes(val) {
|
||||||
|
console.log(val);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
assignFuzzy(val) {
|
||||||
|
this.sortedResults = val;
|
||||||
|
},
|
||||||
check(filterBy, recipeList, matchAny, exclude) {
|
check(filterBy, recipeList, matchAny, exclude) {
|
||||||
let isMatch = true;
|
let isMatch = true;
|
||||||
if (filterBy.length === 0) return isMatch;
|
if (filterBy.length === 0) return isMatch;
|
||||||
|
|
|
@ -3,7 +3,7 @@ import ThisWeek from "@/pages/MealPlan/ThisWeek";
|
||||||
import { api } from "@/api";
|
import { api } from "@/api";
|
||||||
|
|
||||||
import i18n from "@/i18n.js";
|
import i18n from "@/i18n.js";
|
||||||
import utils from "@/utils";
|
import { utils } from "@/utils";
|
||||||
|
|
||||||
export const mealRoutes = [
|
export const mealRoutes = [
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { vueApp } from "../main";
|
import { vueApp } from "../main";
|
||||||
|
import { recipe } from "@/utils/recipe";
|
||||||
|
|
||||||
// TODO: Migrate to Mixins
|
// TODO: Migrate to Mixins
|
||||||
const notifyHelpers = {
|
const notifyHelpers = {
|
||||||
|
@ -9,7 +10,8 @@ const notifyHelpers = {
|
||||||
info: "notify-info-color",
|
info: "notify-info-color",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export const utils = {
|
||||||
|
recipe: recipe,
|
||||||
getImageURL(image) {
|
getImageURL(image) {
|
||||||
return `/api/recipes/${image}/image?image_type=small`;
|
return `/api/recipes/${image}/image?image_type=small`;
|
||||||
},
|
},
|
||||||
|
|
31
frontend/src/utils/recipe.js
Normal file
31
frontend/src/utils/recipe.js
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
export const recipe = {
|
||||||
|
/**
|
||||||
|
* Sorts a list of recipes in place
|
||||||
|
* @param {Array<Object>} list of recipes
|
||||||
|
* @param {Boolean} inverse - Z or A First
|
||||||
|
*/
|
||||||
|
sortAToZ(list) {
|
||||||
|
list.sort((a, b) => {
|
||||||
|
var textA = a.name.toUpperCase();
|
||||||
|
var textB = b.name.toUpperCase();
|
||||||
|
return textA < textB ? -1 : textA > textB ? 1 : 0;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
sortByCreated(list) {
|
||||||
|
list.sort((a, b) => (a.dateAdded > b.dateAdded ? -1 : 1));
|
||||||
|
},
|
||||||
|
sortUpdated(list) {
|
||||||
|
list.sort((a, b) => (a.dateUpdated > b.dateUpdated ? -1 : 1));
|
||||||
|
},
|
||||||
|
sortByRating(list) {
|
||||||
|
list.sort((a, b) => (a.rating > b.rating ? -1 : 1));
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Array<Object>} list
|
||||||
|
* @returns String / Recipe Slug
|
||||||
|
*/
|
||||||
|
randomRecipe(list) {
|
||||||
|
return list[Math.floor(Math.random() * list.length)];
|
||||||
|
},
|
||||||
|
};
|
Loading…
Add table
Add a link
Reference in a new issue