diff options
Diffstat (limited to 'web/templates.templ')
| -rw-r--r-- | web/templates.templ | 88 |
1 files changed, 87 insertions, 1 deletions
diff --git a/web/templates.templ b/web/templates.templ index 14e9aab..d41dd39 100644 --- a/web/templates.templ +++ b/web/templates.templ @@ -15,7 +15,7 @@ templ Layout(title string, content templ.Component) { <body> <header class="site-header"> <a class="brand" href="/">biking_home</a> - <nav class="nav"><a href="/">Rides</a><a href="/analytics">Analytics</a><a href="/preview">Preview</a><a href="/data-quality">Data quality</a><a href="/sync">Sync Strava</a></nav> + <nav class="nav"><a href="/">Rides</a><a href="/climbs">Climbs</a><a href="/analytics">Analytics</a><a href="/preview">Preview</a><a href="/data-quality">Data quality</a><a href="/sync">Sync Strava</a></nav> </header> <main class="container"> @content @@ -485,3 +485,89 @@ templ DataQualityContent(data DataQualityPageData) { } </section> } +templ ClimbsPage(data ClimbsPageData) { + @Layout("Climbs", ClimbsContent(data)) +} + +templ ClimbsContent(data ClimbsPageData) { + <p class="eyebrow">Official climbs</p> + <section class="panel"> + if len(data.Items) == 0 { + <div class="empty">No official climbs yet. Create one from a ride detail page.</div> + } else { + <table> + <thead><tr> + for _, header := range data.Headers { + <th class={ header.Class } scope="col" aria-sort={ header.AriaSort }><a class="sort-link" href={ templ.URL(header.URL) }>{ header.Label }<span class="sort-indicator" aria-hidden="true">{ header.Indicator }</span></a></th> + } + </tr></thead> + <tbody> + for _, item := range data.Items { + <tr><td><strong><a href={ templ.URL(item.URL) }>{ item.Climb.Name }</a></strong></td><td>{ item.Category }</td><td class="numeric">{ formatClimbCount(item.Climb.Attempts) }</td><td class="numeric">{ item.Distance }</td><td class="numeric">{ item.Slope }</td><td class="numeric">{ item.Cotacol }</td><td class="numeric">{ item.BestTime }</td></tr> + } + </tbody> + </table> + } + </section> +} + +templ ClimbDetailPage(data ClimbDetailPageData) { + @Layout("Climb", ClimbDetailContent(data)) +} + +templ ClimbDetailContent(data ClimbDetailPageData) { + <div class="toolbar"> + <div><h1 class="ride-detail-title">{ data.Climb.Name }</h1><p class="lead">Official climb ยท { data.Stats.Category }</p></div> + <div class="toolbar-actions"><a class="button secondary" href="/climbs">Back to climbs</a></div> + </div> + <section class="panel summary-panel"> + <dl> + <div><dt>Attempts</dt><dd>{ data.Stats.Attempts }</dd></div> + <div><dt>Distance</dt><dd>{ data.Stats.Distance }</dd></div> + <div><dt>Elevation</dt><dd>{ data.Stats.ElevationG }</dd></div> + <div><dt>Avg slope</dt><dd>{ data.Stats.Slope }</dd></div> + <div><dt>Cotacol</dt><dd>{ data.Stats.Cotacol }</dd></div> + <div><dt>Best time</dt><dd>{ data.Stats.BestTime }</dd></div> + </dl> + </section> + <section class="panel map-panel"> + <div id="climb-map" class="ride-map" role="img" aria-label="Official climb map"></div> + </section> + if len(data.Profile.Elevations) > 0 { + <section class="panel"> + <div class="section-heading"><div><p class="eyebrow">Profile</p><h2>Median profile</h2></div></div> + <div class="profile-chart"><canvas id="climb-profile" data-climb-profile tabindex="0" role="img" aria-label={ officialProfileLabel(data.Climb.Name) }></canvas></div> + <p class="profile-hover" data-climb-profile-hover aria-live="polite">Hover or focus the profile to inspect the climb at a distance.</p> + <div class="official-climb-profile-legend" role="list" aria-label="Average slope color scale"> + <span role="listitem"><i class="profile-band-swatch profile-band-downhill" aria-hidden="true"></i><=0%</span> + <span role="listitem"><i class="profile-band-swatch profile-band-0-3" aria-hidden="true"></i>0โ3%</span> + <span role="listitem"><i class="profile-band-swatch profile-band-3-6" aria-hidden="true"></i>3โ6%</span> + <span role="listitem"><i class="profile-band-swatch profile-band-6-9" aria-hidden="true"></i>6โ9%</span> + <span role="listitem"><i class="profile-band-swatch profile-band-9-plus" aria-hidden="true"></i>9%+</span> + </div> + </section> + } + <section class="panel"> + <div class="section-heading"> + <div><p class="eyebrow">History</p><h2>Attempts</h2></div> + <span class="section-count">{ formatClimbCount(len(data.Attempts)) }</span> + </div> + if len(data.Attempts) == 0 { + <div class="empty">No attempts recorded yet. Open a ride containing this climb to record one.</div> + } else { + <table> + <thead><tr><th>Date</th><th>Ride</th><th class="numeric">Time</th><th class="numeric">Distance</th><th class="numeric">Cotacol</th></tr></thead> + <tbody> + for _, attempt := range data.Attempts { + <tr><td>{ attempt.Date }</td><td><a href={ templ.URL(rideDetailURL(attempt.RideID)) }>{ attempt.RideName }</a></td><td class="numeric">{ attempt.Duration }</td><td class="numeric">{ attempt.Distance }</td><td class="numeric">{ attempt.Cotacol }</td></tr> + } + </tbody> + </table> + } + </section> + @templ.JSONScript("climb-profile-data", data.Profile) + @templ.JSONScript("climb-endpoints", data.Endpoints) + <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script> + <script type="module" src="/static/climb-profile.js"></script> + <script type="module" src="/static/climb-map.js"></script> +} |
