12
This commit is contained in:
parent
d7cd3adc0e
commit
71ee90fe50
@ -3,7 +3,6 @@ body {
|
||||
background-color: #142E35; /* Dark green background */
|
||||
color: #ffffff; /* White text */
|
||||
font-family: 'Poppins', sans-serif;
|
||||
padding-top: 40px; /* Make space for garland */
|
||||
}
|
||||
|
||||
/* Headings */
|
||||
@ -15,7 +14,7 @@ h1, h2, h3, h4, h5, h6 {
|
||||
input,
|
||||
button,
|
||||
.btn {
|
||||
border-radius: 8px !important;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
|
||||
@ -93,8 +92,8 @@ body::before {
|
||||
|
||||
.form-control:focus {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
border-color: #C83434; /* Coral red accent */
|
||||
box-shadow: 0 0 0 0.25rem rgba(200, 52, 52, 0.25);
|
||||
border-color: #0a1a1f; /* Dark green accent */
|
||||
box-shadow: 0 0 0 0.25rem rgba(10, 26, 31, 0.25);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
@ -136,6 +135,7 @@ body::before {
|
||||
background-color: rgba(255, 255, 255, 0.15);
|
||||
border: none;
|
||||
color: #ffffff;
|
||||
padding: 12px 30px;
|
||||
}
|
||||
|
||||
/* Shopping List & Recipe Cards */
|
||||
@ -258,8 +258,8 @@ animation: fall linear infinite;
|
||||
}
|
||||
|
||||
.form-check-input:focus {
|
||||
border-color: #C83434;
|
||||
box-shadow: 0 0 0 0.25rem rgba(200, 52, 52, 0.25);
|
||||
border-color: #0a1a1f;
|
||||
box-shadow: 0 0 0 0.25rem rgba(10, 26, 31, 0.25);
|
||||
}
|
||||
|
||||
@media print {
|
||||
@ -306,11 +306,21 @@ animation: fall linear infinite;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#recipe-form-modal .modal-header, #add-product-modal .modal-header, #confirmationModal .modal-header {
|
||||
#recipe-form-modal .modal-header,
|
||||
#add-product-modal .modal-header,
|
||||
#confirmRemoveModal .modal-header {
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
#recipe-form-modal .btn-close, #add-product-modal .btn-close, #confirmationModal .btn-close {
|
||||
#recipe-form-modal .modal-footer,
|
||||
#add-product-modal .modal-footer,
|
||||
#confirmRemoveModal .modal-footer {
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
#recipe-form-modal .btn-close,
|
||||
#add-product-modal .btn-close,
|
||||
#confirmRemoveModal .btn-close {
|
||||
filter: invert(1);
|
||||
}
|
||||
|
||||
@ -344,10 +354,10 @@ animation: fall linear infinite;
|
||||
}
|
||||
|
||||
/* Shopping List Quantity Controls */
|
||||
.btn-quantity-modifier {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50% !important;
|
||||
.btn.btn-quantity-modifier {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
padding: 0;
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
@ -355,16 +365,16 @@ animation: fall linear infinite;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: none !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
color: white;
|
||||
background-color: #142E35; /* Very dark green */
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-quantity-modifier:hover {
|
||||
background-color: #1e3c46; /* Slightly lighter on hover */
|
||||
.btn.btn-quantity-modifier:hover {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.quantity-controls .quantity {
|
||||
@ -375,3 +385,6 @@ animation: fall linear infinite;
|
||||
.card .btn.delete-recipe {
|
||||
padding: .25rem .5rem;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
16
assets/images/christmas/bauble.svg
Normal file
16
assets/images/christmas/bauble.svg
Normal file
@ -0,0 +1,16 @@
|
||||
<svg width="100" height="120" viewBox="0 0 100 120" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Bauble Cap -->
|
||||
<rect x="40" y="0" width="20" height="10" fill="#f1c40f"/>
|
||||
|
||||
<!-- Bauble Loop -->
|
||||
<path d="M 50 10 Q 55 20 60 10" stroke="#f1c40f" stroke-width="2" fill="none"/>
|
||||
|
||||
<!-- Main Bauble with Gradient -->
|
||||
<defs>
|
||||
<radialGradient id="baubleGradient" cx="0.3" cy="0.3" r="0.7">
|
||||
<stop offset="0%" style="stop-color: #e74c3c; stop-opacity: 1" />
|
||||
<stop offset="100%" style="stop-color: #c0392b; stop-opacity: 1" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<circle cx="50" cy="60" r="40" fill="url(#baubleGradient)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 638 B |
31
assets/images/christmas/candy-cane.svg
Normal file
31
assets/images/christmas/candy-cane.svg
Normal file
@ -0,0 +1,31 @@
|
||||
<svg width="125" height="195" viewBox="-5 0 105 155" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient id="candy-stripes" gradientTransform="rotate(45)">
|
||||
<stop offset="0%" stop-color="#d51f28" />
|
||||
<stop offset="12.5%" stop-color="#d51f28" />
|
||||
<stop offset="12.5%" stop-color="white" />
|
||||
<stop offset="25%" stop-color="white" />
|
||||
<stop offset="25%" stop-color="#d51f28" />
|
||||
<stop offset="37.5%" stop-color="#d51f28" />
|
||||
<stop offset="37.5%" stop-color="white" />
|
||||
<stop offset="50%" stop-color="white" />
|
||||
<stop offset="50%" stop-color="#d51f28" />
|
||||
<stop offset="62.5%" stop-color="#d51f28" />
|
||||
<stop offset="62.5%" stop-color="white" />
|
||||
<stop offset="75%" stop-color="white" />
|
||||
<stop offset="75%" stop-color="#d51f28" />
|
||||
<stop offset="87.5%" stop-color="#d51f28" />
|
||||
<stop offset="87.5%" stop-color="white" />
|
||||
<stop offset="100%" stop-color="white" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<path
|
||||
d="M 75 140 V 50 C 75 22.38 52.62 0 25 0 S -25 22.38 -25 50"
|
||||
transform="translate(25, 5)"
|
||||
stroke="url(#candy-stripes)"
|
||||
stroke-width="25"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
6
assets/images/christmas/star.svg
Normal file
6
assets/images/christmas/star.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<svg width="100" height="100" viewBox="0 0 100 100">
|
||||
<polygon
|
||||
points="50,5 61,40 98,40 68,62 79,96 50,75 21,96 32,62 2,40 39,40"
|
||||
fill="#FFD700"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 165 B |
@ -451,61 +451,60 @@ const app = {
|
||||
const key = e.target.dataset.key;
|
||||
const [name, unit] = key.split('|');
|
||||
|
||||
// Find or create the item in additionalProducts to track adjustments
|
||||
if (!app.state.additionalProducts) {
|
||||
app.state.additionalProducts = [];
|
||||
}
|
||||
|
||||
let productToModify = app.state.additionalProducts.find(p => p.name.toLowerCase() === name.toLowerCase() && p.unit.toLowerCase() === unit.toLowerCase());
|
||||
if (!productToModify) {
|
||||
const properName = name.charAt(0).toUpperCase() + name.slice(1);
|
||||
productToModify = {
|
||||
name: properName,
|
||||
quantity: 0,
|
||||
unit: unit,
|
||||
source: 'Additional product'
|
||||
};
|
||||
app.state.additionalProducts.push(productToModify);
|
||||
}
|
||||
|
||||
if (productToModify && productToModify.quantity > 0) {
|
||||
productToModify.quantity--;
|
||||
app.ui.updateShoppingList();
|
||||
} else {
|
||||
// It's a recipe ingredient, show confirmation
|
||||
let recipeName = '';
|
||||
let ingredientName = '';
|
||||
let recipeId = null;
|
||||
let ingredientIndex = -1;
|
||||
|
||||
// Check if this ingredient is part of any recipe
|
||||
let isRecipeIngredient = false;
|
||||
let recipeNameForModal = '';
|
||||
for (const recipe of app.state.recipes) {
|
||||
const foundIngredientIndex = recipe.ingredients.findIndex(ing => ing.name.toLowerCase() === name.toLowerCase() && ing.unit.toLowerCase() === unit.toLowerCase());
|
||||
if (foundIngredientIndex !== -1) {
|
||||
recipeName = recipe.name;
|
||||
ingredientName = recipe.ingredients[foundIngredientIndex].name;
|
||||
recipeId = recipe.id;
|
||||
ingredientIndex = foundIngredientIndex;
|
||||
if (recipe.ingredients.some(ing => ing.name.toLowerCase() === name.toLowerCase() && ing.unit.toLowerCase() === unit.toLowerCase())) {
|
||||
isRecipeIngredient = true;
|
||||
recipeNameForModal = recipe.name; // Just need one name for the modal
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (recipeId !== null) {
|
||||
const confirmationKey = `${recipeId}-${name.toLowerCase()}-${unit.toLowerCase()}`;
|
||||
const recipeToUpdate = app.state.recipes.find(r => r.id === recipeId);
|
||||
|
||||
const proceedWithRemoval = () => {
|
||||
if (recipeToUpdate && recipeToUpdate.ingredients[ingredientIndex].quantity > 0) {
|
||||
recipeToUpdate.ingredients[ingredientIndex].quantity--;
|
||||
}
|
||||
app.ui.updateShoppingList();
|
||||
};
|
||||
// If it's a recipe ingredient and we're about to remove from the recipe's contribution
|
||||
if (isRecipeIngredient && productToModify.quantity <= 0) {
|
||||
const confirmationKey = `${name.toLowerCase()}-${unit.toLowerCase()}`;
|
||||
|
||||
if (app.state.confirmedRecipeProducts.includes(confirmationKey)) {
|
||||
proceedWithRemoval();
|
||||
productToModify.quantity--;
|
||||
app.ui.updateShoppingList();
|
||||
} else {
|
||||
document.getElementById('modal-recipe-name').textContent = recipeName;
|
||||
document.getElementById('modal-ingredient-name').textContent = ingredientName;
|
||||
document.getElementById('modal-recipe-name').textContent = recipeNameForModal;
|
||||
document.getElementById('modal-ingredient-name').textContent = productToModify.name;
|
||||
|
||||
const confirmModal = new bootstrap.Modal(document.getElementById('confirmRemoveModal'));
|
||||
confirmModal.show();
|
||||
|
||||
document.getElementById('confirm-remove-btn').onclick = () => {
|
||||
app.state.confirmedRecipeProducts.push(confirmationKey);
|
||||
proceedWithRemoval();
|
||||
productToModify.quantity--;
|
||||
app.ui.updateShoppingList();
|
||||
confirmModal.hide();
|
||||
};
|
||||
}
|
||||
} else if (productToModify.quantity > 0) {
|
||||
// It's not a recipe ingredient about to be removed, but has been added via '+'
|
||||
productToModify.quantity--;
|
||||
app.ui.updateShoppingList();
|
||||
}
|
||||
}
|
||||
// If not a recipe ingredient and quantity is 0, do nothing.
|
||||
}
|
||||
});
|
||||
|
||||
@ -519,7 +518,11 @@ const app = {
|
||||
|
||||
app.dom.recipeSearchInput.addEventListener('input', function() {
|
||||
const searchTerm = app.dom.recipeSearchInput.value.toLowerCase();
|
||||
const filteredRecipes = app.state.recipes.filter(recipe => recipe.name.toLowerCase().includes(searchTerm));
|
||||
const filteredRecipes = app.state.recipes.filter(recipe => {
|
||||
const recipeName = recipe.name.toLowerCase();
|
||||
const ingredients = recipe.ingredients.map(ing => ing.name.toLowerCase()).join(' ');
|
||||
return recipeName.includes(searchTerm) || ingredients.includes(searchTerm);
|
||||
});
|
||||
app.ui.renderRecipeCards(filteredRecipes);
|
||||
});
|
||||
|
||||
|
||||
BIN
assets/pasted-20251130-190335-947532cc.png
Normal file
BIN
assets/pasted-20251130-190335-947532cc.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 208 KiB |
BIN
assets/pasted-20251130-190720-ae17f828.png
Normal file
BIN
assets/pasted-20251130-190720-ae17f828.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 208 KiB |
Loading…
x
Reference in New Issue
Block a user