diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | web/frontend/analytics-logic.test.ts | 26 | ||||
| -rw-r--r-- | web/frontend/analytics-logic.ts | 35 | ||||
| -rw-r--r-- | web/frontend/analytics.ts | 223 | ||||
| -rw-r--r-- | web/frontend/types.d.ts | 8 | ||||
| -rw-r--r-- | web/static/style.css | 4 | ||||
| -rw-r--r-- | web/templates.templ | 3 | ||||
| -rw-r--r-- | web/templates_templ.go | 1755 |
8 files changed, 299 insertions, 1756 deletions
@@ -7,5 +7,6 @@ france-latest.osm.pbf biking_home node_modules/ web/static/*.js +web/*_templ.go .juggler/ diff --git a/web/frontend/analytics-logic.test.ts b/web/frontend/analytics-logic.test.ts new file mode 100644 index 0000000..74fdddd --- /dev/null +++ b/web/frontend/analytics-logic.test.ts @@ -0,0 +1,26 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import { formatCotacol, formatSpeed, niceStep, ticks } from "./analytics-logic.ts"; + +test("computes a pleasant axis step within a 1-2-5-10 series", () => { + assert.equal(niceStep(25, 5), 5); + assert.equal(niceStep(60, 5), 10); + assert.equal(niceStep(3.6, 5), 0.5); + assert.equal(niceStep(0, 5), 1); +}); + +test("produces ascending ticks that bracket the data range and include its max", () => { + assert.deepEqual(ticks(0, 27.9), [0, 5, 10, 15, 20, 25]); + assert.deepEqual(ticks(0, 315), [0, 50, 100, 150, 200, 250, 300]); + const values = ticks(0, 27.9); + for (let index = 1; index < values.length; index++) { + assert.ok(values[index] > values[index - 1]); + } + assert.ok(values[values.length - 1] <= 27.9 + 1e-9); +}); + +test("formats speed and cotacol per 100 km for axis labels", () => { + assert.equal(formatSpeed(25.2), "25.2"); + assert.equal(formatCotacol(300), "300"); + assert.equal(formatCotacol(50), "50.0"); +}); diff --git a/web/frontend/analytics-logic.ts b/web/frontend/analytics-logic.ts new file mode 100644 index 0000000..7a53944 --- /dev/null +++ b/web/frontend/analytics-logic.ts @@ -0,0 +1,35 @@ +export const niceStep = (range: number, target: number): number => { + if (range <= 0) return 1; + const ideal = range / target; + const magnitude = 10 ** Math.floor(Math.log10(ideal)); + let best = magnitude; + let bestDistance = Number.POSITIVE_INFINITY; + for (const factor of [1, 2, 5, 10]) { + const candidate = factor * magnitude; + const distance = Math.abs(candidate - ideal); + if (distance < bestDistance) { + bestDistance = distance; + best = candidate; + } + } + return best; +}; + +export const ticks = (min: number, max: number, target = 5): number[] => { + const step = niceStep(max - min, target); + const values: number[] = []; + for (let value = Math.floor(min / step) * step; value <= max + 1e-9; value += step) { + if (value >= min - 1e-9) values.push(roundStep(value)); + } + return values; +}; + +const roundStep = (value: number): number => { + if (!Number.isFinite(value) || value === 0) return 0; + const decimals = Math.max(0, -Math.floor(Math.log10(value) + 1e-9)); + return Number(value.toFixed(decimals)); +}; + +export const formatSpeed = (speed: number): string => `${speed.toFixed(1)}`; + +export const formatCotacol = (cotacol: number): string => (cotacol >= 100 ? `${Math.round(cotacol)}` : `${cotacol.toFixed(1)}`); diff --git a/web/frontend/analytics.ts b/web/frontend/analytics.ts new file mode 100644 index 0000000..5dfad52 --- /dev/null +++ b/web/frontend/analytics.ts @@ -0,0 +1,223 @@ +import { formatCotacol, formatSpeed, ticks } from "./analytics-logic.js"; +import type { AnalyticsPoint } from "./types.js"; + +interface Plot { + left: number; + right: number; + top: number; + bottom: number; +} + +interface AnalyticsColors { + surface: string; + grid: string; + subtle: string; + forest: string; + accent: string; + mutedText: string; +} + +const POINT_RADIUS = 4; +const HOVER_RADIUS = 7; +const HIT_RADIUS = 12; +export class AnalyticsScatter { + private readonly canvas: HTMLCanvasElement; + private readonly points: AnalyticsPoint[]; + private readonly colors: AnalyticsColors; + private readonly output: HTMLElement | null; + private readonly context: CanvasRenderingContext2D; + private plot: Plot | null; + private hoveredIndex: number; + private readonly minSpeed: number; + private readonly maxSpeed: number; + private readonly minCotacol: number; + private readonly maxCotacol: number; + + constructor(canvas: HTMLCanvasElement, points: AnalyticsPoint[], colors: AnalyticsColors) { + this.canvas = canvas; + this.points = points; + this.colors = colors; + this.output = document.getElementById("analytics-hover"); + const context = canvas.getContext("2d"); + if (!context) throw new Error("Analytics canvas is unavailable"); + this.context = context; + this.plot = null; + this.hoveredIndex = -1; + let maxSpeed = 0; + let maxCotacol = 0; + for (const point of points) { + maxSpeed = Math.max(maxSpeed, point.speedKmh); + maxCotacol = Math.max(maxCotacol, point.cotacolPer100Km); + } + this.minSpeed = 0; + this.minCotacol = 0; + this.maxSpeed = maxSpeed * 1.08 || 1; + this.maxCotacol = maxCotacol * 1.08 || 1; + this.bindEvents(); + } + + redraw(): void { + this.draw(); + } + + private draw(): void { + const rect = this.canvas.getBoundingClientRect(); + if (rect.width === 0 || rect.height === 0) return; + const ratio = window.devicePixelRatio || 1; + this.canvas.width = Math.floor(rect.width * ratio); + this.canvas.height = Math.floor(rect.height * ratio); + this.context.setTransform(ratio, 0, 0, ratio, 0, 0); + const plot: Plot = { left: 44, right: rect.width - 16, top: 16, bottom: rect.height - 30 }; + this.plot = plot; + this.context.clearRect(0, 0, rect.width, rect.height); + this.context.fillStyle = this.colors.surface; + this.context.fillRect(0, 0, rect.width, rect.height); + this.drawGrid(plot); + this.drawPoints(plot); + if (this.hoveredIndex >= 0) this.drawHover(plot); + } + + private drawGrid(plot: Plot): void { + this.context.font = "11px system-ui, sans-serif"; + const xTicks = ticks(this.minSpeed, this.maxSpeed); + for (const tick of xTicks) { + const x = this.xForSpeed(tick, plot); + this.context.strokeStyle = this.colors.grid; + this.context.lineWidth = 1; + this.context.beginPath(); + this.context.moveTo(x, plot.top); + this.context.lineTo(x, plot.bottom); + this.context.stroke(); + this.context.fillStyle = this.colors.subtle; + this.context.textAlign = "center"; + this.context.textBaseline = "top"; + this.context.fillText(formatSpeed(tick), x, plot.bottom + 8); + } + this.context.fillStyle = this.colors.mutedText; + this.context.textAlign = "right"; + this.context.fillText("km/h", plot.right, plot.bottom + 8); + const yTicks = ticks(this.minCotacol, this.maxCotacol); + for (const tick of yTicks) { + const y = this.yForCotacol(tick, plot); + this.context.strokeStyle = this.colors.grid; + this.context.lineWidth = 1; + this.context.beginPath(); + this.context.moveTo(plot.left, y); + this.context.lineTo(plot.right, y); + this.context.stroke(); + this.context.fillStyle = this.colors.subtle; + this.context.textAlign = "right"; + this.context.textBaseline = "middle"; + this.context.fillText(formatCotacol(tick), plot.left - 8, y); + } + } + + private drawPoints(plot: Plot): void { + for (let index = 0; index < this.points.length; index++) { + const point = this.points[index]; + this.context.fillStyle = this.colors.accent; + this.context.beginPath(); + this.context.arc(this.xForSpeed(point.speedKmh, plot), this.yForCotacol(point.cotacolPer100Km, plot), POINT_RADIUS, 0, 2 * Math.PI); + this.context.fill(); + } + } + + private drawHover(plot: Plot): void { + const point = this.points[this.hoveredIndex]; + const x = this.xForSpeed(point.speedKmh, plot); + const y = this.yForCotacol(point.cotacolPer100Km, plot); + this.context.strokeStyle = this.colors.forest; + this.context.lineWidth = 2; + this.context.beginPath(); + this.context.arc(x, y, HOVER_RADIUS, 0, 2 * Math.PI); + this.context.stroke(); + } + + private xForSpeed(speed: number, plot: Plot): number { + const span = Math.max(this.maxSpeed - this.minSpeed, 1); + return plot.left + ((speed - this.minSpeed) / span) * (plot.right - plot.left); + } + + private yForCotacol(cotacol: number, plot: Plot): number { + const span = Math.max(this.maxCotacol - this.minCotacol, 1); + return plot.bottom - ((cotacol - this.minCotacol) / span) * (plot.bottom - plot.top); + } + + private nearestPoint(x: number, y: number): number { + if (!this.plot) return -1; + let nearest = -1; + let best = Infinity; + for (let index = 0; index < this.points.length; index++) { + const point = this.points[index]; + const dx = this.xForSpeed(point.speedKmh, this.plot) - x; + const dy = this.yForCotacol(point.cotacolPer100Km, this.plot) - y; + const distance = Math.hypot(dx, dy); + if (distance < best) { + best = distance; + nearest = index; + } + } + return best <= HIT_RADIUS ? nearest : -1; + } + + private bindEvents(): void { + this.canvas.addEventListener("pointermove", (event: PointerEvent) => { + const rect = this.canvas.getBoundingClientRect(); + const index = this.nearestPoint(event.clientX - rect.left, event.clientY - rect.top); + this.canvas.style.cursor = index >= 0 ? "pointer" : "default"; + this.setHovered(index); + }); + this.canvas.addEventListener("pointerleave", () => { + this.canvas.style.cursor = "default"; + this.setHovered(-1); + }); + this.canvas.addEventListener("pointercancel", () => this.setHovered(-1)); + this.canvas.addEventListener("click", () => { + if (this.hoveredIndex < 0) return; + window.location.href = this.points[this.hoveredIndex].url; + }); + } + + private setHovered(index: number): void { + if (index === this.hoveredIndex) return; + this.hoveredIndex = index; + if (this.output) { + if (index < 0) { + this.output.textContent = "Hover a point to inspect a ride."; + } else { + const point = this.points[index]; + this.output.textContent = `${point.name} · ${formatSpeed(point.speedKmh)} km/h · ${formatCotacol(point.cotacolPer100Km)} Cotacol/100km · click for details`; + } + } + this.draw(); + } +} + +export const mountAnalytics = (): void => { + const canvas = document.getElementById("analytics-chart"); + const pointsScript = document.getElementById("analytics-points"); + if (!canvas || !pointsScript) return; + const data = JSON.parse(pointsScript.textContent ?? "") as AnalyticsPoint[]; + if (data.length === 0) return; + const colorProbe = document.createElement("span"); + colorProbe.hidden = true; + document.body.append(colorProbe); + const resolveColor = (name: string): string => { + colorProbe.style.color = `var(${name})`; + return getComputedStyle(colorProbe).color; + }; + const colors: AnalyticsColors = { + surface: resolveColor("--color-plot-surface"), + grid: resolveColor("--color-plot-grid"), + subtle: resolveColor("--color-subtle"), + forest: resolveColor("--color-forest"), + accent: resolveColor("--color-accent"), + mutedText: resolveColor("--color-muted"), + }; + colorProbe.remove(); + const scatter = new AnalyticsScatter(canvas as HTMLCanvasElement, data, colors); + window.addEventListener("resize", () => scatter.redraw()); + scatter.redraw(); +}; + +mountAnalytics(); diff --git a/web/frontend/types.d.ts b/web/frontend/types.d.ts index 07c8204..c7fb152 100644 --- a/web/frontend/types.d.ts +++ b/web/frontend/types.d.ts @@ -115,6 +115,14 @@ export interface RideMapColors { climbRoute: string; } +export interface AnalyticsPoint { + id: number; + name: string; + url: string; + speedKmh: number; + cotacolPer100Km: number; +} + export interface SyncProgress { total: number; completed: number; diff --git a/web/static/style.css b/web/static/style.css index 5ab6fa1..55d6549 100644 --- a/web/static/style.css +++ b/web/static/style.css @@ -126,6 +126,10 @@ select { border: 1px solid var(--color-input-border); border-radius: .55rem; pad .profile-chart canvas { display: block; width: 100%; height: 22rem; border-radius: .65rem; background: var(--color-plot-surface); outline: none; } .profile-chart canvas:focus-visible { box-shadow: 0 0 0 .2rem var(--color-focus); } .profile-hover { display: block; min-height: 1.4rem; margin: .7rem 0 0; color: var(--color-muted); font-size: .9rem; } +.analytics-chart { margin-top: 1rem; } +.analytics-chart canvas { display: block; width: 100%; height: 26rem; border-radius: .65rem; background: var(--color-plot-surface); outline: none; } +.analytics-chart canvas:focus-visible { box-shadow: 0 0 0 .2rem var(--color-focus); } +.analytics-hover { display: block; min-height: 1.4rem; margin: .7rem 0 0; color: var(--color-muted); font-size: .9rem; } .section-heading { display: flex; align-items: center; justify-content: space-between; gap: 1rem; } .section-heading .eyebrow { margin-bottom: .2rem; } .section-heading h2 { margin: 0; font-size: 1.2rem; } diff --git a/web/templates.templ b/web/templates.templ index 1cda7f2..0bfef9c 100644 --- a/web/templates.templ +++ b/web/templates.templ @@ -130,7 +130,8 @@ templ AnalyticsContent(data AnalyticsPageData) { if len(data.Points) == 0 { <div class="empty">No eligible rides yet. <a href="/sync">Import rides to see the chart.</a></div> } else { - <div class="analytics-chart"><canvas id="analytics-chart" role="img" aria-label="Scatter plot of ride average speed against Cotacol per 100 km"></canvas></div> + <div class="analytics-chart"><canvas id="analytics-chart" tabindex="0" role="img" aria-label="Scatter plot of ride average speed against Cotacol per 100 km"></canvas></div> + <output id="analytics-hover" class="analytics-hover" aria-live="polite">Hover a point to inspect a ride.</output> } </section> @templ.JSONScript("analytics-points", data.Points) diff --git a/web/templates_templ.go b/web/templates_templ.go deleted file mode 100644 index aeedf66..0000000 --- a/web/templates_templ.go +++ /dev/null @@ -1,1755 +0,0 @@ -// Code generated by templ - DO NOT EDIT. - -// templ: version: v0.2.793 -package web - -//lint:file-ignore SA4006 This context is only used if a nested component is present. - -import "github.com/a-h/templ" -import templruntime "github.com/a-h/templ/runtime" - -func Layout(title string, content templ.Component) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var1 := templ.GetChildren(ctx) - if templ_7745c5c3_Var1 == nil { - templ_7745c5c3_Var1 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><title>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var2 string - templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(title) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 9, Col: 16} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" · biking_home</title><link rel=\"stylesheet\" href=\"https://unpkg.com/leaflet@1.9.4/dist/leaflet.css\"><link rel=\"stylesheet\" href=\"/static/style.css\"></head><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=\"/sync\">Sync Strava</a></nav></header><main class=\"container\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = content.Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</main></body></html>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return templ_7745c5c3_Err - }) -} - -func RidesPage(data RidesPageData) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var3 := templ.GetChildren(ctx) - if templ_7745c5c3_Var3 == nil { - templ_7745c5c3_Var3 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = Layout("Rides", RidesContent(data)).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return templ_7745c5c3_Err - }) -} - -func RidesContent(data RidesPageData) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var4 := templ.GetChildren(ctx) - if templ_7745c5c3_Var4 == nil { - templ_7745c5c3_Var4 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p class=\"eyebrow\">Ride library</p><section class=\"panel ride-filters-panel\"><form id=\"ride-filters\" class=\"ride-filters\" method=\"get\" action=\"/\" aria-label=\"Ride filters\"><div class=\"section-heading\"><div><p class=\"eyebrow\">Refine</p><h2>Filter rides</h2></div><div class=\"ride-filter-actions\"><button class=\"button\" type=\"submit\">Apply filters</button><a class=\"button secondary\" href=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var5 templ.SafeURL = templ.URL(data.Filters.ResetURL) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var5))) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">Reset</a></div></div><input type=\"hidden\" name=\"sort\" value=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var6 string - templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(data.Sort.Column) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 37, Col: 60} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"> <input type=\"hidden\" name=\"dir\" value=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var7 string - templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(rideSortDirection(data.Sort)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 38, Col: 71} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><div class=\"ride-filter-ranges\"><fieldset class=\"ride-filter-group\"><legend>Distance</legend><div class=\"range-values\"><output data-range-value=\"min\" for=\"distance-min\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var8 string - templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterDistance(data.Filters.DistanceMinKm)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 42, Col: 135} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</output><span aria-hidden=\"true\">to</span><output data-range-value=\"max\" for=\"distance-max\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var9 string - templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterDistance(data.Filters.DistanceMaxKm)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 42, Col: 284} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</output></div><div class=\"range-control\" data-range-filter=\"distance\" data-range-format=\"distance\"><div class=\"range-track\" data-range-track></div><input id=\"distance-min\" class=\"range-input range-input-min\" type=\"range\" name=\"distance_min\" min=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var10 string - templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(rideFilterDistanceMinKm)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 45, Col: 150} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" max=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var11 string - templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(rideFilterDistanceMaxKm)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 45, Col: 203} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" step=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var12 string - templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(rideFilterDistanceStepKm)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 45, Col: 258} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" value=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var13 string - templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(data.Filters.DistanceMinKm)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 45, Col: 316} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" data-range-min aria-label=\"Minimum distance\"> <input id=\"distance-max\" class=\"range-input range-input-max\" type=\"range\" name=\"distance_max\" min=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var14 string - templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(rideFilterDistanceMinKm)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 46, Col: 150} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" max=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var15 string - templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(rideFilterDistanceMaxKm)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 46, Col: 203} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" step=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var16 string - templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(rideFilterDistanceStepKm)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 46, Col: 258} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" value=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var17 string - templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(data.Filters.DistanceMaxKm)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 46, Col: 316} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" data-range-max aria-label=\"Maximum distance\"></div></fieldset><fieldset class=\"ride-filter-group\"><legend>Moving duration</legend><div class=\"range-values\"><output data-range-value=\"min\" for=\"duration-min\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var18 string - templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterDuration(data.Filters.DurationMinMinutes)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 51, Col: 140} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</output><span aria-hidden=\"true\">to</span><output data-range-value=\"max\" for=\"duration-max\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var19 string - templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterDuration(data.Filters.DurationMaxMinutes)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 51, Col: 294} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</output></div><div class=\"range-control\" data-range-filter=\"duration\" data-range-format=\"duration\"><div class=\"range-track\" data-range-track></div><input id=\"duration-min\" class=\"range-input range-input-min\" type=\"range\" name=\"duration_min\" min=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var20 string - templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(rideFilterDurationMinMinutes)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 54, Col: 155} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" max=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var21 string - templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(rideFilterDurationMaxMinutes)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 54, Col: 213} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" step=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var22 string - templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(rideFilterDurationStepMinutes)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 54, Col: 273} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" value=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var23 string - templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(data.Filters.DurationMinMinutes)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 54, Col: 336} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" data-range-min aria-label=\"Minimum moving duration\"> <input id=\"duration-max\" class=\"range-input range-input-max\" type=\"range\" name=\"duration_max\" min=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var24 string - templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(rideFilterDurationMinMinutes)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 55, Col: 155} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" max=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var25 string - templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(rideFilterDurationMaxMinutes)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 55, Col: 213} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" step=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var26 string - templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(rideFilterDurationStepMinutes)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 55, Col: 273} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" value=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var27 string - templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(data.Filters.DurationMaxMinutes)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 55, Col: 336} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" data-range-max aria-label=\"Maximum moving duration\"></div></fieldset><fieldset class=\"ride-filter-group\"><legend>Cotacol</legend><div class=\"range-values\"><output data-range-value=\"min\" for=\"cotacol-min\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var28 string - templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterCotacol(data.Filters.CotacolMinPoints)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 60, Col: 136} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</output><span aria-hidden=\"true\">to</span><output data-range-value=\"max\" for=\"cotacol-max\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var29 string - templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterCotacol(data.Filters.CotacolMaxPoints)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 60, Col: 286} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</output></div><div class=\"range-control\" data-range-filter=\"cotacol\" data-range-format=\"cotacol\"><div class=\"range-track\" data-range-track></div><input id=\"cotacol-min\" class=\"range-input range-input-min\" type=\"range\" name=\"cotacol_min\" min=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var30 string - templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(rideFilterCotacolMinPoints)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 63, Col: 151} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" max=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var31 string - templ_7745c5c3_Var31, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(rideFilterCotacolMaxPoints)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 63, Col: 207} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var31)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" step=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var32 string - templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(rideFilterCotacolStepPoints)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 63, Col: 265} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var32)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" value=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var33 string - templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(data.Filters.CotacolMinPoints)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 63, Col: 326} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" data-range-min aria-label=\"Minimum Cotacol\"> <input id=\"cotacol-max\" class=\"range-input range-input-max\" type=\"range\" name=\"cotacol_max\" min=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var34 string - templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(rideFilterCotacolMinPoints)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 64, Col: 151} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" max=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var35 string - templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(rideFilterCotacolMaxPoints)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 64, Col: 207} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var35)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" step=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var36 string - templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(rideFilterCotacolStepPoints)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 64, Col: 265} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var36)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" value=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var37 string - templ_7745c5c3_Var37, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideFilterInt(data.Filters.CotacolMaxPoints)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 64, Col: 326} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var37)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" data-range-max aria-label=\"Maximum Cotacol\"></div></fieldset></div><div class=\"ride-filter-meta\"><fieldset class=\"ride-filter-group date-filter-group\"><legend>Started</legend><div class=\"date-filter-inputs\"><label for=\"ride-date-from\">From<input id=\"ride-date-from\" type=\"date\" name=\"date_from\" value=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var38 string - templ_7745c5c3_Var38, templ_7745c5c3_Err = templ.JoinStringErrs(data.Filters.DateFrom) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 71, Col: 154} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var38)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"></label><label for=\"ride-date-to\">To<input id=\"ride-date-to\" type=\"date\" name=\"date_to\" value=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var39 string - templ_7745c5c3_Var39, templ_7745c5c3_Err = templ.JoinStringErrs(data.Filters.DateTo) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 71, Col: 273} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var39)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"></label></div></fieldset><label class=\"route-filter\" for=\"ride-route\">Route <select id=\"ride-route\" name=\"route\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if data.Filters.Route == rideRouteFilterAny { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<option value=\"\" selected>Any route</option> ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<option value=\"\">Any route</option> ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if data.Filters.Route == rideRouteFilterAvailable { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<option value=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var40 string - templ_7745c5c3_Var40, templ_7745c5c3_Err = templ.JoinStringErrs(rideRouteFilterAvailable) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 81, Col: 47} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var40)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" selected>Recorded route</option> ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<option value=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var41 string - templ_7745c5c3_Var41, templ_7745c5c3_Err = templ.JoinStringErrs(rideRouteFilterAvailable) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 83, Col: 47} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var41)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">Recorded route</option> ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if data.Filters.Route == rideRouteFilterMissing { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<option value=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var42 string - templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinStringErrs(rideRouteFilterMissing) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 86, Col: 45} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" selected>Metadata only</option>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<option value=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var43 string - templ_7745c5c3_Var43, templ_7745c5c3_Err = templ.JoinStringErrs(rideRouteFilterMissing) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 88, Col: 45} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var43)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">Metadata only</option>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</select></label></div></form></section><section class=\"panel\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if len(data.Items) == 0 { - if data.Filters.Active { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"empty\">No rides match the selected filters. <a href=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var44 templ.SafeURL = templ.URL(data.Filters.ResetURL) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var44))) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">Clear filters.</a></div>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"empty\">No rides stored yet. <a href=\"/sync\">Import your first Strava rides.</a></div>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - } else { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<table><thead><tr>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - for _, header := range data.Headers { - var templ_7745c5c3_Var45 = []any{header.Class} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var45...) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<th class=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var46 string - templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var45).String()) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 1, Col: 0} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" scope=\"col\" aria-sort=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var47 string - templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.JoinStringErrs(header.AriaSort) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 106, Col: 72} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var47)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><a class=\"sort-link\" href=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var48 templ.SafeURL = templ.URL(header.URL) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var48))) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var49 string - templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.JoinStringErrs(header.Label) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 106, Col: 141} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var49)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<span class=\"sort-indicator\" aria-hidden=\"true\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var50 string - templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.JoinStringErrs(header.Indicator) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 106, Col: 209} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var50)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span></a></th>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</tr></thead> <tbody>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - for _, item := range data.Items { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<tr><td><strong><a href=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var51 templ.SafeURL = templ.URL(rideDetailURL(item.ID)) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var51))) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var52 string - templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.JoinStringErrs(item.Name) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 111, Col: 79} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var52)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></strong><br><small>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var53 string - templ_7745c5c3_Var53, templ_7745c5c3_Err = templ.JoinStringErrs(item.Type) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 111, Col: 117} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var53)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</small></td><td>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var54 string - templ_7745c5c3_Var54, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideDate(item.StartDate)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 111, Col: 168} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var54)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</td><td class=\"numeric\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var55 string - templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.JoinStringErrs(formatDistance(item.DistanceM)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 111, Col: 227} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var55)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</td><td class=\"numeric\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var56 string - templ_7745c5c3_Var56, templ_7745c5c3_Err = templ.JoinStringErrs(item.MovingTime) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 111, Col: 271} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var56)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</td><td class=\"numeric\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var57 string - templ_7745c5c3_Var57, templ_7745c5c3_Err = templ.JoinStringErrs(formatSpeed(item.AverageSpeedMps)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 111, Col: 333} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var57)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</td><td class=\"numeric\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var58 string - templ_7745c5c3_Var58, templ_7745c5c3_Err = templ.JoinStringErrs(formatElevation(item.TotalElevationGainM)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 111, Col: 403} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var58)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</td><td class=\"numeric\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var59 string - templ_7745c5c3_Var59, templ_7745c5c3_Err = templ.JoinStringErrs(item.Cotacol) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 111, Col: 444} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var59)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</td><td class=\"numeric\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var60 string - templ_7745c5c3_Var60, templ_7745c5c3_Err = templ.JoinStringErrs(item.CotacolPer100Km) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 111, Col: 493} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var60)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</td></tr>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</tbody></table>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</section><script type=\"module\" src=\"/static/ride-filters.js\"></script>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return templ_7745c5c3_Err - }) -} - -func AnalyticsPage(data AnalyticsPageData) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var61 := templ.GetChildren(ctx) - if templ_7745c5c3_Var61 == nil { - templ_7745c5c3_Var61 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = Layout("Analytics", AnalyticsContent(data)).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return templ_7745c5c3_Err - }) -} - -func AnalyticsContent(data AnalyticsPageData) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var62 := templ.GetChildren(ctx) - if templ_7745c5c3_Var62 == nil { - templ_7745c5c3_Var62 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p class=\"eyebrow\">Analytics</p><h1>Ride analytics</h1><p class=\"lead\">One point per ride: average speed on the x axis, Cotacol per 100 km on the y axis.</p><section class=\"panel analytics-panel\"><div class=\"section-heading\"><div><p class=\"eyebrow\">Chart</p><h2>Speed vs. Cotacol per 100 km</h2></div></div>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if len(data.Points) == 0 { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"empty\">No eligible rides yet. <a href=\"/sync\">Import rides to see the chart.</a></div>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"analytics-chart\"><canvas id=\"analytics-chart\" role=\"img\" aria-label=\"Scatter plot of ride average speed against Cotacol per 100 km\"></canvas></div>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</section>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ.JSONScript("analytics-points", data.Points).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<script type=\"module\" src=\"/static/analytics.js\"></script>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return templ_7745c5c3_Err - }) -} - -func RideDetailPage(data RideDetailView) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var63 := templ.GetChildren(ctx) - if templ_7745c5c3_Var63 == nil { - templ_7745c5c3_Var63 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = Layout("Ride detail", RideDetailContent(data)).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return templ_7745c5c3_Err - }) -} - -func RideDetailContent(data RideDetailView) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var64 := templ.GetChildren(ctx) - if templ_7745c5c3_Var64 == nil { - templ_7745c5c3_Var64 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"toolbar\"><div><h1 class=\"ride-detail-title\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var65 string - templ_7745c5c3_Var65, templ_7745c5c3_Err = templ.JoinStringErrs(data.Ride.Name) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 146, Col: 53} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var65)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h1><p class=\"lead\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var66 string - templ_7745c5c3_Var66, templ_7745c5c3_Err = templ.JoinStringErrs(data.Ride.Type) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 146, Col: 92} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var66)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" · ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var67 string - templ_7745c5c3_Var67, templ_7745c5c3_Err = templ.JoinStringErrs(formatRideDate(data.Ride.StartDate)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 146, Col: 135} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var67)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</p></div><a class=\"button secondary\" href=\"/\">Back to rides</a></div>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if data.RouteError != "" { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"error\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var68 string - templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.JoinStringErrs(data.RouteError) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 150, Col: 38} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var68)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if data.Notice != "" { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"notice\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var69 string - templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.JoinStringErrs(data.Notice) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 153, Col: 35} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var69)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if data.ActionError != "" { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"error\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var70 string - templ_7745c5c3_Var70, templ_7745c5c3_Err = templ.JoinStringErrs(data.ActionError) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 156, Col: 39} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var70)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"ride-detail-grid\"><section class=\"panel summary-panel\"><dl><div><dt>Distance</dt><dd>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var71 string - templ_7745c5c3_Var71, templ_7745c5c3_Err = templ.JoinStringErrs(formatDistance(data.Ride.DistanceM)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 161, Col: 67} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var71)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</dd></div><div><dt>Moving time</dt><dd>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var72 string - templ_7745c5c3_Var72, templ_7745c5c3_Err = templ.JoinStringErrs(data.MovingTime) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 162, Col: 50} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var72)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</dd></div><div><dt>Speed</dt><dd>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var73 string - templ_7745c5c3_Var73, templ_7745c5c3_Err = templ.JoinStringErrs(formatSpeed(data.Ride.AverageSpeedMps)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 163, Col: 67} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var73)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</dd></div><div><dt>Elevation</dt><dd>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var74 string - templ_7745c5c3_Var74, templ_7745c5c3_Err = templ.JoinStringErrs(formatElevation(data.Ride.TotalElevationGainM)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 164, Col: 79} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var74)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</dd></div></dl></section>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if data.HasRoute { - if len(data.Profile.OfficialClimbs()) > 0 { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<section class=\"panel official-climbs-panel\"><div class=\"section-heading\"><p class=\"eyebrow\">Official climbs</p></div><div class=\"official-climb-list\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - for _, climb := range data.Profile.OfficialClimbs() { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<details class=\"official-climb-card\" data-official-climb-card><summary><span class=\"official-climb-card-title\"><span class=\"climb-number\">Climb ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var75 string - templ_7745c5c3_Var75, templ_7745c5c3_Err = templ.JoinStringErrs(formatClimbNumber(climb.Index)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 177, Col: 114} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var75)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span><strong>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var76 string - templ_7745c5c3_Var76, templ_7745c5c3_Err = templ.JoinStringErrs(climb.OfficialName) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 177, Col: 151} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var76)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</strong></span><dl class=\"official-climb-summary-stats\"><div><dt>Length</dt><dd>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var77 string - templ_7745c5c3_Var77, templ_7745c5c3_Err = templ.JoinStringErrs(formatProfileDistance(climb.DistanceKm)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 179, Col: 75} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var77)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</dd></div><div><dt>Cotacol</dt><dd>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var78 string - templ_7745c5c3_Var78, templ_7745c5c3_Err = templ.JoinStringErrs(formatCotacol(climb.Cotacol)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 180, Col: 65} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var78)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</dd></div><div><dt>Avg slope</dt><dd>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var79 string - templ_7745c5c3_Var79, templ_7745c5c3_Err = templ.JoinStringErrs(formatSlope(climb.SlopePercent)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 181, Col: 70} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var79)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</dd></div></dl><span class=\"official-climb-chevron\" aria-hidden=\"true\">⌄</span></summary><div class=\"official-climb-card-body\"><canvas class=\"official-climb-profile\" data-official-profile data-profile-start=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var80 string - templ_7745c5c3_Var80, templ_7745c5c3_Err = templ.JoinStringErrs(formatRouteIndex(climb.StartIndex)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 186, Col: 125} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var80)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" data-profile-end=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var81 string - templ_7745c5c3_Var81, templ_7745c5c3_Err = templ.JoinStringErrs(formatRouteIndex(climb.EndIndex)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 186, Col: 179} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var81)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" tabindex=\"0\" role=\"img\" aria-label=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var82 string - templ_7745c5c3_Var82, templ_7745c5c3_Err = templ.JoinStringErrs(officialProfileLabel(climb.OfficialName)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 186, Col: 259} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var82)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"></canvas><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></div></details>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></section>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var83 = []any{rideDetailColumnsClass(len(data.Profile.UnmatchedClimbs()))} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var83...) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var84 string - templ_7745c5c3_Var84, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var83).String()) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 1, Col: 0} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var84)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if len(data.Profile.UnmatchedClimbs()) > 0 { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<section class=\"panel climbs-panel\"><div class=\"section-heading\"><div><p class=\"eyebrow\">Next steps</p><h2>Climbs to match</h2></div><span class=\"section-count\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var85 string - templ_7745c5c3_Var85, templ_7745c5c3_Err = templ.JoinStringErrs(formatClimbCount(len(data.Profile.UnmatchedClimbs()))) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 205, Col: 89} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var85)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span></div><nav class=\"climb-navigation\" aria-label=\"Climb navigation\"><button class=\"button secondary\" type=\"button\" data-climb-previous aria-label=\"Previous climb\">←</button> <output data-climb-position>Climb 1 of ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var86 string - templ_7745c5c3_Var86, templ_7745c5c3_Err = templ.JoinStringErrs(formatClimbCount(len(data.Profile.UnmatchedClimbs()))) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 209, Col: 100} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var86)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</output> <button class=\"button secondary\" type=\"button\" data-climb-next aria-label=\"Next climb\">→</button></nav><div class=\"climb-list\" data-climb-list>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - for _, climb := range data.Profile.UnmatchedClimbs() { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<article class=\"climb-item\" data-climb-item data-climb-index=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var87 string - templ_7745c5c3_Var87, templ_7745c5c3_Err = templ.JoinStringErrs(formatRouteIndex(climb.Index)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 214, Col: 99} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var87)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><div class=\"climb-item-heading\"><strong><span class=\"climb-number\">Climb ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var88 string - templ_7745c5c3_Var88, templ_7745c5c3_Err = templ.JoinStringErrs(formatClimbNumber(climb.Index)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 216, Col: 82} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var88)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var89 string - templ_7745c5c3_Var89, templ_7745c5c3_Err = templ.JoinStringErrs(climb.Name) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 216, Col: 103} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var89)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</strong> <span class=\"climb-range\" data-climb-summary>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var90 string - templ_7745c5c3_Var90, templ_7745c5c3_Err = templ.JoinStringErrs(formatProfileDistance(climb.StartKm)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 217, Col: 92} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var90)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("–") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var91 string - templ_7745c5c3_Var91, templ_7745c5c3_Err = templ.JoinStringErrs(formatProfileDistance(climb.EndKm)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 217, Col: 133} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var91)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span></div><p class=\"climb-metrics\" data-climb-metrics>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var92 string - templ_7745c5c3_Var92, templ_7745c5c3_Err = templ.JoinStringErrs(climb.Category) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 219, Col: 68} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var92)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" · ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var93 string - templ_7745c5c3_Var93, templ_7745c5c3_Err = templ.JoinStringErrs(formatProfileDistance(climb.DistanceKm)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 219, Col: 115} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var93)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" at ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var94 string - templ_7745c5c3_Var94, templ_7745c5c3_Err = templ.JoinStringErrs(formatSlope(climb.SlopePercent)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 219, Col: 154} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var94)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" · Cotacol ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var95 string - templ_7745c5c3_Var95, templ_7745c5c3_Err = templ.JoinStringErrs(formatCotacol(climb.Cotacol)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 219, Col: 198} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var95)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</p><p class=\"climb-status\">Waiting for an official climb match.</p><form class=\"official-climb-form\" data-official-climb-form method=\"post\" action=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var96 templ.SafeURL = templ.URL(officialClimbCreateURL(data.Ride.ID)) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var96))) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><label>Name<input type=\"text\" name=\"name\" required placeholder=\"Official climb name\"></label> <input type=\"hidden\" name=\"start_index\" value=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var97 string - templ_7745c5c3_Var97, templ_7745c5c3_Err = templ.JoinStringErrs(formatRouteIndex(climb.StartIndex)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 223, Col: 92} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var97)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" data-boundary-input=\"start\"> <input type=\"hidden\" name=\"end_index\" value=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var98 string - templ_7745c5c3_Var98, templ_7745c5c3_Err = templ.JoinStringErrs(formatRouteIndex(climb.EndIndex)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 224, Col: 87} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var98)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" data-boundary-input=\"end\"><div class=\"boundary-controls\"><div><strong>Start</strong><button class=\"button secondary\" type=\"button\" data-boundary-button=\"start\" data-boundary-source=\"profile\" aria-label=\"Select on profile for start\">Profile</button><button class=\"button secondary\" type=\"button\" data-boundary-button=\"start\" data-boundary-source=\"map\" aria-label=\"Select on map for start\">Map</button><output data-boundary-output=\"start\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var99 string - templ_7745c5c3_Var99, templ_7745c5c3_Err = templ.JoinStringErrs(formatProfileDistance(climb.StartKm)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 226, Col: 428} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var99)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</output></div><div><strong>End</strong><button class=\"button secondary\" type=\"button\" data-boundary-button=\"end\" data-boundary-source=\"profile\" aria-label=\"Select on profile for end\">Profile</button><button class=\"button secondary\" type=\"button\" data-boundary-button=\"end\" data-boundary-source=\"map\" aria-label=\"Select on map for end\">Map</button><output data-boundary-output=\"end\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var100 string - templ_7745c5c3_Var100, templ_7745c5c3_Err = templ.JoinStringErrs(formatProfileDistance(climb.EndKm)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 227, Col: 414} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var100)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</output></div></div><output class=\"boundary-preview\" data-boundary-preview>Preview the corrected climb boundaries.</output> <button class=\"button\" type=\"submit\">Save official climb</button></form></article>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></section>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"ride-detail-main\"><section class=\"panel profile-panel\"><div class=\"profile-heading\"><h2>Elevation profile</h2><p>Hover or focus the profile to inspect the ride at that distance.</p></div><div class=\"profile-chart\"><canvas id=\"ride-profile-chart\" tabindex=\"0\" role=\"img\" aria-describedby=\"ride-profile-hover\" aria-label=\"Interactive ride elevation profile\"></canvas></div><output id=\"ride-profile-hover\" class=\"profile-hover\" aria-live=\"polite\">Hover or focus the profile to inspect elevation.</output></section><section class=\"panel map-panel\"><div id=\"ride-map\" class=\"ride-map\" role=\"img\" aria-label=\"Recorded ride route map\"></div></section></div></div>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if data.HasRoute { - templ_7745c5c3_Err = templ.JSONScript("ride-route", data.Route).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ.JSONScript("ride-profile", data.Profile).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ.JSONScript("ride-passes", data.Passes).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <script src=\"https://unpkg.com/leaflet@1.9.4/dist/leaflet.js\"></script> <script type=\"module\" src=\"/static/ride-detail.js\"></script>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - return templ_7745c5c3_Err - }) -} - -func SyncPage(data SyncPageData) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var101 := templ.GetChildren(ctx) - if templ_7745c5c3_Var101 == nil { - templ_7745c5c3_Var101 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = Layout("Sync Strava", SyncContent(data)).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return templ_7745c5c3_Err - }) -} - -func SyncContent(data SyncPageData) templ.Component { - return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { - templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context - if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var102 := templ.GetChildren(ctx) - if templ_7745c5c3_Var102 == nil { - templ_7745c5c3_Var102 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p class=\"eyebrow\">Data import</p><h1>Sync Strava rides</h1><p class=\"lead\">Choose a date range. New rides are downloaded as GPX files and recorded in the local library.</p>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if data.Notice != "" { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div id=\"sync-notice\" class=\"notice\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var103 string - templ_7745c5c3_Var103, templ_7745c5c3_Err = templ.JoinStringErrs(data.Notice) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 273, Col: 52} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var103)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div id=\"sync-notice\" class=\"notice\" hidden></div>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - if data.Error != "" { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div id=\"sync-error\" class=\"error\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var104 string - templ_7745c5c3_Var104, templ_7745c5c3_Err = templ.JoinStringErrs(data.Error) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 278, Col: 49} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var104)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div id=\"sync-error\" class=\"error\" hidden></div>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<section class=\"panel\">") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if !data.HasAuth { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p>Strava authorization is required before the first sync.</p><a class=\"button secondary\" href=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var105 templ.SafeURL = templ.URL("/strava/login?return_to=/sync") - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var105))) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">Authorize Strava</a>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<form id=\"sync-form\" method=\"post\" action=\"/sync\"><div class=\"form-row\"><label>From<input type=\"date\" name=\"from\" value=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var106 string - templ_7745c5c3_Var106, templ_7745c5c3_Err = templ.JoinStringErrs(data.From) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 289, Col: 64} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var106)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" required></label> <label>To<input type=\"date\" name=\"to\" value=\"") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var107 string - templ_7745c5c3_Var107, templ_7745c5c3_Err = templ.JoinStringErrs(data.To) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `web/templates.templ`, Line: 290, Col: 58} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var107)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" required></label> <button class=\"button\" type=\"submit\">Sync rides</button></div></form><div id=\"sync-progress\" class=\"sync-progress\" role=\"status\" aria-live=\"polite\" hidden><div class=\"progress-heading\"><strong>Importing rides</strong><span id=\"sync-progress-count\">0 / 0</span></div><progress id=\"sync-progress-bar\" max=\"1\" value=\"0\" aria-label=\"Strava import progress\"></progress> <span id=\"sync-progress-details\">0 imported · 0 skipped</span></div>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</section><script type=\"module\" src=\"/static/sync.js\"></script>") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return templ_7745c5c3_Err - }) -} - -var _ = templruntime.GeneratedTemplate |
