From 55bcec90c14db6f2956ed51cf4df1503c0767f81 Mon Sep 17 00:00:00 2001 From: Ken D'Ambrosio Date: Mon, 25 May 2026 00:46:10 +0000 Subject: =?UTF-8?q?Initial=20commit=20=E2=80=94=20menu.jots.org=20Flask/SQ?= =?UTF-8?q?Lite=20meal=20planner?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Full-featured weekly menu planner with: - Recipe library with ratings, comments, cuisine/nationality, added-by attribution - AI recipe assistant (Claude) with URL fetching and file upload - Weekly meal plan grid with shopping list generation - Sort by name, prep/cook time, or rating - Print and copy-link support - Deployed on LXC container (192.168.10.51) behind Apache reverse proxy Co-Authored-By: Claude Sonnet 4.6 --- app/templates/ai_chat.html | 241 ++++++++++++++++++++++++++++++++ app/templates/base.html | 99 +++++++++++++ app/templates/index.html | 116 ++++++++++++++++ app/templates/login.html | 39 ++++++ app/templates/meal_plan.html | 265 +++++++++++++++++++++++++++++++++++ app/templates/recipe_add.html | 216 +++++++++++++++++++++++++++++ app/templates/recipe_detail.html | 290 +++++++++++++++++++++++++++++++++++++++ app/templates/recipes.html | 121 ++++++++++++++++ app/templates/shopping_list.html | 167 ++++++++++++++++++++++ 9 files changed, 1554 insertions(+) create mode 100644 app/templates/ai_chat.html create mode 100644 app/templates/base.html create mode 100644 app/templates/index.html create mode 100644 app/templates/login.html create mode 100644 app/templates/meal_plan.html create mode 100644 app/templates/recipe_add.html create mode 100644 app/templates/recipe_detail.html create mode 100644 app/templates/recipes.html create mode 100644 app/templates/shopping_list.html (limited to 'app/templates') diff --git a/app/templates/ai_chat.html b/app/templates/ai_chat.html new file mode 100644 index 0000000..82d2604 --- /dev/null +++ b/app/templates/ai_chat.html @@ -0,0 +1,241 @@ +{% extends "base.html" %} +{% block title %}Recipe Assistant — Menu Planner{% endblock %} + +{% block content %} +
+ + +
+
+

Recipe Assistant

+

Paste any recipe — I'll parse it, adapt it for low-carb, and add it to the library.

+
+ +
+ + {% if not has_api_key %} +
+ + API key not configured. Set ANTHROPIC_API_KEY in the Docker environment to enable the recipe assistant. +
+ {% else %} + + +
+
+
+

👋 Hi! I can add recipes to the planner for you. Just paste a recipe — from a website, cookbook, or your own notes — and I'll handle the rest.

+

I'll parse ingredients, estimate nutrition, categorize it, and adapt for low-carb if needed.

+
+
+
+ + +
+
+ + + +
+
+ + + +
+
+ Shift+Enter for new line · Enter to send + +
+
+ + {% endif %} +
+{% endblock %} + +{% block scripts %} +{% if has_api_key %} + +{% endif %} +{% endblock %} diff --git a/app/templates/base.html b/app/templates/base.html new file mode 100644 index 0000000..b58ef64 --- /dev/null +++ b/app/templates/base.html @@ -0,0 +1,99 @@ + + + + + + {% block title %}Menu Planner{% endblock %} + + + + + + + + +
+ {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} + + {% endfor %} + {% endif %} + {% endwith %} + {% block content %}{% endblock %} +
+ +
+ Menu Planner — Low-carb, big flavor +
+ + + +{% block scripts %}{% endblock %} + + diff --git a/app/templates/index.html b/app/templates/index.html new file mode 100644 index 0000000..c33e348 --- /dev/null +++ b/app/templates/index.html @@ -0,0 +1,116 @@ +{% extends "base.html" %} +{% block title %}Dashboard — Menu Planner{% endblock %} + +{% block content %} +
+
+

This Week's Plan

+

{{ week_start.strftime('%B %d') }} – {{ (dates[-1]).strftime('%B %d, %Y') }}

+
+ +
+ + +
+
+
+
{{ plan | length }}
+
Meals Planned
+
+
+
+
+
{{ stat_map.get('favorited', 0) }}
+
Favorited Recipes
+
+
+
+
+
{{ stat_map.get('candidate', 0) + stat_map.get('favorited', 0) }}
+
Active Recipes
+
+
+
+
+
{{ 21 - (plan | length) }}
+
Open Slots
+
+
+
+ + +
+
+
+ + + + + {% for d in dates %} + + {% endfor %} + + + + {% for mt in meal_types %} + + + {% for d in dates %} + {% set key = d.isoformat() + '_' + mt %} + + {% endfor %} + + {% endfor %} + +
+
{{ d.strftime('%a') }}
+
{{ d.strftime('%b %d') }}
+
{{ mt }} + {% if key in plan %} + {% set entry = plan[key] %} +
+ {{ cuisine_emoji.get(entry.cuisine, '') }} + {{ entry.recipe_name }} +
+ {% else %} + + {% endif %} +
+
+
+
+ + + +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/app/templates/login.html b/app/templates/login.html new file mode 100644 index 0000000..2d7254f --- /dev/null +++ b/app/templates/login.html @@ -0,0 +1,39 @@ +{% extends "base.html" %} +{% block title %}Log In — Menu Planner{% endblock %} + +{% block content %} +
+
+
+
+
+ +

