Generalised ingredients editor

This commit is contained in:
jableader 2024-05-12 17:00:26 +10:00
parent 6b3a87ebc8
commit 1663f3788d
5 changed files with 26 additions and 157 deletions

View file

@ -1,6 +1,8 @@
<template>
<div>
<button v-if="editing" @click="$emit('on-add')">Add Ingredient</button>
<button @click="toggleEditing">{{ editing ? 'Finished Editing' : 'Edit' }}</button>
<ul>
<li v-for="ingredient in ingredients" :key="ingredient.id">
<div v-if="editing">
@ -19,8 +21,6 @@
</div>
</li>
</ul>
<button v-if="editing" @click="$emit('on-add')">Add Ingredient</button>
<button @click="editing = !editing">{{ editing ? 'Done' : 'Edit' }}</button>
</div>
</template>
@ -81,6 +81,12 @@ export default {
const newIngredients = await data.parseIngredients([line]);
this.$emit('on-update-ingredient', ingredient, newIngredients[0]);
},
toggleEditing() {
this.editing = !this.editing;
if (this.editing && !this.ingredients.length) {
this.$emit('on-add');
}
}
}
}

View file

@ -1,89 +0,0 @@
<template>
<div class="ingredient-add-box" :class="{ 'adding-ingredient': showIngredientLine}">
<p class="ingredient-line" v-if="showIngredientLine">
<ingredient-line ref="line" :ingredient="ingredient"
@update-ingredient="updateIngredient"
@update-product-link="updateProduct" />
</p>
<p>
<button v-if="showIngredientLine" @click="addIngredient(ingredient)">
<img :src="require('@/assets/chevron-up.svg')" /> <br>
Add ingredient
</button>
<button v-if="showIngredientLine" @click="showIngredientLine = false">
<img :src="require('@/assets/close.svg')" /> <br>
Cancel
</button>
<button v-else @click="showIngredientLine = true">
<img :src="require('@/assets/create.svg')" /> <br>
Add ingredient
</button>
</p>
</div>
</template>
<script>
import IngredientLine from './IngredientLine.vue';
import data from '@/data.js'
export default {
name: 'IngredientAddBox',
components: { IngredientLine },
data() {
return {
ingredient: {},
showIngredientLine: false,
}
},
methods: {
addIngredient() {
this.$emit('add-ingredient', this.ingredient);
this.ingredient = {};
this.showIngredientLine = false;
},
async updateProduct(ingredient, product_link) {
this.ingredient.product = await data.parseProduct(ingredient, product_link);
},
async updateIngredient(ingredient, line) {
const newIngredients = await data.parseIngredients([line]);
this.ingredient = newIngredients[0];
},
}
}
</script>
<style scoped>
.ingredient-add-box {
display: flex;
flex-direction: column;
margin: 1ex 2em;
padding: 1em;
}
.adding-ingredient {
border: solid 1px #ccc;
border-radius: 5px;
}
.ingredient-line {
flex: 1;
}
button {
border: 0;
background: none;
cursor: pointer;
padding: 2ex 1em;
}
button img {
width: 3em;
}
button:hover {
background-color: #ccc;
}
</style>

View file

