Private
Public Access
1
0
Files
madplaner/templates/dashboard.html
Rasmus dd2c15ba67 moved to server
Update readme.md

Signed-off-by: rasmus <rsbendtsen@gmail.com>

Update readme.md

Update Dockerfile

Update Dockerfile
2025-12-30 17:41:28 +01:00

204 lines
12 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "base.html" %}
{% block content %}
<div class="max-w-6xl mx-auto px-6 py-12">
<div class="mb-12">
<h1 class="text-4xl font-light text-stone-900 tracking-tight">
Hej, <span class="font-serif italic text-emerald-800">{{ current_user.username }}</span>
</h1>
<p class="text-stone-500 font-light mt-2">Lets design a menu for the days ahead.</p>
</div>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-12">
<div class="lg:col-span-2">
<div class="mb-6 flex items-center gap-3 px-1">
<div class="w-8 h-8 bg-emerald-50 rounded-lg flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-emerald-700" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4" />
</svg>
</div>
<h2 class="text-xl font-medium text-stone-800 tracking-tight">Personal preferences</h2>
</div>
<div class="bg-white p-8 md:p-10 rounded-[2rem] shadow-sm border border-stone-100">
<form action="{{ url_for('generate') }}" method="POST" class="space-y-8">
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-8 gap-y-6">
{% set fields = [
('people_count', 'Number of People', [('1 adult', '1 adult'), ('2 adults', '2 adults'), ('Family
of 4', 'Family of 4')]),
('budget_level', 'Budget Level', [('Low', 'Low'), ('Medium', 'Medium'), ('High', 'High')]),
('max_cooking_time', 'Max Cooking Time', [('20', '20 min'), ('30', '30 min'), ('45', '45 min'),
('60', '60 min')]),
('skill_level', 'Cooking Skill', [('Beginner (simple steps)', 'Beginner'), ('Intermediate
(comfortable with techniques)', 'Intermediate'), ('Expert (advanced methods)', 'Advanced')]),
('dietary_preference', 'Dietary Preference', [('Standard (Omnivore)', 'Standard'),
('Vegetarian', 'Vegetarian'), ('Vegan', 'Vegan'), ('Pescatarian', 'Pescatarian')]),
('dietary_focus', 'Dietary Focus', [('Balanced', 'Balanced'), ('High Protein', 'High Protein'),
('Low Carb', 'Low Carb'), ('Kid-Friendly', 'Kid-Friendly')])
] %}
{% for name, label, options in fields %}
<div>
<label class="block text-xs font-semibold text-stone-400 uppercase tracking-widest mb-3">{{
label }}</label>
<select name="{{ name }}"
class="w-full px-4 py-3 bg-stone-50 border border-stone-200 rounded-xl text-stone-700 focus:ring-2 focus:ring-emerald-800/20 focus:border-emerald-800 outline-none transition-all appearance-none cursor-pointer">
{% for val, display in options %}
<option value="{{ val }}" {% if val=='2 adults' or val=='Medium' or val=='30' or
val=='Intermediate (comfortable with techniques)' or val=='Standard (Omnivore)' or
val=='Balanced' %}selected{% endif %}>{{ display }}</option>
{% endfor %}
</select>
</div>
{% endfor %}
</div>
<div class="pt-8 border-t border-stone-50 space-y-6">
<div>
<label
class="block text-xs font-semibold text-stone-400 uppercase tracking-widest mb-3">Meal
Strategy</label>
<select name="meal_strategy"
class="w-full px-4 py-3 bg-stone-50 border border-stone-200 rounded-xl text-stone-700 focus:ring-2 focus:ring-emerald-800/20 focus:border-emerald-800 outline-none transition-all appearance-none cursor-pointer">
<option value="Maximize ingredient reuse" selected>Maximize Reuse (Zero Waste)</option>
<option value="Variety-focused">Maximum Variety</option>
<option value="Quick & Easy">Quick & Easy</option>
</select>
</div>
<div>
<label
class="block text-xs font-semibold text-stone-400 uppercase tracking-widest mb-3">Fridge
Clear-out</label>
<input type="text" name="fridge_items" placeholder="e.g. 2 Carrots, half a cabbage..."
class="w-full px-4 py-4 border-2 border-emerald-50/50 rounded-xl bg-emerald-50/30 text-stone-700 focus:border-emerald-800/30 focus:bg-white outline-none transition-all placeholder:text-stone-300">
</div>
<div>
<label
class="block text-xs font-semibold text-stone-400 uppercase tracking-widest mb-3">Output
Language</label>
<div class="flex gap-4">
<label class="relative flex-1 cursor-pointer group">
<input type="radio" name="output_language" value="English" checked
class="peer sr-only">
<div
class="flex items-center justify-center gap-3 p-3 bg-stone-50 border border-stone-200 rounded-xl peer-checked:border-emerald-800 peer-checked:bg-emerald-50 transition-all">
<span class="text-2xl">🇬🇧</span>
<span
class="text-sm font-medium text-stone-600 group-hover:text-stone-900">English</span>
</div>
</label>
<label class="relative flex-1 cursor-pointer group">
<input type="radio" name="output_language" value="Danish" class="peer sr-only">
<div
class="flex items-center justify-center gap-3 p-3 bg-stone-50 border border-stone-200 rounded-xl peer-checked:border-emerald-800 peer-checked:bg-emerald-50 transition-all">
<span class="text-2xl">🇩🇰</span>
<span
class="text-sm font-medium text-stone-600 group-hover:text-stone-900">Dansk</span>
</div>
</label>
</div>
</div>
</div>
<button type="submit" id="submitBtn"
class="w-full bg-emerald-800 text-white font-medium py-5 rounded-2xl shadow-lg hover:bg-emerald-700 hover:-translate-y-0.5 transition-all duration-300 flex items-center justify-center gap-3">
<span id="btnText">Generate Personalized Plan</span>
<div id="btnLoader" class="hidden">
<svg class="animate-spin h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor"
stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
</path>
</svg>
</div>
</button>
</form>
</div>
</div>
<div class="lg:col-span-1">
<div class="mb-6 flex items-center gap-3 px-1">
<div class="w-8 h-8 bg-stone-100 rounded-lg flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-stone-600" fill="none"
viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<h2 class="text-xl font-medium text-stone-800 tracking-tight">Recent Activity</h2>
</div>
<div class="space-y-4 max-h-[800px] overflow-y-auto pr-2 custom-scrollbar">
{% for plan in plans %}
<div
class="bg-white p-6 rounded-2xl border border-stone-100 shadow-sm hover:shadow-md hover:border-emerald-100 transition-all group">
<h3 class="text-stone-800 font-medium leading-snug group-hover:text-emerald-800 transition-colors">
{{ plan.description }}</h3>
<div class="flex justify-between items-center mt-6">
<span class="text-[10px] font-bold text-stone-300 uppercase tracking-widest">Plan #{{ plan.id
}}</span>
<a href="{{ url_for('view_plan', plan_id=plan.id) }}"
class="text-xs font-semibold text-emerald-800 flex items-center gap-1 hover:gap-2 transition-all">
View Plan <span></span>
</a>
</div>
</div>
{% else %}
<div class="text-center py-16 bg-stone-50/50 rounded-3xl border-2 border-dashed border-stone-100">
<p class="text-stone-400 font-light italic text-sm px-4">Your culinary history will appear here.</p>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
<style>
/* Subtle scrollbar for history sidebar */
.custom-scrollbar::-webkit-scrollbar {
width: 4px;
}
.custom-scrollbar::-webkit-scrollbar-track {
background: transparent;
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background: #e7e5e4;
border-radius: 10px;
}
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
background: #d6d3d1;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 1. Identify the form and button elements
const planForm = document.querySelector('form[action="{{ url_for("generate") }}"]');
const submitBtn = document.getElementById('submitBtn');
const btnText = document.getElementById('btnText');
const btnLoader = document.getElementById('btnLoader');
// 2. Add submission logic
if (planForm && submitBtn) {
planForm.addEventListener('submit', function () {
// Disable button to prevent double-clicks
submitBtn.disabled = true;
// Trigger Nordic-style loading animations
submitBtn.classList.add('opacity-80', 'cursor-not-allowed', 'animate-pulse');
// Update text and show the SVG spinner
if (btnText) btnText.innerText = 'Generating your plan...';
if (btnLoader) btnLoader.classList.remove('hidden');
});
}
});
</script>
{% endblock %}