diff options
| -rw-r--r-- | web/rides.go | 9 | ||||
| -rw-r--r-- | web/templates.templ | 7 | ||||
| -rw-r--r-- | web/views.go | 17 |
3 files changed, 26 insertions, 7 deletions
diff --git a/web/rides.go b/web/rides.go index f59c0a4..c945801 100644 --- a/web/rides.go +++ b/web/rides.go @@ -53,7 +53,7 @@ func (s *Server) handleRide(w http.ResponseWriter, r *http.Request) { } if item.FitPath == "" && item.GPXPath == "" { slog.Info("Loaded ride detail without route", "ride_id", id) - kcore.RenderPage(r.Context(), RideDetailPage(RideDetailView{RideView: buildRideView(item), Notice: rideDetailNotice(r)}), w) + kcore.RenderPage(r.Context(), RideDetailPage(RideDetailView{RideView: buildRideView(item), ExternalURL: externalRideURL(item.ExternalID), Notice: rideDetailNotice(r)}), w) return } // Prefer FIT; fallback to GPX for legacy rides pending backfill. @@ -71,9 +71,10 @@ func (s *Server) handleRide(w http.ResponseWriter, r *http.Request) { } if err != nil { kcore.RenderPage(r.Context(), RideDetailPage(RideDetailView{ - RideView: buildRideView(item), - RouteError: "The recorded route is unavailable.", - Notice: rideDetailNotice(r), + RideView: buildRideView(item), + ExternalURL: externalRideURL(item.ExternalID), + RouteError: "The recorded route is unavailable.", + Notice: rideDetailNotice(r), }), w) return } diff --git a/web/templates.templ b/web/templates.templ index 10008d2..db60ca9 100644 --- a/web/templates.templ +++ b/web/templates.templ @@ -207,7 +207,12 @@ templ RideDetailPage(data RideDetailView) { templ RideDetailContent(data RideDetailView) { <div class="toolbar"> <div><h1 class="ride-detail-title">{ data.Ride.Name }</h1><p class="lead">{ data.Ride.Type } ยท { formatRideDate(data.Ride.StartDate) }</p></div> - <a class="button secondary" href="/">Back to rides</a> + <div class="toolbar-actions"> + if data.ExternalURL != "" { + <a class="button secondary" href={ templ.URL(data.ExternalURL) } target="_blank" rel="noopener">View on Strava</a> + } + <a class="button secondary" href="/">Back to rides</a> + </div> </div> if data.RouteError != "" { <div class="error">{ data.RouteError }</div> diff --git a/web/views.go b/web/views.go index 9a79906..ddea27e 100644 --- a/web/views.go +++ b/web/views.go @@ -75,6 +75,7 @@ type RideDetailView struct { RouteError string ActionError string Notice string + ExternalURL string } type RideMapPass struct { @@ -295,8 +296,9 @@ func buildRideDetailView(item ride.StoredRide, parsed ride.Ride, passes []mounta } profile := buildRideProfile(parsed, passes, officialClimbs, matchPolicy) return RideDetailView{ - RideView: buildRideView(item), - Passes: buildRideMapPasses(passes), + RideView: buildRideView(item), + Passes: buildRideMapPasses(passes), + ExternalURL: externalRideURL(item.ExternalID), Route: GeoJSONFeatureCollection{ Type: "FeatureCollection", Features: []GeoJSONFeature{{ @@ -312,6 +314,17 @@ func buildRideDetailView(item ride.StoredRide, parsed ride.Ride, passes []mounta } } +func externalRideURL(externalID string) string { + const prefix = "strava:" + if len(externalID) > len(prefix) && externalID[:len(prefix)] == prefix { + id := externalID[len(prefix):] + if id != "" { + return "https://www.strava.com/activities/" + id + } + } + return "" +} + func buildRideMapPasses(passes []mountain_pass.MountainPass) []RideMapPass { mapPasses := make([]RideMapPass, 0, len(passes)) for _, mountainPass := range passes { |