@ -29,18 +29,7 @@
</div>
<div class="ingredients">
<h2>Sides & Additional Ingredients</h2>
<ul v-if="meal.extra_ingredients && meal.extra_ingredients.length">
<li v-for="ingredient in meal.extra_ingredients" :key="ingredient" class="saved-ingredient">
<compact-parsed-ingredient :ingredient="ingredient" />
<button @click="deleteIngredient(ingredient)">
<img class="icon" :src="require('@/assets/trash.svg')" />
</button>
</li>
</ul>
<div v-else>
<p>Add some ingredients using the search box</p>
</div>
<ingredient-add-box @add-ingredient="addIngredient" />
<editable-ingredients-panel :ingredients="meal.extra_ingredients" @on-add="addIngredient" @on-delete="deleteIngredient" @on-update-ingredient="updateIngredient" />
</div>
<button @click="saveMeal">Save</button>
</div>
@ -50,14 +39,13 @@
import data from '@/data.js'
import RecipeSearchBox from '@/components/recipes/RecipeSearchBox.vue';
import RecipeCard from '@/components/recipes/RecipeCard.vue';
import CompactParsedIngredient from '@/components/ingredients/CompactParsedIngredient.vue';
import DatePicker from './DatePicker.vue';
import IngredientAddBox from '@/components/ingredients/IngredientAddBox.vue';
import EditableIngredientsPanel from '../ingredients/EditableIngredientsPanel.vue';
import PersonList from './PersonList.vue';
export default {
props: ['id'],
components: { RecipeSearchBox, DatePicker, RecipeCard, IngredientAddBox, CompactParsedIngredient, PersonList },
components: { RecipeSearchBox, DatePicker, RecipeCard, EditableIngredientsPanel, PersonList },
data() {
return {
meal: {
@ -98,12 +86,15 @@ export default {
removeRecipe(recipe) {
this.meal.recipes = this.meal.recipes.filter(r => r.id !== recipe.id);
},
addIngredient(ingredient) {
this.meal.extra_ingredients.push(ingredient);
addIngredient() {
this.meal.extra_ingredients = [{ line: '', product: null }, ...this.meal.extra_ingredients];
},
deleteIngredient(ingredient) {
this.meal.extra_ingredients = this.meal.extra_ingredients.filter(i => i != ingredient);
},
updateIngredient(ingredient, newIngredient) {
this.meal.extra_ingredients = this.meal.extra_ingredients.map(i => i == ingredient ? newIngredient : i);
},
removePerson(list, person) {
this.meal[list] = this.meal[list].filter(p => p.id !== person.id);
},

View file

@ -15,19 +15,12 @@
<h1><input class="recipe-name" type="text" v-model="recipe.name" /></h1>
<h3 class="recipe-link"><a :href="recipe.link">View Recipe</a></h3>
<h2>Ingredients</h2>
<ul>
<li v-for="ingredient in recipe.ingredients" :key="ingredient.line">
<p class="ingredient-line">
<ingredient-line
:ingredient="ingredient"
@update-ingredient="updateIngredient"
@update-product-link="updateProduct" />
</p>
<button @click="deleteIngredient(ingredient)">Delete</button>
</li>
</ul>
<editable-ingredients-panel
:ingredients="recipe.ingredients"
:edit-only="true"
@on-add="addIngredient" @on-delete="deleteIngredient" @on-update-ingredient="updateIngredient"
/>
<button @click="addIngredient">Add Ingredient</button>
<div>
<button v-if="recipe.id" class="delete-btn" @click="deleteRecipe">Delete</button>
<button class="submit-btn" @click="saveRecipe">{{ recipe.id ? "Save" : "Create" }}</button>
@ -65,40 +58,18 @@ input.recipe-name {
text-decoration: none;
}
ul {
padding: 0;
}
li {
list-style: none;
display: flex;
flex-direction: row;
justify-content: space-between;
border: 1px solid #ccc;
border-radius: 5px;
padding: 5px;
}
.ingredient-line {
flex: 1;
margin: 0;
margin-right: 1em;
}
</style>
<script>
import data from '@/data.js'
import IngredientLine from '@/components/ingredients/IngredientLine.vue'
import EditableIngredientsPanel from '@/components/ingredients/EditableIngredientsPanel.vue'
export default {
props: {
id: { type: Number, optional: true }
},
components: {
IngredientLine
},
components: { EditableIngredientsPanel },
data() {
return {
link: this.$route.query.url ?? "",
@ -139,17 +110,7 @@ export default {
this.recipe = null;
}
},
async updateProduct(ingredient, product_link) {
const product = await data.parseProduct(ingredient, product_link);
this.recipe.ingredients = this.recipe.ingredients.map(i => i.name == ingredient.name ? { ...i, product, product_id: product.id } : i);
},
async updateIngredient(ingredient, line) {
const newIngredients = await data.parseIngredients([line]);
const newIngredient = newIngredients[0];
if (!newIngredient?.product) {
newIngredient.product = ingredient.product;
}
async updateIngredient(ingredient, newIngredient) {
this.recipe.ingredients = this.recipe.ingredients.map(i => i == ingredient ? newIngredient : i);
},
deleteIngredient(ingredient) {
@ -174,7 +135,7 @@ export default {
}
},
addIngredient() {
this.recipe.ingredients.push({ line: '', product: null });
this.recipe.ingredients = [{ line: '', product: null }, ...this.recipe.ingredients];
},
async deleteRecipe() {
if (confirm('Are you sure you want to delete this recipe?')) {

View file

@ -90,7 +90,7 @@ export default {
const person = await data.currentUser();
if (!person) return;
this.sources = this.sources.concat([{ ingredient: { id: 0 }, person }]);
this.sources = [{ ingredient: { id: 0 }, person }, ...this.sources];
},
async deleteIngredient(ingredient) {
const person = await data.currentUser();