summaryrefslogtreecommitdiffstats
path: root/app/templates/recipe_add.html
diff options
context:
space:
mode:
Diffstat (limited to 'app/templates/recipe_add.html')
-rw-r--r--app/templates/recipe_add.html216
1 files changed, 216 insertions, 0 deletions
diff --git a/app/templates/recipe_add.html b/app/templates/recipe_add.html
new file mode 100644
index 0000000..f0a0538
--- /dev/null
+++ b/app/templates/recipe_add.html
@@ -0,0 +1,216 @@
+{% extends "base.html" %}
+{% block title %}Add Recipe — Menu Planner{% endblock %}
+
+{% block content %}
+<div class="mb-3">
+ <a href="/recipes" class="btn btn-sm btn-outline-secondary"><i class="bi bi-arrow-left me-1"></i>Back to Recipes</a>
+</div>
+
+<h1 class="h3 fw-bold mb-4">Add a New Recipe</h1>
+
+<form method="POST" action="/recipes/add" id="recipeForm">
+ <div class="row g-4">
+
+ <!-- Left column: basic info + instructions -->
+ <div class="col-lg-7">
+
+ <!-- Basic info -->
+ <div class="card shadow-sm mb-4">
+ <div class="card-header fw-semibold">Basic Information</div>
+ <div class="card-body">
+ <div class="mb-3">
+ <label class="form-label fw-semibold">Recipe Name <span class="text-danger">*</span></label>
+ <input type="text" name="name" class="form-control" required
+ value="{{ form.get('name','') }}" placeholder="e.g. Chicken Marsala">
+ </div>
+ <div class="row g-3 mb-3">
+ <div class="col-sm-6">
+ <label class="form-label fw-semibold">Cuisine <span class="text-danger">*</span></label>
+ <input type="text" name="cuisine" class="form-control" required
+ list="cuisine-list" autocomplete="off"
+ placeholder="e.g. Italian, Mexican…"
+ value="{{ form.get('cuisine', '') }}">
+ <datalist id="cuisine-list">
+ {% for c in cuisines %}<option value="{{ c }}">{% endfor %}
+ </datalist>
+ </div>
+ <div class="col-sm-6">
+ <label class="form-label fw-semibold">Default Servings</label>
+ <input type="number" name="servings" class="form-control" min="1" max="20"
+ value="{{ form.get('servings', 2) }}">
+ <div class="form-text">Base recipe yields (shopping list scales from this)</div>
+ </div>
+ </div>
+ <div class="mb-0">
+ <label class="form-label fw-semibold">Description</label>
+ <textarea name="description" class="form-control" rows="2"
+ placeholder="One sentence that makes this dish sound irresistible…">{{ form.get('description','') }}</textarea>
+ </div>
+ </div>
+ </div>
+
+ <!-- Timing -->
+ <div class="card shadow-sm mb-4">
+ <div class="card-header fw-semibold">Timing</div>
+ <div class="card-body">
+ <div class="row g-3">
+ <div class="col-sm-6">
+ <label class="form-label fw-semibold">Prep Time (minutes)</label>
+ <input type="number" name="prep_time" class="form-control" min="0"
+ value="{{ form.get('prep_time', '') }}" placeholder="15">
+ </div>
+ <div class="col-sm-6">
+ <label class="form-label fw-semibold">Cook Time (minutes)</label>
+ <input type="number" name="cook_time" class="form-control" min="0"
+ value="{{ form.get('cook_time', '') }}" placeholder="30">
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <!-- Instructions -->
+ <div class="card shadow-sm mb-4">
+ <div class="card-header fw-semibold">Instructions</div>
+ <div class="card-body">
+ <textarea name="instructions" class="form-control font-monospace" rows="10"
+ placeholder="1. First step.&#10;2. Second step.&#10;3. Third step.">{{ form.get('instructions','') }}</textarea>
+ <div class="form-text mt-1">Number each step: <code>1. Heat oil…</code></div>
+ </div>
+ </div>
+
+ </div>
+
+ <!-- Right column: nutrition + ingredients -->
+ <div class="col-lg-5">
+
+ <!-- Nutrition -->
+ <div class="card shadow-sm mb-4">
+ <div class="card-header fw-semibold">Nutrition <span class="text-muted small fw-normal">(per serving)</span></div>
+ <div class="card-body">
+ <div class="row g-2">
+ <div class="col-6">
+ <label class="form-label small fw-semibold">Calories</label>
+ <div class="input-group input-group-sm">
+ <input type="number" name="calories_per_serving" class="form-control"
+ min="0" step="5" value="{{ form.get('calories_per_serving','') }}" placeholder="400">
+ <span class="input-group-text">kcal</span>
+ </div>
+ </div>
+ <div class="col-6">
+ <label class="form-label small fw-semibold">Net Carbs</label>
+ <div class="input-group input-group-sm">
+ <input type="number" name="carbs_per_serving" class="form-control"
+ min="0" step="0.5" value="{{ form.get('carbs_per_serving','') }}" placeholder="8">
+ <span class="input-group-text">g</span>
+ </div>
+ </div>
+ <div class="col-6">
+ <label class="form-label small fw-semibold">Protein</label>
+ <div class="input-group input-group-sm">
+ <input type="number" name="protein_per_serving" class="form-control"
+ min="0" step="0.5" value="{{ form.get('protein_per_serving','') }}" placeholder="40">
+ <span class="input-group-text">g</span>
+ </div>
+ </div>
+ <div class="col-6">
+ <label class="form-label small fw-semibold">Fat</label>
+ <div class="input-group input-group-sm">
+ <input type="number" name="fat_per_serving" class="form-control"
+ min="0" step="0.5" value="{{ form.get('fat_per_serving','') }}" placeholder="20">
+ <span class="input-group-text">g</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <!-- Ingredients -->
+ <div class="card shadow-sm">
+ <div class="card-header d-flex align-items-center justify-content-between fw-semibold">
+ Ingredients
+ <button type="button" id="addIngBtn" class="btn btn-sm btn-outline-primary">
+ <i class="bi bi-plus"></i> Add Row
+ </button>
+ </div>
+ <div class="card-body p-2">
+ <table class="table table-sm mb-0" id="ingTable">
+ <thead class="table-light">
+ <tr>
+ <th style="width:70px">Qty</th>
+ <th style="width:85px">Unit</th>
+ <th>Ingredient</th>
+ <th style="width:120px">Category</th>
+ <th style="width:30px"></th>
+ </tr>
+ </thead>
+ <tbody id="ingBody">
+ <!-- 3 starter rows -->
+ </tbody>
+ </table>
+ </div>
+ </div>
+
+ </div>
+ </div>
+
+ <div class="d-flex gap-2 mt-4 justify-content-end">
+ <a href="/recipes" class="btn btn-outline-secondary">Cancel</a>
+ <button type="submit" class="btn btn-primary px-4">
+ <i class="bi bi-check-circle me-1"></i>Save Recipe
+ </button>
+ </div>
+</form>
+{% endblock %}
+
+{% block scripts %}
+<script>
+const UNITS = {{ units | tojson }};
+const CATS = {{ categories | tojson }};
+
+function unitOptions(selected='whole') {
+ return UNITS.map(u => `<option value="${u}"${u===selected?' selected':''}>${u}</option>`).join('');
+}
+function catOptions(selected='Produce') {
+ return CATS.map(c => `<option value="${c}"${c===selected?' selected':''}>${c}</option>`).join('');
+}
+
+function newRow(qty='', unit='whole', name='', cat='Produce') {
+ const tr = document.createElement('tr');
+ tr.className = 'ing-row';
+ tr.innerHTML = `
+ <td><input type="number" name="ing_qty" class="form-control form-control-sm" min="0" step="0.25" value="${qty}" placeholder="1"></td>
+ <td><select name="ing_unit" class="form-select form-select-sm">${unitOptions(unit)}</select></td>
+ <td><input type="text" name="ing_name" class="form-control form-control-sm" value="${name}" placeholder="Ingredient…"></td>
+ <td><select name="ing_category" class="form-select form-select-sm">${catOptions(cat)}</select></td>
+ <td><button type="button" class="btn btn-sm btn-link text-danger p-0 remove-row" title="Remove"><i class="bi bi-x-lg"></i></button></td>
+ `;
+ return tr;
+}
+
+const body = document.getElementById('ingBody');
+
+// Seed 4 empty rows
+for (let i = 0; i < 4; i++) body.appendChild(newRow());
+
+document.getElementById('addIngBtn').addEventListener('click', () => {
+ body.appendChild(newRow());
+ body.lastElementChild.querySelector('input[name="ing_name"]').focus();
+});
+
+body.addEventListener('click', e => {
+ const btn = e.target.closest('.remove-row');
+ if (btn) {
+ const rows = body.querySelectorAll('.ing-row');
+ if (rows.length > 1) btn.closest('tr').remove();
+ }
+});
+
+// Don't submit empty ingredient rows
+document.getElementById('recipeForm').addEventListener('submit', function() {
+ body.querySelectorAll('.ing-row').forEach(row => {
+ const name = row.querySelector('input[name="ing_name"]').value.trim();
+ if (!name) row.querySelectorAll('input, select').forEach(el => el.disabled = true);
+ });
+});
+</script>
+{% endblock %}