Compare commits

..

5 commits

8 changed files with 129 additions and 92 deletions

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#000000" width="800px" height="800px" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M26 3 A 1.0001 1.0001 0 0 0 25 4L25 7.6972656L21.167969 13.445312 A 1.0001 1.0001 0 0 0 21.166016 13.447266 A 1.0001 1.0001 0 0 0 21.130859 13.505859 A 1.0001 1.0001 0 0 0 21.111328 13.542969 A 1.0001 1.0001 0 0 0 21.105469 13.558594 A 1.0001 1.0001 0 0 0 21.037109 13.732422 A 1.0001 1.0001 0 0 0 21.033203 13.748047 A 1.0001 1.0001 0 0 0 21.017578 13.816406 A 1.0001 1.0001 0 0 0 21.003906 13.90625 A 1.0001 1.0001 0 0 0 21.003906 13.914062 A 1.0001 1.0001 0 0 0 21 14 A 1.0001 1.0001 0 0 0 21 14.011719L21 20L5 20 A 1.0001 1.0001 0 0 0 4 21L4 45 A 1.0001 1.0001 0 0 0 5 46L14.275391 46C15.040306 46.872658 15.962077 47.569588 16.976562 48.027344C19.557836 49.192064 22.896153 48.926876 25.537109 46.894531 A 1.0001 1.0001 0 0 0 26 47L39 47L45 47 A 1.0001 1.0001 0 0 0 46 46L46 14 A 1.0001 1.0001 0 0 0 45.894531 13.552734L43 7.7636719L43 4 A 1.0001 1.0001 0 0 0 42 3L26 3 z M 27 5L41 5L41 7L27 7L27 5 z M 26.535156 9L40.382812 9L38.382812 13L23.869141 13L26.535156 9 z M 42 10.236328L44 14.236328L44 45L40 45L40 14.236328L42 10.236328 z M 23 15L38 15L38 45L27.378906 45C27.836847 44.384682 28.253606 43.697922 28.605469 42.917969C29.82748 40.209741 30.243093 37.066535 29.869141 34.294922C29.495189 31.523309 28.310947 29.004254 26.023438 27.972656C25.451584 27.714611 24.856442 27.571327 24.248047 27.523438C23.836595 27.49105 23.419451 27.509295 23 27.560547L23 21L23 15 z M 6 22L21 22L21 28 A 1.0001 1.0001 0 0 0 21.003906 28.082031C20.230505 28.384537 19.468236 28.786964 18.740234 29.273438C16.41485 30.827333 14.331355 33.219577 13.109375 35.927734C11.755522 38.92815 11.922502 41.766212 12.96875 44L6 44L6 22 z M 24.064453 29.527344C24.475261 29.553208 24.857775 29.64192 25.201172 29.796875C26.574663 30.416278 27.567171 32.19216 27.886719 34.560547C28.206267 36.928934 27.832189 39.770931 26.783203 42.095703C24.705876 46.700399 20.586111 47.462754 17.798828 46.205078C15.011465 44.947365 12.854414 41.353558 14.931641 36.75C15.980661 34.425157 17.864447 32.265354 19.851562 30.9375C20.845122 30.273573 21.838486 29.833234 22.755859 29.636719C23.214546 29.538461 23.653646 29.501479 24.064453 29.527344 z"/></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -110,6 +110,10 @@
border-bottom: 1px solid #ccc;
}
.date-picker-dropdown li:hover {
background-color: #eee;
}
.date-picker-dropdown li:last-child {
border-bottom: none;
}

View file

