diff options
| author | Dennis Fink | 2026-07-23 00:18:21 +0200 |
|---|---|---|
| committer | Dennis Fink | 2026-07-23 00:18:21 +0200 |
| commit | 1fe1d13c600b7dfe421b3b99b833b7d5d1232724 (patch) | |
| tree | 2e8636160cc1719c907be56f5ef8cbc7e0f10a53 /assets/static/css/trail.css | |
| parent | ca77de06be474dfd712402c327dc436864d233a3 (diff) | |
| download | dennisfink.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 'assets/static/css/trail.css')
| -rw-r--r-- | assets/static/css/trail.css | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/assets/static/css/trail.css b/assets/static/css/trail.css new file mode 100644 index 0000000..5637668 --- /dev/null +++ b/assets/static/css/trail.css @@ -0,0 +1,334 @@ +@charset "UTF-8"; + +:root { + --trail-map-height: 30rem; + --trail-breakout: var(--breakout-xs); + + --trail-route-color: var(--dim-red); + --trail-route-width: 4px; + --trail-route-opacity: 1; + + --trail-chart-color: var(--dim-red); + --trail-chart-opacity: 0.25; + + --trail-start-color: var(--green); + --trail-finish-color: var(--red); + --trail-loop-color: var(--blue); +} + +.trail { + box-sizing: border-box; + width: calc(100% + 2 * var(--trail-breakout)); + max-width: 100vw; + min-width: 0; + margin: 2.5rem 0; + transform: translateX(calc(-1 * var(--trail-breakout))); + + > [data-trail-map] { + box-sizing: border-box; + width: 100%; + max-width: 100%; + min-width: 0; + overflow: hidden; + border: 1px solid var(--foreground); + border-radius: 0.5rem; + background: var(--background); + } + + > [data-trail-map] { + position: relative; + height: var(--trail-map-height); + + img.leaflet-tile { + max-width: none !important; + max-height: none !important; + } + + .leaflet-marker-icon:focus-visible, + .leaflet-interactive:focus-visible, + .leaflet-control a:focus-visible { + outline: 3px solid var(--yellow); + outline-offset: 2px; + } + } + + > details { + margin-top: 1rem; + border: 1px solid var(--foreground); + border-radius: 0.5rem; + + > summary { + padding: 0.75rem 1rem; + cursor: pointer; + color: var(--green); + font-weight: bold; + } + + > div { + display: grid; + gap: 1rem; + padding: 0 1rem 1rem; + } + + [data-trail-chart] { + box-sizing: border-box; + width: 100%; + max-width: 100%; + min-width: 0; + overflow: hidden; + background: var(--background); + + .elevation-control { + box-sizing: border-box; + width: 100% !important; + max-width: none !important; + height: 100%; + margin: 0; + background: var(--background); + color: var(--foreground); + font-family: "Libre Baskerville", Georgia, serif; + + text { + fill: var(--foreground) !important; + font: inherit; + font-size: 1rem; + font-weight: normal; + text-shadow: none !important; + paint-order: normal; + stroke: none !important; + } + + .background { + background-color: var(--background); + } + } + + svg { + display: block; + max-width: none; + } + + text { + fill: var(--foreground); + } + + .area { + fill: var(--trail-chart-color); + fill-opacity: var(--trail-chart-opacity); + stroke: var(--trail-chart-color); + } + + .axis { + path, + line { + stroke: var(--dim-foreground); + } + + text { + font-size: 0.85rem; + } + } + + .grid line, + .mouse-focus-line { + stroke: var(--dim-foreground); + } + + .elevation-summary { + display: none; + } + + .mouse-focus-label-text { + fill: var(--foreground) !important; + font: inherit !important; + font-size: 1rem; + font-weight: normal !important; + text-shadow: none !important; + stroke: none !important; + } + + .mouse-focus-label-rect { + fill: var(--background); + fill-opacity: 0.95; + stroke: var(--foreground); + stroke-width: 1px; + } + + .mouse-focus-label-time, + .mouse-focus-label-slope, + .mouse-focus-label-speed { + display: none; + } + } + + [data-trail-summary] { + overflow: hidden; + + table { + width: 100%; + margin: 0.5rem 0; + border-collapse: collapse; + font-size: 1rem; + + tr { + &:not(:last-of-type) { + border-bottom: 1px solid var(--foreground); + + th, + td { + padding-bottom: 0.5rem; + } + } + &:not(:first-of-type) { + th, + td { + padding-top: 0.5rem; + } + } + } + + th { + padding-right: 0.5rem; + color: var(--blue); + text-align: left; + } + + td { + padding-right: 0.5rem; + text-align: right; + } + } + + @media (max-width: 1300px) { + table, + tbody, + tr { + display: contents; + } + + table { + display: grid; + grid-template-columns: + minmax(0, 1fr) + max-content; + margin: 0; + } + + th, + td { + box-sizing: border-box; + padding: 0.5rem 0.75rem; + border-bottom: 1px solid var(--foreground); + } + + th { + text-align: left; + + &:first-child { + padding-left: 0.75rem; + } + } + + td { + text-align: right; + } + + tbody > tr:last-child > :last-child, + tbody > tr:last-child > :nth-last-child(2) { + border-bottom: 0; + } + } + } + + > div > p { + max-inline-size: none; + margin: 0; + text-align: center; + } + + @media (max-width: 700px) { + [data-trail-chart] { + height: 18rem; + } + } + + a { + font-size: 1.2rem; + } + } + + /* + * Classes below are required by Leaflet or generated + * dynamically for custom Leaflet markers. + */ + + .trail-marker { + border: 0; + background: transparent; + + .trail-marker-symbol { + box-sizing: border-box; + display: grid; + place-items: center; + width: 1.75rem; + height: 1.75rem; + border: 2px solid var(--background); + border-radius: 50%; + color: var(--background); + box-shadow: 0 0 0 1px var(--foreground); + font-family: system-ui, sans-serif; + font-size: 0.8rem; + font-weight: 700; + line-height: 1; + } + + &.trail-marker-start { + .trail-marker-symbol { + background: var(--trail-start-color); + + &::before { + content: "S"; + } + } + } + + &.trail-marker-finish { + .trail-marker-symbol { + background: var(--trail-finish-color); + + &::before { + content: "F"; + } + } + } + + &.trail-marker-loop { + .trail-marker-symbol { + background: var(--trail-loop-color); + + &::before { + content: "↻"; + } + } + } + } + + .trail-marker-hidden { + display: none; + } + + .trail-theme.elevation-polyline { + stroke: var(--trail-route-color); + stroke-width: var(--trail-route-width); + stroke-opacity: var(--trail-route-opacity); + } + + .trail-parking-marker { + filter: drop-shadow(0 1px 1px rgb(0 0 0 / 0.4)); + } + + @media (max-width: 500px) { + width: 100%; + transform: none; + } +} |