Menu Planner

+

Log in to plan meals and manage recipes

+
+ +
+
+ + +
+
+ + +
+ +
+ +
+

+ Browsing and viewing is open to everyone. +

+
+
+
+
+{% endblock %} diff --git a/app/templates/meal_plan.html b/app/templates/meal_plan.html new file mode 100644 index 0000000..3c3a932 --- /dev/null +++ b/app/templates/meal_plan.html @@ -0,0 +1,265 @@ +{% extends "base.html" %} +{% block title %}Meal Plan — Menu Planner{% endblock %} + +{% block content %} +
+
+

Meal Plan

+

{{ week_start.strftime('%B %d') }} – {{ dates[-1].strftime('%B %d, %Y') }}

+
+
+ + This Week + + + {% if current_user.is_authenticated %} + + {% endif %} +
+
+ +{% if not current_user.is_authenticated %} +
+ + Log in to add or remove meals from the plan. +
+{% endif %} + + +
+
+
+ + + + + {% for d in dates %} + + {% endfor %} + + + + {% for mt in meal_types %} + + + {% for d in dates %} + {% set key = d.isoformat() + '_' + mt %} + + {% endfor %} + + {% endfor %} + +
+
{{ d.strftime('%A') }}
+
{{ d.strftime('%b %d') }}
+
{{ mt }} + {% if key in plan %} + {% set entry = plan[key] %} +
+
+
+
+ {{ cuisine_emoji.get(entry.cuisine, '') }} + {{ entry.recipe_name }} +
+
+ {{ entry.calories_per_serving|int }} cal + · + {{ entry.carbs_per_serving|int }}g carbs + · + {{ entry.servings }} ppl +
+
+ {% if current_user.is_authenticated %} + + {% endif %} +
+
+ {% else %} + {% if current_user.is_authenticated %} + + {% else %} + + {% endif %} + {% endif %} +
+
+
+
+ + +
+ +
+ + + +{% endblock %} + +{% block scripts %} + +{% endblock %} 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 %} + + +

Add a New Recipe

