aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Kagamino Lehoux <martin@lehoux.net>2026-08-21 19:19:45 +0200
committerMartin Kagamino Lehoux <martin@lehoux.net>2026-08-21 19:19:45 +0200
commit72cc720e91e531fda3da073a8231951e0cccb696 (patch)
treeacc51bc53166f59531d1a4bf9be979042cc600b9
parentb3a83b2fdd5b406d020398e7c3cf6f46149a2523 (diff)
Componentize and isolate the ride range filter
-rw-r--r--web/ride-filters.go70
-rw-r--r--web/ride-range-filter.templ13
-rw-r--r--web/templates.templ30
3 files changed, 86 insertions, 27 deletions
diff --git a/web/ride-filters.go b/web/ride-filters.go
index 888d6bc..1fb647b 100644
--- a/web/ride-filters.go
+++ b/web/ride-filters.go
@@ -65,6 +65,76 @@ type RideFilterView struct {
ResetURL string
}
+type RangeFilterConfig struct {
+ Legend string
+ IDPrefix string
+ Format string
+ ParamMin string
+ ParamMax string
+ BoundMin int
+ BoundMax int
+ Step int
+ ValueMin int
+ ValueMax int
+ LabelMin string
+ LabelMax string
+ FormatValue func(int) string
+}
+
+func rideDistanceFilterConfig(view RideFilterView) RangeFilterConfig {
+ return RangeFilterConfig{
+ Legend: "Distance",
+ IDPrefix: "distance",
+ Format: "distance",
+ ParamMin: rideFilterDistanceMinParam,
+ ParamMax: rideFilterDistanceMaxParam,
+ BoundMin: rideFilterDistanceMinKm,
+ BoundMax: rideFilterDistanceMaxKm,
+ Step: rideFilterDistanceStepKm,
+ ValueMin: view.DistanceMinKm,
+ ValueMax: view.DistanceMaxKm,
+ LabelMin: "Minimum distance",
+ LabelMax: "Maximum distance",
+ FormatValue: formatRideFilterDistance,
+ }
+}
+
+func rideDurationFilterConfig(view RideFilterView) RangeFilterConfig {
+ return RangeFilterConfig{
+ Legend: "Moving duration",
+ IDPrefix: "duration",
+ Format: "duration",
+ ParamMin: rideFilterDurationMinParam,
+ ParamMax: rideFilterDurationMaxParam,
+ BoundMin: rideFilterDurationMinMinutes,
+ BoundMax: rideFilterDurationMaxMinutes,
+ Step: rideFilterDurationStepMinutes,
+ ValueMin: view.DurationMinMinutes,
+ ValueMax: view.DurationMaxMinutes,
+ LabelMin: "Minimum moving duration",
+ LabelMax: "Maximum moving duration",
+ FormatValue: formatRideFilterDuration,
+ }
+}
+
+func rideCotacolFilterConfig(view RideFilterView) RangeFilterConfig {
+ return RangeFilterConfig{
+ Legend: "Cotacol",
+ IDPrefix: "cotacol",
+ Format: "cotacol",
+ ParamMin: rideFilterCotacolMinParam,
+ ParamMax: rideFilterCotacolMaxParam,
+ BoundMin: rideFilterCotacolMinPoints,
+ BoundMax: rideFilterCotacolMaxPoints,
+ Step: rideFilterCotacolStepPoints,
+ ValueMin: view.CotacolMinPoints,
+ ValueMax: view.CotacolMaxPoints,
+ LabelMin: "Minimum Cotacol",
+ LabelMax: "Maximum Cotacol",
+ FormatValue: formatRideFilterCotacol,
+ }
+}
+
func parseRideFilters(query url.Values) RideFilters {
filters := RideFilters{
DistanceMinKm: parseRideFilterInt(query.Get(rideFilterDistanceMinParam), rideFilterDistanceMinKm, rideFilterDistanceMaxKm, rideFilterDistanceStepKm),
diff --git a/web/ride-range-filter.templ b/web/ride-range-filter.templ
new file mode 100644
index 0000000..27eb802
--- /dev/null
+++ b/web/ride-range-filter.templ
@@ -0,0 +1,13 @@
+package web
+
+templ RideRangeFilter(field RangeFilterConfig) {
+ <fieldset class="ride-filter-group">
+ <legend>{ field.Legend }</legend>
+ <div class="range-values"><output data-range-value="min" for={ field.IDPrefix + "-min" }>{ field.FormatValue(field.ValueMin) }</output><span aria-hidden="true">to</span><output data-range-value="max" for={ field.IDPrefix + "-max" }>{ field.FormatValue(field.ValueMax) }</output></div>
+ <div class="range-control" data-range-filter={ field.Format } data-range-format={ field.Format }>
+ <div class="range-track" data-range-track></div>
+ <input id={ field.IDPrefix + "-min" } class="range-input range-input-min" type="range" name={ field.ParamMin } min={ formatRideFilterInt(field.BoundMin) } max={ formatRideFilterInt(field.BoundMax) } step={ formatRideFilterInt(field.Step) } value={ formatRideFilterInt(field.ValueMin) } data-range-min aria-label={ field.LabelMin }/>
+ <input id={ field.IDPrefix + "-max" } class="range-input range-input-max" type="range" name={ field.ParamMax } min={ formatRideFilterInt(field.BoundMin) } max={ formatRideFilterInt(field.BoundMax) } step={ formatRideFilterInt(field.Step) } value={ formatRideFilterInt(field.ValueMax) } data-range-max aria-label={ field.LabelMax }/>
+ </div>
+ </fieldset>
+}
diff --git a/web/templates.templ b/web/templates.templ
index 0bfef9c..71df20b 100644
--- a/web/templates.templ
+++ b/web/templates.templ
@@ -37,33 +37,9 @@ templ RidesContent(data RidesPageData) {
<input type="hidden" name="sort" value={ data.Sort.Column }/>
<input type="hidden" name="dir" value={ rideSortDirection(data.Sort) }/>
<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">{ formatRideFilterDistance(data.Filters.DistanceMinKm) }</output><span aria-hidden="true">to</span><output data-range-value="max" for="distance-max">{ formatRideFilterDistance(data.Filters.DistanceMaxKm) }</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={ formatRideFilterInt(rideFilterDistanceMinKm) } max={ formatRideFilterInt(rideFilterDistanceMaxKm) } step={ formatRideFilterInt(rideFilterDistanceStepKm) } value={ formatRideFilterInt(data.Filters.DistanceMinKm) } data-range-min aria-label="Minimum distance"/>
- <input id="distance-max" class="range-input range-input-max" type="range" name="distance_max" min={ formatRideFilterInt(rideFilterDistanceMinKm) } max={ formatRideFilterInt(rideFilterDistanceMaxKm) } step={ formatRideFilterInt(rideFilterDistanceStepKm) } value={ formatRideFilterInt(data.Filters.DistanceMaxKm) } 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">{ formatRideFilterDuration(data.Filters.DurationMinMinutes) }</output><span aria-hidden="true">to</span><output data-range-value="max" for="duration-max">{ formatRideFilterDuration(data.Filters.DurationMaxMinutes) }</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={ formatRideFilterInt(rideFilterDurationMinMinutes) } max={ formatRideFilterInt(rideFilterDurationMaxMinutes) } step={ formatRideFilterInt(rideFilterDurationStepMinutes) } value={ formatRideFilterInt(data.Filters.DurationMinMinutes) } data-range-min aria-label="Minimum moving duration"/>
- <input id="duration-max" class="range-input range-input-max" type="range" name="duration_max" min={ formatRideFilterInt(rideFilterDurationMinMinutes) } max={ formatRideFilterInt(rideFilterDurationMaxMinutes) } step={ formatRideFilterInt(rideFilterDurationStepMinutes) } value={ formatRideFilterInt(data.Filters.DurationMaxMinutes) } 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">{ formatRideFilterCotacol(data.Filters.CotacolMinPoints) }</output><span aria-hidden="true">to</span><output data-range-value="max" for="cotacol-max">{ formatRideFilterCotacol(data.Filters.CotacolMaxPoints) }</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={ formatRideFilterInt(rideFilterCotacolMinPoints) } max={ formatRideFilterInt(rideFilterCotacolMaxPoints) } step={ formatRideFilterInt(rideFilterCotacolStepPoints) } value={ formatRideFilterInt(data.Filters.CotacolMinPoints) } data-range-min aria-label="Minimum Cotacol"/>
- <input id="cotacol-max" class="range-input range-input-max" type="range" name="cotacol_max" min={ formatRideFilterInt(rideFilterCotacolMinPoints) } max={ formatRideFilterInt(rideFilterCotacolMaxPoints) } step={ formatRideFilterInt(rideFilterCotacolStepPoints) } value={ formatRideFilterInt(data.Filters.CotacolMaxPoints) } data-range-max aria-label="Maximum Cotacol"/>
- </div>
- </fieldset>
+ @RideRangeFilter(rideDistanceFilterConfig(data.Filters))
+ @RideRangeFilter(rideDurationFilterConfig(data.Filters))
+ @RideRangeFilter(rideCotacolFilterConfig(data.Filters))
</div>
<div class="ride-filter-meta">
<fieldset class="ride-filter-group date-filter-group">