summaryrefslogtreecommitdiff
path: root/templates/blocks/trail.html
diff options
context:
space:
mode:
authorDennis Fink2026-07-23 00:18:21 +0200
committerDennis Fink2026-07-23 00:18:21 +0200
commit1fe1d13c600b7dfe421b3b99b833b7d5d1232724 (patch)
tree2e8636160cc1719c907be56f5ef8cbc7e0f10a53 /templates/blocks/trail.html
parentca77de06be474dfd712402c327dc436864d233a3 (diff)
downloaddennisfink.me-1fe1d13c600b7dfe421b3b99b833b7d5d1232724.tar.gz
dennisfink.me-1fe1d13c600b7dfe421b3b99b833b7d5d1232724.zip
Add GPX trail maps to blog posts
This adds a trail flow block so posts can include attached GPX files as interactive maps with route display, elevation charts, activity summaries, and start/finish markers. The trail assets are loaded only when needed, keeping the shared templates clean while vendoring the Leaflet dependencies required for offline, self-hosted map rendering.
Diffstat (limited to '')
-rw-r--r--templates/blocks/trail.html71
1 files changed, 71 insertions, 0 deletions
diff --git a/templates/blocks/trail.html b/templates/blocks/trail.html
new file mode 100644
index 0000000..b32b7c1
--- /dev/null
+++ b/templates/blocks/trail.html
@@ -0,0 +1,71 @@
+{% set trail_gpx = record.attachments.get(this.trail_gpx) if this.trail_gpx else none %}
+{% set activity_gpx = record.attachments.get(this.activity_gpx) if this.activity_gpx else none %}
+{% if trail_gpx %}
+ {% set trail_gpx_url = trail_gpx | url(absolute=True, external=False) %}
+{% endif %}
+{% if activity_gpx %}
+ {% set activity_gpx_url = activity_gpx | url(absolute=True, external=False) %}
+{% endif %}
+{% if trail_gpx or activity_gpx %}
+ <figure class="trail"
+ {% if trail_gpx %}data-trail-gpx-url="{{ trail_gpx_url }}"{% endif %}
+ {% if activity_gpx %}data-activity-gpx-url="{{ activity_gpx_url }}"{% endif %}>
+ <figcaption class="visually-hidden">Interactive map of the trail</figcaption>
+ <div data-trail-map role="region" aria-label="Interactive trail map"></div>
+ <details>
+ <summary>Trail details</summary>
+ <div>
+ <div data-trail-chart role="region" aria-label="Trail elevation profile"></div>
+ <div data-trail-summary>
+ <table aria-label="Trail summary">
+ <tbody>
+ <tr>
+ <th scope="row">Distance:</th>
+ <td data-trail-distance></td>
+ <th scope="row">Time:</th>
+ <td data-trail-time></td>
+ <th scope="row">Overall pace:</th>
+ <td data-trail-pace></td>
+ </tr>
+ <tr>
+ <th scope="row">Maximum elevation:</th>
+ <td data-trail-maximum-elevation></td>
+ <th scope="row">Minimum elevation:</th>
+ <td data-trail-minimum-elevation></td>
+ <th scope="row">Average elevation:</th>
+ <td data-trail-average-elevation></td>
+ </tr>
+ <tr>
+ <th scope="row">Ascent:</th>
+ <td data-trail-ascent></td>
+ <th scope="row">Descent:</th>
+ <td data-trail-descent></td>
+ </tr>
+ <tr>
+ <th scope="row">Average speed:</th>
+ <td data-trail-average-speed></td>
+ <th scope="row">Maximum speed:</th>
+ <td data-trail-maximum-speed></td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ <p>
+ <a href="{% if trail_gpx %}{{ trail_gpx_url }}{% else %}{{ activity_gpx_url }}{% endif %}"
+ download>Download the GPX track</a>
+ </p>
+
+ </div>
+ </details>
+
+ <p data-trail-message role="status" hidden>The interactive trail map could not be loaded.</p>
+ <noscript>
+ <p class="trail-message">JavaScript is required to display the interactive trail map.</p>
+ </noscript>
+ </figure>
+{% else %}
+ <figure class="trail">
+ <figcaption class="visually-hidden">Interactive map of the trail</figcaption>
+ <p class="trail-message" role="status">The interactive trail map could not be loaded.</p>
+ </figure>
+{% endif %}