@ -11,19 +11,33 @@
<div class="recipes">
<h2>Recipes</h2>
<ul v-if="meal.recipes && meal.recipes.length">
<li v-for="meal_recipe in meal.recipes" :key="meal_recipe.recipe.id" class="saved-recipe">
<li v-for="mealRecipe in meal.recipes" :key="mealRecipe.recipe.id">
<div class="saved-recipe">
<p class="recipe-card">
<recipe-card :recipe="meal_recipe.recipe" />
<recipe-card :recipe="mealRecipe.recipe" />
</p>
<p class="servings">
<input type="number" v-model="meal_recipe.servings" min="1" />
<input type="number" v-model="mealRecipe.servings" min="1" />
<small><em>servings</em></small>
</p>
<button class="delete-button" @click="removeRecipe(meal_recipe)">
<input type="checkbox" class="show-ingredient-checkbox" :checked="showIngredient(mealRecipe)" />
<label for="show-ingredients" @click="showIngredient(mealRecipe, !showIngredient(mealRecipe))">
<img class="icon" :src="require('@/assets/show-ingredients.svg')" />
</label>
<button class="icon-button" @click="removeRecipe(mealRecipe)">
<img class="icon" :src="require('@/assets/trash.svg')" />
</button>
</div>
<div v-if="showIngredient(mealRecipe)">
<ul>
<li v-for="ingredient in scaleIngredients(mealRecipe)" :key="ingredient.id" class="saved-ingredient">
<CompactParsedIngredient :ingredient="ingredient" />
</li>
</ul>
</div>
</li>
</ul>
<div v-else>
@ -39,20 +53,23 @@
</div>
<button @click="saveMeal">Save</button>
<p v-if="meal.purchase_date"><em>Purchased {{ formatDate(meal.purchase_date) }}</em></p>
<p v-if="meal.purchase_date"><em>Purchased {{ ago(meal.purchase_date) }}</em></p>
</div>
</template>
<script>
import data from '@/data.js';
import alert from '@/alert.js';
import { ago } from '@/dateformats.js';
import RecipeSearchBox from '@/components/recipes/RecipeSearchBox.vue';
import RecipeCard from '@/components/recipes/RecipeCard.vue';
import DatePicker from './DatePicker.vue';
import EditableIngredientsPanel from '../ingredients/EditableIngredientsPanel.vue';
import PersonList from './PersonList.vue';
import CompactParsedIngredient from '../ingredients/CompactParsedIngredient.vue';
function addPersonIfNotExists(list, person) {
if (!list.find(p => p.id === person.id)) {
@ -62,9 +79,10 @@ function addPersonIfNotExists(list, person) {
export default {
props: ['id'],
components: { RecipeSearchBox, DatePicker, RecipeCard, EditableIngredientsPanel, PersonList },
components: { RecipeSearchBox, DatePicker, RecipeCard, EditableIngredientsPanel, PersonList, CompactParsedIngredient },
data() {
return {
showIngredients: {},
meal: {
id: -1,
suggested_date: new Date(),
@ -86,6 +104,7 @@ export default {
}
},
methods: {
ago,
async selectRecipe(recipe) {
// Refetch to get additional details
recipe = await data.getRecipe(recipe.id);
@ -104,31 +123,10 @@ export default {
selectDate(date) {
this.meal.suggested_date = date;
},
formatDate(date) {
// If it's today, show 'x hours ago'
// If it's within the last week, show 'x days ago'
// If it's within the last month weeks, show 'x weeks ago'
// Otherwise, show the date as dd/mm
const now = new Date();
const diff = now - date;
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
if (days === 0) {
const hours = Math.floor(diff / (1000 * 60 * 60));
return `${hours} hour${hours === 1 ? '' : 's'} ago`;
}
if (days < 7) {
return `${days} day${days === 1 ? '' : 's'} ago`;
}
if (days < 30) {
return `${Math.floor(days / 7)} week${days === 7 ? '' : 's'} ago`;
}
return date.toLocaleDateString('en-au', { day: 'numeric', month: 'numeric' });
},
removeRecipe(mealRecipe) {
if (confirm(`Are you sure you want to remove ${mealRecipe.servings} servings of ${mealRecipe.recipe.name} from this meal?`)) {
this.meal.recipes = this.meal.recipes.filter(r => r != mealRecipe);
}
},
addIngredient() {
this.meal.extra_ingredients = [{ line: '', product: null }, ...this.meal.extra_ingredients];
@ -164,7 +162,24 @@ export default {
else {
this.meal.extra_ingredients = this.meal.extra_ingredients.filter(i => i.line);
}
},
showIngredient(mealRecipe, value) {
const index = this.meal.recipes.indexOf(mealRecipe);
const key = `${mealRecipe.recipe.id}-${index}`;
if (value === undefined) {
return this.showIngredients[key];
}
return this.showIngredients[key] = value;
},
scaleIngredients(mealRecipe) {
return mealRecipe.recipe.ingredients.map(i => {
return {
...i,
quantity: i.quantity * mealRecipe.servings / mealRecipe.recipe.serves
};
});
},
}
}
</script>
@ -250,7 +265,7 @@ li {
font-style: italic;
}
.delete-button {
.icon-button {
background: none;
border: none;
cursor: pointer;
@ -258,9 +273,28 @@ li {
padding: 0.5em;
}
.delete-button:hover {
.icon-button:hover {
/* Invert the colors of the trash icon */
filter: invert(1);
}
.show-ingredient-checkbox {
display: none;
}
.show-ingredient-checkbox + label {
cursor: pointer;
background-color: #fff;
padding: 0.5em;
border-radius: 1em;
}
.show-ingredient-checkbox + label:hover {
background-color: #eee;
}
.show-ingredient-checkbox:checked + label {
filter: invert(1);
}
</style>

View file

@ -40,7 +40,7 @@
<span v-if="!meal.consumers.length">somebody?</span>
</p>
<p v-if="meal.purchase_date">
Purchased {{ formatDate(meal.purchase_date) }}
Purchased {{ ago(meal.purchase_date) }}
</p>
</div>
</template>
@ -49,6 +49,9 @@
</style>
<script>
import { ago } from '@/dateformats.js'
export default {
name: 'MealCard',
props: ['meal'],
@ -71,25 +74,7 @@ export default {
return ', ';
}
},
formatDate(datetime) {
// If its less than a week, use "2 minutes ago" style
const diff = new Date() - datetime;
if (diff < 1000 * 60 * 60 * 24 * 7) {
const minutes = Math.floor(diff / 1000 / 60);
if (minutes < 60) {
return `${minutes} minute${minutes === 1 ? '' : 's'} ago`;
}
const hours = Math.floor(minutes / 60);
if (hours < 24) {
return `${hours} hour${hours === 1 ? '' : 's'} ago`;
}
const days = Math.floor(hours / 24);
return `${days} day${days === 1 ? '' : 's'} ago`;
}
// Otherwise, use a date format with the day of week prepended
return `${datetime.toLocaleDateString('en-au', { weekday: 'long' })} ${datetime.toLocaleDateString('en-au', { month: 'numeric', day: 'numeric' })}`;
}
ago
}
}
</script>

View file

@ -10,6 +10,12 @@
</li>
</ul>
<div v-if="productGroupsToPurchase.length === 0">
<p>
No items to purchase
</p>
</div>
<div class="purchased-slider">
<span v-if="purchasedGroups.length === 0"></span>
<button v-else-if="showPurchased" @click="showPurchased=false" > Hide Purchased </button>
@ -27,6 +33,10 @@
</div>
</div>
<div class="spacer" v-if="selected.length">
&nbsp;
</div>
<!-- Display 'Stocked', 'Purchased' and 'Cancel' buttons in a vertical stack fixed to the bottom of the screen when any elements are selected -->
<div class="footer-buttons" v-if="selected.length">
<p v-if="selected.length === 1">
@ -114,6 +124,10 @@ button img {
height: 2em;
}
.spacer {
height: 12em;
}
</style>
<script>

View file

@ -1,5 +1,5 @@
<template>
<h3>Purchased {{ shoppingList?.purchased_date?.toLocaleDateString({ year: 'numeric', month: '2-digit', day: '2-digit' }) || '' }}</h3>
<h3>Purchased {{ shoppingList ? ago(shoppingList.created_date) : '' }}</h3>
<h4>Included Meals</h4>
<meal-selection-list :checked="includedMeals" :meals="includedMeals" />
@ -29,6 +29,8 @@
<script>
import { ago } from '@/dateformats.js'
import data from '@/data.js'
import { purchasedToProductModel } from './shopping.js'
@ -53,6 +55,9 @@ export default {
this.includedMeals = this.shoppingList.requests.map(r => r.meal).filter(m => m);
this.listByProduct = purchasedToProductModel(this.shoppingList);
},
methods: {
ago
}
}
</script>

View file

@ -108,6 +108,7 @@
<script>
import { ago } from '@/dateformats.js';
import { calculateTotals } from '@/units.js';
export default {
@ -136,35 +137,7 @@ export default {
if (!date)
return '';
// Eg 30 seconds ago, 5 minutes ago, 1 hour ago, 2 days ago, 3 weeks ago, 4 months ago, 5 years ago
const seconds = Math.floor((new Date() - date) / 1000);
let interval = Math.floor(seconds / 31536000);
if (interval > 1) {
return interval + " years ago";
}
interval = Math.floor(seconds / 2592000);
if (interval > 1) {
return interval + " months ago";
}
interval = Math.floor(seconds / 86400);
if (interval > 1) {
return interval + " days ago";
}
interval = Math.floor(seconds / 3600);
if (interval > 1) {
return interval + " hours ago";
}
interval = Math.floor(seconds / 60);
if (interval > 1) {
return interval + " minutes ago";
}
return "moments ago";
return ago(date);
},
formatQuantity(quantity) {
const log10 = Math.log10(quantity);

20
src/dateformats.js Normal file
View file

@ -0,0 +1,20 @@
export function ago(date) {
const now = new Date();
const diff = now - date;
if (diff < 1000) {
return "just now";
}
if (diff < 60 * 1000) {
return Math.floor(diff / 1000) + " seconds ago";
}
if (diff < 60 * 60 * 1000) {
return Math.floor(diff / (60 * 1000)) + " minutes ago";
}
if (diff < 24 * 60 * 60 * 1000) {
return Math.floor(diff / (60 * 60 * 1000)) + " hours ago";
}
if (diff < 7 * 24 * 60 * 60 * 1000) {
return Math.floor(diff / (24 * 60 * 60 * 1000)) + " days ago";
}
return date.toLocaleDateString();
}