summaryrefslogtreecommitdiff
path: root/web/frontend/ride-filters.ts
blob: 24c23e8e41ea6c4e0ffead7e393ae42e22d73f68 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import { requireElement } from "./dom.js";
import {
  formatRideFilterValue,
  normalizeRideFilterRange,
  type RideFilterRangeFormat,
  type RideFilterRangeHandle,
} from "./ride-filters-logic.js";

const mountRangeFilter = (container: HTMLElement): void => {
  const format = container.dataset.rangeFormat as RideFilterRangeFormat | undefined;
  if (!format) throw new Error("Missing ride filter range format");
  const minInput = requireElement(container.querySelector<HTMLInputElement>("[data-range-min]"), "ride filter minimum input");
  const maxInput = requireElement(container.querySelector<HTMLInputElement>("[data-range-max]"), "ride filter maximum input");
  const track = requireElement(container.querySelector<HTMLElement>("[data-range-track]"), "ride filter range track");
  const group = requireElement(container.parentElement, "ride filter group");
  const minOutput = requireElement(group.querySelector<HTMLOutputElement>('[data-range-value="min"]'), "ride filter minimum output");
  const maxOutput = requireElement(group.querySelector<HTMLOutputElement>('[data-range-value="max"]'), "ride filter maximum output");
  const lowerBound = Number(minInput.min);
  const upperBound = Number(minInput.max);

  const update = (changed?: RideFilterRangeHandle): void => {
    const range = normalizeRideFilterRange(Number(minInput.value), Number(maxInput.value), changed ?? "min");
    minInput.value = String(range.min);
    maxInput.value = String(range.max);
    const span = Math.max(upperBound - lowerBound, 1);
    const start = ((range.min - lowerBound) / span) * 100;
    const end = ((range.max - lowerBound) / span) * 100;
    track.style.setProperty("--range-start", `${start}%`);
    track.style.setProperty("--range-end", `${end}%`);
    const minLabel = formatRideFilterValue(format, range.min);
    const maxLabel = formatRideFilterValue(format, range.max);
    minOutput.value = minLabel;
    maxOutput.value = maxLabel;
    minOutput.textContent = minLabel;
    maxOutput.textContent = maxLabel;
    minInput.setAttribute("aria-valuetext", minLabel);
    maxInput.setAttribute("aria-valuetext", maxLabel);
  };

  minInput.addEventListener("input", () => update("min"));
  maxInput.addEventListener("input", () => update("max"));
  update();
};

export const mountRideFilters = (): void => {
  document.querySelectorAll<HTMLElement>("[data-range-filter]").forEach(mountRangeFilter);
};

mountRideFilters();