Make sidebar category/manufacturer sorting selectable
Kategorien and Hersteller/Quellen lists were hardcoded to sort by count descending. Add a small dropdown (Name A-Z / Anzahl) above the lists on both the Links and Prompts pages, backed by a new facet_sort query param plumbed through facets()/prompt_facets(). Defaults to alphabetical, which was the actual ask; count sort stays available for anyone who preferred the old behavior. All sidebar facet links carry the current facet_sort so it doesn't reset when filtering. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
32
app/main.py
32
app/main.py
@@ -110,18 +110,25 @@ def normalize_url(url: str) -> str:
|
|||||||
return url
|
return url
|
||||||
|
|
||||||
|
|
||||||
def facets(db: Session, user: User) -> dict:
|
# Sortierung der Kategorie-/Hersteller-Listen in der Seitenleiste.
|
||||||
|
FACET_SORT_OPTIONS = {"name": "Name A–Z", "count": "Anzahl"}
|
||||||
|
DEFAULT_FACET_SORT = "name"
|
||||||
|
|
||||||
|
|
||||||
|
def facets(db: Session, user: User, facet_sort: str = DEFAULT_FACET_SORT) -> dict:
|
||||||
|
cat_order = Link.category if facet_sort == "name" else func.count().desc()
|
||||||
cat_rows = db.execute(
|
cat_rows = db.execute(
|
||||||
select(Link.category, func.count())
|
select(Link.category, func.count())
|
||||||
.where(Link.user_id == user.id, Link.category != "")
|
.where(Link.user_id == user.id, Link.category != "")
|
||||||
.group_by(Link.category)
|
.group_by(Link.category)
|
||||||
.order_by(func.count().desc())
|
.order_by(cat_order)
|
||||||
).all()
|
).all()
|
||||||
|
man_order = Link.manufacturer if facet_sort == "name" else func.count().desc()
|
||||||
man_rows = db.execute(
|
man_rows = db.execute(
|
||||||
select(Link.manufacturer, func.count())
|
select(Link.manufacturer, func.count())
|
||||||
.where(Link.user_id == user.id, Link.manufacturer != "")
|
.where(Link.user_id == user.id, Link.manufacturer != "")
|
||||||
.group_by(Link.manufacturer)
|
.group_by(Link.manufacturer)
|
||||||
.order_by(func.count().desc())
|
.order_by(man_order)
|
||||||
).all()
|
).all()
|
||||||
review_count = db.scalar(
|
review_count = db.scalar(
|
||||||
select(func.count())
|
select(func.count())
|
||||||
@@ -200,12 +207,13 @@ def query_links(
|
|||||||
return sort_links(matches, sort)
|
return sort_links(matches, sort)
|
||||||
|
|
||||||
|
|
||||||
def prompt_facets(db: Session, user: User) -> dict:
|
def prompt_facets(db: Session, user: User, facet_sort: str = DEFAULT_FACET_SORT) -> dict:
|
||||||
|
cat_order = Prompt.category if facet_sort == "name" else func.count().desc()
|
||||||
cat_rows = db.execute(
|
cat_rows = db.execute(
|
||||||
select(Prompt.category, func.count())
|
select(Prompt.category, func.count())
|
||||||
.where(Prompt.user_id == user.id, Prompt.category != "")
|
.where(Prompt.user_id == user.id, Prompt.category != "")
|
||||||
.group_by(Prompt.category)
|
.group_by(Prompt.category)
|
||||||
.order_by(func.count().desc())
|
.order_by(cat_order)
|
||||||
).all()
|
).all()
|
||||||
return {"categories": [(name, count) for name, count in cat_rows]}
|
return {"categories": [(name, count) for name, count in cat_rows]}
|
||||||
|
|
||||||
@@ -343,6 +351,7 @@ def index(
|
|||||||
semantic: str = "",
|
semantic: str = "",
|
||||||
sort: str = DEFAULT_SORT,
|
sort: str = DEFAULT_SORT,
|
||||||
review: str = "",
|
review: str = "",
|
||||||
|
facet_sort: str = DEFAULT_FACET_SORT,
|
||||||
db: Session = Depends(get_db),
|
db: Session = Depends(get_db),
|
||||||
):
|
):
|
||||||
user = current_user(request, db)
|
user = current_user(request, db)
|
||||||
@@ -351,6 +360,8 @@ def index(
|
|||||||
|
|
||||||
if sort not in SORT_OPTIONS:
|
if sort not in SORT_OPTIONS:
|
||||||
sort = DEFAULT_SORT
|
sort = DEFAULT_SORT
|
||||||
|
if facet_sort not in FACET_SORT_OPTIONS:
|
||||||
|
facet_sort = DEFAULT_FACET_SORT
|
||||||
is_semantic = semantic in ("1", "on", "true")
|
is_semantic = semantic in ("1", "on", "true")
|
||||||
review_only = review in ("1", "on", "true")
|
review_only = review in ("1", "on", "true")
|
||||||
links = query_links(
|
links = query_links(
|
||||||
@@ -362,7 +373,7 @@ def index(
|
|||||||
"request": request,
|
"request": request,
|
||||||
"user": user,
|
"user": user,
|
||||||
"links": links,
|
"links": links,
|
||||||
"facets": facets(db, user),
|
"facets": facets(db, user, facet_sort),
|
||||||
"q": q,
|
"q": q,
|
||||||
"active_category": category,
|
"active_category": category,
|
||||||
"active_manufacturer": manufacturer,
|
"active_manufacturer": manufacturer,
|
||||||
@@ -371,6 +382,8 @@ def index(
|
|||||||
"sort": sort,
|
"sort": sort,
|
||||||
"sort_options": SORT_OPTIONS,
|
"sort_options": SORT_OPTIONS,
|
||||||
"review_only": review_only,
|
"review_only": review_only,
|
||||||
|
"facet_sort": facet_sort,
|
||||||
|
"facet_sort_options": FACET_SORT_OPTIONS,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -632,6 +645,7 @@ def prompts_index(
|
|||||||
q: str = "",
|
q: str = "",
|
||||||
category: str = "",
|
category: str = "",
|
||||||
sort: str = DEFAULT_SORT,
|
sort: str = DEFAULT_SORT,
|
||||||
|
facet_sort: str = DEFAULT_FACET_SORT,
|
||||||
db: Session = Depends(get_db),
|
db: Session = Depends(get_db),
|
||||||
):
|
):
|
||||||
user = current_user(request, db)
|
user = current_user(request, db)
|
||||||
@@ -640,6 +654,8 @@ def prompts_index(
|
|||||||
|
|
||||||
if sort not in SORT_OPTIONS:
|
if sort not in SORT_OPTIONS:
|
||||||
sort = DEFAULT_SORT
|
sort = DEFAULT_SORT
|
||||||
|
if facet_sort not in FACET_SORT_OPTIONS:
|
||||||
|
facet_sort = DEFAULT_FACET_SORT
|
||||||
prompts = query_prompts(db, user, q, category, sort)
|
prompts = query_prompts(db, user, q, category, sort)
|
||||||
return templates.TemplateResponse(
|
return templates.TemplateResponse(
|
||||||
"prompts.html",
|
"prompts.html",
|
||||||
@@ -647,12 +663,14 @@ def prompts_index(
|
|||||||
"request": request,
|
"request": request,
|
||||||
"user": user,
|
"user": user,
|
||||||
"prompts": prompts,
|
"prompts": prompts,
|
||||||
"facets": prompt_facets(db, user),
|
"facets": prompt_facets(db, user, facet_sort),
|
||||||
"q": q,
|
"q": q,
|
||||||
"active_category": category,
|
"active_category": category,
|
||||||
"ai_enabled": config.AI_ENABLED,
|
"ai_enabled": config.AI_ENABLED,
|
||||||
"sort": sort,
|
"sort": sort,
|
||||||
"sort_options": SORT_OPTIONS,
|
"sort_options": SORT_OPTIONS,
|
||||||
|
"facet_sort": facet_sort,
|
||||||
|
"facet_sort_options": FACET_SORT_OPTIONS,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -7,14 +7,23 @@
|
|||||||
<div class="layout">
|
<div class="layout">
|
||||||
<aside class="sidebar">
|
<aside class="sidebar">
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
<a href="/?sort={{ sort }}" class="facet {% if not active_category and not active_manufacturer and not review_only %}active{% endif %}">
|
<a href="/?sort={{ sort }}&facet_sort={{ facet_sort }}" class="facet {% if not active_category and not active_manufacturer and not review_only %}active{% endif %}">
|
||||||
<span>{{ icons.grid(size=14) }} Alle Links</span>
|
<span>{{ icons.grid(size=14) }} Alle Links</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
<div style="display:flex; justify-content:flex-end; margin-top:12px;">
|
||||||
|
<select onchange="const u=new URL(location); u.searchParams.set('facet_sort', this.value); location.href=u;"
|
||||||
|
title="Sortierung der Kategorie-/Hersteller-Listen" style="font-size:.75rem; padding:3px 6px;">
|
||||||
|
{% for value, label in facet_sort_options.items() %}
|
||||||
|
<option value="{{ value }}" {% if facet_sort == value %}selected{% endif %}>{{ label }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="facet-group">
|
<div class="facet-group">
|
||||||
<h3>Kategorien</h3>
|
<h3>Kategorien</h3>
|
||||||
{% for name, count in facets.categories %}
|
{% for name, count in facets.categories %}
|
||||||
<a href="/?category={{ name | urlencode }}&sort={{ sort }}"
|
<a href="/?category={{ name | urlencode }}&sort={{ sort }}&facet_sort={{ facet_sort }}"
|
||||||
class="facet {% if active_category == name and not review_only %}active{% endif %}">
|
class="facet {% if active_category == name and not review_only %}active{% endif %}">
|
||||||
<span>{{ name }}</span><span class="count">{{ count }}</span>
|
<span>{{ name }}</span><span class="count">{{ count }}</span>
|
||||||
</a>
|
</a>
|
||||||
@@ -26,7 +35,7 @@
|
|||||||
<div class="facet-group">
|
<div class="facet-group">
|
||||||
<h3>Hersteller / Quellen</h3>
|
<h3>Hersteller / Quellen</h3>
|
||||||
{% for name, count in facets.manufacturers %}
|
{% for name, count in facets.manufacturers %}
|
||||||
<a href="/?manufacturer={{ name | urlencode }}&sort={{ sort }}"
|
<a href="/?manufacturer={{ name | urlencode }}&sort={{ sort }}&facet_sort={{ facet_sort }}"
|
||||||
class="facet {% if active_manufacturer == name and not review_only %}active{% endif %}">
|
class="facet {% if active_manufacturer == name and not review_only %}active{% endif %}">
|
||||||
<span>{{ name }}</span><span class="count">{{ count }}</span>
|
<span>{{ name }}</span><span class="count">{{ count }}</span>
|
||||||
</a>
|
</a>
|
||||||
@@ -37,7 +46,7 @@
|
|||||||
|
|
||||||
<div class="facet-group">
|
<div class="facet-group">
|
||||||
<h3>Merkliste</h3>
|
<h3>Merkliste</h3>
|
||||||
<a href="/?review=1&sort={{ sort }}" class="facet {% if review_only %}active{% endif %}">
|
<a href="/?review=1&sort={{ sort }}&facet_sort={{ facet_sort }}" class="facet {% if review_only %}active{% endif %}">
|
||||||
<span>{{ icons.bookmark(size=14) }} Zur Durchsicht</span><span class="count">{{ facets.review_count }}</span>
|
<span>{{ icons.bookmark(size=14) }} Zur Durchsicht</span><span class="count">{{ facets.review_count }}</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,14 +7,23 @@
|
|||||||
<div class="layout">
|
<div class="layout">
|
||||||
<aside class="sidebar">
|
<aside class="sidebar">
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
<a href="/prompts?sort={{ sort }}" class="facet {% if not active_category %}active{% endif %}">
|
<a href="/prompts?sort={{ sort }}&facet_sort={{ facet_sort }}" class="facet {% if not active_category %}active{% endif %}">
|
||||||
<span>{{ icons.grid(size=14) }} Alle Prompts</span>
|
<span>{{ icons.grid(size=14) }} Alle Prompts</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
<div style="display:flex; justify-content:flex-end; margin-top:12px;">
|
||||||
|
<select onchange="const u=new URL(location); u.searchParams.set('facet_sort', this.value); location.href=u;"
|
||||||
|
title="Sortierung der Kategorie-Liste" style="font-size:.75rem; padding:3px 6px;">
|
||||||
|
{% for value, label in facet_sort_options.items() %}
|
||||||
|
<option value="{{ value }}" {% if facet_sort == value %}selected{% endif %}>{{ label }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="facet-group">
|
<div class="facet-group">
|
||||||
<h3>Kategorien</h3>
|
<h3>Kategorien</h3>
|
||||||
{% for name, count in facets.categories %}
|
{% for name, count in facets.categories %}
|
||||||
<a href="/prompts?category={{ name | urlencode }}&sort={{ sort }}"
|
<a href="/prompts?category={{ name | urlencode }}&sort={{ sort }}&facet_sort={{ facet_sort }}"
|
||||||
class="facet {% if active_category == name %}active{% endif %}">
|
class="facet {% if active_category == name %}active{% endif %}">
|
||||||
<span>{{ name }}</span><span class="count">{{ count }}</span>
|
<span>{{ name }}</span><span class="count">{{ count }}</span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
Reference in New Issue
Block a user