+ +
+
+ + +
+ + +
+
Basic Information
+
+
+ + +
+
+
+ + + + {% for c in cuisines %} +
+
+ + +
Base recipe yields (shopping list scales from this)
+
+
+
+ + +
+
+
+ + +
+
Timing
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
Instructions
+
+ +
Number each step: 1. Heat oil…
+
+
+ +
+ + +
+ + +
+
Nutrition (per serving)
+
+
+
+ +
+ + kcal +
+
+
+ +
+ + g +
+
+
+ +
+ + g +
+
+
+ +
+ + g +
+
+
+
+
+ + +
+
+ Ingredients + +
+
+ + + + + + + + + + + + + +
QtyUnitIngredientCategory
+
+
+ +
+
+ +
+ Cancel + +
+
+{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/app/templates/recipe_detail.html b/app/templates/recipe_detail.html new file mode 100644 index 0000000..65aa0b0 --- /dev/null +++ b/app/templates/recipe_detail.html @@ -0,0 +1,290 @@ +{% extends "base.html" %} +{% block title %}{{ recipe.name }} — Menu Planner{% endblock %} + +{% block content %} +
+ Back to Recipes + + +
+ +
+ +
+
+
+
+
+ {{ cuisine_emoji.get(recipe.cuisine, '') }} {{ recipe.cuisine }} +

{{ recipe.name }}

+

{{ recipe.description }}

+ {% if recipe.added_by %} +

Added by {{ recipe.added_by }}

+ {% endif %} +
+
+ {% if recipe.status == 'favorited' %} +
+ Favorited + {% endif %} +
+
+ + +
+ + {{ recipe.calories_per_serving|int }} cal / serving + + + {{ recipe.carbs_per_serving|int }}g net carbs + + {% if recipe.protein_per_serving %} + + {{ recipe.protein_per_serving|int }}g protein + + {% endif %} + {% if recipe.fat_per_serving %} + + {{ recipe.fat_per_serving|int }}g fat + + {% endif %} + + Prep: {{ recipe.prep_time }} min + + + Cook: {{ recipe.cook_time }} min + + + {{ recipe.servings }} servings + +
+ + +
+ Your rating: + + {% for i in range(1, 6) %} + + {% endfor %} + + {% if recipe.rating %}({{ recipe.rating }}/5){% endif %} +
+ + +

Ingredients

+ {% set categories = ingredients | map(attribute='category') | list | unique | list %} + {% for cat in ['Meat & Poultry','Seafood','Dairy & Eggs','Produce','Pantry','Spices & Herbs'] %} + {% set cat_ings = ingredients | selectattr('category', 'equalto', cat) | list %} + {% if cat_ings %} +
+
{{ cat }}
+
    + {% for ing in cat_ings %} +
  • + + {% if ing.quantity == ing.quantity|int %}{{ ing.quantity|int }}{% else %}{{ ing.quantity }}{% endif %} + {{ ing.unit }} + + {{ ing.name }} +
  • + {% endfor %} +
+
+ {% endif %} + {% endfor %} + + +

Instructions

+
+ {% for line in recipe.instructions.strip().split('\n') %} + {% if line.strip() %} +
{{ line.strip() }}
+ {% endif %} + {% endfor %} +
+
+
+ + +
+
Comments + {% if comments %}{{ comments|length }}{% endif %} +
+
+ {% for c in comments %} +
+
+
+ {{ c.username }} + {{ c.created_at[:16].replace('T',' ') }} +
+ {% if current_user.is_authenticated and current_user.username == c.username %} +
+ +
+ {% endif %} +
+

{{ c.body }}

+
+ {% else %} +

No comments yet.

+ {% endfor %} + + {% if current_user.is_authenticated %} +
+
+ +
+ +
+ {% else %} +

Log in to leave a comment.

+ {% endif %} +
+
+
+ + +
+ {% if current_user.is_authenticated %} +
+
+
Add to Meal Plan
+
+ + +
+
+
+ + +
+
+ + +
+
+ +
+
+
+ +
+
+
Recipe Status
+
+ + + +
+
+
+ {% else %} +
+
+ +

Log in to add this to your meal plan or update its status.

+ Log in +
+
+ {% endif %} +
+
+{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/app/templates/recipes.html b/app/templates/recipes.html new file mode 100644 index 0000000..92a13bb --- /dev/null +++ b/app/templates/recipes.html @@ -0,0 +1,121 @@ +{% extends "base.html" %} +{% block title %}Recipes — Menu Planner{% endblock %} + +{% block content %} +
+

Recipe Library

+ {{ recipes | length }} recipes +
+ + +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ + +
+ All + {% for c in cuisines %} + + {{ cuisine_emoji[c] }} {{ c }} + + {% endfor %} +
+ +{% if recipes %} +
+ {% for r in recipes %} +
+
+
+
+ {{ cuisine_emoji.get(r.cuisine, '') }} {{ r.cuisine }} + {% if r.status == 'favorited' %} + + {% elif r.status == 'ignored' %} + + {% endif %} +
+
{{ r.name }}
+

{{ r.description[:100] }}{% if r.description|length > 100 %}…{% endif %}

+ {% if r.added_by %}

{{ r.added_by }}

{% endif %} + {% if r.rating %} +
+ {% for i in range(1,6) %}{% endfor %} +
+ {% endif %} +
+ {{ r.calories_per_serving|int }} cal + {{ r.carbs_per_serving|int }}g carbs + {{ r.prep_time + r.cook_time }} min +
+
+ View + + +
+
+
+
+ {% endfor %} +
+{% else %} +
+ +

No recipes found. Try adjusting the filters.

+
+{% endif %} +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/app/templates/shopping_list.html b/app/templates/shopping_list.html new file mode 100644 index 0000000..e6cfaaf --- /dev/null +++ b/app/templates/shopping_list.html @@ -0,0 +1,167 @@ +{% extends "base.html" %} +{% block title %}Shopping List — Menu Planner{% endblock %} + +{% block content %} +
+
+

Shopping List

+

+ Week of {{ week_start.strftime('%B %d, %Y') }} + {% if total %} ·  {{ checked }}/{{ total }} checked{% endif %} +

+
+
+ + This Week + + + {% if current_user.is_authenticated %} + + {% if total %} + + {% endif %} + {% endif %}{# end is_authenticated #} +
+
+ +{% if categories %} + + +{% if total %} +
+
+ {{ checked }} of {{ total }} items collected + {{ (checked / total * 100)|int }}% +
+
+
+
+
+{% endif %} + +
+ {% for cat_name, items in categories %} +
+
+
+ {% if cat_name == 'Meat & Poultry' %} + {% elif cat_name == 'Seafood' %} + {% elif cat_name == 'Dairy & Eggs' %} + {% elif cat_name == 'Produce' %} + {% elif cat_name == 'Pantry' %} + {% elif cat_name == 'Spices & Herbs' %} + {% else %}{% endif %} + {{ cat_name }} + {{ items|length }} +
+
    + {% for item in items %} +
  • +
    + + + {% if item.recipe_sources %} + + + + {% endif %} +
    + {% if item.recipe_sources %} +
    {{ item.recipe_sources }}
    + {% endif %} +
  • + {% endfor %} +
+
+
+ {% endfor %} +
+ +{% else %} +
+ +

No shopping list yet for this week.

+

Add meals to your meal plan first, then click Regenerate.

+ +
+{% endif %} + + +
+ +
+{% endblock %} + +{% block scripts %} + +{% endblock %} -- cgit v1.2.3