mirror of
https://github.com/mealie-recipes/mealie.git
synced 2026-02-26 17:53:12 -05:00
v0.4.1 - Frontend/UI Improvements (#267)
* fix links * actually fix #238 * Feature/mkdocs version bump (#240) * fix links (#239) Co-authored-by: hay-kot <hay-kot@pm.me> * fix #238 * bump mkdocs version * light/dark toggle * light/dark mode css * API_DOCS defaults to True * disable build on push for master Co-authored-by: hay-kot <hay-kot@pm.me> * 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> * changelog v0.4.1 * bug/backup-download (#245) * fix blocked download * + download blocked Co-authored-by: hay-kot <hay-kot@pm.me> * Feature/meal planner (#246) * fixes duplicate recipes in meal-plan #221 * add quick week option * scope css * add mealplanner info Co-authored-by: hay-kot <hay-kot@pm.me> * Nextcloud Import Bugs - #248 (#250) * parses datetime properly + clean category - #248 * add default credentials to docs Co-authored-by: hay-kot <hay-kot@pm.me> * Add bulk import examples to docs. (#252) * Add bulk import examples to docs. * Update api-usage.md * Add Python example for bulk import. * Change IP address in API example. * Refactor/app settings (#251) * fix env setup bugs * remove unused import * fix layout issues * changelog Co-authored-by: hay-kot <hay-kot@pm.me> * env setup fixes * Feature/about api (#253) * fix settings * app info cleanup Co-authored-by: hay-kot <hay-kot@pm.me> * Feature/image minify (#256) * fix settings * app info cleanup * bottom-bar experiment * remove dup key * type hints * add dependency * updated image with query parameters * read image options * add image minification * add image minification step * alt image routes * add image minification * set mobile bar to top Co-authored-by: hay-kot <hay-kot@pm.me> * Feature/additional endpoints (#257) * new recipe summary route * add categories to cards * add pillow * show tags instead of categories * additional debug info * add todays meal image url * about page * fix reactive tag * changelog + docs * bump version Co-authored-by: hay-kot <hay-kot@pm.me> * add pillow dependencies (#258) Co-authored-by: hay-kot <hay-kot@pm.me> * Feature/search page (#259) * add pillow dependencies * advanced search page * advanced search apge * remove extra dependencies * add pre-run script Co-authored-by: hay-kot <hay-kot@pm.me> * no image assignment * advanced search * fix docker dev build * Do not force theme settings on login form (#260) * Fix docker dev db persistence (#264) * Fix docker dev db persistence * Make run.sh the only startup script for prod + dev Credits to @hay-kot for run.sh script logic * Restore dev backend initialization in non-docker setup * Make run.sh POSIX-friendly * Allow dev backend to auto-reload in Docker * Frontend Refactor + Bug Fixes * merge category and tag selector * unifiy category selector * add hint * spacing * fix nextcloud migration * simplify email validator #261 * formatting * cleanup * auto-gen * format * update run script * unified category/tag selector * rename component * Add advanced search link * remove old code * convert keywords to tags * add proper behavior on rename * proper image name association on rename * fix test cleanup * changelog * set docker comppand * minify on migration Co-authored-by: hay-kot <hay-kot@pm.me> * bug-fixes/category-tag-creator (#266) * fix category labels * set loader for migration * v0.4.1 Co-authored-by: hay-kot <hay-kot@pm.me> Co-authored-by: hay-kot <hay-kot@pm.me> Co-authored-by: Nat <nathanynath@yahoo.fr> Co-authored-by: sephrat <34862846+sephrat@users.noreply.github.com>
This commit is contained in:
91
frontend/src/pages/Admin/About/index.vue
Normal file
91
frontend/src/pages/Admin/About/index.vue
Normal file
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-card class="mt-3">
|
||||
<v-card-title class="headline">
|
||||
About Mealie
|
||||
</v-card-title>
|
||||
<v-divider></v-divider>
|
||||
<v-card-text>
|
||||
<v-list-item-group color="primary">
|
||||
<v-list-item v-for="property in prettyInfo" :key="property.name">
|
||||
<v-list-item-icon>
|
||||
<v-icon> {{ property.icon || "mdi-account" }} </v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="pl-4 flex row justify-space-between">
|
||||
<div>{{ property.name }}</div>
|
||||
<div>{{ property.value }}</div>
|
||||
</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list-item-group>
|
||||
</v-card-text>
|
||||
<v-divider></v-divider>
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { api } from "@/api";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
prettyInfo: [],
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
await this.getInfo();
|
||||
},
|
||||
methods: {
|
||||
async getInfo() {
|
||||
const debugInfo = await api.meta.getDebugInfo();
|
||||
|
||||
this.prettyInfo = [
|
||||
{
|
||||
name: "Version",
|
||||
icon: "mdi-information",
|
||||
value: debugInfo.version,
|
||||
},
|
||||
{
|
||||
name: "Application Mode",
|
||||
icon: "mdi-dev-to",
|
||||
value: debugInfo.production ? "Production" : "Development",
|
||||
},
|
||||
{
|
||||
name: "Demo Status",
|
||||
icon: "mdi-test-tube",
|
||||
value: debugInfo.demoStatus ? "Demo" : "Not Demo",
|
||||
},
|
||||
{
|
||||
name: "API Port",
|
||||
icon: "mdi-api",
|
||||
value: debugInfo.apiPort,
|
||||
},
|
||||
{
|
||||
name: "API Docs",
|
||||
icon: "mdi-file-document",
|
||||
value: debugInfo.apiDocs ? "Enabled" : "Disabled",
|
||||
},
|
||||
{
|
||||
name: "Database Type",
|
||||
icon: "mdi-database",
|
||||
value: debugInfo.dbType,
|
||||
},
|
||||
{
|
||||
name: "SQLite File",
|
||||
icon: "mdi-file-cabinet",
|
||||
value: debugInfo.sqliteFile,
|
||||
},
|
||||
{
|
||||
name: "Default Group",
|
||||
icon: "mdi-account-group",
|
||||
value: debugInfo.defaultGroup,
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
@@ -7,41 +7,19 @@
|
||||
<v-card-text>
|
||||
<h2 class="mt-1">{{ $t("recipe.categories") }}</h2>
|
||||
|
||||
<v-row>
|
||||
<v-col sm="12" md="6">
|
||||
<v-select
|
||||
outlined
|
||||
:flat="isFlat"
|
||||
elavation="0"
|
||||
v-model="groupSettings.categories"
|
||||
:items="categories"
|
||||
item-text="name"
|
||||
return-object
|
||||
multiple
|
||||
chips
|
||||
:hint="
|
||||
$t(
|
||||
'meal-plan.only-recipes-with-these-categories-will-be-used-in-meal-plans'
|
||||
)
|
||||
"
|
||||
class="mt-2"
|
||||
persistent-hint
|
||||
>
|
||||
<template v-slot:selection="data">
|
||||
<v-chip
|
||||
outlined
|
||||
:input-value="data.selected"
|
||||
close
|
||||
@click:close="removeCategory(data.index)"
|
||||
color="secondary"
|
||||
dark
|
||||
>
|
||||
{{ data.item.name }}
|
||||
</v-chip>
|
||||
</template>
|
||||
</v-select>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<CategoryTagSelector
|
||||
class="mt-4"
|
||||
:solo="true"
|
||||
:dense="false"
|
||||
v-model="groupSettings.categories"
|
||||
:return-object="true"
|
||||
:show-add="true"
|
||||
:hint="
|
||||
$t(
|
||||
'meal-plan.only-recipes-with-these-categories-will-be-used-in-meal-plans'
|
||||
)
|
||||
"
|
||||
/>
|
||||
</v-card-text>
|
||||
<v-divider> </v-divider>
|
||||
<v-card-text>
|
||||
@@ -57,28 +35,23 @@
|
||||
<strong>{{ groupSettings.webhookTime }}</strong>
|
||||
</p>
|
||||
|
||||
<v-row dense align="center">
|
||||
<v-col cols="12" md="2" sm="5">
|
||||
<v-switch
|
||||
v-model="groupSettings.webhookEnable"
|
||||
:label="$t('general.enabled')"
|
||||
></v-switch>
|
||||
</v-col>
|
||||
<v-col cols="12" md="3" sm="5">
|
||||
<TimePickerDialog @save-time="saveTime" />
|
||||
</v-col>
|
||||
<v-col cols="12" md="4" sm="5">
|
||||
<v-btn text color="info" @click="testWebhooks">
|
||||
<v-icon left> mdi-webhook </v-icon>
|
||||
{{ $t("settings.webhooks.test-webhooks") }}
|
||||
</v-btn>
|
||||
</v-col>
|
||||
<v-row dense class="flex align-center">
|
||||
<v-switch
|
||||
class="mx-2"
|
||||
v-model="groupSettings.webhookEnable"
|
||||
:label="$t('general.enabled')"
|
||||
></v-switch>
|
||||
<TimePickerDialog @save-time="saveTime" class="ma-2" />
|
||||
<v-btn class="ma-2" color="info" @click="testWebhooks">
|
||||
<v-icon left> mdi-webhook </v-icon>
|
||||
{{ $t("settings.webhooks.test-webhooks") }}
|
||||
</v-btn>
|
||||
</v-row>
|
||||
|
||||
<v-row
|
||||
v-for="(url, index) in groupSettings.webhookUrls"
|
||||
:key="index"
|
||||
align="center"
|
||||
align=" center"
|
||||
dense
|
||||
>
|
||||
<v-col cols="1">
|
||||
@@ -110,9 +83,11 @@
|
||||
<script>
|
||||
import { api } from "@/api";
|
||||
import TimePickerDialog from "@/components/Admin/MealPlanner/TimePickerDialog";
|
||||
import CategoryTagSelector from "@/components/FormHelpers/CategoryTagSelector";
|
||||
export default {
|
||||
components: {
|
||||
TimePickerDialog,
|
||||
CategoryTagSelector,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -160,6 +135,7 @@ export default {
|
||||
this.groupSettings.webhookUrls.splice(index, 1);
|
||||
},
|
||||
async saveGroupSettings() {
|
||||
console.log(this.groupSettings);
|
||||
await api.groups.update(this.groupSettings);
|
||||
await this.$store.dispatch("requestCurrentGroup");
|
||||
this.getSiteSettings();
|
||||
@@ -167,9 +143,6 @@ export default {
|
||||
testWebhooks() {
|
||||
api.settings.testWebhooks();
|
||||
},
|
||||
removeCategory(index) {
|
||||
this.groupSettings.categories.splice(index, 1);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -117,7 +117,7 @@ export default {
|
||||
return utils.getDateAsTextAlt(dateObject);
|
||||
},
|
||||
getImage(image) {
|
||||
return utils.getImageURL(image);
|
||||
return api.recipes.recipeTinyImage(image);
|
||||
},
|
||||
|
||||
editPlan(id) {
|
||||
|
||||
@@ -52,7 +52,6 @@
|
||||
|
||||
<script>
|
||||
import { api } from "@/api";
|
||||
import utils from "@/utils";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@@ -68,7 +67,7 @@ export default {
|
||||
else return 0;
|
||||
},
|
||||
getImage(image) {
|
||||
return utils.getImageURL(image);
|
||||
return api.recipes.recipeImage(image);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<v-card v-else id="myRecipe">
|
||||
<v-img
|
||||
height="400"
|
||||
:src="getImage(recipeDetails.image)"
|
||||
:src="getImage(recipeDetails.slug)"
|
||||
class="d-print-none"
|
||||
:key="imageKey"
|
||||
>
|
||||
@@ -71,7 +71,6 @@
|
||||
|
||||
<script>
|
||||
import { api } from "@/api";
|
||||
import utils from "@/utils";
|
||||
import VJsoneditor from "v-jsoneditor";
|
||||
import RecipeViewer from "@/components/Recipe/RecipeViewer";
|
||||
import RecipeEditor from "@/components/Recipe/RecipeEditor";
|
||||
@@ -160,7 +159,7 @@ export default {
|
||||
},
|
||||
getImage(image) {
|
||||
if (image) {
|
||||
return utils.getImageURL(image) + "?rnd=" + this.imageKey;
|
||||
return api.recipes.recipeImage(image) + "&rnd=" + this.imageKey;
|
||||
}
|
||||
},
|
||||
deleteRecipe() {
|
||||
|
||||
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 currentTag() {
|
||||
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>
|
||||
@@ -1,58 +0,0 @@
|
||||
<template>
|
||||
<v-container>
|
||||
<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
|
||||
:name="item.item.name"
|
||||
:description="item.item.description"
|
||||
:slug="item.item.slug"
|
||||
:rating="item.item.rating"
|
||||
:image="item.item.image"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SearchBar from "../components/UI/Search/SearchBar";
|
||||
import RecipeCard from "../components/Recipe/RecipeCard";
|
||||
export default {
|
||||
components: {
|
||||
SearchBar,
|
||||
RecipeCard,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchResults: [],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
updateResults(results) {
|
||||
this.searchResults = results;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
69
frontend/src/pages/SearchPage/FilterSelector.vue
Normal file
69
frontend/src/pages/SearchPage/FilterSelector.vue
Normal file
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<v-toolbar dense flat>
|
||||
<v-btn-toggle
|
||||
dense
|
||||
v-model="selected"
|
||||
tile
|
||||
color="primary accent-3"
|
||||
@change="emitMulti"
|
||||
group
|
||||
mandatory
|
||||
>
|
||||
<v-btn :value="false">
|
||||
Include
|
||||
</v-btn>
|
||||
|
||||
<v-btn :value="true">
|
||||
Exclude
|
||||
</v-btn>
|
||||
</v-btn-toggle>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn-toggle
|
||||
dense
|
||||
v-model="match"
|
||||
tile
|
||||
color="primary accent-3"
|
||||
@change="emitMulti"
|
||||
group
|
||||
mandatory
|
||||
>
|
||||
<v-btn :value="false">
|
||||
And
|
||||
</v-btn>
|
||||
<v-btn :value="true">
|
||||
Or
|
||||
</v-btn>
|
||||
</v-btn-toggle>
|
||||
</v-toolbar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
default: "include", // Optionas: "include", "exclude", "any"
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selected: false,
|
||||
match: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
emitChange() {
|
||||
this.$emit("input", this.selected);
|
||||
},
|
||||
emitMulti() {
|
||||
const updateData = {
|
||||
exclude: this.selected,
|
||||
matchAny: this.match,
|
||||
};
|
||||
this.$emit("update", updateData);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
178
frontend/src/pages/SearchPage/index.vue
Normal file
178
frontend/src/pages/SearchPage/index.vue
Normal file
@@ -0,0 +1,178 @@
|
||||
<template>
|
||||
<v-container>
|
||||
<CategorySidebar />
|
||||
<v-card flat>
|
||||
<v-row dense>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
v-model="searchString"
|
||||
outlined
|
||||
color="primary accent-3"
|
||||
placeholder="Placeholder"
|
||||
append-icon="mdi-magnify"
|
||||
>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" md="2" sm="12">
|
||||
<v-text-field
|
||||
class="mt-0 pt-0"
|
||||
label="Max Results"
|
||||
v-model="maxResults"
|
||||
type="number"
|
||||
outlined
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row dense class="mt-0 flex-row align-center justify-space-around">
|
||||
<v-col>
|
||||
<h3 class="pl-2 text-center headline">Category Filter</h3>
|
||||
<FilterSelector class="mb-1" @update="updateCatParams" />
|
||||
<CategoryTagSelector
|
||||
:solo="true"
|
||||
:dense="false"
|
||||
v-model="includeCategories"
|
||||
:return-object="false"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<h3 class="pl-2 text-center headline">Tag Filter</h3>
|
||||
<FilterSelector class="mb-1" @update="updateTagParams" />
|
||||
|
||||
<CategoryTagSelector
|
||||
:solo="true"
|
||||
:dense="false"
|
||||
v-model="includeTags"
|
||||
:return-object="false"
|
||||
:tag-selector="true"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row v-if="fuzzyRecipes">
|
||||
<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-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Fuse from "fuse.js";
|
||||
import RecipeCard from "@/components/Recipe/RecipeCard";
|
||||
import CategorySidebar from "@/components/UI/CategorySidebar";
|
||||
import CategoryTagSelector from "@/components/FormHelpers/CategoryTagSelector";
|
||||
import FilterSelector from "./FilterSelector.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
RecipeCard,
|
||||
CategorySidebar,
|
||||
CategoryTagSelector,
|
||||
FilterSelector,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchString: "",
|
||||
maxResults: 21,
|
||||
searchResults: [],
|
||||
catFilter: {
|
||||
exclude: false,
|
||||
matchAny: false,
|
||||
},
|
||||
tagFilter: {
|
||||
exclude: false,
|
||||
matchAny: false,
|
||||
},
|
||||
includeCategories: [],
|
||||
includeTags: [],
|
||||
options: {
|
||||
shouldSort: true,
|
||||
threshold: 0.6,
|
||||
location: 0,
|
||||
distance: 100,
|
||||
findAllMatches: true,
|
||||
maxPatternLength: 32,
|
||||
minMatchCharLength: 2,
|
||||
keys: ["name", "description"],
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
allRecipes() {
|
||||
return this.$store.getters.getRecentRecipes;
|
||||
},
|
||||
filteredRecipes() {
|
||||
return this.allRecipes.filter(recipe => {
|
||||
const includesTags = this.check(
|
||||
this.includeTags,
|
||||
recipe.tags,
|
||||
this.tagFilter.matchAny,
|
||||
this.tagFilter.exclude
|
||||
);
|
||||
const includesCats = this.check(
|
||||
this.includeCategories,
|
||||
recipe.recipeCategory,
|
||||
this.catFilter.matchAny,
|
||||
this.catFilter.exclude
|
||||
);
|
||||
return [includesTags, includesCats].every(x => x === true);
|
||||
});
|
||||
},
|
||||
fuse() {
|
||||
return new Fuse(this.filteredRecipes, this.options);
|
||||
},
|
||||
fuzzyRecipes() {
|
||||
if (this.searchString.trim() === "") {
|
||||
return this.filteredRecipes.map(x => ({ item: x }));
|
||||
}
|
||||
const result = this.fuse.search(this.searchString.trim());
|
||||
return result;
|
||||
},
|
||||
isSearching() {
|
||||
return this.searchString && this.searchString.length > 0;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
check(filterBy, recipeList, matchAny, exclude) {
|
||||
let isMatch = true;
|
||||
if (filterBy.length === 0) return isMatch;
|
||||
|
||||
if (recipeList) {
|
||||
if (matchAny) {
|
||||
isMatch = filterBy.some(t => recipeList.includes(t)); // Checks if some items are a match
|
||||
} else {
|
||||
isMatch = filterBy.every(t => recipeList.includes(t)); // Checks if every items is a match
|
||||
}
|
||||
return exclude ? !isMatch : isMatch;
|
||||
} else;
|
||||
return false;
|
||||
},
|
||||
|
||||
updateTagParams(params) {
|
||||
this.tagFilter = params;
|
||||
},
|
||||
updateCatParams(params) {
|
||||
this.catFilter = params;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
Reference in New Issue
Block a user