feature/category-tag-crud (#354)

* update tag route

* search.and

* offset for mobile

* relative imports

* get settings

* new page

* category/tag CRUD

* bulk assign frontend

* Bulk assign

* debounce search

* remove dev data

* recipe store refactor

* fix mobile view

* fix failing tests

* commit test data

Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
Hayden
2021-04-27 11:17:00 -08:00
committed by GitHub
parent f748bbba68
commit 846d1eda5b
40 changed files with 1028 additions and 145 deletions

View File

@@ -3,7 +3,8 @@
<v-card-title class=" headline">
{{ $t("meal-plan.create-a-new-meal-plan") }}
<v-btn color="info" class="ml-auto" @click="setQuickWeek()">
<v-icon left>mdi-calendar-minus</v-icon> {{$t('meal-plan.quick-week')}}
<v-icon left>mdi-calendar-minus</v-icon>
{{ $t("meal-plan.quick-week") }}
</v-btn>
</v-card-title>
@@ -153,7 +154,7 @@ export default {
return recipes.length > 0 ? recipes : this.items;
},
allRecipes() {
return this.$store.getters.getRecentRecipes;
return this.$store.getters.getAllRecipes;
},
},

View File

@@ -60,10 +60,10 @@
<v-row v-else dense>
<v-col
cols="12"
sm="12"
md="6"
lg="4"
xl="3"
:sm="singleColumn ? '12' : '12'"
:md="singleColumn ? '12' : '6'"
:lg="singleColumn ? '12' : '4'"
:xl="singleColumn ? '12' : '3'"
v-for="recipe in recipes.slice(0, cardLimit)"
:key="recipe.name"
>
@@ -79,14 +79,16 @@
</v-row>
</div>
<div v-intersect="bumpList" class="d-flex">
<v-progress-circular
v-if="loading"
class="mx-auto mt-1"
:size="50"
:width="7"
color="primary"
indeterminate
></v-progress-circular>
<v-expand-x-transition>
<v-progress-circular
v-if="loading"
class="mx-auto mt-1"
:size="50"
:width="7"
color="primary"
indeterminate
></v-progress-circular>
</v-expand-x-transition>
</div>
</div>
</template>
@@ -109,6 +111,12 @@ export default {
hardLimit: {
default: 99999,
},
mobileCards: {
default: false,
},
singleColumn: {
defualt: false,
},
recipes: Array,
},
data() {
@@ -117,8 +125,14 @@ export default {
loading: false,
};
},
watch: {
recipes() {
this.bumpList();
},
},
computed: {
viewScale() {
if (this.mobileCards) return true;
switch (this.$vuetify.breakpoint.name) {
case "xs":
return true;
@@ -128,10 +142,16 @@ export default {
return false;
}
},
effectiveHardLimit() {
return Math.min(this.hardLimit, this.recipes.length);
},
},
methods: {
bumpList() {
const newCardLimit = Math.min(this.cardLimit + 20, this.hardLimit);
const newCardLimit = Math.min(
this.cardLimit + 20,
this.effectiveHardLimit
);
if (this.loading === false && newCardLimit > this.cardLimit) {
this.setLoader();
@@ -141,7 +161,7 @@ export default {
},
async setLoader() {
this.loading = true;
await new Promise(r => setTimeout(r, 3000));
await new Promise(r => setTimeout(r, 1000));
this.loading = false;
},
},

View File

@@ -1,21 +1,38 @@
<template>
<div>
<v-dialog v-model="dialog" :width="modalWidth + 'px'">
<v-app-bar dark :color="color" class="mt-n1 mb-2">
<v-icon large left v-if="!loading">
{{ titleIcon }}
</v-icon>
<v-progress-circular
v-else
<v-dialog
v-model="dialog"
:width="modalWidth + 'px'"
:content-class="top ? 'top-dialog' : undefined"
>
<v-card class="pb-10" height="100%">
<v-app-bar dark :color="color" class="mt-n1 mb-2">
<v-icon large left>
{{ titleIcon }}
</v-icon>
<v-toolbar-title class="headline"> {{ title }} </v-toolbar-title>
<v-spacer></v-spacer>
</v-app-bar>
<v-progress-linear
v-if="loading"
indeterminate
color="white"
large
class="mr-2"
>
</v-progress-circular>
<v-toolbar-title class="headline"> {{ title }} </v-toolbar-title>
<v-spacer></v-spacer>
</v-app-bar>
color="primary"
></v-progress-linear>
<slot> </slot>
<v-card-actions>
<slot name="card-actions">
<v-btn text color="grey" @click="dialog = false">
Cancel
</v-btn>
<v-spacer></v-spacer>
<v-btn color="success" @click="$emit('submit')">
Submit
</v-btn>
</slot>
</v-card-actions>
<slot name="below-actions"> </slot>
</v-card>
</v-dialog>
</div>
</template>
@@ -35,6 +52,12 @@ export default {
modalWidth: {
default: "500",
},
loading: {
default: false,
},
top: {
default: false,
},
},
data() {
return {
@@ -45,9 +68,15 @@ export default {
open() {
this.dialog = true;
},
close() {
this.dialog = false;
},
},
};
</script>
<style scoped>
.top-dialog {
align-self: flex-start;
}
</style>

View File

@@ -1,8 +1,10 @@
<template>
<div>
<v-btn icon @click="dialog = true" class="mt-n1">
<v-icon :color="color">mdi-plus</v-icon>
</v-btn>
<slot>
<v-btn icon @click="dialog = true" class="mt-n1">
<v-icon :color="color">mdi-plus</v-icon>
</v-btn>
</slot>
<v-dialog v-model="dialog" width="500">
<v-card>
<v-app-bar dense dark color="primary mb-2">
@@ -80,6 +82,9 @@ export default {
},
methods: {
open() {
this.dialog = true;
},
async select() {
const newItem = await (async () => {
if (this.tagDialog) {

View File

@@ -0,0 +1,79 @@
<template>
<div>
<slot> </slot>
</div>
</template>
<script>
const RESULTS_EVENT = "results";
import Fuse from "fuse.js";
export default {
props: {
search: {
default: "",
},
rawData: {
default: true,
},
/** Defaults to Show All Results */
showAll: {
default: true,
},
keys: {
type: Array,
default: () => ["name"],
},
defaultOptions: {
default: () => ({
shouldSort: true,
threshold: 0.6,
location: 0,
distance: 100,
findAllMatches: true,
maxPatternLength: 32,
minMatchCharLength: 2,
}),
},
},
data() {
return {
results: [],
fuseResults: [],
};
},
computed: {
options() {
return { ...this.defaultOptions, ...{ keys: this.keys } };
},
autoResults() {
return this.fuseResults.length > 1 ? this.fuseResults : this.results;
},
fuse() {
return new Fuse(this.rawData, this.options);
},
isSearching() {
return this.search && this.search.length > 0;
},
},
watch: {
search() {
try {
this.results = this.fuse.search(this.search.trim());
} catch {
this.results = this.rawData
.map(x => ({ item: x }))
.sort((a, b) => (a.name > b.name ? 1 : -1));
}
this.$emit(RESULTS_EVENT, this.results);
if (this.showResults === true) {
this.fuseResults = this.results;
}
},
},
};
</script>
<style scoped>
</style>

View File

@@ -132,7 +132,7 @@ export default {
},
computed: {
data() {
return this.$store.getters.getRecentRecipes;
return this.$store.getters.getAllRecipes;
},
autoResults() {
return this.fuseResults.length > 1 ? this.fuseResults : this.results;

View File

@@ -163,6 +163,11 @@ export default {
to: "/admin/settings",
title: this.$t("settings.site-settings"),
},
{
icon: "mdi-tools",
to: "/admin/toolbox",
title: this.$t("settings.toolbox.toolbox"),
},
{
icon: "mdi-account-group",
to: "/admin/manage-users",

View File

@@ -6,6 +6,7 @@
bottom
right
offset-y
offset-overflow
open-on-hover
close-delay="200"
>
@@ -72,7 +73,7 @@ export default {
},
{
icon: "mdi-logout",
title: this.$t('user.logout'),
title: this.$t("user.logout"),
restricted: true,
nav: "/logout",
},
@@ -85,7 +86,6 @@ export default {
],
};
},
mounted() {},
computed: {
filteredItems() {
if (this.loggedIn) {