M3: Reorder + Inspiration – Schritt 2 (UI): Planungsliste mit SortableJS, Tagesansicht /mahlzeiten/tage, Inspiration /inspiration mit 'Weitere 5' + 1-Klick-Adopt, Feature-Tests
This commit is contained in:
@@ -1,12 +1,17 @@
|
||||
{#
|
||||
Mahlzeiten-Partial (eine Zeile). Wird sowohl in der Tagesansicht/Archiv
|
||||
eingebunden als auch als htmx-Fragment von den CheckOff/Uncheck-Endpunkten
|
||||
Mahlzeiten-Partial (eine Zeile). Wird in Planungsliste/Tagesansicht/Archiv
|
||||
eingebunden und als htmx-Fragment von den CheckOff/Uncheck-Endpunkten
|
||||
zurückgeliefert (htmx ersetzt per hx-swap="outerHTML" genau diese <li>).
|
||||
|
||||
@param MahlzeitResponse m
|
||||
@param bool sortierbar optional: zeigt Drag-Handle + data-id (Planungsliste)
|
||||
#}
|
||||
<li class="item" id="mahlzeit-{{ m.id }}">
|
||||
<li class="item" id="mahlzeit-{{ m.id }}"
|
||||
{% if sortierbar is defined and sortierbar %}data-id="{{ m.id }}"{% endif %}>
|
||||
<div>
|
||||
{% if sortierbar is defined and sortierbar %}
|
||||
<span class="drag-handle" title="Ziehen zum Sortieren">⋮</span>
|
||||
{% endif %}
|
||||
<strong>{{ m.name }}</strong>
|
||||
{% if m.notiz != '' %}
|
||||
<div class="muted">{{ m.notiz }}</div>
|
||||
|
||||
@@ -7,25 +7,53 @@
|
||||
<div class="row-between">
|
||||
<div>
|
||||
<h1 style="margin: 0;">Mahlzeiten</h1>
|
||||
<div class="muted" style="margin-top: 0.2rem;">Tagesansicht nach Wochentag</div>
|
||||
<div class="muted" style="margin-top: 0.2rem;">Planungsliste – per Drag & Drop sortieren</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a class="btn" href="{{ path('mahlzeiten_neu') }}">+ Neue Mahlzeit</a>
|
||||
<a class="btn btn-link" href="{{ path('mahlzeiten_inspiration') }}">Inspiration</a>
|
||||
<a class="btn btn-link" href="{{ path('mahlzeiten_tage') }}">Tagesansicht</a>
|
||||
<a class="btn btn-link" href="{{ path('mahlzeiten_archiv') }}">Archiv</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if total == 0 %}
|
||||
<p class="muted" style="margin-top: 1rem;">Noch keine Mahlzeiten angelegt.</p>
|
||||
<p class="muted" style="margin-top: 1rem;">Noch keine Mahlzeiten in der Planung.</p>
|
||||
{% else %}
|
||||
{% for tag, mahlzeiten in tage %}
|
||||
<h2 style="margin: 1.25rem 0 0;">{{ tag }}</h2>
|
||||
<ul class="list">
|
||||
{% for m in mahlzeiten %}
|
||||
{{ include('mahlzeiten/_mahlzeit.html.twig', { m: m }) }}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
<ul class="list sortierbar">
|
||||
{% for m in mahlzeiten %}
|
||||
{{ include('mahlzeiten/_mahlzeit.html.twig', { m: m, sortierbar: true }) }}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script src="{{ asset('js/sortable.min.js') }}"></script>
|
||||
<script>
|
||||
(function () {
|
||||
const liste = document.querySelector('ul.sortierbar');
|
||||
if (!liste || typeof Sortable === 'undefined') { return; }
|
||||
const url = '{{ path("mahlzeiten_reorder") }}';
|
||||
Sortable.create(liste, {
|
||||
handle: '.drag-handle',
|
||||
animation: 150,
|
||||
ghostClass: 'item-drag',
|
||||
onEnd: function () {
|
||||
const ids = Array.prototype.map.call(
|
||||
liste.querySelectorAll('li[data-id]'),
|
||||
function (li) { return Number(li.getAttribute('data-id')); }
|
||||
);
|
||||
fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ ids: ids }),
|
||||
}).then(function (antwort) {
|
||||
if (!antwort.ok) { window.location.reload(); }
|
||||
}).catch(function () { window.location.reload(); });
|
||||
},
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
{% extends 'layout/base.html.twig' %}
|
||||
|
||||
{% block title %}Inspiration · svc-essensplanung{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="card">
|
||||
<div class="row-between">
|
||||
<div>
|
||||
<h1 style="margin: 0;">Inspiration</h1>
|
||||
<div class="muted" style="margin-top: 0.2rem;">Gerichte aus dem Archiv – was kochst du mal wieder?</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a class="btn btn-link" href="{{ path('mahlzeiten_index') }}">← Mahlzeiten</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Für "Weitere 5" / Adopt-Kontext: bisheriger Ausschluss + die IDs dieser Seite #}
|
||||
{% set alleAusschluss = ausschluss + gezeigte %}
|
||||
|
||||
{% if total == 0 %}
|
||||
<p class="muted" style="margin-top: 1rem;">
|
||||
Noch keine Inspiration: Hake Mahlzeiten ab – dann erscheinen sie hier als Vorschlag.
|
||||
</p>
|
||||
{% else %}
|
||||
<ul class="list">
|
||||
{% for v in vorschlaege %}
|
||||
<li class="item" id="vorschlag-{{ v.id }}">
|
||||
<div>
|
||||
<strong>{{ v.name }}</strong>
|
||||
{% if v.notiz != '' %}
|
||||
<div class="muted">{{ v.notiz }}</div>
|
||||
{% endif %}
|
||||
<span class="status">
|
||||
{% if v.gegessenAm %}
|
||||
zuletzt gegessen · {{ v.gegessenAm|date('d.m.Y') }}
|
||||
{% else %}
|
||||
aus dem Archiv
|
||||
{% endif %}
|
||||
· {{ v.auftraete }}× in der Küche
|
||||
</span>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<form method="post" action="{{ path('mahlzeiten_adopt', { id: v.id }) }}">
|
||||
{% for id in alleAusschluss %}
|
||||
<input type="hidden" name="ausschluss[]" value="{{ id }}">
|
||||
{% endfor %}
|
||||
<button type="submit" class="btn">Übernehmen</button>
|
||||
</form>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% if mehrVerfuegbar %}
|
||||
<p style="margin: 1rem 0 0;">
|
||||
<a class="btn btn-link"
|
||||
href="{{ path('mahlzeiten_inspiration', { ausschluss: alleAusschluss|join(',') }) }}">Weitere 5 Vorschläge</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,31 @@
|
||||
{% extends 'layout/base.html.twig' %}
|
||||
|
||||
{% block title %}Tagesansicht · svc-essensplanung{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="card">
|
||||
<div class="row-between">
|
||||
<div>
|
||||
<h1 style="margin: 0;">Tagesansicht</h1>
|
||||
<div class="muted" style="margin-top: 0.2rem;">Alle Mahlzeiten nach Wochentag</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a class="btn btn-link" href="{{ path('mahlzeiten_index') }}">← Mahlzeiten</a>
|
||||
<a class="btn" href="{{ path('mahlzeiten_neu') }}">+ Neue Mahlzeit</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if total == 0 %}
|
||||
<p class="muted" style="margin-top: 1rem;">Noch keine Mahlzeiten angelegt.</p>
|
||||
{% else %}
|
||||
{% for tag, mahlzeiten in tage %}
|
||||
<h2 style="margin: 1.25rem 0 0;">{{ tag }}</h2>
|
||||
<ul class="list">
|
||||
{% for m in mahlzeiten %}
|
||||
{{ include('mahlzeiten/_mahlzeit.html.twig', { m: m }) }}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user