diff --git a/agenda/types.py b/agenda/types.py index 50a2612..4642566 100644 --- a/agenda/types.py +++ b/agenda/types.py @@ -6,6 +6,7 @@ import typing from collections import Counter from dataclasses import dataclass, field +import emoji from pycountry.db import Country import agenda @@ -42,6 +43,18 @@ class TripElement: element_type: str detail: StrDict + def get_emoji(self) -> str | None: + """Emjoji for trip element.""" + if self.element_type in ("check-in", "check-out"): + return emoji.emojize(":hotel:", language="alias") + if self.element_type == "train": + return emoji.emojize(":train:", language="alias") + if self.element_type == "flight": + return emoji.emojize(":airplane:", language="alias") + if self.element_type == "ferry": + return emoji.emojize(":ferry:", language="alias") + return None + def airport_label(airport: StrDict) -> str: """Airport label: name and iata.""" @@ -259,6 +272,16 @@ class Trip: day = as_date(element.when) grouped_elements[day].append(element) + # Sort elements within each day + for day in grouped_elements: + grouped_elements[day].sort( + key=lambda e: ( + e.element_type == "check-in", # check-out elements last + e.element_type != "check-out", # check-in elements first + as_datetime(e.when), # then sort by time + ) + ) + # Convert the dictionary to a sorted list of tuples grouped_elements_list = sorted(grouped_elements.items()) diff --git a/requirements.txt b/requirements.txt index ba7a169..3ed2d57 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,4 @@ dateutil ephem flask requests +emoji diff --git a/templates/trip/list.html b/templates/trip/list.html index 7b2a3ab..662c020 100644 --- a/templates/trip/list.html +++ b/templates/trip/list.html @@ -82,13 +82,21 @@ <div class="heading"><h2>{{ heading }}</h2></div> <p>{{ items | count }} trips</p> {% for trip in items %} + {% set distances_by_transport_type = trip.distances_by_transport_type() %} {% set total_distance = trip.total_distance() %} {% set end = trip.end %} <div class="border border-2 rounded mb-2 p-2"> <h3> {{ trip_link(trip) }} <small class="text-muted">({{ display_date(trip.start) }})</small></h3> - <div>Countries: {{ trip.countries_str }}</div> + <ul class="list-unstyled"> + {% for c in trip.countries %} + <li> + {{ c.name }} + {{ c.flag }} + </li> + {% endfor %} + </ul> {% if end %} <div>Dates: {{ display_date_no_year(trip.start) }} to {{ display_date_no_year(end) }}</div> {% else %} @@ -100,60 +108,63 @@ </div> {% endif %} - {# - {% for day in trip.days() %} - <h4>{{ display_date_no_year(day) }}</h4> + {% if distances_by_transport_type %} + {% for transport_type, distance in distances_by_transport_type %} + <div>{{ transport_type | title }} distance: + {{ "{:,.0f} km / {:,.0f} miles".format(distance, distance / 1.60934) }} + </div> + {% endfor %} + {% endif %} + + {% for item in trip.conferences %} + {% set country = get_country(item.country) if item.country else None %} + <div class="card my-1"> + <div class="card-body"> + <h5 class="card-title"> + <a href="{{ item.url }}">{{ item.name }}</a> + <small class="text-muted"> + {{ display_date_no_year(item.start) }} to {{ display_date_no_year(item.end) }} + </small> + </h5> + <p class="card-text"> + Topic: {{ item.topic }} + | Venue: {{ item.venue }} + | Location: {{ item.location }} + {% if country %} + {{ 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 %} - #} - - {% for item in trip.conferences %} - {% set country = get_country(item.country) if item.country else None %} - <div class="card my-1"> - <div class="card-body"> - <h5 class="card-title"> - <a href="{{ item.url }}">{{ item.name }}</a> - <small class="text-muted"> - {{ display_date_no_year(item.start) }} to {{ display_date_no_year(item.end) }} - </small> - </h5> - <p class="card-text"> - Topic: {{ item.topic }} - | Venue: {{ item.venue }} - | Location: {{ item.location }} - {% if country %} - {{ 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 %} - - {% set date_heading = None %} {% for day, elements in trip.elements_grouped_by_day() %} <h4>{{ display_date_no_year(day) }}</h4> {% for e in elements %} - <div> + {% if e.element_type == "check-out" %} + <div>{{ e.get_emoji() }} {{ e.title }} (check-out)</div> + {% elif e.element_type == "check-in" %} + <div>{{ e.get_emoji() }} {{ e.title }} (check-in)</div> + {% else %} <div> + {{ e.get_emoji() }} {{ display_time(e.when) }} — - {{ e.element_type }} - — {{ e.title }} </div> - </div> + {% endif %} {% endfor %} {% endfor %}