- Move datetime import to module level
- Replace assert on load_cached_launches with or {} fallback so the
updater doesn't crash when the cache file is absent
- Condense upcoming-trips list comprehension to one line
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each Gantt bar and table row gets a data-conf-key attribute
(ISO start date + conference name). A small JS lookup map connects
them so hovering either element highlights both simultaneously:
- Gantt bar: filter brightness + inset white box-shadow
- Table row: yellow tint via background-color
Hovering a Gantt bar also scrolls the matching table row into view
(scrollIntoView nearest) so future conferences are reachable without
manual scrolling. The key field is pre-computed in
build_conference_timeline() to keep the template simple.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Proper <table> with colgroup widths, table-sm table-hover align-middle
- Month-divider rows (MARCH 2026, APRIL 2026, …) break up long lists
- Date ranges collapsed to a single column (e.g. "25–28 Mar 2026")
- Row highlight (conf-going) for conferences marked going=true
- Topic and date columns styled text-muted small to reduce visual noise
- Trip links replaced with 🧳 emoji: shows just the emoji when the trip
title matches the conference name (the common case), otherwise appends
the trip title (e.g. "🧳 Budapest" for FOSDEM); full title always in
tooltip
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Shows the next 90 days as a horizontal bar chart above the conference
list. A greedy interval-colouring algorithm assigns each conference to a
lane so overlapping conferences appear in separate rows. Lane colour
cycles through a fixed palette so simultaneous events are easy to tell
apart. Month boundary markers and a red today-line provide orientation.
All position maths happens in build_conference_timeline() in Python;
the Jinja template is pure rendering.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Web view was calling the OpenWeatherMap API directly on every request
(home + all trip locations), causing >1000 calls/day. Now web_view.py
uses cache_only=True everywhere so it never triggers live API calls —
update.py (cron) is the sole API caller. Also warms home location cache
in update_weather(), and increases TTL from 6h to 24h.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prevents hitting the SpaceDevs rate limit by skipping the API call
when the launches cache is still fresh (< 2 hours old), matching the
same TTL pattern already used for the active crewed flights cache.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add render_trip_element macro to macros.html; use it in trip_item for
the trip list page, giving a consistent one-line-per-element format
with emoji, route, times, duration, operator, distance, and CO₂
- Redesign trip_page.html itinerary: day headers use date-only (no year),
condense check-out to a single accent line, show time-only on transport
cards, humanise duration (Xh Ym), km-only distance, add CO₂ for all
transport modes, fix seat display for integer seat values
- Fix UndefinedError on /trip/past caused by absent 'arrive' key (Jinja2
Undefined is truthy) and date-only depart/arrive fields (no .date())
- Improve mobile map layout: text column before map in HTML order, reduce
mobile map heights, hide toggle button on mobile
- Add trips.css with design system (Playfair Display / Source Sans 3 /
JetBrains Mono, navy/gold/amber palette, card variants by type)
- Add tests/test_trip_list_render.py covering the rendering edge cases
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Transit countries (e.g. Madrid on the Peru trip) were already included
in trip.countries via flight data, but get_destination_timezones only
iterated trip.locations() which comes from accommodation/conferences/events.
Now also extract airport cities from flights and append any that aren't
already covered by a stay, using the airport coordinates for timezone lookup.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Don't write rate-limit/error responses to disk in next_launch_api_data,
so they can't become the "most recent" cache file and cause KeyError crashes
in read_cached_launches. Add defensive results-list checks in
read_cached_launches and get_launches to handle any existing bad files.
Drop refresh=True from the updater's get_active_crewed_flights call so the
2-hour TTL applies; the paginated spacecraft/flight crawl was running on
every hourly cron job and likely causing the burst that triggered throttling.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Show 8-day Bristol home weather on the index and weekends pages.
Show destination weather per day on the trip list and trip page.
Cache forecasts in ~/lib/data/weather/ and refresh via update.py.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When attend_start or attend_end is set, display the full conference
date range in parentheses after the attended dates, e.g.
"Wed 6 Mar to Sun 10 Mar (full conference: Sun 3 Mar to Sun 10 Mar)".
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Allows recording when you arrive late or leave early at a multi-day
conference. Both fields accept a plain date or datetime with time.
Trip pages display the attendance dates instead of the official
conference dates when these fields are set.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extract `load_road_transport()` as a shared helper for bus and coach,
combining the near-identical route rendering blocks in `get_trip_routes`
and `Trip.elements()` into single `in ("coach", "bus")` branches.
Document transport type patterns in AGENTS.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add case "bus" to get_locations() and bus route handling to
get_trip_routes() in trip.py. Coach stations now populate a dedicated
"coach_station" dict instead of the train station list. Add
"coach_station" (🚌) and "bus_stop" (🚏) emoji types to map.js.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Use Bootstrap cards and collapsible sections to make the long
lists of airlines, airports, and stations easier to read. Items
are now displayed as badges and hidden by default.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Aggregate yearly stats into overall totals so the trip stats page
shows flight segments by airline, airports used, and stations used
in the summary section at the top.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>