agenda/templates/macros.html
Edward Betts 574b4feb1f trip: redesign itinerary display and add trip list macro
- 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>
2026-03-03 09:15:51 +00:00

534 lines
22 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% macro display_datetime(dt) %}{{ dt.strftime("%a, %d, %b %Y %H:%M %z") }}{% endmacro %}
{% macro display_time(dt) %}
{% if dt %}{{ dt.strftime("%H:%M %z") }}{% endif %}
{% endmacro %}
{% macro display_date(dt) %}{{ dt.strftime("%a %-d %b %Y") }}{% endmacro %}
{% macro display_date_no_year(dt) %}{{ dt.strftime("%a %-d %b") }}{% endmacro %}
{% macro display_conf_date_no_year(dt) %}{%- if dt.hour is defined %}{{ dt.strftime("%a %-d %b %H:%M") }}{% else %}{{ dt.strftime("%a %-d %b") }}{% endif %}{% endmacro %}
{% macro format_distance(distance) %}
{{ "{:,.0f} km / {:,.0f} miles".format(distance, distance / 1.60934) }}
{% endmacro %}
{% macro trip_link(trip) %}
<a href="{{ url_for("trip_page", start=trip.start.isoformat()) }}">{{ trip.title }}</a>
{% endmacro %}
{% macro conference_row(item, badge, show_flags=True) %}
{% set country = get_country(item.country) if item.country else None %}
<div class="grid-item text-end text-nowrap">{{ item.start.strftime("%a, %d %b %Y") }}</div>
<div class="grid-item text-end text-nowrap">{{ item.end.strftime("%a, %d %b") }}</div>
<div class="grid-item">
{% if item.url %}
<a href="{{ item.url }}">{{ item.name }}</a>
{% else %}
{{ item.name }}
{% endif %}
{% if item.going and not (item.accommodation_booked or item.travel_booked) %}
<span class="badge text-bg-primary">
{{ badge }}
</span>
{% endif %}
{% if item.accommodation_booked %}
<span class="badge text-bg-success">accommodation</span>
{% endif %}
{% if item.transport_booked %}
<span class="badge text-bg-success">transport</span>
{% endif %}
</div>
<div class="grid-item text-end">
{% if item.price and item.currency %}
<span class="badge bg-info text-nowrap">{{ "{:,d}".format(item.price | int) }} {{ item.currency }}</span>
{% if item.currency != "GBP" and item.currency in fx_rate %}
<span class="badge bg-info text-nowrap">{{ "{:,.2f}".format(item.price / fx_rate[item.currency]) }} GBP</span>
{% endif %}
{% elif item.free %}
<span class="badge bg-success text-nowrap">free to attend</span>
{% endif %}
</div>
<div class="grid-item">{{ item.topic }}</div>
<div class="grid-item">{{ item.location }}</div>
<div class="grid-item text-end text-nowrap">{{ display_date(item.cfp_end) if item.cfp_end else "" }}</div>
<div class="grid-item">
{% if country %}
{% if show_flags %}{{ country.flag }}{% endif %} {{ country.name }}
{% elif item.online %}
💻 Online
{% else %}
<span class="text-bg-danger p-2">
country code <strong>{{ item.country }}</strong> not found
</span>
{% endif %}
</div>
{% endmacro %}
{% macro accommodation_row(item, badge, show_flags=True) %}
{% set country = get_country(item.country) %}
{% set nights = (item.to.date() - item.from.date()).days %}
<div class="grid-item text-end">{{ item.from.strftime("%a, %d %b %Y") }}</div>
<div class="grid-item text-end">{{ item.to.strftime("%a, %d %b") }}</div>
<div class="grid-item text-end">{% if nights == 1 %}1 night{% else %}{{ nights }} nights{% endif %}</div>
<div class="grid-item">{{ item.operator }}</div>
<div class="grid-item">{{ item.location }}</div>
<div class="grid-item">
{% if country %}
{% if show_flags %}{{ country.flag }}{% endif %} {{ country.name }}
{% else %}
<span class="text-bg-danger p-2">
country code <strong>{{ item.country }}</strong> not found
</span>
{% endif %}
</div>
<div class="grid-item">
{% if g.user.is_authenticated and item.url %}
<a href="{{ item.url }}">{{ item.name }}</a>
{% else %}
{{ item.name }}
{% endif %}
</div>
<div class="grid-item text-end">
{% if g.user.is_authenticated and item.price and item.currency %}
<span class="badge bg-info text-nowrap">{{ "{:,f}".format(item.price) }} {{ item.currency }}</span>
{% if item.currency != "GBP" %}
<span class="badge bg-info text-nowrap">{{ "{:,.2f}".format(item.price / fx_rate[item.currency]) }} GBP</span>
{% endif %}
{% endif %}
</div>
{% endmacro %}
{% macro flightradar24_url(flight) -%}
https://www.flightradar24.com/data/flights/{{ flight.airline_detail.iata | lower + flight.flight_number }}
{%- endmacro %}
{% macro flight_booking_row(booking, show_flags=True) %}
<div class="grid-item">
{% if g.user.is_authenticated %}
{{ booking.booking_reference or "reference missing" }}
{% else %}
<em>redacted</em>
{% endif %}
</div>
<div class="grid-item text-end">
{% if g.user.is_authenticated and booking.price and booking.currency %}
<span class="badge bg-info text-nowrap">{{ "{:,f}".format(booking.price) }} {{ booking.currency }}</span>
{% if booking.currency != "GBP" %}
<span class="badge bg-info text-nowrap">{{ "{:,.2f}".format(booking.price / fx_rate[booking.currency]) }} GBP</span>
{% endif %}
{% endif %}
</div>
{% for i in range(9) %}
<div class="grid-item"></div>
{% endfor %}
{% for item in booking.flights %}
{% set full_flight_number = item.airline_code + item.flight_number %}
{% set radarbox_url = "https://www.radarbox.com/data/flights/" + full_flight_number %}
<div class="grid-item"></div>
<div class="grid-item"></div>
<div class="grid-item text-end">{{ item.depart.strftime("%a, %d %b %Y") }}</div>
<div class="grid-item">{{ item.from }} → {{ item.to }}</div>
<div class="grid-item">{{ item.depart.strftime("%H:%M") }}</div>
<div class="grid-item">
{% if item.arrive %}
{{ item.arrive.strftime("%H:%M") }}
{% if item.arrive.date() != item.depart.date() %}+1 day{% endif %}
{% endif %}
</div>
<div class="grid-item">{{ item.duration }}</div>
<div class="grid-item">{{ full_flight_number }}</div>
<div class="grid-item">
<a href="{{ flightradar24_url(item) }}">flightradar24</a>
| <a href="https://uk.flightaware.com/live/flight/{{ full_flight_number }}">FlightAware</a>
| <a href="{{ radarbox_url }}">radarbox</a>
</div>
<div class="grid-item text-end">
{% if item.distance %}
{{ "{:,.0f} km / {:,.0f} miles".format(item.distance, item.distance / 1.60934) }}
{% endif %}
</div>
<div class="grid-item text-end">{{ "{:,.1f}".format(item.co2_kg) }} kg</div>
{% endfor %}
{% endmacro %}
{% macro flight_row(item) %}
{% set full_flight_number = item.airline_code + item.flight_number %}
{% set radarbox_url = "https://www.radarbox.com/data/flights/" + full_flight_number %}
<div class="grid-item text-end">{{ item.depart.strftime("%a, %d %b %Y") }}</div>
<div class="grid-item">{{ item.from }} → {{ item.to }}</div>
<div class="grid-item">{{ item.depart.strftime("%H:%M") }}</div>
<div class="grid-item">
{% if item.arrive %}
{{ item.arrive.strftime("%H:%M") }}
{% if item.arrive.date() != item.depart.date() %}+1 day{% endif %}
{% endif %}
</div>
<div class="grid-item">{{ item.duration }}</div>
<div class="grid-item">{{ full_flight_number }}</div>
<div class="grid-item">
{% if g.user.is_authenticated %}
{{ item.booking_reference }}
{% else %}
<em>redacted</em>
{% endif %}
</div>
<div class="grid-item">
<a href="{{ flightradar24_url(item) }}">flightradar24</a>
| <a href="https://uk.flightaware.com/live/flight/{{ full_flight_number }}">FlightAware</a>
| <a href="{{ radarbox_url }}">radarbox</a>
</div>
<div class="grid-item text-end">
{% if item.distance %}
{{ "{:,.0f} km / {:,.0f} miles".format(item.distance, item.distance / 1.60934) }}
{% endif %}
</div>
<div class="grid-item text-end">
{% if g.user.is_authenticated and item.price and item.currency %}
<span class="badge bg-info text-nowrap">{{ "{:,f}".format(item.price) }} {{ item.currency }}</span>
{% if item.currency != "GBP" %}
<span class="badge bg-info text-nowrap">{{ "{:,.2f}".format(item.price / fx_rate[item.currency]) }} GBP</span>
{% endif %}
{% endif %}
</div>
{% endmacro %}
{% macro train_row(item) %}
{% set url = item.url %}
<div class="grid-item text-end">{{ item.depart.strftime("%a, %d %b %Y") }}</div>
<div class="grid-item">
{% if g.user.is_authenticated and item.url %}<a href="{{ url }}">{% endif %}
{{ item.from }} → {{ item.to }}
{% if g.user.is_authenticated and item.url %}</a>{% endif %}
</div>
<div class="grid-item">{{ item.depart.strftime("%H:%M") }}</div>
<div class="grid-item">
{% if item.arrive %}
{{ item.arrive.strftime("%H:%M") }}
{% if item.depart != item.arrive and item.arrive.date() != item.depart.date() %}+1 day{% endif %}
{% endif %}
</div>
<div class="grid-item">{{ ((item.arrive - item.depart).total_seconds() // 60) | int }} mins</div>
<div class="grid-item">{{ item.operator }}</div>
<div class="grid-item">
{% if g.user.is_authenticated %}
{{ item.booking_reference }}
{% else %}
<em>redacted</em>
{% endif %}
</div>
<div class="grid-item">
{% for leg in item.legs %}
{% if leg.url %}
<a href="{{ leg.url }}">[{{ loop.index }}]</a>
{% endif %}
{% endfor %}
</div>
<div class="grid-item text-end">
{% if item.distance %}
{{ "{:,.0f} km / {:,.0f} miles".format(item.distance, item.distance / 1.60934) }}
{% endif %}
</div>
<div class="grid-item text-end">
{% if g.user.is_authenticated and item.price and item.currency %}
<span class="badge bg-info text-nowrap">{{ "{:,f}".format(item.price) }} {{ item.currency }}</span>
{% if item.currency != "GBP" and item.currency in fx_rate %}
<span class="badge bg-info text-nowrap">{{ "{:,.2f}".format(item.price / fx_rate[item.currency]) }} GBP</span>
{% endif %}
{% endif %}
</div>
{% endmacro %}
{% macro coach_row(item) %}
{% set url = item.url %}
<div class="grid-item text-end">{{ item.depart.strftime("%a, %d %b %Y") }}</div>
<div class="grid-item">
{% if g.user.is_authenticated and item.url %}<a href="{{ url }}">{% endif %}
{{ item.from }} → {{ item.to }}
{% if g.user.is_authenticated and item.url %}</a>{% endif %}
</div>
<div class="grid-item">{{ item.depart.strftime("%H:%M") }}</div>
<div class="grid-item">
{% if item.arrive %}
{{ item.arrive.strftime("%H:%M") }}
{% if item.depart != item.arrive and item.arrive.date() != item.depart.date() %}+1 day{% endif %}
{% endif %}
</div>
<div class="grid-item">{{ ((item.arrive - item.depart).total_seconds() // 60) | int }} mins</div>
<div class="grid-item">{{ item.operator }}</div>
<div class="grid-item">
{% if g.user.is_authenticated %}
{{ item.booking_reference }}
{% else %}
<em>redacted</em>
{% endif %}
</div>
<div class="grid-item">
</div>
<div class="grid-item text-end">
{% if item.distance %}
{{ "{:,.0f} km / {:,.0f} miles".format(item.distance, item.distance / 1.60934) }}
{% endif %}
</div>
<div class="grid-item text-end">
{% if g.user.is_authenticated and item.price and item.currency %}
<span class="badge bg-info text-nowrap">{{ "{:,f}".format(item.price) }} {{ item.currency }}</span>
{% if item.currency != "GBP" and item.currency in fx_rate %}
<span class="badge bg-info text-nowrap">{{ "{:,.2f}".format(item.price / fx_rate[item.currency]) }} GBP</span>
{% endif %}
{% endif %}
</div>
{% endmacro %}
{% macro bus_row(item) %}
{% set url = item.url %}
<div class="grid-item text-end">{{ item.depart.strftime("%a, %d %b %Y") }}</div>
<div class="grid-item">
{% if g.user.is_authenticated and item.url %}<a href="{{ url }}">{% endif %}
{{ item.from }} → {{ item.to }}
{% if g.user.is_authenticated and item.url %}</a>{% endif %}
</div>
<div class="grid-item">{{ item.depart.strftime("%H:%M") }}</div>
<div class="grid-item">
{% if item.arrive %}
{{ item.arrive.strftime("%H:%M") }}
{% if item.depart != item.arrive and item.arrive.date() != item.depart.date() %}+1 day{% endif %}
{% endif %}
</div>
<div class="grid-item">{{ ((item.arrive - item.depart).total_seconds() // 60) | int }} mins</div>
<div class="grid-item">{{ item.operator }}</div>
<div class="grid-item">
{% if g.user.is_authenticated %}
{{ item.booking_reference }}
{% else %}
<em>redacted</em>
{% endif %}
</div>
<div class="grid-item">
</div>
<div class="grid-item text-end">
{% if item.distance %}
{{ "{:,.0f} km / {:,.0f} miles".format(item.distance, item.distance / 1.60934) }}
{% endif %}
</div>
<div class="grid-item text-end">
{% if g.user.is_authenticated and item.price and item.currency %}
<span class="badge bg-info text-nowrap">{{ "{:,f}".format(item.price) }} {{ item.currency }}</span>
{% if item.currency != "GBP" and item.currency in fx_rate %}
<span class="badge bg-info text-nowrap">{{ "{:,.2f}".format(item.price / fx_rate[item.currency]) }} GBP</span>
{% endif %}
{% endif %}
</div>
{% endmacro %}
{% macro ferry_row(item) %}
<div class="grid-item text-end">{{ item.depart.strftime("%a, %d %b %Y") }}</div>
<div class="grid-item">
{{ item.from }} → {{ item.to }}
</div>
<div class="grid-item">{{ item.depart.strftime("%H:%M") }}</div>
<div class="grid-item">
{% if item.arrive %}
{{ item.arrive.strftime("%H:%M") }}
{% if item.depart != item.arrive and item.arrive.date() != item.depart.date() %}+1 day{% endif %}
{% endif %}
</div>
<div class="grid-item"></div>
<div class="grid-item">{{ item.operator }}</div>
<div class="grid-item"></div>
<div class="grid-item"></div>
<div class="grid-item"></div>
<div class="grid-item text-end">
{% if g.user.is_authenticated and item.price and item.currency %}
<span class="badge bg-info text-nowrap">{{ "{:,f}".format(item.price) }} {{ item.currency }}</span>
{% if item.currency != "GBP" %}
<span class="badge bg-info text-nowrap">{{ "{:,.2f}".format(item.price / fx_rate[item.currency]) }} GBP</span>
{% endif %}
{% endif %}
</div>
{# <div class="grid-item">{{ item | pprint }}</div> #}
{% endmacro %}
{% macro flag(trip, flag) %}{% if trip.show_flags %}{{ flag }}{% endif %}{% endmacro %}
{% macro conference_list(trip) %}
{% for item in trip.conferences %}
{% set country = get_country(item.country) if item.country else None %}
<div class="trip-conference-card my-1">
<div class="card-body">
<h5 class="card-title">
<a href="{{ item.url }}">{{ item.name }}</a>
<small class="text-muted">
{{ display_conf_date_no_year(item.attend_start if item.attend_start else item.start) }} to {{ display_conf_date_no_year(item.attend_end if item.attend_end else item.end) }}
{% if item.attend_start or item.attend_end %}
(full conference: {{ display_date_no_year(item.start) }} to {{ display_date_no_year(item.end) }})
{% endif %}
</small>
</h5>
<p class="card-text">
Topic: {{ item.topic }}
| Venue: {{ item.venue }}
| Location: {{ item.location }}
{% if country %}
{{ flag(trip, country.flag) }}
{% elif item.online %}
💻 Online
{% else %}
<span class="text-bg-danger p-2">
country code <strong>{{ item.country }}</strong> not found
</span>
{% endif %}
{% if item.free %}
| <span class="badge bg-success text-nowrap">free to attend</span>
{% elif item.price and item.currency %}
| <span class="badge bg-info text-nowrap">price: {{ item.price }} {{ item.currency }}</span>
{% endif %}
</p>
</div>
</div>
{% endfor %}
{% endmacro %}
{% macro render_trip_element(e, trip) %}
{% set item = e.detail %}
{% if e.element_type == "check-in" %}
{% set nights = (item.to.date() - item.from.date()).days %}
<div class="trip-element">
{{ e.get_emoji() }} <strong>{{ item.name }}</strong>
{% if item.operator and item.operator != item.name %}<small class="text-muted">{{ item.operator }}</small>{% endif %}
<small class="text-muted">({% if nights == 1 %}1 night{% else %}{{ nights }} nights{% endif %})</small>
</div>
{% elif e.element_type == "check-out" %}
<div class="trip-checkout">
{{ e.get_emoji() }} Check out: {{ item.name }}
{% if item.operator and item.operator != item.name %}<span class="text-muted small">{{ item.operator }}</span>{% endif %}
</div>
{% elif e.element_type != "conference" %}
{# Transport: flight, train, ferry, coach, bus #}
{% set has_arrive = item.arrive is defined and item.arrive %}
{# item.depart may be a date (no .date() method) or a datetime (has .date()) #}
{% set has_time = item.depart is defined and item.depart and item.depart.hour is defined %}
{% set depart_date = item.depart.date() if has_time else item.depart %}
{% set arrive_date = item.arrive.date() if (has_arrive and item.arrive.hour is defined) else item.arrive %}
{% set is_overnight = has_arrive and depart_date != arrive_date %}
{% set dur_mins = ((item.arrive - item.depart).total_seconds() // 60) | int if (has_time and has_arrive) else none %}
<div class="trip-element">
{% if is_overnight %}🌙{% else %}{{ e.get_emoji() }}{% endif %}
{{ e.start_loc }} → {{ e.end_loc }}
{% if has_time %}
· {{ item.depart.strftime("%H:%M") }}{% if has_arrive and item.arrive.hour is defined %} → {{ item.arrive.strftime("%H:%M") }}{% if is_overnight %} <span class="text-muted small">+1 day</span>{% endif %}{% endif %}
{% endif %}
{% if dur_mins %}
{%- set h = dur_mins // 60 %}{%- set m = dur_mins % 60 %}
<span class="text-muted">🕒{% if h %}{{ h }}h {% endif %}{% if m %}{{ m }}m{% endif %}</span>
{% endif %}
{% if e.element_type == "flight" %}
<small class="text-muted">· {{ item.airline_name }} {{ item.airline_code }}{{ item.flight_number }}</small>
{% elif item.operator %}
<small class="text-muted">· {{ item.operator }}</small>
{% endif %}
{% if item.distance %}
<span class="text-muted small">· {{ "{:,.0f} km".format(item.distance) }}</span>
{% endif %}
{% if item.co2_kg is defined and item.co2_kg is not none %}
<span class="text-muted small">CO₂ {{ "{:,.1f}".format(item.co2_kg) }} kg</span>
{% endif %}
</div>
{% endif %}
{% endmacro %}
{% macro trip_item(trip) %}
{% set distances_by_transport_type = trip.distances_by_transport_type() %}
{% set total_distance = trip.total_distance() %}
{% set total_co2_kg = trip.total_co2_kg() %}
{% set end = trip.end %}
{% set trip_end = end or trip.start %}
{% set is_current = trip.start <= today and trip_end >= today %}
<div class="trip-card{% if is_current %} trip-current{% endif %}">
<h3 class="trip-name">
{{ trip_link(trip) }}
<small>({{ display_date(trip.start) }})</small></h3>
{% set school_holidays = trip_school_holiday_map.get(trip.start.isoformat(), []) if trip_school_holiday_map is defined else [] %}
{% if school_holidays %}
<div class="school-holiday-info">
<span class="badge bg-warning text-dark">UK school holiday</span>
{% for item in school_holidays %}
<span class="text-muted">{{ item.title }} ({{ display_date_no_year(item.as_date) }} to {{ display_date_no_year(item.end_as_date) }})</span>
{% endfor %}
</div>
{% endif %}
<ul class="list-unstyled trip-countries">
{% for c in trip.countries %}
<li>{{ c.flag }} {{ c.name }}</li>
{% endfor %}
</ul>
{% if end %}
<div class="trip-dates">Dates: {{ display_date_no_year(trip.start) }} to {{ display_date_no_year(end) }}
{% if g.user.is_authenticated and trip.start <= today %}
<a href="https://photos.4angle.com/search?query=%7B%22takenAfter%22%3A%22{{trip.start}}T00%3A00%3A00.000Z%22%2C%22takenBefore%22%3A%22{{end}}T23%3A59%3A59.999Z%22%7D">photos</a>
{% endif %}
</div>
{% else %}
<div>Start: {{ display_date_no_year(trip.start) }} (end date missing)</div>
{% endif %}
<div class="trip-stats">
{% if total_distance %}
<span class="trip-stat">{{ format_distance(total_distance) }}</span>
{% endif %}
{% if distances_by_transport_type %}
{% for transport_type, distance in distances_by_transport_type %}
<span class="trip-stat">{{ transport_type | title }}: {{format_distance(distance) }}</span>
{% endfor %}
{% endif %}
{% if total_co2_kg %}
<span class="trip-stat">CO₂ {{ "{:,.1f}".format(total_co2_kg) }} kg</span>
{% endif %}
{% set co2_by_transport = trip.co2_by_transport_type() %}
{% if co2_by_transport %}
{% for transport_type, co2_kg in co2_by_transport %}
<span class="trip-stat">{{ transport_type | title }} CO₂ {{ "{:,.1f}".format(co2_kg) }} kg</span>
{% endfor %}
{% endif %}
</div>
{% if trip.schengen_compliance %}
<div>
<strong>Schengen:</strong>
{% if trip.schengen_compliance.is_compliant %}
<span class="badge bg-success">✅ Compliant</span>
{% else %}
<span class="badge bg-danger">❌ Non-compliant</span>
{% endif %}
<span class="text-muted small">({{ trip.schengen_compliance.total_days_used }}/90 days used)</span>
</div>
{% endif %}
{{ conference_list(trip) }}
{% set trip_weather = trip_weather_map.get(trip.start.isoformat(), {}) if trip_weather_map is defined else {} %}
{% for day, elements in trip.elements_grouped_by_day() %}
{% set weather = trip_weather.get(day.isoformat()) %}
<h4 class="trip-day-header">{{ display_date_no_year(day) }}
{% if weather %}
<span class="trip-weather-inline">
<img src="https://openweathermap.org/img/wn/{{ weather.icon }}.png" alt="{{ weather.status }}" title="{{ weather.detailed_status }}" width="18" height="18">
{{ weather.temp_min }}{{ weather.temp_max }}°C
<span class="fw-normal fst-italic">{{ weather.detailed_status }}</span>
</span>
{% endif %}
{% if g.user.is_authenticated and day <= today %}
<a class="ms-2 small fw-normal" href="https://photos.4angle.com/search?query=%7B%22takenAfter%22%3A%22{{day}}T00%3A00%3A00.000Z%22%2C%22takenBefore%22%3A%22{{day}}T23%3A59%3A59.999Z%22%7D">photos</a>
{% endif %}
</h4>
{% for e in elements %}
{{ render_trip_element(e, trip) }}
{% endfor %}
{% endfor %}
</div>
{% endmacro %}