397 lines
22 KiB
HTML
397 lines
22 KiB
HTML
{% extends "base.html" %}
|
||
{% block title %}{% if item %}Bearbeiten{% else %}Neu{% endif %} | Nouri{% endblock %}
|
||
{% block content %}
|
||
<section class="page-intro">
|
||
<div>
|
||
<p class="eyebrow">{{ item_kind_labels[kind] }}</p>
|
||
<h1>
|
||
{% if item and kind == 'meal' %}
|
||
{{ item.name }}
|
||
{% elif item %}
|
||
{{ item.name }} bearbeiten
|
||
{% else %}
|
||
Neue {{ item_kind_singular_labels[kind] }}
|
||
{% endif %}
|
||
</h1>
|
||
<p class="lead">
|
||
{% if kind == 'food' %}
|
||
Name, Sichtbarkeit und ein paar ruhige Hinweise dazu, wie ein Lebensmittel in Vorschlägen gut passt.
|
||
{% else %}
|
||
Name, Sichtbarkeit, Tageszeit und ein kurzer Charakter der Idee. So bleiben Mahlzeitenideen alltagsnah und leicht pflegbar.
|
||
{% endif %}
|
||
</p>
|
||
</div>
|
||
{% if item %}
|
||
<div class="intro-pills">
|
||
<span class="status-pill">{{ item.visibility_label }}</span>
|
||
<span class="status-pill status-soft">{{ item.owner_label }}</span>
|
||
<span class="status-pill">{{ item.for_label }}</span>
|
||
</div>
|
||
{% endif %}
|
||
</section>
|
||
|
||
<section class="panel form-panel">
|
||
<form method="post" enctype="multipart/form-data" class="stack-form">
|
||
{{ csrf_input() }}
|
||
<label>
|
||
Name
|
||
<input type="text" name="name" value="{{ form_data.name }}" required>
|
||
</label>
|
||
|
||
<div class="dual-grid">
|
||
<label>
|
||
Sichtbarkeit
|
||
<select name="visibility">
|
||
{% for value, label in visibility_options %}
|
||
<option value="{{ value }}" {% if form_data.visibility == value %}selected{% endif %}>{{ label }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<small class="helper-text">{{ visibility_descriptions[form_data.visibility] }}</small>
|
||
</label>
|
||
|
||
<label>
|
||
Für wen?
|
||
<select name="target_user_id">
|
||
{% for option in target_user_options %}
|
||
<option value="{{ option.value }}" {% if form_data.target_user_raw == option.value %}selected{% endif %}>{{ option.label }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</label>
|
||
</div>
|
||
|
||
{% if kind == 'food' %}
|
||
<div class="dual-grid">
|
||
<label>
|
||
Baustein
|
||
<select name="base_type">
|
||
{% for value, label in builder_options %}
|
||
<option value="{{ value }}" {% if form_data.base_type == value %}selected{% endif %}>{{ label }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<small class="helper-text">{{ builder_descriptions[form_data.base_type] }}</small>
|
||
</label>
|
||
|
||
<label>
|
||
Geschmacksrichtung
|
||
<select name="flavor_profile">
|
||
{% for value, label in food_flavor_options %}
|
||
<option value="{{ value }}" {% if form_data.flavor_profile == value %}selected{% endif %}>{{ label }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<small class="helper-text">{{ food_flavor_descriptions[form_data.flavor_profile] }}</small>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="dual-grid">
|
||
<label>
|
||
Rolle in Vorschlägen
|
||
<select name="suggestion_role">
|
||
{% for value, label in food_role_options %}
|
||
<option value="{{ value }}" {% if form_data.suggestion_role == value %}selected{% endif %}>{{ label }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<small class="helper-text">{{ food_role_descriptions[form_data.suggestion_role] }}</small>
|
||
</label>
|
||
|
||
<label>
|
||
Wird eher vorgeschlagen
|
||
<select name="suggestion_priority">
|
||
{% for value, label in suggestion_priority_options %}
|
||
<option value="{{ value }}" {% if form_data.suggestion_priority == value %}selected{% endif %}>{{ label }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</label>
|
||
</div>
|
||
|
||
<label class="inline-check">
|
||
<input type="checkbox" name="can_be_meal_core" value="1" {% if form_data.can_be_meal_core %}checked{% endif %}>
|
||
<span>Kann gut eine Mahlzeit tragen</span>
|
||
</label>
|
||
<small class="helper-text">Praktisch für Dinge wie Tofu, Joghurt oder Müsli. Extras wie Proteinpulver, Tomatenmark oder Saaten bleiben so eher Ergänzungen.</small>
|
||
{% else %}
|
||
<div class="dual-grid">
|
||
<label>
|
||
Mahlzeittyp
|
||
<select name="meal_type">
|
||
{% for value, label in meal_type_options %}
|
||
<option value="{{ value }}" {% if form_data.meal_type == value %}selected{% endif %}>{{ label }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</label>
|
||
|
||
<label>
|
||
Energiedichte
|
||
<select name="energy_density">
|
||
{% for value, label in energy_density_options %}
|
||
<option value="{{ value }}" {% if form_data.energy_density == value %}selected{% endif %}>{{ label }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<small class="helper-text">Hilft Nouri dabei, passende Ideen etwas ruhiger und persönlicher zu sortieren.</small>
|
||
</label>
|
||
</div>
|
||
|
||
<fieldset>
|
||
<legend>Charakter der Mahlzeit</legend>
|
||
<div class="checkbox-grid meal-style-option-grid">
|
||
{% for value, label in meal_style_options %}
|
||
<label class="meal-style-option">
|
||
<input type="checkbox" name="meal_tags" value="{{ value }}" {% if value in form_data.meal_tags %}checked{% endif %}>
|
||
<span class="meal-style-option-card">
|
||
<span class="meal-style-option-icon">
|
||
<span class="ui-icon icon-meal-style-{{ value }}"></span>
|
||
</span>
|
||
<span class="meal-style-option-label">{{ label }}</span>
|
||
</span>
|
||
</label>
|
||
{% endfor %}
|
||
</div>
|
||
<small class="helper-text">Nur das auswählen, was wirklich hilft. Alles andere kann leer bleiben.</small>
|
||
</fieldset>
|
||
{% endif %}
|
||
|
||
{% if kind == 'food' %}
|
||
<label>
|
||
Energiedichte
|
||
<select name="energy_density">
|
||
{% for value, label in energy_density_options %}
|
||
<option value="{{ value }}" {% if form_data.energy_density == value %}selected{% endif %}>{{ label }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<small class="helper-text">Hilft Nouri dabei, passende Ideen etwas ruhiger und persönlicher zu sortieren.</small>
|
||
</label>
|
||
{% endif %}
|
||
|
||
<label>
|
||
Notiz
|
||
<textarea name="note" rows="4" placeholder="Optional, wenn eine kleine Erinnerung hilfreich ist.">{{ form_data.note }}</textarea>
|
||
</label>
|
||
|
||
<label>
|
||
Foto
|
||
<input type="file" name="photo" accept="image/png,image/jpeg,image/gif,image/webp">
|
||
</label>
|
||
|
||
{% if item and item.photo_filename %}
|
||
<div class="inline-photo">
|
||
<img
|
||
src="{{ image_url(item.photo_filename, 'lg') }}"
|
||
srcset="{{ image_srcset(item.photo_filename) }}"
|
||
sizes="{{ image_sizes('detail') }}"
|
||
alt="{{ item.name }}"
|
||
loading="lazy">
|
||
</div>
|
||
{% endif %}
|
||
|
||
{% if kind == 'food' %}
|
||
<fieldset>
|
||
<legend>Passende Tageszeiten</legend>
|
||
<div class="checkbox-grid daypart-option-grid">
|
||
{% for daypart in dayparts %}
|
||
<label class="daypart-option">
|
||
<input type="checkbox" name="daypart_ids" value="{{ daypart.id }}" {% if daypart.id in form_data.daypart_ids %}checked{% endif %}>
|
||
<span class="daypart-option-card">
|
||
<span class="daypart-option-icon">
|
||
<span class="ui-icon {{ daypart_icon_class(daypart.slug) }}"></span>
|
||
</span>
|
||
<span class="daypart-option-label">{{ daypart.name }}</span>
|
||
</span>
|
||
</label>
|
||
{% endfor %}
|
||
</div>
|
||
</fieldset>
|
||
{% endif %}
|
||
|
||
{% if kind == 'meal' %}
|
||
<fieldset>
|
||
<legend>Bestandteile der Mahlzeitenidee</legend>
|
||
<p class="muted">Du kannst eine Mahlzeitenidee frei benennen oder aus sichtbaren Lebensmitteln zusammensetzen. Nouri nutzt dabei später Grundtyp, Rolle und Tageszeit der Lebensmittel für ruhigere Vorschläge.</p>
|
||
<div class="meal-component-search">
|
||
<label class="wide">
|
||
Lebensmittel suchen
|
||
<input
|
||
type="text"
|
||
name="food_search"
|
||
value="{{ form_data.food_search }}"
|
||
placeholder="z. B. Reis, Banane, Joghurt"
|
||
data-filter-input
|
||
data-filter-target="#meal-components-list"
|
||
data-filter-limit="8"
|
||
>
|
||
</label>
|
||
</div>
|
||
<div class="selected-component-stack is-live" data-selected-preview="#meal-components-list">
|
||
<p class="helper-text">Ausgewählt</p>
|
||
<p class="helper-text" data-selected-preview-empty>Noch nichts ausgewählt.</p>
|
||
<div class="selected-components-grid">
|
||
{% for group in food_groups %}
|
||
{% for component in group["items"] %}
|
||
{% set component_icon_class = {
|
||
'protein': 'icon-component-protein',
|
||
'carb': 'icon-component-carb',
|
||
'veg': 'icon-component-veg',
|
||
'fruit': 'icon-component-fruit',
|
||
'dairy': 'icon-component-dairy',
|
||
'nuts': 'icon-component-nuts',
|
||
'seeds': 'icon-component-seeds',
|
||
'neutral': 'icon-component-neutral',
|
||
}.get(component.primary_builder_key or component.base_type, 'icon-component-neutral') %}
|
||
<article
|
||
class="selected-component-card {% if not component.is_home %}is-needed{% endif %}"
|
||
data-selected-preview-card="{{ component.id }}"
|
||
>
|
||
<button class="selected-component-remove" type="button" data-uncheck-component="{{ component.id }}">
|
||
<span aria-hidden="true">×</span>
|
||
<span class="sr-only">{{ component.name }} entfernen</span>
|
||
</button>
|
||
<div class="selected-component-visual">
|
||
{% if component.photo_filename %}
|
||
<img
|
||
src="{{ image_url(component.photo_filename, 'md') }}"
|
||
srcset="{{ image_srcset(component.photo_filename) }}"
|
||
sizes="{{ image_sizes('grid') }}"
|
||
alt="{{ component.name }}"
|
||
loading="lazy">
|
||
{% else %}
|
||
<span class="selected-component-fallback">
|
||
<span class="ui-icon {{ component_icon_class }}"></span>
|
||
</span>
|
||
{% endif %}
|
||
</div>
|
||
<div class="selected-component-main">
|
||
<strong>{{ component.name }}</strong>
|
||
<small class="food-status-badge {% if not component.is_home %}is-needed{% endif %}">
|
||
<span class="ui-icon {% if component.is_home %}icon-house{% else %}icon-shopping-cart{% endif %}"></span>
|
||
<span>{{ component.availability_label }}</span>
|
||
</small>
|
||
</div>
|
||
</article>
|
||
{% endfor %}
|
||
{% endfor %}
|
||
</div>
|
||
</div>
|
||
<p class="helper-text">Während der Suche zeigt Nouri die passendsten Lebensmittel. Nicht vorrätige Lebensmittel sind mit Einkaufswagen markiert.</p>
|
||
{% if food_groups %}
|
||
<div class="meal-component-results" id="meal-components-list">
|
||
{% for group in food_groups %}
|
||
<div class="component-group">
|
||
<div class="panel-head">
|
||
<h3>{{ group["title"] }}</h3>
|
||
<span>{{ group["items"]|length }} Einträge</span>
|
||
</div>
|
||
<div class="meal-component-option-grid" data-filter-group>
|
||
{% for food in group["items"] %}
|
||
{% set food_icon_class = {
|
||
'protein': 'icon-component-protein',
|
||
'carb': 'icon-component-carb',
|
||
'veg': 'icon-component-veg',
|
||
'fruit': 'icon-component-fruit',
|
||
'dairy': 'icon-component-dairy',
|
||
'nuts': 'icon-component-nuts',
|
||
'seeds': 'icon-component-seeds',
|
||
'neutral': 'icon-component-neutral',
|
||
}.get(food.primary_builder_key or food.base_type, 'icon-component-neutral') %}
|
||
<label class="meal-component-option" data-filter-label="{{ food.name|lower }} {{ food.category|default('', true)|lower }} {{ food.base_type_label|lower }} {{ food.suggestion_role_label|lower }} {{ food.availability_label|lower }}">
|
||
<input type="checkbox" name="component_ids" value="{{ food.id }}" {% if food.id in form_data.component_ids %}checked{% endif %}>
|
||
<span class="meal-component-option-card">
|
||
<span class="meal-component-option-visual">
|
||
{% if food.photo_filename %}
|
||
<img
|
||
src="{{ image_url(food.photo_filename, 'md') }}"
|
||
srcset="{{ image_srcset(food.photo_filename) }}"
|
||
sizes="{{ image_sizes('grid') }}"
|
||
alt=""
|
||
loading="lazy">
|
||
{% else %}
|
||
<span class="ui-icon {{ food_icon_class }}"></span>
|
||
{% endif %}
|
||
</span>
|
||
<span class="meal-component-option-copy">
|
||
<strong>{{ food.name }}</strong>
|
||
<small class="food-status-badge {% if not food.is_home %}is-needed{% endif %}">
|
||
<span class="ui-icon {% if food.is_home %}icon-house{% else %}icon-shopping-cart{% endif %}"></span>
|
||
<span>{{ food.availability_label }}</span>
|
||
</small>
|
||
</span>
|
||
</span>
|
||
</label>
|
||
{% endfor %}
|
||
</div>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
{% else %}
|
||
<p class="empty-state">Lege zuerst ein paar Lebensmittel an, damit du daraus Mahlzeitenideen bauen kannst.</p>
|
||
{% endif %}
|
||
<div class="quick-food-panel">
|
||
<div class="panel-head">
|
||
<h3>Neues Lebensmittel direkt anlegen</h3>
|
||
<span>ohne die Seite zu verlassen</span>
|
||
</div>
|
||
<div class="quick-food-grid">
|
||
<label>
|
||
Name
|
||
<input type="text" name="quick_food_name" value="{{ form_data.quick_food_name }}" placeholder="z. B. Hüttenkäse">
|
||
</label>
|
||
<label>
|
||
Baustein
|
||
<select name="quick_food_base_type">
|
||
{% for value, label in builder_options %}
|
||
<option value="{{ value }}" {% if form_data.quick_food_base_type == value %}selected{% endif %}>{{ label }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</label>
|
||
<label>
|
||
Geschmacksrichtung
|
||
<select name="quick_food_flavor_profile">
|
||
{% for value, label in food_flavor_options %}
|
||
<option value="{{ value }}" {% if form_data.quick_food_flavor_profile == value %}selected{% endif %}>{{ label }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</label>
|
||
<label>
|
||
Rolle in Vorschlägen
|
||
<select name="quick_food_role">
|
||
{% for value, label in food_role_options %}
|
||
<option value="{{ value }}" {% if form_data.quick_food_role == value %}selected{% endif %}>{{ label }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</label>
|
||
<label>
|
||
Wird eher vorgeschlagen
|
||
<select name="quick_food_priority">
|
||
{% for value, label in suggestion_priority_options %}
|
||
<option value="{{ value }}" {% if form_data.quick_food_priority == value %}selected{% endif %}>{{ label }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</label>
|
||
<label>
|
||
Energiedichte
|
||
<select name="quick_food_energy_density">
|
||
{% for value, label in energy_density_options %}
|
||
<option value="{{ value }}" {% if form_data.quick_food_energy_density == value %}selected{% endif %}>{{ label }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</label>
|
||
<label class="inline-check">
|
||
<input type="checkbox" name="quick_food_can_be_meal_core" value="1" {% if form_data.quick_food_can_be_meal_core %}checked{% endif %}>
|
||
<span>Kann gut eine Mahlzeit tragen</span>
|
||
</label>
|
||
<label class="wide">
|
||
Notiz
|
||
<input type="text" name="quick_food_note" value="{{ form_data.quick_food_note }}" placeholder="Optional">
|
||
</label>
|
||
<button type="submit" name="form_action" value="quick_add_food" class="secondary">Lebensmittel anlegen und übernehmen</button>
|
||
</div>
|
||
</div>
|
||
</fieldset>
|
||
{% endif %}
|
||
|
||
<div class="form-actions">
|
||
<button type="submit" name="save_mode" value="stay">Speichern</button>
|
||
<button class="secondary" type="submit" name="save_mode" value="close">Speichern und schließen</button>
|
||
<a class="ghost-button" href="{{ url_for('main.item_list', kind=kind) }}">Zurück</a>
|
||
</div>
|
||
</form>
|
||
</section>
|
||
{% endblock %}
|