From 10fcc764f6c9b2f52b4ec54beae4b2634d2230af Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Sat, 25 Apr 2026 16:30:38 -0500 Subject: [PATCH] feat(rover): live slider labels via RoverSlider hook for forecast hour + drive time --- assets/js/app.ts | 3 +- assets/js/rover_slider_hook.ts | 42 ++++++++++++++++++++++++ lib/microwaveprop_web/live/rover_live.ex | 17 ++++++++-- 3 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 assets/js/rover_slider_hook.ts diff --git a/assets/js/app.ts b/assets/js/app.ts index 9e88fa67..0e63f9b4 100644 --- a/assets/js/app.ts +++ b/assets/js/app.ts @@ -20,6 +20,7 @@ import {ElevationProfile} from "./elevation_profile_hook" import {WeatherMap} from "./weather_map_hook" import {LocateMe, CopyLink} from "./locate_me_hook" import {RoverMap} from "./rover_map_hook" +import {RoverSlider} from "./rover_slider_hook" import {BeaconMap} from "./beacon_map_hook" import {BeaconsListMap} from "./beacons_list_map_hook" @@ -311,7 +312,7 @@ const csrfToken = document.querySelector("meta[name='csrf-token']")!.getAttribut const liveSocket = new LiveSocket("/live", Socket, { longPollFallbackMs: 2500, params: initLiveStash({_csrf_token: csrfToken}), - hooks: {...colocatedHooks, PropagationMap, PathForecast, UtcClock, ContactMap, ContactsMap, ElevationProfile, WeatherMap, LocateMe, CopyLink, RoverMap, BeaconMap, BeaconsListMap, CommaNumber, ImportConfetti, EmeGlobe, Skewt}, + hooks: {...colocatedHooks, PropagationMap, PathForecast, UtcClock, ContactMap, ContactsMap, ElevationProfile, WeatherMap, LocateMe, CopyLink, RoverMap, RoverSlider, BeaconMap, BeaconsListMap, CommaNumber, ImportConfetti, EmeGlobe, Skewt}, }) // live_table rows are dead on their own — wire up whole-row clicks to diff --git a/assets/js/rover_slider_hook.ts b/assets/js/rover_slider_hook.ts new file mode 100644 index 00000000..4e55445f --- /dev/null +++ b/assets/js/rover_slider_hook.ts @@ -0,0 +1,42 @@ +import type { ViewHook } from "phoenix_live_view" + +interface RoverSliderHook extends ViewHook { + labelEl: HTMLElement | null + formatter: (v: number) => string + inputHandler: () => void +} + +const formatters: Record string> = { + forecast: (v) => `+${v}h`, + drive: (v) => { + const hours = Math.round((v / 60) * 10) / 10 + return `${hours}h` + } +} + +export const RoverSlider: Partial = { + mounted(this: RoverSliderHook) { + const labelId = this.el.dataset.labelId || "" + const format = this.el.dataset.format || "forecast" + + this.formatter = formatters[format] || formatters.forecast + this.labelEl = document.getElementById(labelId) + + this.inputHandler = () => { + if (this.labelEl) { + this.labelEl.textContent = this.formatter(Number((this.el as HTMLInputElement).value)) + } + } + + this.el.addEventListener("input", this.inputHandler) + this.inputHandler() + }, + + updated(this: RoverSliderHook) { + if (this.inputHandler) this.inputHandler() + }, + + destroyed(this: RoverSliderHook) { + if (this.inputHandler) this.el.removeEventListener("input", this.inputHandler) + } +} diff --git a/lib/microwaveprop_web/live/rover_live.ex b/lib/microwaveprop_web/live/rover_live.ex index f4918bb2..eaed690d 100644 --- a/lib/microwaveprop_web/live/rover_live.ex +++ b/lib/microwaveprop_web/live/rover_live.ex @@ -630,10 +630,17 @@ defmodule MicrowavepropWeb.RoverLive do value={@forecast_hour} phx-change="set_forecast_hour" phx-debounce="200" + phx-hook="RoverSlider" + phx-update="ignore" + id="rover-forecast-slider" + data-label-id="rover-forecast-label" + data-format="forecast" name="value" class="range range-xs range-primary" /> -
+{@forecast_hour}h
+
+ +{@forecast_hour}h +
<.sidebar_section title="BAND"> @@ -662,11 +669,17 @@ defmodule MicrowavepropWeb.RoverLive do value={@max_drive_min} phx-change="set_max_drive_time" phx-debounce="200" + phx-hook="RoverSlider" + phx-update="ignore" + id="rover-drive-slider" + data-label-id="rover-drive-label" + data-format="drive" name="value" class="range range-xs range-primary" />
- {Float.round(@max_drive_min / 60, 1)}h from {@home.label} + {Float.round(@max_drive_min / 60, 1)}h + from {@home.label}