mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-08-02 20:15:24 +02:00
fix linter issues
This commit is contained in:
parent
a1b1b529a3
commit
3ed197a843
21 changed files with 58 additions and 33 deletions
|
@ -1,173 +0,0 @@
|
|||
<template>
|
||||
<v-row>
|
||||
<SearchDialog ref="mealselect" @selected="setSlug" />
|
||||
<BaseDialog
|
||||
ref="customMealDialog"
|
||||
title="Custom Meal"
|
||||
:title-icon="$globals.icons.primary"
|
||||
:submit-text="$t('general.save')"
|
||||
:top="true"
|
||||
@submit="pushCustomMeal"
|
||||
>
|
||||
<v-card-text>
|
||||
<v-text-field v-model="customMeal.name" autofocus :label="$t('general.name')"> </v-text-field>
|
||||
<v-textarea v-model="customMeal.description" :label="$t('recipe.description')"> </v-textarea>
|
||||
</v-card-text>
|
||||
</BaseDialog>
|
||||
<v-col v-for="(planDay, index) in value" :key="index" cols="12" sm="12" md="6" lg="4" xl="3">
|
||||
<v-hover v-slot="{ hover }" :open-delay="50">
|
||||
<v-card :class="{ 'on-hover': hover }" :elevation="hover ? 12 : 2">
|
||||
<CardImage large :slug="planDay.meals[0].slug" icon-size="200" @click="openSearch(index, modes.primary)">
|
||||
<div>
|
||||
<v-fade-transition>
|
||||
<v-btn v-if="hover" small color="info" class="ma-1" @click.stop="addCustomItem(index, modes.primary)">
|
||||
<v-icon left>
|
||||
{{ $globals.icons.edit }}
|
||||
</v-icon>
|
||||
{{ $t("reicpe.no-recipe") }}
|
||||
</v-btn>
|
||||
</v-fade-transition>
|
||||
</div>
|
||||
</CardImage>
|
||||
|
||||
<v-card-title class="my-n3 mb-n6">
|
||||
{{ $d(new Date(planDay.date.replaceAll("-", "/")), "short") }}
|
||||
</v-card-title>
|
||||
<v-card-subtitle class="mb-0 pb-0"> {{ planDay.meals[0].name }}</v-card-subtitle>
|
||||
<v-hover v-slot="{ hover }">
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-fade-transition>
|
||||
<v-btn v-if="hover" small color="info" text @click.stop="addCustomItem(index, modes.sides)">
|
||||
<v-icon left>
|
||||
{{ $globals.icons.edit }}
|
||||
</v-icon>
|
||||
{{ $t("reicpe.no-recipe") }}
|
||||
</v-btn>
|
||||
</v-fade-transition>
|
||||
<v-btn color="info" outlined small @click="openSearch(index, modes.sides)">
|
||||
<v-icon small class="mr-1">
|
||||
{{ $globals.icons.create }}
|
||||
</v-icon>
|
||||
{{ $t("meal-plan.side") }}
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-hover>
|
||||
<v-divider class="mx-2"></v-divider>
|
||||
<v-list dense>
|
||||
<v-list-item v-for="(recipe, i) in planDay.meals.slice(1)" :key="i">
|
||||
<v-list-item-avatar color="accent">
|
||||
<v-img :alt="recipe.slug" :src="getImage(recipe.slug)"></v-img>
|
||||
</v-list-item-avatar>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="recipe.name"></v-list-item-title>
|
||||
</v-list-item-content>
|
||||
|
||||
<v-list-item-icon>
|
||||
<v-btn icon @click="removeSide(index, i + 1)">
|
||||
<v-icon color="error">
|
||||
{{ $globals.icons.delete }}
|
||||
</v-icon>
|
||||
</v-btn>
|
||||
</v-list-item-icon>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-card>
|
||||
</v-hover>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BaseDialog from "@/components/UI/Dialogs/BaseDialog";
|
||||
import { api } from "@/api";
|
||||
import SearchDialog from "../UI/Dialogs/SearchDialog";
|
||||
import CardImage from "../Recipe/CardImage.vue";
|
||||
export default {
|
||||
components: {
|
||||
SearchDialog,
|
||||
CardImage,
|
||||
BaseDialog,
|
||||
},
|
||||
props: {
|
||||
value: Array,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeIndex: 0,
|
||||
mode: "PRIMARY",
|
||||
modes: {
|
||||
primary: "PRIMARY",
|
||||
sides: "SIDES",
|
||||
},
|
||||
customMeal: {
|
||||
slug: null,
|
||||
name: "",
|
||||
description: "",
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
getImage(slug) {
|
||||
if (slug) {
|
||||
return api.recipes.recipeSmallImage(slug);
|
||||
}
|
||||
},
|
||||
setSide(name, slug = null, description = "") {
|
||||
const meal = { name, slug, description };
|
||||
this.value[this.activeIndex].meals.push(meal);
|
||||
},
|
||||
setPrimary(name, slug, description = "") {
|
||||
this.value[this.activeIndex].meals[0].slug = slug;
|
||||
this.value[this.activeIndex].meals[0].name = name;
|
||||
this.value[this.activeIndex].meals[0].description = description;
|
||||
},
|
||||
setSlug(recipe) {
|
||||
switch (this.mode) {
|
||||
case this.modes.primary:
|
||||
this.setPrimary(recipe.name, recipe.slug);
|
||||
break;
|
||||
default:
|
||||
this.setSide(recipe.name, recipe.slug);
|
||||
break;
|
||||
}
|
||||
},
|
||||
openSearch(index, mode) {
|
||||
this.mode = mode;
|
||||
this.activeIndex = index;
|
||||
this.$refs.mealselect.open();
|
||||
},
|
||||
removeSide(dayIndex, sideIndex) {
|
||||
this.value[dayIndex].meals.splice(sideIndex, 1);
|
||||
},
|
||||
addCustomItem(index, mode) {
|
||||
this.mode = mode;
|
||||
this.activeIndex = index;
|
||||
this.$refs.customMealDialog.open();
|
||||
},
|
||||
pushCustomMeal() {
|
||||
switch (this.mode) {
|
||||
case this.modes.primary:
|
||||
this.setPrimary(this.customMeal.name, this.customMeal.slug, this.customMeal.description);
|
||||
break;
|
||||
default:
|
||||
this.setSide(this.customMeal.name, this.customMeal.slug, this.customMeal.description);
|
||||
break;
|
||||
}
|
||||
this.customMeal = { name: "", slug: null, description: "" };
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.relative-card {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.custom-button {
|
||||
z-index: -1;
|
||||
}
|
||||
</style>
|
|
@ -1,46 +0,0 @@
|
|||
<template>
|
||||
<v-card>
|
||||
<v-card-title class="headline">
|
||||
{{ $t("meal-plan.edit-meal-plan") }}
|
||||
</v-card-title>
|
||||
<v-divider></v-divider>
|
||||
|
||||
<v-card-text>
|
||||
<MealPlanCard v-model="mealPlan.planDays" />
|
||||
<v-row align="center" justify="end">
|
||||
<v-card-actions>
|
||||
<TheButton update @click="update" />
|
||||
<v-spacer></v-spacer>
|
||||
</v-card-actions>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { api } from "@/api";
|
||||
import { utils } from "@/utils";
|
||||
import MealPlanCard from "./MealPlanCard";
|
||||
export default {
|
||||
components: {
|
||||
MealPlanCard,
|
||||
},
|
||||
props: {
|
||||
mealPlan: Object,
|
||||
},
|
||||
|
||||
methods: {
|
||||
formatDate(timestamp) {
|
||||
const dateObject = new Date(timestamp);
|
||||
return utils.getDateAsPythonDate(dateObject);
|
||||
},
|
||||
async update() {
|
||||
if (await api.mealPlans.update(this.mealPlan.uid, this.mealPlan)) {
|
||||
this.$emit("updated");
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
|
@ -1,227 +0,0 @@
|
|||
<template>
|
||||
<v-card>
|
||||
<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> {{ $globals.icons.calendarMinus }} </v-icon>
|
||||
{{ $t("meal-plan.quick-week") }}
|
||||
</v-btn>
|
||||
</v-card-title>
|
||||
|
||||
<v-divider></v-divider>
|
||||
<v-card-text>
|
||||
<v-row dense>
|
||||
<v-col cols="12" lg="6" md="6" sm="12">
|
||||
<v-menu
|
||||
ref="menu1"
|
||||
v-model="menu1"
|
||||
:close-on-content-click="true"
|
||||
transition="scale-transition"
|
||||
offset-y
|
||||
max-width="290px"
|
||||
min-width="290px"
|
||||
>
|
||||
<template #activator="{ on, attrs }">
|
||||
<v-text-field
|
||||
v-model="startComputedDateFormatted"
|
||||
:label="$t('meal-plan.start-date')"
|
||||
persistent-hint
|
||||
:prepend-icon="$globals.icons.calendarMinus"
|
||||
readonly
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
></v-text-field>
|
||||
</template>
|
||||
<DatePicker v-model="startDate" no-title @input="menu2 = false" />
|
||||
</v-menu>
|
||||
</v-col>
|
||||
<v-col cols="12" lg="6" md="6" sm="12">
|
||||
<v-menu
|
||||
ref="menu2"
|
||||
v-model="menu2"
|
||||
:close-on-content-click="true"
|
||||
transition="scale-transition"
|
||||
offset-y
|
||||
max-width="290px"
|
||||
min-width="290px"
|
||||
>
|
||||
<template #activator="{ on, attrs }">
|
||||
<v-text-field
|
||||
v-model="endComputedDateFormatted"
|
||||
:label="$t('meal-plan.end-date')"
|
||||
persistent-hint
|
||||
:prepend-icon="$globals.icons.calendarMinus"
|
||||
readonly
|
||||
v-bind="attrs"
|
||||
v-on="on"
|
||||
></v-text-field>
|
||||
</template>
|
||||
<DatePicker v-model="endDate" no-title @input="menu2 = false" />
|
||||
</v-menu>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-text v-if="startDate">
|
||||
<MealPlanCard v-model="planDays" />
|
||||
</v-card-text>
|
||||
<v-row align="center" justify="end">
|
||||
<v-card-actions class="mr-5">
|
||||
<TheButton v-if="planDays.length > 0" edit text @click="random">
|
||||
<template #icon>
|
||||
{{ $globals.icons.diceMultiple }}
|
||||
</template>
|
||||
{{ $t("general.random") }}
|
||||
</TheButton>
|
||||
<TheButton create :disabled="planDays.length == 0" @click="save" />
|
||||
</v-card-actions>
|
||||
</v-row>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DatePicker from "@/components/FormHelpers/DatePicker";
|
||||
import { api } from "@/api";
|
||||
import { utils } from "@/utils";
|
||||
import MealPlanCard from "./MealPlanCard";
|
||||
const CREATE_EVENT = "created";
|
||||
export default {
|
||||
components: {
|
||||
MealPlanCard,
|
||||
DatePicker,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
planDays: [],
|
||||
items: [],
|
||||
|
||||
// Dates
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
menu1: false,
|
||||
menu2: false,
|
||||
usedRecipes: [1],
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
groupSettings() {
|
||||
return this.$store.getters.getCurrentGroup;
|
||||
},
|
||||
actualStartDate() {
|
||||
if (!this.startDate) return null;
|
||||
return Date.parse(this.startDate.replaceAll("-", "/"));
|
||||
},
|
||||
actualEndDate() {
|
||||
if (!this.endDate) return null;
|
||||
return Date.parse(this.endDate.replaceAll("-", "/"));
|
||||
},
|
||||
dateDif() {
|
||||
if (!this.actualEndDate || !this.actualStartDate) return null;
|
||||
const dateDif = (this.actualEndDate - this.actualStartDate) / (1000 * 3600 * 24) + 1;
|
||||
if (dateDif < 1) {
|
||||
return null;
|
||||
}
|
||||
return dateDif;
|
||||
},
|
||||
startComputedDateFormatted() {
|
||||
return this.formatDate(this.actualStartDate);
|
||||
},
|
||||
endComputedDateFormatted() {
|
||||
return this.formatDate(this.actualEndDate);
|
||||
},
|
||||
filteredRecipes() {
|
||||
const recipes = this.items.filter(x => !this.usedRecipes.includes(x));
|
||||
return recipes.length > 0 ? recipes : this.items;
|
||||
},
|
||||
allRecipes() {
|
||||
return this.$store.getters.getAllRecipes;
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
dateDif() {
|
||||
this.planDays = [];
|
||||
for (let i = 0; i < this.dateDif; i++) {
|
||||
this.planDays.push({
|
||||
date: this.getDate(i),
|
||||
meals: [
|
||||
{
|
||||
name: "",
|
||||
slug: "empty",
|
||||
description: "empty",
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
await this.$store.dispatch("requestCurrentGroup");
|
||||
await this.$store.dispatch("requestAllRecipes");
|
||||
await this.buildMealStore();
|
||||
},
|
||||
|
||||
methods: {
|
||||
async buildMealStore() {
|
||||
const categories = Array.from(this.groupSettings.categories, x => x.name);
|
||||
this.items = await api.recipes.getAllByCategory(categories);
|
||||
|
||||
if (this.items.length === 0) {
|
||||
this.items = this.allRecipes;
|
||||
}
|
||||
},
|
||||
getRandom(list) {
|
||||
return list[Math.floor(Math.random() * list.length)];
|
||||
},
|
||||
random() {
|
||||
this.usedRecipes = [1];
|
||||
this.planDays.forEach((_, index) => {
|
||||
const recipe = this.getRandom(this.filteredRecipes);
|
||||
this.planDays[index].meals[0].slug = recipe.slug;
|
||||
this.planDays[index].meals[0].name = recipe.name;
|
||||
this.usedRecipes.push(recipe);
|
||||
});
|
||||
},
|
||||
getDate(index) {
|
||||
const dateObj = new Date(this.actualStartDate.valueOf() + 1000 * 3600 * 24 * index);
|
||||
return utils.getDateAsPythonDate(dateObj);
|
||||
},
|
||||
async save() {
|
||||
const mealBody = {
|
||||
group: this.groupSettings.name,
|
||||
startDate: this.startDate,
|
||||
endDate: this.endDate,
|
||||
planDays: this.planDays,
|
||||
};
|
||||
if (await api.mealPlans.create(mealBody)) {
|
||||
this.$emit(CREATE_EVENT);
|
||||
this.planDays = [];
|
||||
this.startDate = null;
|
||||
this.endDate = null;
|
||||
}
|
||||
},
|
||||
formatDate(date) {
|
||||
if (!date) return null;
|
||||
|
||||
return this.$d(date);
|
||||
},
|
||||
getNextDayOfTheWeek(dayName, excludeToday = true, refDate = new Date()) {
|
||||
const dayOfWeek = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"].indexOf(dayName.slice(0, 3).toLowerCase());
|
||||
if (dayOfWeek < 0) return;
|
||||
refDate.setUTCHours(0, 0, 0, 0);
|
||||
refDate.setDate(refDate.getDate() + +!!excludeToday + ((dayOfWeek + 7 - refDate.getDay() - +!!excludeToday) % 7));
|
||||
return refDate;
|
||||
},
|
||||
setQuickWeek() {
|
||||
const nextMonday = this.getNextDayOfTheWeek("Monday", false);
|
||||
const nextEndDate = new Date(nextMonday);
|
||||
nextEndDate.setDate(nextEndDate.getDate() + 4);
|
||||
|
||||
this.startDate = utils.getDateAsPythonDate(nextMonday);
|
||||
this.endDate = utils.getDateAsPythonDate(nextEndDate);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -1,61 +0,0 @@
|
|||
<template>
|
||||
<v-list-item two-line to="/admin/profile">
|
||||
<v-list-item-avatar color="accent" class="white--text">
|
||||
<v-img v-if="!noImage" :src="profileImage" />
|
||||
<div v-else>
|
||||
{{ initials }}
|
||||
</div>
|
||||
</v-list-item-avatar>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-title> {{ user.fullName }}</v-list-item-title>
|
||||
<v-list-item-subtitle> {{ user.admin ? $t("user.admin") : $t("user.user") }}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { initials } from "@/mixins/initials";
|
||||
import axios from "axios";
|
||||
import { api } from "@/api";
|
||||
export default {
|
||||
mixins: [initials],
|
||||
props: {
|
||||
user: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
noImage: false,
|
||||
profileImage: "",
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
async user() {
|
||||
this.setImage();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async setImage() {
|
||||
const userImageURL = api.users.userProfileImage(this.user.id);
|
||||
if (await this.imageExists(userImageURL)) {
|
||||
this.noImage = false;
|
||||
this.profileImage = userImageURL;
|
||||
} else {
|
||||
this.noImage = true;
|
||||
}
|
||||
},
|
||||
async imageExists(url) {
|
||||
const response = await axios.get(url).catch(() => {
|
||||
this.noImage = true;
|
||||
return { status: 404 };
|
||||
});
|
||||
return response.status !== 404;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
|
@ -1,153 +0,0 @@
|
|||
<template>
|
||||
<v-form ref="form">
|
||||
<v-card-text>
|
||||
<v-row dense>
|
||||
<ImageUploadBtn class="my-1" :slug="value.slug" @upload="uploadImage" @refresh="$emit('upload')" />
|
||||
<SettingsMenu class="my-1 mx-1" :value="value.settings" @upload="uploadImage" />
|
||||
</v-row>
|
||||
<v-row dense>
|
||||
<v-col>
|
||||
<v-text-field v-model="value.totalTime" :label="$t('recipe.total-time')"></v-text-field>
|
||||
</v-col>
|
||||
<v-col><v-text-field v-model="value.prepTime" :label="$t('recipe.prep-time')"></v-text-field></v-col>
|
||||
<v-col><v-text-field v-model="value.performTime" :label="$t('recipe.perform-time')"></v-text-field></v-col>
|
||||
</v-row>
|
||||
<v-text-field v-model="value.name" class="my-3" :label="$t('recipe.recipe-name')" :rules="[existsRule]">
|
||||
</v-text-field>
|
||||
<v-textarea v-model="value.description" auto-grow min-height="100" :label="$t('recipe.description')">
|
||||
</v-textarea>
|
||||
<div class="my-2"></div>
|
||||
<v-row dense disabled>
|
||||
<v-col sm="4">
|
||||
<v-text-field v-model="value.recipeYield" :label="$t('recipe.servings')" class="rounded-sm"> </v-text-field>
|
||||
</v-col>
|
||||
<v-spacer></v-spacer>
|
||||
<Rating v-model="value.rating" :emit-only="true" />
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="4" lg="4">
|
||||
<Ingredients v-model="value.recipeIngredient" :edit="true" />
|
||||
<v-card class="mt-6">
|
||||
<v-card-title class="py-2">
|
||||
{{ $t("recipe.categories") }}
|
||||
</v-card-title>
|
||||
<v-divider class="mx-2"></v-divider>
|
||||
<v-card-text>
|
||||
<CategoryTagSelector
|
||||
v-model="value.recipeCategory"
|
||||
:return-object="false"
|
||||
:show-add="true"
|
||||
:show-label="false"
|
||||
/>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<v-card class="mt-2">
|
||||
<v-card-title class="py-2">
|
||||
{{ $t("tag.tags") }}
|
||||
</v-card-title>
|
||||
<v-divider class="mx-2"></v-divider>
|
||||
<v-card-text>
|
||||
<CategoryTagSelector
|
||||
v-model="value.tags"
|
||||
:return-object="false"
|
||||
:show-add="true"
|
||||
:tag-selector="true"
|
||||
:show-label="false"
|
||||
/>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<Nutrition v-model="value.nutrition" :edit="true" />
|
||||
<Assets v-model="value.assets" :edit="true" :slug="value.slug" />
|
||||
<ExtrasEditor :extras="value.extras" @save="saveExtras" />
|
||||
</v-col>
|
||||
|
||||
<v-divider class="my-divider" :vertical="true"></v-divider>
|
||||
|
||||
<v-col cols="12" sm="12" md="8" lg="8">
|
||||
<Instructions v-model="value.recipeInstructions" :edit="true" />
|
||||
<div class="d-flex row justify-end mt-2">
|
||||
<BulkAdd class="mr-2" @bulk-data="appendSteps" />
|
||||
<v-btn color="secondary" dark class="mr-4" @click="addStep">
|
||||
<v-icon>{{ $globals.icons.create }}</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
<Notes v-model="value.notes" :edit="true" />
|
||||
|
||||
<v-text-field v-model="value.orgURL" class="mt-10" :label="$t('recipe.original-url')"></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
</v-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BulkAdd from "@/components/Recipe/Parts/Helpers/BulkAdd";
|
||||
import ExtrasEditor from "@/components/Recipe/Parts/Helpers/ExtrasEditor";
|
||||
import CategoryTagSelector from "@/components/FormHelpers/CategoryTagSelector";
|
||||
import ImageUploadBtn from "@/components/Recipe/Parts/Helpers/ImageUploadBtn";
|
||||
import { validators } from "@/mixins/validators";
|
||||
import Nutrition from "@/components/Recipe/Parts/Nutrition";
|
||||
import Instructions from "@/components/Recipe/Parts/Instructions";
|
||||
import Ingredients from "@/components/Recipe/Parts/Ingredients";
|
||||
import Assets from "@/components/Recipe/Parts/Assets.vue";
|
||||
import Notes from "@/components/Recipe/Parts/Notes.vue";
|
||||
import SettingsMenu from "@/components/Recipe/Parts/Helpers/SettingsMenu.vue";
|
||||
import Rating from "@/components/Recipe/Parts/Rating";
|
||||
const UPLOAD_EVENT = "upload";
|
||||
export default {
|
||||
components: {
|
||||
BulkAdd,
|
||||
ExtrasEditor,
|
||||
CategoryTagSelector,
|
||||
Nutrition,
|
||||
ImageUploadBtn,
|
||||
Instructions,
|
||||
Ingredients,
|
||||
Assets,
|
||||
Notes,
|
||||
SettingsMenu,
|
||||
Rating,
|
||||
},
|
||||
mixins: [validators],
|
||||
props: {
|
||||
value: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
fileObject: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
uploadImage(fileObject) {
|
||||
this.$emit(UPLOAD_EVENT, fileObject);
|
||||
},
|
||||
appendSteps(steps) {
|
||||
this.value.recipeInstructions.push(
|
||||
...steps.map(x => ({
|
||||
title: "",
|
||||
text: x,
|
||||
}))
|
||||
);
|
||||
},
|
||||
addStep() {
|
||||
this.value.recipeInstructions.push({ title: "", text: "" });
|
||||
},
|
||||
saveExtras(extras) {
|
||||
this.value.extras = extras;
|
||||
},
|
||||
validateRecipe() {
|
||||
return this.$refs.form.validate();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.disabled-card {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.my-divider {
|
||||
margin: 0 -1px;
|
||||
}
|
||||
</style>
|
|
@ -1,142 +0,0 @@
|
|||
<template>
|
||||
<div>
|
||||
<v-card-title class="headline">
|
||||
{{ recipe.name }}
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<VueMarkdown :source="recipe.description"> </VueMarkdown>
|
||||
<v-row dense disabled>
|
||||
<v-col>
|
||||
<v-btn
|
||||
v-if="recipe.recipeYield"
|
||||
dense
|
||||
small
|
||||
:hover="false"
|
||||
type="label"
|
||||
:ripple="false"
|
||||
elevation="0"
|
||||
color="secondary darken-1"
|
||||
class="rounded-sm static"
|
||||
>
|
||||
{{ recipe.recipeYield }}
|
||||
</v-btn>
|
||||
</v-col>
|
||||
<Rating :key="recipe.slug" :value="recipe.rating" :name="recipe.name" :slug="recipe.slug" />
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="4" lg="4">
|
||||
<Ingredients :value="recipe.recipeIngredient" :edit="false" />
|
||||
<div v-if="medium">
|
||||
<v-card v-if="recipe.recipeCategory.length > 0" class="mt-2">
|
||||
<v-card-title class="py-2">
|
||||
{{ $t("recipe.categories") }}
|
||||
</v-card-title>
|
||||
<v-divider class="mx-2"></v-divider>
|
||||
<v-card-text>
|
||||
<RecipeChips :items="recipe.recipeCategory" />
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<v-card v-if="recipe.tags.length > 0" class="mt-2">
|
||||
<v-card-title class="py-2">
|
||||
{{ $t("tag.tags") }}
|
||||
</v-card-title>
|
||||
<v-divider class="mx-2"></v-divider>
|
||||
<v-card-text>
|
||||
<RecipeChips :items="recipe.tags" :is-category="false" />
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<Nutrition v-if="recipe.settings.showNutrition" :value="recipe.nutrition" :edit="false" />
|
||||
<Assets v-if="recipe.settings.showAssets" :value="recipe.assets" :edit="false" :slug="recipe.slug" />
|
||||
</div>
|
||||
</v-col>
|
||||
<v-divider v-if="medium" class="my-divider" :vertical="true"></v-divider>
|
||||
|
||||
<v-col cols="12" sm="12" md="8" lg="8">
|
||||
<Instructions :value="recipe.recipeInstructions" :edit="false" />
|
||||
<Notes :value="recipe.notes" :edit="false" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
<div v-if="!medium">
|
||||
<RecipeChips :title="$t('recipe.categories')" :items="recipe.recipeCategory" />
|
||||
<RecipeChips :title="$t('tag.tags')" :items="recipe.tags" />
|
||||
<Nutrition v-if="recipe.settings.showNutrition" :value="recipe.nutrition" :edit="false" />
|
||||
<Assets v-if="recipe.settings.showAssets" :value="recipe.assets" :edit="false" :slug="recipe.slug" />
|
||||
</div>
|
||||
<v-row class="mt-2 mb-1">
|
||||
<v-col></v-col>
|
||||
<v-btn
|
||||
v-if="recipe.orgURL"
|
||||
dense
|
||||
small
|
||||
:hover="false"
|
||||
type="label"
|
||||
:ripple="false"
|
||||
elevation="0"
|
||||
:href="recipe.orgURL"
|
||||
color="secondary darken-1"
|
||||
target="_blank"
|
||||
class="rounded-sm mr-4"
|
||||
>
|
||||
{{ $t("recipe.original-url") }}
|
||||
</v-btn>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Nutrition from "@/components/Recipe/Parts/Nutrition";
|
||||
import VueMarkdown from "@adapttive/vue-markdown";
|
||||
import { utils } from "@/utils";
|
||||
import Rating from "@/components/Recipe/Parts/Rating";
|
||||
import Notes from "@/components/Recipe/Parts/Notes";
|
||||
import Ingredients from "@/components/Recipe/Parts/Ingredients";
|
||||
import Instructions from "@/components/Recipe/Parts/Instructions.vue";
|
||||
import Assets from "../../../../frontend.old/src/components/Recipe/Parts/Assets.vue";
|
||||
import RecipeChips from "./RecipeChips";
|
||||
|
||||
|
||||
export default {
|
||||
components: {
|
||||
VueMarkdown,
|
||||
RecipeChips,
|
||||
Notes,
|
||||
Ingredients,
|
||||
Nutrition,
|
||||
Instructions,
|
||||
Assets,
|
||||
Rating,
|
||||
},
|
||||
props: {
|
||||
recipe: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
disabledSteps: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
medium() {
|
||||
return this.$vuetify.breakpoint.mdAndUp;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
generateKey(item, index) {
|
||||
return utils.generateUniqueKey(item, index);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.static {
|
||||
pointer-events: none;
|
||||
}
|
||||
.my-divider {
|
||||
margin: 0 -1px;
|
||||
}
|
||||
</style>
|
|
@ -57,9 +57,11 @@ export default {
|
|||
props: {
|
||||
comments: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
slug: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
|
@ -85,7 +87,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
resetImage() {
|
||||
this.hideImage == false;
|
||||
this.hideImage = false;
|
||||
},
|
||||
getProfileImage(id) {
|
||||
return api.users.userProfileImage(id);
|
||||
|
|
|
@ -41,7 +41,7 @@ export default {
|
|||
const split = this.inputText.split("\n");
|
||||
|
||||
split.forEach((element, index) => {
|
||||
if ((element === "\n") | (element == false)) {
|
||||
if ((element === "\n") | (element === false)) {
|
||||
split.splice(index, 1);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -49,7 +49,10 @@
|
|||
<script>
|
||||
export default {
|
||||
props: {
|
||||
extras: Object,
|
||||
extras: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -57,8 +60,8 @@ export default {
|
|||
dialog: false,
|
||||
formKey: 1,
|
||||
rules: {
|
||||
required: v => !!v || this.$i18n.t("recipe.key-name-required"),
|
||||
whiteSpace: v => !v || v.split(" ").length <= 1 || this.$i18n.t("recipe.no-white-space-allowed"),
|
||||
required: (v) => !!v || this.$i18n.t("recipe.key-name-required"),
|
||||
whiteSpace: (v) => !v || v.split(" ").length <= 1 || this.$i18n.t("recipe.no-white-space-allowed"),
|
||||
},
|
||||
};
|
||||
},
|
||||
|
|
|
@ -84,6 +84,7 @@ export default {
|
|||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
|
||||
edit: {
|
||||
|
|
|
@ -97,6 +97,7 @@ export default {
|
|||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
|
||||
edit: {
|
||||
|
@ -115,13 +116,13 @@ export default {
|
|||
value: {
|
||||
handler() {
|
||||
this.disabledSteps = [];
|
||||
this.showTitleEditor = this.value.map(x => this.validateTitle(x.title));
|
||||
this.showTitleEditor = this.value.map((x) => this.validateTitle(x.title));
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.showTitleEditor = this.value.map(x => this.validateTitle(x.title));
|
||||
this.showTitleEditor = this.value.map((x) => this.validateTitle(x.title));
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
@ -148,8 +149,6 @@ export default {
|
|||
isChecked(stepIndex) {
|
||||
if (this.disabledSteps.includes(stepIndex) && !this.edit) {
|
||||
return "disabled-card";
|
||||
} else {
|
||||
|
||||
}
|
||||
},
|
||||
toggleShowTitle(index) {
|
||||
|
|
|
@ -43,6 +43,7 @@ export default {
|
|||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
|
||||
edit: {
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<v-list v-if="showViewer" dense class="mt-0 pt-0">
|
||||
<v-list-item v-for="(item, key, index) in labels" :key="index">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="pl-4 text-subtitle-1 flex row ">
|
||||
<v-list-item-title class="pl-4 text-subtitle-1 flex row">
|
||||
<div>{{ item.label }}</div>
|
||||
<div class="ml-auto mr-1">{{ value[key] }}</div>
|
||||
<div>{{ item.suffix }}</div>
|
||||
|
@ -36,7 +36,10 @@
|
|||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: {},
|
||||
value: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
edit: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
|
|
|
@ -69,7 +69,10 @@ export default {
|
|||
VueMarkdown,
|
||||
},
|
||||
props: {
|
||||
recipe: Object,
|
||||
recipe: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -37,7 +37,10 @@
|
|||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
value: Object,
|
||||
value: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
|
|
@ -36,9 +36,11 @@
|
|||
export default {
|
||||
props: {
|
||||
copyText: {
|
||||
type: String,
|
||||
default: "Default Copy Text",
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: "primary",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
export default {
|
||||
props: {
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
small: {
|
||||
|
@ -62,7 +63,7 @@ export default {
|
|||
},
|
||||
waitingText() {
|
||||
return this.$t("general.loading-recipes");
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -23,8 +23,14 @@
|
|||
<script>
|
||||
export default {
|
||||
props: {
|
||||
buttonText: String,
|
||||
value: String,
|
||||
buttonText: {
|
||||
type: String,
|
||||
default: "Choose a color",
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: "#ff0000",
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
|
@ -200,7 +200,8 @@ const icons = {
|
|||
accountPlusOutline: mdiAccountPlusOutline,
|
||||
};
|
||||
|
||||
export default ({ app }, inject) => {
|
||||
// eslint-disable-next-line no-empty-pattern
|
||||
export default ({}, inject) => {
|
||||
// Inject $hello(msg) in Vue, context and store.
|
||||
inject("globals", { icons });
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@ import { store } from "@/store";
|
|||
// TODO: Migrate to Mixins
|
||||
|
||||
export const utils = {
|
||||
recipe: recipe,
|
||||
recipe,
|
||||
generateUniqueKey(item, index) {
|
||||
return `${item}-${index}`;
|
||||
},
|
||||
|
@ -16,35 +16,35 @@ export const utils = {
|
|||
return `${year}-${month}-${day}`;
|
||||
},
|
||||
notify: {
|
||||
info: function(text, title = null) {
|
||||
info(text, title = null) {
|
||||
store.commit("setSnackbar", {
|
||||
open: true,
|
||||
title: title,
|
||||
text: text,
|
||||
title,
|
||||
text,
|
||||
color: "info",
|
||||
});
|
||||
},
|
||||
success: function(text, title = null) {
|
||||
success(text, title = null) {
|
||||
store.commit("setSnackbar", {
|
||||
open: true,
|
||||
title: title,
|
||||
text: text,
|
||||
title,
|
||||
text,
|
||||
color: "success",
|
||||
});
|
||||
},
|
||||
error: function(text, title = null) {
|
||||
error(text, title = null) {
|
||||
store.commit("setSnackbar", {
|
||||
open: true,
|
||||
title: title,
|
||||
text: text,
|
||||
title,
|
||||
text,
|
||||
color: "error",
|
||||
});
|
||||
},
|
||||
warning: function(text, title = null) {
|
||||
warning(text, title = null) {
|
||||
store.commit("setSnackbar", {
|
||||
open: true,
|
||||
title: title,
|
||||
text: text,
|
||||
title,
|
||||
text,
|
||||
color: "warning",
|
||||
});
|
||||
},
|
||||
|
|
|
@ -6,8 +6,8 @@ export const recipe = {
|
|||
*/
|
||||
sortAToZ(list) {
|
||||
list.sort((a, b) => {
|
||||
var textA = a.name.toUpperCase();
|
||||
var textB = b.name.toUpperCase();
|
||||
const textA = a.name.toUpperCase();
|
||||
const textB = b.name.toUpperCase();
|
||||
return textA < textB ? -1 : textA > textB ? 1 : 0;
|
||||
});
|
||||
},
|
||||
|
@ -42,7 +42,7 @@ const rand = n =>
|
|||
Math.floor(Math.random() * n)
|
||||
|
||||
function swap(t, i, j) {
|
||||
let q = t[i];
|
||||
const q = t[i];
|
||||
t[i] = t[j];
|
||||
t[j] = q;
|
||||
return t;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue