première release
This commit is contained in:
57
templates/accompagnements.html
Normal file
57
templates/accompagnements.html
Normal file
@@ -0,0 +1,57 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Mes accompagnements</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="top-nav">
|
||||
<a href="{{ url_for('menu') }}" class="btn btn-secondary">← Retour au menu</a>
|
||||
<a href="{{ url_for('add_accompagnement') }}" class="btn">➕ Ajouter un accompagnement</a>
|
||||
</div>
|
||||
|
||||
<h1>🥗 Mes accompagnements</h1>
|
||||
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div class="alert alert-{{ category }}">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
{% if accompagnements %}
|
||||
<div class="recettes-list">
|
||||
{% for acc in accompagnements %}
|
||||
<div class="recette-card">
|
||||
<h3>{{ acc['nom'] }}</h3>
|
||||
|
||||
{% if acc['descriptif'] %}
|
||||
<div class="ingredients">
|
||||
<strong>Descriptif :</strong>
|
||||
<pre>{{ acc['descriptif'] }}</pre>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="actions">
|
||||
<a href="{{ url_for('edit_accompagnement', id=acc['id']) }}" class="btn-edit">✏️ Modifier</a>
|
||||
<form method="POST" action="{{ url_for('delete_accompagnement', id=acc['id']) }}" style="display: inline;">
|
||||
<button type="submit" class="btn-delete" onclick="return confirm('Supprimer cet accompagnement ?')">🗑️ Supprimer</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p style="text-align: center; color: #666; margin: 40px 0;">
|
||||
Aucun accompagnement pour le moment. Commencez par en ajouter un !
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
31
templates/add_accompagnement.html
Normal file
31
templates/add_accompagnement.html
Normal file
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Ajouter un accompagnement</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>➕ Ajouter un accompagnement</h1>
|
||||
|
||||
<form method="POST" action="{{ url_for('add_accompagnement') }}" class="recipe-form">
|
||||
<div class="form-group">
|
||||
<label for="nom">Nom de l'accompagnement *</label>
|
||||
<input type="text" id="nom" name="nom" required placeholder="Ex: Riz basmati, Frites maison...">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="descriptif">Descriptif (optionnel)</label>
|
||||
<textarea id="descriptif" name="descriptif" rows="4" placeholder="Préparation, suggestions, notes..."></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn">💾 Enregistrer</button>
|
||||
<a href="{{ url_for('accompagnements') }}" class="btn btn-secondary">❌ Annuler</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
41
templates/add_recette.html
Normal file
41
templates/add_recette.html
Normal file
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Ajouter une recette</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>➕ Ajouter une recette</h1>
|
||||
|
||||
<form method="POST" action="{{ url_for('add_recette') }}" class="recipe-form">
|
||||
<div class="form-group">
|
||||
<label for="nom">Nom de la recette *</label>
|
||||
<input type="text" id="nom" name="nom" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="lien">Lien internet (optionnel)</label>
|
||||
<input type="url" id="lien" name="lien" placeholder="https://exemple.com/ma-recette">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="ingredients">Ingrédients</label>
|
||||
<textarea id="ingredients" name="ingredients" rows="6" placeholder="- Ingrédient 1 - Ingrédient 2 - ..."></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="instructions">Instructions</label>
|
||||
<textarea id="instructions" name="instructions" rows="8" placeholder="1. Étape 1 2. Étape 2 3. ..."></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn">💾 Enregistrer</button>
|
||||
<a href="{{ url_for('recettes') }}" class="btn btn-secondary">❌ Annuler</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
31
templates/edit_accompagnement.html
Normal file
31
templates/edit_accompagnement.html
Normal file
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Modifier un accompagnement</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>✏️ Modifier un accompagnement</h1>
|
||||
|
||||
<form method="POST" action="{{ url_for('edit_accompagnement', id=accompagnement['id']) }}" class="recipe-form">
|
||||
<div class="form-group">
|
||||
<label for="nom">Nom de l'accompagnement *</label>
|
||||
<input type="text" id="nom" name="nom" value="{{ accompagnement['nom'] }}" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="descriptif">Description (optionnel)</label>
|
||||
<textarea id="descriptif" name="descriptif" rows="3">{{ accompagnement['descriptif'] or '' }}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">💾 Enregistrer</button>
|
||||
<a href="{{ url_for('accompagnements') }}" class="btn btn-secondary">❌ Annuler</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
41
templates/edit_recette.html
Normal file
41
templates/edit_recette.html
Normal file
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Modifier une recette</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>✏️ Modifier la recette</h1>
|
||||
|
||||
<form method="POST" action="{{ url_for('edit_recette', id=recette['id']) }}" class="recipe-form">
|
||||
<div class="form-group">
|
||||
<label for="nom">Nom de la recette *</label>
|
||||
<input type="text" id="nom" name="nom" value="{{ recette['nom'] }}" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="lien">Lien internet (optionnel)</label>
|
||||
<input type="url" id="lien" name="lien" value="{{ recette['lien'] or '' }}" placeholder="https://exemple.com/ma-recette">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="ingredients">Ingrédients</label>
|
||||
<textarea id="ingredients" name="ingredients" rows="6">{{ recette['ingredients'] or '' }}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="instructions">Instructions</label>
|
||||
<textarea id="instructions" name="instructions" rows="8">{{ recette['instructions'] or '' }}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn">💾 Enregistrer</button>
|
||||
<a href="{{ url_for('recettes') }}" class="btn btn-secondary">❌ Annuler</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
108
templates/login.html
Normal file
108
templates/login.html
Normal file
@@ -0,0 +1,108 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Connexion - Menu Miam</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.login-container {
|
||||
background: white;
|
||||
padding: 40px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 10px 25px rgba(0,0,0,0.2);
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: #333;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
color: #555;
|
||||
font-weight: 500;
|
||||
}
|
||||
input[type="text"],
|
||||
input[type="password"] {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
font-size: 16px;
|
||||
}
|
||||
input[type="text"]:focus,
|
||||
input[type="password"]:focus {
|
||||
outline: none;
|
||||
border-color: #667eea;
|
||||
}
|
||||
button {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
button:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.flash-messages {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.flash {
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.flash.success { background: #d4edda; color: #155724; }
|
||||
.flash.error { background: #f8d7da; color: #721c24; }
|
||||
.flash.warning { background: #fff3cd; color: #856404; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="login-container">
|
||||
<h1>🍽️ Menu Miam</h1>
|
||||
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<div class="flash-messages">
|
||||
{% for category, message in messages %}
|
||||
<div class="flash {{ category }}">{{ message }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<form method="POST">
|
||||
<div class="form-group">
|
||||
<label for="username">Nom d'utilisateur</label>
|
||||
<input type="text" id="username" name="username" required autofocus>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">Mot de passe</label>
|
||||
<input type="password" id="password" name="password" required>
|
||||
</div>
|
||||
|
||||
<button type="submit">Se connecter</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
141
templates/menu(1).html
Normal file
141
templates/menu(1).html
Normal file
@@ -0,0 +1,141 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Menu de la semaine</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="top-nav no-print">
|
||||
<a href="{{ url_for('recettes') }}" class="btn">📚 Gérer mes recettes</a>
|
||||
<a href="{{ url_for('accompagnements') }}" class="btn btn-info">🥗 Gérer les accompagnements</a>
|
||||
<button onclick="window.print()" class="btn btn-print">🖨️ Imprimer</button>
|
||||
</div>
|
||||
|
||||
<h1>🍽️ Menu de la semaine</h1>
|
||||
|
||||
<!-- Navigation semaine -->
|
||||
<div class="week-nav no-print">
|
||||
<form method="POST" action="{{ url_for('change_week') }}" style="display: inline;">
|
||||
<input type="hidden" name="offset" value="{{ offset - 1 }}">
|
||||
<button type="submit">◀ Semaine précédente</button>
|
||||
</form>
|
||||
|
||||
<h2>Semaine du {{ start_date }} au {{ end_date }}</h2>
|
||||
|
||||
<form method="POST" action="{{ url_for('change_week') }}" style="display: inline;">
|
||||
<input type="hidden" name="offset" value="{{ offset + 1 }}">
|
||||
<button type="submit">Semaine suivante ▶</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Grille menu -->
|
||||
<div class="menu-grid">
|
||||
{% for day in days %}
|
||||
<div class="day-card" id="{{ day.name }}">
|
||||
<h3>{{ day.name }}</h3>
|
||||
<p class="date">{{ day.date }}</p>
|
||||
|
||||
{% for meal_type in ['Midi', 'Soir'] %}
|
||||
<div class="meal-slot">
|
||||
<h4>{{ meal_type }}</h4>
|
||||
|
||||
{% set meal_key = day.name + '_' + meal_type %}
|
||||
{% if menu.get(meal_key) %}
|
||||
<div class="recipe-card">
|
||||
<div class="recipe-info">
|
||||
<!-- 🔗 NOM DE LA RECETTE CLIQUABLE VERS LA PAGE D'ÉDITION -->
|
||||
<div class="recipe-name">
|
||||
<a href="{{ url_for('edit_recette', id=menu[meal_key]['id']) }}" class="recipe-title-link no-print">{{ menu[meal_key]['nom'] }}</a>
|
||||
<span class="print-only">{{ menu[meal_key]['nom'] }}</span>
|
||||
</div>
|
||||
|
||||
{% if menu[meal_key].get('ingredients') %}
|
||||
<details class="ingredients-details" open>
|
||||
<summary>📝 Ingrédients</summary>
|
||||
<pre>{{ menu[meal_key]['ingredients'] }}</pre>
|
||||
</details>
|
||||
{% endif %}
|
||||
|
||||
<!-- ✅ ACCOMPAGNEMENTS AVEC AJOUT/SUPPRESSION -->
|
||||
<div class="recipe-accompagnements">
|
||||
<strong>🥗 Accompagnements</strong>
|
||||
|
||||
{% if menu[meal_key].get('accompagnements') and menu[meal_key]['accompagnements']|length > 0 %}
|
||||
<ul>
|
||||
{% for acc in menu[meal_key]['accompagnements'] %}
|
||||
<li>
|
||||
<strong>{{ acc['nom'] }}</strong>
|
||||
{% if acc['descriptif'] %}
|
||||
<em class="acc-descriptif">{{ acc['descriptif'] }}</em>
|
||||
{% endif %}
|
||||
|
||||
<!-- ✅ BOUTON POUR RETIRER L'ACCOMPAGNEMENT -->
|
||||
<form method="POST" action="{{ url_for('remove_accompagnement_from_menu') }}" class="inline-form no-print">
|
||||
<input type="hidden" name="day" value="{{ day.name }}">
|
||||
<input type="hidden" name="meal" value="{{ meal_type }}">
|
||||
<input type="hidden" name="accompagnement_id" value="{{ acc['id'] }}">
|
||||
<input type="hidden" name="offset" value="{{ offset }}">
|
||||
<input type="hidden" name="anchor" value="{{ day.name }}">
|
||||
<button type="submit" class="delete-acc-btn" title="Retirer cet accompagnement">❌</button>
|
||||
</form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
<!-- ✅ DROPDOWN POUR AJOUTER UN ACCOMPAGNEMENT -->
|
||||
<form method="POST" action="{{ url_for('add_accompagnement_to_menu') }}" class="add-acc-form no-print">
|
||||
<input type="hidden" name="day" value="{{ day.name }}">
|
||||
<input type="hidden" name="meal" value="{{ meal_type }}">
|
||||
<input type="hidden" name="offset" value="{{ offset }}">
|
||||
<input type="hidden" name="anchor" value="{{ day.name }}">
|
||||
<select name="accompagnement_id" onchange="this.form.submit()">
|
||||
<option value="" disabled selected>Ajouter un accompagnement...</option>
|
||||
{% for acc in tous_accompagnements %}
|
||||
<option value="{{ acc['id'] }}">{{ acc['nom'] }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% if menu[meal_key].get('lien') %}
|
||||
<div class="recipe-link">
|
||||
<a href="{{ menu[meal_key]['lien'] }}" target="_blank" class="no-print">🔗 Voir la recette</a>
|
||||
<span class="print-only">🔗 {{ menu[meal_key]['lien'] }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<form method="POST" action="{{ url_for('remove_from_menu') }}" class="no-print">
|
||||
<input type="hidden" name="day" value="{{ day.name }}">
|
||||
<input type="hidden" name="meal" value="{{ meal_type }}">
|
||||
<input type="hidden" name="offset" value="{{ offset }}">
|
||||
<input type="hidden" name="anchor" value="{{ day.name }}">
|
||||
<button type="submit" class="delete-btn">🗑️</button>
|
||||
</form>
|
||||
</div>
|
||||
{% else %}
|
||||
<form method="POST" action="{{ url_for('add_to_menu') }}" class="no-print">
|
||||
<input type="hidden" name="day" value="{{ day.name }}">
|
||||
<input type="hidden" name="meal" value="{{ meal_type }}">
|
||||
<input type="hidden" name="offset" value="{{ offset }}">
|
||||
<input type="hidden" name="anchor" value="{{ day.name }}">
|
||||
<select name="recette_id" onchange="this.form.submit()">
|
||||
<option value="">-- Choisir --</option>
|
||||
{% for recette in recettes|sort(attribute='nom') %}
|
||||
<option value="{{ recette['id'] }}">{{ recette['nom'] }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
142
templates/menu.html
Normal file
142
templates/menu.html
Normal file
@@ -0,0 +1,142 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Menu de la semaine</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="top-nav no-print">
|
||||
<a href="{{ url_for('recettes') }}" class="btn">📚 Gérer mes recettes</a>
|
||||
<a href="{{ url_for('accompagnements') }}" class="btn btn-info">🥗 Gérer les accompagnements</a>
|
||||
<a href="{{ url_for('stats') }}" class="btn btn-success">📊 Statistiques</a>
|
||||
<button onclick="window.print()" class="btn btn-print">🖨️ Imprimer</button>
|
||||
</div>
|
||||
|
||||
<h1>🍽️ Menu de la semaine</h1>
|
||||
|
||||
<!-- Navigation semaine -->
|
||||
<div class="week-nav no-print">
|
||||
<form method="POST" action="{{ url_for('change_week') }}" style="display: inline;">
|
||||
<input type="hidden" name="offset" value="{{ offset - 1 }}">
|
||||
<button type="submit">◀ Semaine précédente</button>
|
||||
</form>
|
||||
|
||||
<h2>Semaine du {{ start_date }} au {{ end_date }}</h2>
|
||||
|
||||
<form method="POST" action="{{ url_for('change_week') }}" style="display: inline;">
|
||||
<input type="hidden" name="offset" value="{{ offset + 1 }}">
|
||||
<button type="submit">Semaine suivante ▶</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Grille menu -->
|
||||
<div class="menu-grid">
|
||||
{% for day in days %}
|
||||
<div class="day-card" id="{{ day.name }}">
|
||||
<h3>{{ day.name }}</h3>
|
||||
<p class="date">{{ day.date }}</p>
|
||||
|
||||
{% for meal_type in ['Midi', 'Soir'] %}
|
||||
<div class="meal-slot">
|
||||
<h4>{{ meal_type }}</h4>
|
||||
|
||||
{% set meal_key = day.name + '_' + meal_type %}
|
||||
{% if menu.get(meal_key) %}
|
||||
<div class="recipe-card">
|
||||
<div class="recipe-info">
|
||||
<!-- 🔗 NOM DE LA RECETTE CLIQUABLE VERS LA PAGE D'ÉDITION -->
|
||||
<div class="recipe-name">
|
||||
<a href="{{ url_for('edit_recette', id=menu[meal_key]['id']) }}" class="recipe-title-link no-print">{{ menu[meal_key]['nom'] }}</a>
|
||||
<span class="print-only">{{ menu[meal_key]['nom'] }}</span>
|
||||
</div>
|
||||
|
||||
{% if menu[meal_key].get('ingredients') %}
|
||||
<details class="ingredients-details" open>
|
||||
<summary>📝 Ingrédients</summary>
|
||||
<pre>{{ menu[meal_key]['ingredients'] }}</pre>
|
||||
</details>
|
||||
{% endif %}
|
||||
|
||||
<!-- ✅ ACCOMPAGNEMENTS AVEC AJOUT/SUPPRESSION -->
|
||||
<div class="recipe-accompagnements">
|
||||
<strong>🥗 Accompagnements</strong>
|
||||
|
||||
{% if menu[meal_key].get('accompagnements') and menu[meal_key]['accompagnements']|length > 0 %}
|
||||
<ul>
|
||||
{% for acc in menu[meal_key]['accompagnements'] %}
|
||||
<li>
|
||||
<strong>{{ acc['nom'] }}</strong>
|
||||
{% if acc['descriptif'] %}
|
||||
<em class="acc-descriptif">{{ acc['descriptif'] }}</em>
|
||||
{% endif %}
|
||||
|
||||
<!-- ✅ BOUTON POUR RETIRER L'ACCOMPAGNEMENT -->
|
||||
<form method="POST" action="{{ url_for('remove_accompagnement_from_menu') }}" class="inline-form no-print">
|
||||
<input type="hidden" name="day" value="{{ day.name }}">
|
||||
<input type="hidden" name="meal" value="{{ meal_type }}">
|
||||
<input type="hidden" name="accompagnement_id" value="{{ acc['id'] }}">
|
||||
<input type="hidden" name="offset" value="{{ offset }}">
|
||||
<input type="hidden" name="anchor" value="{{ day.name }}">
|
||||
<button type="submit" class="delete-acc-btn" title="Retirer cet accompagnement">❌</button>
|
||||
</form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
<!-- ✅ DROPDOWN POUR AJOUTER UN ACCOMPAGNEMENT -->
|
||||
<form method="POST" action="{{ url_for('add_accompagnement_to_menu') }}" class="add-acc-form no-print">
|
||||
<input type="hidden" name="day" value="{{ day.name }}">
|
||||
<input type="hidden" name="meal" value="{{ meal_type }}">
|
||||
<input type="hidden" name="offset" value="{{ offset }}">
|
||||
<input type="hidden" name="anchor" value="{{ day.name }}">
|
||||
<select name="accompagnement_id" onchange="this.form.submit()">
|
||||
<option value="" disabled selected>Ajouter un accompagnement...</option>
|
||||
{% for acc in tous_accompagnements %}
|
||||
<option value="{{ acc['id'] }}">{{ acc['nom'] }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% if menu[meal_key].get('lien') %}
|
||||
<div class="recipe-link">
|
||||
<a href="{{ menu[meal_key]['lien'] }}" target="_blank" class="no-print">🔗 Voir la recette</a>
|
||||
<span class="print-only">🔗 {{ menu[meal_key]['lien'] }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<form method="POST" action="{{ url_for('remove_from_menu') }}" class="no-print">
|
||||
<input type="hidden" name="day" value="{{ day.name }}">
|
||||
<input type="hidden" name="meal" value="{{ meal_type }}">
|
||||
<input type="hidden" name="offset" value="{{ offset }}">
|
||||
<input type="hidden" name="anchor" value="{{ day.name }}">
|
||||
<button type="submit" class="delete-btn">🗑️</button>
|
||||
</form>
|
||||
</div>
|
||||
{% else %}
|
||||
<form method="POST" action="{{ url_for('add_to_menu') }}" class="no-print">
|
||||
<input type="hidden" name="day" value="{{ day.name }}">
|
||||
<input type="hidden" name="meal" value="{{ meal_type }}">
|
||||
<input type="hidden" name="offset" value="{{ offset }}">
|
||||
<input type="hidden" name="anchor" value="{{ day.name }}">
|
||||
<select name="recette_id" onchange="this.form.submit()">
|
||||
<option value="">-- Choisir --</option>
|
||||
{% for recette in recettes|sort(attribute='nom') %}
|
||||
<option value="{{ recette['id'] }}">{{ recette['nom'] }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
157
templates/recettes.html
Normal file
157
templates/recettes.html
Normal file
@@ -0,0 +1,157 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Mes recettes</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="top-nav">
|
||||
<div>
|
||||
<a href="{{ url_for('menu') }}" class="btn btn-secondary">← Retour au menu</a>
|
||||
</div>
|
||||
<div style="display: flex; gap: 10px;">
|
||||
<a href="{{ url_for('add_recette') }}" class="btn">➕ Ajouter une recette</a>
|
||||
<a href="{{ url_for('export_recettes') }}" class="btn btn-success">📥 Exporter</a>
|
||||
<button type="button" class="btn btn-info" onclick="openImportModal()">📤 Importer</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1>📚 Mes recettes</h1>
|
||||
|
||||
<!-- 🔔 MESSAGES FLASH -->
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div class="alert alert-{{ category }}">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<!-- 🔍 BARRE DE RECHERCHE -->
|
||||
<form method="GET" action="{{ url_for('recettes') }}" class="search-form">
|
||||
<input
|
||||
type="text"
|
||||
name="search"
|
||||
placeholder="🔍 Rechercher une recette ou un ingrédient..."
|
||||
value="{{ search or '' }}"
|
||||
autofocus
|
||||
>
|
||||
<button type="submit" class="btn">Rechercher</button>
|
||||
{% if search %}
|
||||
<a href="{{ url_for('recettes') }}" class="btn-clear">✖ Effacer</a>
|
||||
{% endif %}
|
||||
</form>
|
||||
|
||||
<!-- Affichage nombre de résultats -->
|
||||
{% if search %}
|
||||
<p class="search-info">
|
||||
{% if recettes %}
|
||||
{{ recettes|length }} résultat(s) pour "<strong>{{ search }}</strong>"
|
||||
{% else %}
|
||||
Aucun résultat pour "<strong>{{ search }}</strong>"
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if recettes %}
|
||||
<div class="recettes-list">
|
||||
{% for recette in recettes %}
|
||||
<div class="recette-card">
|
||||
<h3>{{ recette['nom'] }}</h3>
|
||||
|
||||
{% if recette['lien'] %}
|
||||
<div class="recipe-link" style="margin-bottom: 15px;">
|
||||
<a href="{{ recette['lien'] }}" target="_blank" class="btn-link">🔗 Voir la recette en ligne</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if recette['ingredients'] %}
|
||||
<div class="ingredients">
|
||||
<strong>Ingrédients :</strong>
|
||||
<pre>{{ recette['ingredients'] }}</pre>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if recette['instructions'] %}
|
||||
<div class="instructions">
|
||||
<strong>Instructions :</strong>
|
||||
<pre>{{ recette['instructions'] }}</pre>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="actions">
|
||||
<a href="{{ url_for('edit_recette', id=recette['id']) }}" class="btn-edit">✏️ Modifier</a>
|
||||
<form method="POST" action="{{ url_for('delete_recette', id=recette['id']) }}" style="display: inline;">
|
||||
<button type="submit" class="btn-delete" onclick="return confirm('Supprimer cette recette ?')">🗑️ Supprimer</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
{% if search %}
|
||||
<p style="text-align: center; color: #666; margin: 40px 0;">
|
||||
Aucune recette trouvée. <a href="{{ url_for('recettes') }}">Voir toutes les recettes</a>
|
||||
</p>
|
||||
{% else %}
|
||||
<p style="text-align: center; color: #666; margin: 40px 0;">
|
||||
Aucune recette pour le moment. Commencez par en ajouter une !
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- 📤 MODAL IMPORT -->
|
||||
<div id="importModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2>📤 Importer des recettes</h2>
|
||||
<button class="close-btn" onclick="closeImportModal()">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="POST" action="{{ url_for('import_recettes') }}" enctype="multipart/form-data" id="importForm">
|
||||
<label class="form-label">Sélectionnez un fichier JSON :</label>
|
||||
<input type="file" name="file" accept=".json" class="file-input" required>
|
||||
|
||||
<div class="alert-info">
|
||||
<strong>ℹ️ Format attendu :</strong>
|
||||
<ul>
|
||||
<li>Fichier JSON exporté depuis cette application</li>
|
||||
<li>Les recettes existantes avec le même nom seront mises à jour</li>
|
||||
<li>Les nouvelles recettes seront ajoutées</li>
|
||||
</ul>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" onclick="closeImportModal()">Annuler</button>
|
||||
<button type="submit" form="importForm" class="btn btn-primary">Importer</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function openImportModal() {
|
||||
document.getElementById('importModal').style.display = 'flex';
|
||||
}
|
||||
|
||||
function closeImportModal() {
|
||||
document.getElementById('importModal').style.display = 'none';
|
||||
document.getElementById('importForm').reset();
|
||||
}
|
||||
|
||||
// Fermer modal en cliquant en dehors
|
||||
window.onclick = function(event) {
|
||||
const modal = document.getElementById('importModal');
|
||||
if (event.target == modal) {
|
||||
closeImportModal();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
150
templates/stats.html
Normal file
150
templates/stats.html
Normal file
@@ -0,0 +1,150 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>📊 Statistiques - Menu Miam</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
<style>
|
||||
.stats-container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.stat-card h2 {
|
||||
margin-top: 0;
|
||||
color: #2c3e50;
|
||||
border-bottom: 2px solid #3498db;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 48px;
|
||||
font-weight: bold;
|
||||
color: #3498db;
|
||||
text-align: center;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.stat-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.stat-list li {
|
||||
padding: 10px;
|
||||
margin: 5px 0;
|
||||
background: #f8f9fa;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.stat-badge {
|
||||
background: #3498db;
|
||||
color: white;
|
||||
padding: 5px 15px;
|
||||
border-radius: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.back-button {
|
||||
display: inline-block;
|
||||
margin-bottom: 20px;
|
||||
padding: 10px 20px;
|
||||
background: #3498db;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.back-button:hover {
|
||||
background: #2980b9;
|
||||
}
|
||||
|
||||
.grid-2 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="stats-container">
|
||||
<a href="{{ url_for('menu') }}" class="back-button">← Retour au menu</a>
|
||||
|
||||
<h1>📊 Statistiques des recettes</h1>
|
||||
|
||||
<!-- Statistiques générales -->
|
||||
<div class="grid-2">
|
||||
<div class="stat-card">
|
||||
<h2>📚 Recettes disponibles</h2>
|
||||
<div class="stat-number">{{ total_recettes }}</div>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<h2>📅 Recettes planifiées</h2>
|
||||
<div class="stat-number">{{ total_planifiees }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Top 10 recettes -->
|
||||
<div class="stat-card">
|
||||
<h2>🏆 Top 10 des recettes les plus utilisées</h2>
|
||||
{% if top_recettes %}
|
||||
<ul class="stat-list">
|
||||
{% for recette in top_recettes %}
|
||||
<li>
|
||||
<span>{{ recette['nom'] }}</span>
|
||||
<span class="stat-badge">{{ recette['count'] }}×</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p style="text-align: center; color: #7f8c8d;">Aucune recette planifiée pour le moment</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Top 10 accompagnements -->
|
||||
<div class="stat-card">
|
||||
<h2>🥗 Top 10 des accompagnements les plus utilisés</h2>
|
||||
{% if top_accompagnements %}
|
||||
<ul class="stat-list">
|
||||
{% for acc in top_accompagnements %}
|
||||
<li>
|
||||
<span>{{ acc['nom'] }}</span>
|
||||
<span class="stat-badge">{{ acc['count'] }}×</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p style="text-align: center; color: #7f8c8d;">Aucun accompagnement utilisé pour le moment</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Recettes jamais utilisées -->
|
||||
<div class="stat-card">
|
||||
<h2>💤 Recettes jamais utilisées ({{ jamais_utilisees|length }})</h2>
|
||||
{% if jamais_utilisees %}
|
||||
<ul class="stat-list">
|
||||
{% for recette in jamais_utilisees %}
|
||||
<li>{{ recette['nom'] }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p style="text-align: center; color: #27ae60; font-weight: bold;">🎉 Toutes vos recettes ont été utilisées au moins une fois !</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user