package web templ Layout(title string, content templ.Component) { { title } · biking_home
@content
} templ RidesPage(items []RideView, headers []RideSortHeader) { @Layout("Rides", RidesContent(items, headers)) } templ RidesContent(items []RideView, headers []RideSortHeader) {

Ride library

All rides

Your imported rides, ready for climb analysis.

Sync Strava
if len(items) == 0 {
No rides stored yet. Import your first Strava rides.
} else { for _, header := range headers { } for _, item := range items { }
{ header.Label }
{ item.Name }
{ item.Type }
{ formatRideDate(item.StartDate) }{ formatDistance(item.DistanceM) }{ formatDuration(item.MovingTimeS) }{ formatElevation(item.TotalElevationGainM) }{ item.Cotacol }{ item.CotacolPer100Km }
}
} templ RideDetailPage(data RideDetailView) { @Layout("Ride detail", RideDetailContent(data)) } templ RideDetailContent(data RideDetailView) {

Ride detail

{ data.Ride.Name }

{ data.Ride.Type } · { formatRideDate(data.Ride.StartDate) }

Back to rides
Distance
{ formatDistance(data.Ride.DistanceM) }
Moving time
{ formatDuration(data.Ride.MovingTimeS) }
Elevation
{ formatElevation(data.Ride.TotalElevationGainM) }
if data.RouteError != "" {
{ data.RouteError }
} if data.HasRoute {

Elevation profile

Hover or focus the profile to inspect the ride at that distance.

Hover or focus the profile to inspect elevation.
@templ.JSONScript("ride-route", data.Route) @templ.JSONScript("ride-profile", data.Profile) } } templ SyncPage(data SyncPageData) { @Layout("Sync Strava", SyncContent(data)) } templ SyncContent(data SyncPageData) {

Data import

Sync Strava rides

Choose a date range. New rides are downloaded as GPX files and recorded in the local library.

if data.Notice != "" {
{ data.Notice }
} else { } if data.Error != "" {
{ data.Error }
} else { }
if !data.HasAuth {

Strava authorization is required before the first sync.

Authorize Strava } else {
}
}