feat(rover): make candidate strip scroll horizontally + wheel-to-h-scroll

This commit is contained in:
Graham McIntire 2026-04-26 09:31:10 -05:00
parent 12e0106b7b
commit 3b1a13b0f7
No known key found for this signature in database
GPG key ID: F4ABF488E6029E59
3 changed files with 37 additions and 3 deletions

View file

@ -21,6 +21,7 @@ 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 {HorizontalWheelScroll} from "./horizontal_wheel_scroll_hook"
import {BeaconMap} from "./beacon_map_hook"
import {BeaconsListMap} from "./beacons_list_map_hook"
@ -312,7 +313,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, RoverSlider, BeaconMap, BeaconsListMap, CommaNumber, ImportConfetti, EmeGlobe, Skewt},
hooks: {...colocatedHooks, PropagationMap, PathForecast, UtcClock, ContactMap, ContactsMap, ElevationProfile, WeatherMap, LocateMe, CopyLink, RoverMap, RoverSlider, HorizontalWheelScroll, BeaconMap, BeaconsListMap, CommaNumber, ImportConfetti, EmeGlobe, Skewt},
})
// live_table rows are dead on their own — wire up whole-row clicks to

View file

@ -0,0 +1,29 @@
// Translates a vertical mouse-wheel into horizontal scroll on this
// element so users on a desktop without a horizontal trackpad can
// still scroll a horizontal carousel by using the wheel over it.
import type { ViewHook } from "phoenix_live_view"
interface HorizontalWheelScrollHook extends ViewHook {
wheelHandler?: (e: WheelEvent) => void
}
export const HorizontalWheelScroll: Partial<HorizontalWheelScrollHook> = {
mounted(this: HorizontalWheelScrollHook) {
this.wheelHandler = (e: WheelEvent) => {
// Only convert dominant-vertical wheels; leave true horizontal
// gestures alone so trackpads still feel native.
if (Math.abs(e.deltaY) <= Math.abs(e.deltaX)) return
const el = this.el as HTMLElement
if (el.scrollWidth <= el.clientWidth) return
e.preventDefault()
el.scrollLeft += e.deltaY
}
this.el.addEventListener("wheel", this.wheelHandler, { passive: false })
},
destroyed(this: HorizontalWheelScrollHook) {
if (this.wheelHandler) {
this.el.removeEventListener("wheel", this.wheelHandler)
}
}
}

View file

@ -883,10 +883,14 @@ defmodule MicrowavepropWeb.RoverLive do
<div class="px-3 pt-1 text-[10px] uppercase tracking-wider text-base-content/60 font-semibold">
Ideal locations
</div>
<div class="carousel carousel-start gap-3 px-3 pb-3 pt-1 h-[110px] overflow-x-auto">
<div
id="rover-candidates-strip"
phx-hook="HorizontalWheelScroll"
class="flex flex-row flex-nowrap gap-3 px-3 pb-3 pt-1 h-[110px] overflow-x-auto overflow-y-hidden overscroll-x-contain"
>
<div
:for={c <- @top_candidates}
class="carousel-item w-[280px] card bg-base-200 shadow-sm cursor-pointer"
class="shrink-0 w-[280px] card bg-base-200 shadow-sm cursor-pointer"
phx-click="select_candidate"
phx-value-grid={c.grid}
>