From 54e898bc112f74497ab9e3ec8be035144cf6b559 Mon Sep 17 00:00:00 2001 From: Edward Betts Date: Thu, 23 Apr 2026 14:29:29 +0100 Subject: [PATCH] Show exploration days before/after each conference on trip page For each conference, calculate the number of free days available before and after, relative to the trip boundary or adjacent conference. Multi-conference trips show the gap between conferences as "after" the first and "before" the second. Closes #189 Co-Authored-By: Claude Sonnet 4.6 --- agenda/trip.py | 33 +++++++++++++++++++++++++++++++++ templates/trip_page.html | 10 ++++++++++ web_view.py | 1 + 3 files changed, 44 insertions(+) diff --git a/agenda/trip.py b/agenda/trip.py index 9779831..6ab69ff 100644 --- a/agenda/trip.py +++ b/agenda/trip.py @@ -456,6 +456,39 @@ def coordinate_dict(item: StrDict, coord_type: str) -> StrDict: } +def conference_free_days(trip: Trip) -> dict[str, tuple[int, int]]: + """Return (days_before, days_after) exploration days for each conference. + + Keyed by the conference start date as an ISO string. Days are relative to + the trip boundary or the adjacent conference's end/start for multi-conference + trips. + """ + if not trip.conferences or not trip.end: + return {} + + def conf_attend_start(c: StrDict) -> date: + return as_date(c.get("attend_start") or c["start"]) + + def conf_attend_end(c: StrDict) -> date: + return as_date(c.get("attend_end") or c["end"]) + + sorted_confs = sorted(trip.conferences, key=conf_attend_start) + result: dict[str, tuple[int, int]] = {} + + for i, conf in enumerate(sorted_confs): + before_boundary = conf_attend_end(sorted_confs[i - 1]) if i > 0 else trip.start + after_boundary = ( + conf_attend_start(sorted_confs[i + 1]) + if i < len(sorted_confs) - 1 + else trip.end + ) + days_before = (conf_attend_start(conf) - before_boundary).days + days_after = (after_boundary - conf_attend_end(conf)).days + result[str(conf["start"])] = (days_before, days_after) + + return result + + def collect_trip_coordinates(trip: Trip) -> list[StrDict]: """Extract and de-duplicate travel location coordinates from trip.""" coords = [] diff --git a/templates/trip_page.html b/templates/trip_page.html index 109449a..56f61b7 100644 --- a/templates/trip_page.html +++ b/templates/trip_page.html @@ -239,6 +239,16 @@ {% elif item.price and item.currency %} price: {{ item.price }} {{ item.currency }} {% endif %} + {% set free_days = conference_free_days.get(item.start | string) %} + {% if free_days %} + {% set days_before, days_after = free_days %} + {% if days_before > 0 %} + {{ days_before }} day{{ 's' if days_before != 1 }} to explore before + {% endif %} + {% if days_after > 0 %} + {{ days_after }} day{{ 's' if days_after != 1 }} to explore after + {% endif %} + {% endif %}

diff --git a/web_view.py b/web_view.py index 1f86025..41a4f32 100755 --- a/web_view.py +++ b/web_view.py @@ -1144,6 +1144,7 @@ def trip_page(start: str) -> str: destination_times=get_destination_timezones(trip), human_readable_delta=agenda.utils.human_readable_delta, trip_weather=trip_weather, + conference_free_days=agenda.trip.conference_free_days(trip), )