diff --git a/recipes/forms.py b/recipes/forms.py
index b794a9c..3133747 100644
--- a/recipes/forms.py
+++ b/recipes/forms.py
@@ -138,7 +138,7 @@ class SearchForm(forms.Form):
ansicht = forms.ChoiceField(
label="Anzeigen",
required=False,
- choices=[("", "Alle Rezepte"), ("meine", "Meine Rezepte"), ("favoriten", "Favoriten")],
+ choices=[("", "Alle Rezepte"), ("meine", "Eigene Rezepte"), ("favoriten", "Favoriten")],
)
def ingredient_terms(self):
diff --git a/recipes/views.py b/recipes/views.py
index a52f9df..a35b7b1 100644
--- a/recipes/views.py
+++ b/recipes/views.py
@@ -74,8 +74,9 @@ def recipe_list(request):
page = Paginator(qs, PAGE_SIZE).get_page(request.GET.get("seite"))
tags = Tag.visible_to(request.user)
return render(request, "recipes/list.html", {
- "form": form, "page": page, "tags": tags, "active_tag": data.get("tag", ""),
+ "form": form, "page": page, "tags": tags, "active_tag": data.get("tag", ""), "active_view": view,
"filtered": bool(data.get("q") or data.get("zutat") or data.get("tag") or view),
+ "only_view": bool(view and not (data.get("q") or data.get("zutat") or data.get("tag"))),
})
diff --git a/static/css/app.css b/static/css/app.css
index f1ee96d..fb2b63e 100644
--- a/static/css/app.css
+++ b/static/css/app.css
@@ -209,7 +209,7 @@ input[type="search"] {
display: block; height: 100%; overflow: hidden; text-decoration: none; color: var(--text);
background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
}
-.recipe-card img, .recipe-card .placeholder { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
+.recipe-card img, .recipe-card .placeholder { display: block; width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; }
.recipe-card .placeholder { display: grid; place-items: center; font-size: 2.5rem; background: var(--border); }
.recipe-card-body { padding: 0.6rem 0.75rem 0.75rem; display: flex; flex-direction: column; gap: 0.2rem; line-height: 1.3; }
.recipe-card-body .muted { font-size: 0.82rem; }
@@ -283,3 +283,12 @@ code { font-size: 0.9em; }
.help-box { border-left: 4px solid var(--accent); }
.help-box ol { padding-left: 1.2rem; margin: 0; }
.help-box li { margin-bottom: 0.4rem; }
+
+/* --- Tabs ---------------------------------------------------------------------------- */
+.tabs { display: flex; gap: 0.25rem; margin: 0 0 1rem; border-bottom: 1px solid var(--border); overflow-x: auto; scrollbar-width: none; }
+.tabs::-webkit-scrollbar { display: none; }
+.tab {
+ flex: 0 0 auto; padding: 0.6rem 0.9rem; min-height: var(--tap); display: flex; align-items: center;
+ color: var(--muted); text-decoration: none; font-weight: 600; border-bottom: 3px solid transparent; margin-bottom: -1px;
+}
+.tab[aria-current="page"] { color: var(--accent); border-bottom-color: var(--accent); }
diff --git a/templates/base.html b/templates/base.html
index 62ad72f..87bf460 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -22,6 +22,7 @@
Keine Rezepte gefunden. Filter zurücksetzen
+{% elif filtered and not only_view %} +Keine Rezepte gefunden. Filter zurücksetzen
+{% elif active_view == "favoriten" %} +Noch keine Favoriten. Tippe bei einem Rezept auf „☆ Merken“.
Du hast noch keine eigenen Rezepte.
+ Rezept anlegen +Noch keine Rezepte. Leg das erste an!
diff --git a/tests/test_recipes.py b/tests/test_recipes.py index fd4a944..17d7671 100644 --- a/tests/test_recipes.py +++ b/tests/test_recipes.py @@ -204,3 +204,28 @@ def test_imported_draft_defaults_to_public(user_client, settings): def test_private_can_still_be_chosen(user_client): user_client.post(reverse("recipes:create"), form_data(visibility="private")) assert Recipe.objects.get().visibility == "private" + + +def test_tabs_and_own_recipes_tab(user_client, user, other_user): + make_recipe(user, title="Meins", visibility=Recipe.Visibility.PRIVATE) + make_recipe(other_user, title="Deins") + response = user_client.get(reverse("recipes:list"), {"ansicht": "meine"}) + html = response.content.decode() + assert "Eigene Rezepte" in html and 'aria-current="page">Eigene Rezepte' in html + assert [r.title for r in response.context["page"].object_list] == ["Meins"] + all_titles = {r.title for r in user_client.get(reverse("recipes:list")).context["page"].object_list} + assert all_titles == {"Meins", "Deins"} + + +def test_search_stays_in_own_tab(user_client, user, other_user): + make_recipe(user, title="Linsensuppe") + make_recipe(other_user, title="Linsensalat") + response = user_client.get(reverse("recipes:list"), {"ansicht": "meine", "q": "linsen"}) + assert [r.title for r in response.context["page"].object_list] == ["Linsensuppe"] + assert '' in response.content.decode() + + +def test_own_tab_empty_state(user_client, other_user): + make_recipe(other_user, title="Deins") + html = user_client.get(reverse("recipes:list"), {"ansicht": "meine"}).content.decode() + assert "noch keine eigenen Rezepte" in html and "Deins" not in html