diff options
| author | Caine <caine@jihakuz.xyz> | 2026-04-02 23:08:43 +0100 |
|---|---|---|
| committer | Caine <caine@jihakuz.xyz> | 2026-04-02 23:08:43 +0100 |
| commit | c4ca4348edc5c4fd6cc36e9833fbb9c697f3bf9d (patch) | |
| tree | 54b06b47d639e15f7860b3366db40bdd648e9885 /kitchen/templates | |
| parent | 963ca2dd5549843e992af718053d08c10d5ec843 (diff) | |
Phase 4: HTMX frontend with dark palette
- 4 pages: Pantry, Recipes, Shopping List, Cook Log
- HTMX-powered: add/delete pantry items, toggle shopping, generate smart list
- Custom 13-colour palette from Lospec (dark bg, yellow accent)
- Mobile-responsive
- Whitenoise for static files in production
- All routes under /app/
- API (/api/) stays internal, frontend (/app/) for browser use
Diffstat (limited to 'kitchen/templates')
| -rw-r--r-- | kitchen/templates/kitchen/base.html | 409 | ||||
| -rw-r--r-- | kitchen/templates/kitchen/log.html | 10 | ||||
| -rw-r--r-- | kitchen/templates/kitchen/pantry.html | 43 | ||||
| -rw-r--r-- | kitchen/templates/kitchen/partials/cook_log.html | 31 | ||||
| -rw-r--r-- | kitchen/templates/kitchen/partials/pantry_table.html | 82 | ||||
| -rw-r--r-- | kitchen/templates/kitchen/partials/recipe_list.html | 63 | ||||
| -rw-r--r-- | kitchen/templates/kitchen/partials/shopping_list.html | 25 | ||||
| -rw-r--r-- | kitchen/templates/kitchen/recipes.html | 10 | ||||
| -rw-r--r-- | kitchen/templates/kitchen/shopping.html | 26 |
9 files changed, 699 insertions, 0 deletions
diff --git a/kitchen/templates/kitchen/base.html b/kitchen/templates/kitchen/base.html new file mode 100644 index 0000000..0bdc5f3 --- /dev/null +++ b/kitchen/templates/kitchen/base.html @@ -0,0 +1,409 @@ +{% load static %} +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>{% block title %}Kitchen{% endblock %}</title> + <script src="{% static 'kitchen/htmx.min.js' %}"></script> + <style> + :root { + --bg-dark: #15131c; + --navy: #0e0e5b; + --teal-dark: #325664; + --red-dark: #aa1010; + --orange-burnt: #bd6611; + --sage: #658d89; + --red-bright: #f01111; + --yellow: #f9df11; + --orange-warm: #fa9f45; + --teal-light: #87d1d1; + --grey-light: #babcc4; + --peach: #fdceb0; + --cream: #f7fdc7; + } + + * { margin: 0; padding: 0; box-sizing: border-box; } + + body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; + background: var(--bg-dark); + color: var(--grey-light); + min-height: 100vh; + line-height: 1.5; + } + + /* --- NAV --- */ + nav { + background: var(--navy); + padding: 0.75rem 1.5rem; + display: flex; + align-items: center; + gap: 2rem; + border-bottom: 2px solid var(--teal-dark); + position: sticky; + top: 0; + z-index: 100; + } + + nav .logo { + font-size: 1.25rem; + font-weight: 700; + color: var(--yellow); + text-decoration: none; + letter-spacing: 0.5px; + } + + nav .links { + display: flex; + gap: 0.25rem; + } + + nav a { + color: var(--grey-light); + text-decoration: none; + padding: 0.4rem 0.75rem; + border-radius: 4px; + font-size: 0.9rem; + transition: all 0.15s; + } + + nav a:hover, nav a.active { + background: var(--teal-dark); + color: var(--cream); + } + + /* --- LAYOUT --- */ + .container { + max-width: 960px; + margin: 0 auto; + padding: 1.5rem; + } + + h1 { + color: var(--yellow); + font-size: 1.5rem; + margin-bottom: 1rem; + font-weight: 600; + } + + h2 { + color: var(--teal-light); + font-size: 1.15rem; + margin: 1.5rem 0 0.75rem; + font-weight: 600; + } + + /* --- CARDS --- */ + .card { + background: rgba(50, 86, 100, 0.15); + border: 1px solid var(--teal-dark); + border-radius: 6px; + padding: 1rem; + margin-bottom: 0.75rem; + } + + .card-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 0.5rem; + } + + .card-title { + color: var(--cream); + font-weight: 600; + font-size: 1rem; + } + + /* --- TABLES --- */ + table { + width: 100%; + border-collapse: collapse; + margin-bottom: 1rem; + } + + th { + text-align: left; + color: var(--teal-light); + font-weight: 600; + font-size: 0.8rem; + text-transform: uppercase; + letter-spacing: 0.5px; + padding: 0.5rem 0.75rem; + border-bottom: 1px solid var(--teal-dark); + } + + td { + padding: 0.5rem 0.75rem; + border-bottom: 1px solid rgba(50, 86, 100, 0.3); + font-size: 0.9rem; + } + + tr:hover { + background: rgba(50, 86, 100, 0.15); + } + + /* --- BADGES --- */ + .badge { + display: inline-block; + padding: 0.15rem 0.5rem; + border-radius: 3px; + font-size: 0.75rem; + font-weight: 600; + } + + .badge-fridge { background: var(--teal-dark); color: var(--teal-light); } + .badge-freezer { background: var(--navy); color: var(--teal-light); } + .badge-cupboard { background: rgba(189, 102, 17, 0.25); color: var(--orange-warm); } + + .badge-ok { background: rgba(101, 141, 137, 0.25); color: var(--sage); } + .badge-expiring { background: rgba(250, 159, 69, 0.25); color: var(--orange-warm); } + .badge-expired { background: rgba(240, 17, 17, 0.25); color: var(--red-bright); } + + .badge-ready { background: rgba(101, 141, 137, 0.3); color: var(--sage); } + .badge-partial { background: rgba(249, 223, 17, 0.2); color: var(--yellow); } + .badge-missing { background: rgba(170, 16, 16, 0.25); color: var(--red-bright); } + + /* --- RATING --- */ + .stars { color: var(--yellow); letter-spacing: 1px; } + .stars-empty { color: var(--teal-dark); } + + /* --- BUTTONS --- */ + .btn { + display: inline-block; + padding: 0.4rem 0.9rem; + border: none; + border-radius: 4px; + font-size: 0.85rem; + font-weight: 600; + cursor: pointer; + transition: all 0.15s; + text-decoration: none; + } + + .btn-primary { + background: var(--yellow); + color: var(--bg-dark); + } + .btn-primary:hover { background: var(--cream); } + + .btn-secondary { + background: var(--teal-dark); + color: var(--grey-light); + } + .btn-secondary:hover { background: var(--sage); color: var(--cream); } + + .btn-danger { + background: transparent; + color: var(--red-dark); + border: 1px solid var(--red-dark); + } + .btn-danger:hover { background: var(--red-dark); color: var(--cream); } + + .btn-sm { + padding: 0.2rem 0.5rem; + font-size: 0.75rem; + } + + /* --- FORMS --- */ + input, select, textarea { + background: rgba(14, 14, 91, 0.3); + border: 1px solid var(--teal-dark); + color: var(--cream); + padding: 0.4rem 0.6rem; + border-radius: 4px; + font-size: 0.9rem; + font-family: inherit; + } + + input:focus, select:focus, textarea:focus { + outline: none; + border-color: var(--yellow); + box-shadow: 0 0 0 2px rgba(249, 223, 17, 0.15); + } + + input::placeholder { color: var(--sage); } + + label { + display: block; + color: var(--teal-light); + font-size: 0.8rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; + margin-bottom: 0.25rem; + } + + .form-group { margin-bottom: 0.75rem; } + + .form-row { + display: flex; + gap: 0.75rem; + flex-wrap: wrap; + } + + .form-row .form-group { flex: 1; min-width: 120px; } + + /* --- SLOT PICKER --- */ + .slot { + margin-bottom: 1rem; + } + + .slot-name { + color: var(--orange-warm); + font-size: 0.8rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; + margin-bottom: 0.4rem; + } + + .slot-options { + display: flex; + flex-wrap: wrap; + gap: 0.4rem; + } + + .slot-option { + padding: 0.3rem 0.7rem; + border: 1px solid var(--teal-dark); + border-radius: 4px; + font-size: 0.85rem; + cursor: pointer; + transition: all 0.15s; + background: transparent; + color: var(--grey-light); + } + + .slot-option:hover { + border-color: var(--yellow); + color: var(--cream); + } + + .slot-option.selected { + background: rgba(249, 223, 17, 0.15); + border-color: var(--yellow); + color: var(--yellow); + } + + .slot-option.unavailable { + opacity: 0.4; + border-style: dashed; + } + + /* --- SHOPPING LIST --- */ + .shop-item { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.5rem 0; + border-bottom: 1px solid rgba(50, 86, 100, 0.2); + } + + .shop-item input[type="checkbox"] { + accent-color: var(--yellow); + width: 1.1rem; + height: 1.1rem; + } + + .shop-item.checked .shop-name { + text-decoration: line-through; + color: var(--sage); + opacity: 0.6; + } + + .shop-section { + color: var(--orange-warm); + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; + padding: 0.75rem 0 0.25rem; + } + + /* --- COOK LOG --- */ + .log-entry { + display: flex; + gap: 1rem; + align-items: flex-start; + padding: 0.75rem 0; + border-bottom: 1px solid rgba(50, 86, 100, 0.2); + } + + .log-date { + color: var(--sage); + font-size: 0.8rem; + min-width: 5rem; + } + + .log-notes { + color: var(--grey-light); + font-size: 0.85rem; + font-style: italic; + margin-top: 0.25rem; + } + + /* --- EMPTY STATE --- */ + .empty { + text-align: center; + padding: 3rem; + color: var(--sage); + } + + .empty-icon { font-size: 2rem; margin-bottom: 0.5rem; } + + /* --- HTMX LOADING --- */ + .htmx-indicator { + display: none; + color: var(--yellow); + font-size: 0.8rem; + } + .htmx-request .htmx-indicator { display: inline; } + .htmx-request.htmx-indicator { display: inline; } + + /* --- TOAST --- */ + .toast { + position: fixed; + bottom: 1.5rem; + right: 1.5rem; + padding: 0.75rem 1.25rem; + border-radius: 6px; + font-size: 0.9rem; + font-weight: 600; + z-index: 1000; + animation: fadeIn 0.2s, fadeOut 0.3s 2.5s forwards; + } + + .toast-success { background: var(--sage); color: var(--bg-dark); } + .toast-error { background: var(--red-dark); color: var(--cream); } + + @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } + @keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } } + + /* --- RESPONSIVE --- */ + @media (max-width: 640px) { + nav { padding: 0.5rem 1rem; gap: 1rem; flex-wrap: wrap; } + .container { padding: 1rem; } + .form-row { flex-direction: column; } + .form-row .form-group { min-width: 100%; } + td, th { padding: 0.35rem 0.5rem; font-size: 0.8rem; } + } + </style> +</head> +<body> + <nav> + <a href="{% url 'app-pantry' %}" class="logo">🍳 Kitchen</a> + <div class="links"> + <a href="{% url 'app-pantry' %}" {% if active_tab == 'pantry' %}class="active"{% endif %}>Pantry</a> + <a href="{% url 'app-recipes' %}" {% if active_tab == 'recipes' %}class="active"{% endif %}>Recipes</a> + <a href="{% url 'app-shopping' %}" {% if active_tab == 'shopping' %}class="active"{% endif %}>Shopping</a> + <a href="{% url 'app-log' %}" {% if active_tab == 'log' %}class="active"{% endif %}>Cook Log</a> + </div> + </nav> + + <div class="container"> + {% block content %}{% endblock %} + </div> +</body> +</html> diff --git a/kitchen/templates/kitchen/log.html b/kitchen/templates/kitchen/log.html new file mode 100644 index 0000000..d45defb --- /dev/null +++ b/kitchen/templates/kitchen/log.html @@ -0,0 +1,10 @@ +{% extends "kitchen/base.html" %} +{% block title %}Cook Log — Kitchen{% endblock %} + +{% block content %} +<h1>Cook Log</h1> + +<div id="log-entries"> + {% include "kitchen/partials/cook_log.html" %} +</div> +{% endblock %} diff --git a/kitchen/templates/kitchen/pantry.html b/kitchen/templates/kitchen/pantry.html new file mode 100644 index 0000000..fac4d91 --- /dev/null +++ b/kitchen/templates/kitchen/pantry.html @@ -0,0 +1,43 @@ +{% extends "kitchen/base.html" %} +{% block title %}Pantry — Kitchen{% endblock %} + +{% block content %} +<h1>Pantry</h1> + +<!-- Add item form --> +<div class="card" style="margin-bottom: 1.5rem;"> + <form hx-post="{% url 'app-pantry-add' %}" hx-target="#pantry-items" hx-swap="innerHTML" hx-on::after-request="if(event.detail.successful) this.reset()"> + {% csrf_token %} + <div class="form-row"> + <div class="form-group" style="flex: 2;"> + <label for="ingredient_name">Ingredient</label> + <input type="text" id="ingredient_name" name="ingredient_name" placeholder="e.g. chicken thighs" required style="width: 100%;"> + </div> + <div class="form-group"> + <label for="quantity">Qty</label> + <input type="number" id="quantity" name="quantity" step="0.01" placeholder="2" required style="width: 100%;"> + </div> + <div class="form-group"> + <label for="unit">Unit</label> + <input type="text" id="unit" name="unit" placeholder="items" required style="width: 100%;"> + </div> + <div class="form-group"> + <label for="location">Location</label> + <select id="location" name="location" style="width: 100%;"> + <option value="fridge">Fridge</option> + <option value="freezer">Freezer</option> + <option value="cupboard">Cupboard</option> + </select> + </div> + <div class="form-group" style="display: flex; align-items: flex-end;"> + <button type="submit" class="btn btn-primary">Add</button> + </div> + </div> + </form> +</div> + +<!-- Pantry items --> +<div id="pantry-items"> + {% include "kitchen/partials/pantry_table.html" %} +</div> +{% endblock %} diff --git a/kitchen/templates/kitchen/partials/cook_log.html b/kitchen/templates/kitchen/partials/cook_log.html new file mode 100644 index 0000000..e0450f5 --- /dev/null +++ b/kitchen/templates/kitchen/partials/cook_log.html @@ -0,0 +1,31 @@ +{% for entry in entries %} +<div class="log-entry"> + <div class="log-date">{{ entry.date|date:"j M" }}</div> + <div style="flex: 1;"> + <div> + <span class="card-title">{{ entry.recipe_name }}</span> + {% if entry.rating %} + <span class="stars" style="margin-left: 0.5rem;"> + {% for i in "12345" %}{% if forloop.counter <= entry.rating %}★{% else %}<span class="stars-empty">★</span>{% endif %}{% endfor %} + </span> + {% endif %} + </div> + {% if entry.slot_choices %} + <div style="margin-top: 0.25rem;"> + {% for slot, choice in entry.slot_choices.items %} + <span class="badge badge-cupboard">{{ choice }}</span> + {% endfor %} + </div> + {% endif %} + {% if entry.notes %} + <div class="log-notes">{{ entry.notes }}</div> + {% endif %} + <div style="color: var(--sage); font-size: 0.75rem; margin-top: 0.25rem;">{{ entry.servings }} serving{{ entry.servings|pluralize }}</div> + </div> +</div> +{% empty %} +<div class="empty"> + <div class="empty-icon">📝</div> + <p>No cooks logged yet.</p> +</div> +{% endfor %} diff --git a/kitchen/templates/kitchen/partials/pantry_table.html b/kitchen/templates/kitchen/partials/pantry_table.html new file mode 100644 index 0000000..507eb17 --- /dev/null +++ b/kitchen/templates/kitchen/partials/pantry_table.html @@ -0,0 +1,82 @@ +{% if fridge_items or freezer_items or cupboard_items %} + +{% if fridge_items %} +<h2>🧊 Fridge</h2> +<table> + <thead><tr><th>Item</th><th>Qty</th><th>Expiry</th><th></th></tr></thead> + <tbody> + {% for item in fridge_items %} + <tr id="pantry-row-{{ item.id }}"> + <td>{{ item.ingredient.name }}</td> + <td>{{ item.quantity|floatformat:0 }} {{ item.unit }}</td> + <td> + {% if item.is_expired %} + <span class="badge badge-expired">Expired {{ item.expiry_date }}</span> + {% elif item.expiring_soon %} + <span class="badge badge-expiring">{{ item.expiry_date }}</span> + {% elif item.expiry_date %} + <span class="badge badge-ok">{{ item.expiry_date }}</span> + {% else %} + <span style="color: var(--sage);">—</span> + {% endif %} + </td> + <td style="text-align: right;"> + <button class="btn btn-danger btn-sm" + hx-delete="{% url 'app-pantry-delete' item.id %}" + hx-target="#pantry-items" + hx-confirm="Remove {{ item.ingredient.name }}?">✕</button> + </td> + </tr> + {% endfor %} + </tbody> +</table> +{% endif %} + +{% if freezer_items %} +<h2>❄️ Freezer</h2> +<table> + <thead><tr><th>Item</th><th>Qty</th><th></th></tr></thead> + <tbody> + {% for item in freezer_items %} + <tr id="pantry-row-{{ item.id }}"> + <td>{{ item.ingredient.name }}</td> + <td>{{ item.quantity|floatformat:0 }} {{ item.unit }}</td> + <td style="text-align: right;"> + <button class="btn btn-danger btn-sm" + hx-delete="{% url 'app-pantry-delete' item.id %}" + hx-target="#pantry-items" + hx-confirm="Remove {{ item.ingredient.name }}?">✕</button> + </td> + </tr> + {% endfor %} + </tbody> +</table> +{% endif %} + +{% if cupboard_items %} +<h2>🗄️ Cupboard</h2> +<table> + <thead><tr><th>Item</th><th>Qty</th><th></th></tr></thead> + <tbody> + {% for item in cupboard_items %} + <tr id="pantry-row-{{ item.id }}"> + <td>{{ item.ingredient.name }}{% if item.is_staple %} <span style="color: var(--yellow); font-size: 0.7rem;">STAPLE</span>{% endif %}</td> + <td>{{ item.quantity|floatformat:0 }} {{ item.unit }}</td> + <td style="text-align: right;"> + <button class="btn btn-danger btn-sm" + hx-delete="{% url 'app-pantry-delete' item.id %}" + hx-target="#pantry-items" + hx-confirm="Remove {{ item.ingredient.name }}?">✕</button> + </td> + </tr> + {% endfor %} + </tbody> +</table> +{% endif %} + +{% else %} +<div class="empty"> + <div class="empty-icon">🥡</div> + <p>Pantry's empty. Add some items above.</p> +</div> +{% endif %} diff --git a/kitchen/templates/kitchen/partials/recipe_list.html b/kitchen/templates/kitchen/partials/recipe_list.html new file mode 100644 index 0000000..6f6b777 --- /dev/null +++ b/kitchen/templates/kitchen/partials/recipe_list.html @@ -0,0 +1,63 @@ +{% for recipe in recipes %} +<div class="card"> + <div class="card-header"> + <span class="card-title"> + {% if recipe.status == 'ready' %} + <span class="badge badge-ready">✅ Ready</span> + {% elif recipe.status == 'partial' %} + <span class="badge badge-partial">⚠️ Partial</span> + {% else %} + <span class="badge badge-missing">❌ Missing</span> + {% endif %} + {{ recipe.name }} + </span> + {% if recipe.type == 'meta_recipe' %} + <span style="color: var(--sage); font-size: 0.8rem;">{{ recipe.gear }}</span> + {% endif %} + </div> + + {% if recipe.type == 'meta_recipe' %} + {% for slot in recipe.slots %} + <div class="slot"> + <div class="slot-name"> + {{ slot.name }} + {% if not slot.required %}<span style="color: var(--sage); font-size: 0.7rem;">(optional)</span>{% endif %} + </div> + <div class="slot-options"> + {% for opt in slot.available_options %} + <span class="slot-option" title="Have: {{ opt.have }}{% if opt.notes %} — {{ opt.notes }}{% endif %}"> + {{ opt.ingredient }} + </span> + {% endfor %} + {% for opt in slot.missing_options %} + <span class="slot-option unavailable" title="Need: {{ opt.needed }}{% if opt.notes %} — {{ opt.notes }}{% endif %}"> + {{ opt.ingredient }} + </span> + {% endfor %} + </div> + </div> + {% endfor %} + + {% if recipe.base_missing %} + <div style="margin-top: 0.5rem;"> + <span style="color: var(--red-bright); font-size: 0.8rem;"> + Missing base: {% for b in recipe.base_missing %}{{ b.ingredient }} ({{ b.needed }}){% if not forloop.last %}, {% endif %}{% endfor %} + </span> + </div> + {% endif %} + {% endif %} + + {% if recipe.warnings %} + <div style="margin-top: 0.5rem;"> + {% for w in recipe.warnings %} + <span style="color: var(--orange-warm); font-size: 0.8rem;">⚠ {{ w }}</span><br> + {% endfor %} + </div> + {% endif %} +</div> +{% empty %} +<div class="empty"> + <div class="empty-icon">📖</div> + <p>No recipes yet.</p> +</div> +{% endfor %} diff --git a/kitchen/templates/kitchen/partials/shopping_list.html b/kitchen/templates/kitchen/partials/shopping_list.html new file mode 100644 index 0000000..67e1bfc --- /dev/null +++ b/kitchen/templates/kitchen/partials/shopping_list.html @@ -0,0 +1,25 @@ +{% regroup items by section as sections %} +{% for section in sections %} +<div class="shop-section">{{ section.grouper|default:"Other" }}</div> +{% for item in section.list %} +<div class="shop-item {% if item.checked %}checked{% endif %}"> + <input type="checkbox" + {% if item.checked %}checked{% endif %} + hx-post="{% url 'app-shopping-toggle' item.id %}" + hx-target="#shopping-items" + hx-swap="innerHTML"> + <span class="shop-name"> + {{ item.name }} + {% if item.quantity %}<span style="color: var(--sage);">× {{ item.quantity|floatformat:0 }} {{ item.unit }}</span>{% endif %} + </span> + {% if item.reason %} + <span style="color: var(--sage); font-size: 0.75rem; margin-left: auto;">{{ item.reason }}</span> + {% endif %} +</div> +{% endfor %} +{% empty %} +<div class="empty"> + <div class="empty-icon">🛒</div> + <p>Shopping list is empty. Hit "Generate Smart List" to get suggestions.</p> +</div> +{% endfor %} diff --git a/kitchen/templates/kitchen/recipes.html b/kitchen/templates/kitchen/recipes.html new file mode 100644 index 0000000..d77b1bb --- /dev/null +++ b/kitchen/templates/kitchen/recipes.html @@ -0,0 +1,10 @@ +{% extends "kitchen/base.html" %} +{% block title %}Recipes — Kitchen{% endblock %} + +{% block content %} +<h1>What Can I Cook?</h1> + +<div id="recipe-list"> + {% include "kitchen/partials/recipe_list.html" %} +</div> +{% endblock %} diff --git a/kitchen/templates/kitchen/shopping.html b/kitchen/templates/kitchen/shopping.html new file mode 100644 index 0000000..ba2990f --- /dev/null +++ b/kitchen/templates/kitchen/shopping.html @@ -0,0 +1,26 @@ +{% extends "kitchen/base.html" %} +{% block title %}Shopping List — Kitchen{% endblock %} + +{% block content %} +<h1>Shopping List</h1> + +<div style="display: flex; gap: 0.75rem; margin-bottom: 1.5rem;"> + <button class="btn btn-primary" + hx-post="{% url 'app-shopping-generate' %}" + hx-target="#shopping-items" + hx-swap="innerHTML"> + 🔄 Generate Smart List + </button> + <button class="btn btn-secondary" + hx-post="{% url 'app-shopping-clear' %}" + hx-target="#shopping-items" + hx-swap="innerHTML" + hx-confirm="Clear checked items?"> + Clear Checked + </button> +</div> + +<div id="shopping-items"> + {% include "kitchen/partials/shopping_list.html" %} +</div> +{% endblock %} |
