{notice}
{/if} diff --git a/goodnews/api.py b/goodnews/api.py index 01e0bcb..9b72ca1 100644 --- a/goodnews/api.py +++ b/goodnews/api.py @@ -37,6 +37,7 @@ from .filters import filter_articles, prefs_from_json from .hero import safe_to_lead from .llm import LocalModelClient from .moods import MOODS, mood_filter +from .lanes import build_lane_pool from .paywall import is_paywalled from .taxonomy import FAMILIES, FLAVORS, TOPICS @@ -866,6 +867,18 @@ def create_app() -> FastAPI: # client merges with the user's own Calm Filters. return MOODS + @app.get("/api/lanes") + def lanes() -> dict: + # The customizable quick-access rail: 'today' is always pinned, and the + # reader pins any subset of these moods / topics / Discovery tags. Live + # counts let the client gate empty lanes and show volume. + with get_conn() as conn: + tagc = queries.tag_counts(conn) + topicc: dict[str, int] = {} + for row in queries.category_counts(conn): + topicc[row["topic"]] = topicc.get(row["topic"], 0) + int(row["count"]) + return build_lane_pool(topicc, tagc) + @app.get("/api/families") def families() -> list[dict]: # Grouping vocabulary organised into calm families for the Explore UI. diff --git a/goodnews/lanes.py b/goodnews/lanes.py new file mode 100644 index 0000000..5f2d317 --- /dev/null +++ b/goodnews/lanes.py @@ -0,0 +1,75 @@ +"""Nav lanes — the customizable quick-access rail above the feed. + +"Today" is always pinned (the daily brief). Past that, a reader pins whichever +lanes they like from a pool of three kinds, all of which the feed already knows +how to render as a view: + + * moods — curated filter presets (see moods.py); key is the bare mood key. + * topics — the eight primary categories; key is the bare topic key. + * tags — high-volume grouping tags (Discovery); key is "tag: