fix(contacts/map): align line colors with sidebar legend
The polylines were sourcing from --band-* CSS vars (a separate, theme-aware design palette) while the legend swatches rendered from the Elixir @band_colors map, so the two diverged for every band — e.g. 10 GHz showed lime on the map and emerald in the legend. Emit `data-band-color` on each band checkbox and have the JS hook read from there, making the legend the single source of truth. Drops the now-redundant theme observer / restyleLines plumbing.
This commit is contained in:
parent
90cc554c4f
commit
18680b35e5
2 changed files with 13 additions and 58 deletions
|
|
@ -40,7 +40,6 @@ interface ContactsMapHook extends ViewHook {
|
|||
map: L.Map
|
||||
delegatedChange: (e: Event) => void
|
||||
delegatedClick: (e: Event) => void
|
||||
themeObserver: MutationObserver | null
|
||||
initMap(this: ContactsMapHook): void
|
||||
buildLines(this: ContactsMapHook): void
|
||||
syncBandLayers(this: ContactsMapHook): void
|
||||
|
|
@ -49,7 +48,6 @@ interface ContactsMapHook extends ViewHook {
|
|||
updateCount(this: ContactsMapHook, count: number): void
|
||||
wireControls(this: ContactsMapHook): void
|
||||
unwireControls(this: ContactsMapHook): void
|
||||
restyleLines(this: ContactsMapHook): void
|
||||
}
|
||||
|
||||
function inDateRange(tsDate: string, startDate: string, endDate: string): boolean {
|
||||
|
|
@ -60,48 +58,26 @@ function inDateRange(tsDate: string, startDate: string, endDate: string): boolea
|
|||
return true
|
||||
}
|
||||
|
||||
// Amateur-band palette. Nine of these map to the design system's --band-*
|
||||
// CSS vars (defined in assets/css/app.css); the higher mm-wave bands above
|
||||
// 47 GHz fall back to hard-coded hues since the design set only spans up
|
||||
// to 6mm. CSS vars are resolved once per page via getComputedStyle because
|
||||
// Leaflet writes the color onto the SVG `stroke` attribute, which does not
|
||||
// evaluate `var()` references.
|
||||
const BAND_VAR: Record<number, string> = {
|
||||
1296: "--band-23cm",
|
||||
2304: "--band-13cm",
|
||||
3400: "--band-9cm",
|
||||
5760: "--band-6cm",
|
||||
10000: "--band-3cm",
|
||||
24000: "--band-1-25cm",
|
||||
47000: "--band-6mm",
|
||||
}
|
||||
|
||||
const BAND_FALLBACK: Record<number, string> = {
|
||||
68000: "#dc2626",
|
||||
75000: "#c026d3",
|
||||
122000: "#db2777",
|
||||
134000: "#e11d48",
|
||||
241000: "#b91c1c",
|
||||
}
|
||||
|
||||
// Band colors are sourced from the legend swatches in the sidebar — each
|
||||
// band checkbox carries `data-band-color` set server-side from
|
||||
// `Microwaveprop.ContactMapLive`'s @band_colors map. Reading from the DOM
|
||||
// keeps the legend the single source of truth: change the Elixir map and
|
||||
// both the swatch and the polyline update in lockstep.
|
||||
let BAND_COLORS: Record<number, string> | null = null
|
||||
|
||||
function resolveBandColors(): Record<number, string> {
|
||||
if (BAND_COLORS) return BAND_COLORS
|
||||
const styles = getComputedStyle(document.documentElement)
|
||||
const resolved: Record<number, string> = { ...BAND_FALLBACK }
|
||||
for (const [band, cssVar] of Object.entries(BAND_VAR)) {
|
||||
const value = styles.getPropertyValue(cssVar).trim()
|
||||
if (value) resolved[Number(band)] = value
|
||||
const resolved: Record<number, string> = {}
|
||||
const inputs = document.querySelectorAll<HTMLInputElement>("input[data-band][data-band-color]")
|
||||
for (const inp of inputs) {
|
||||
const band = parseInt(inp.dataset.band || "", 10)
|
||||
const color = inp.dataset.bandColor
|
||||
if (Number.isFinite(band) && color) resolved[band] = color
|
||||
}
|
||||
BAND_COLORS = resolved
|
||||
return resolved
|
||||
}
|
||||
|
||||
function invalidateBandColors(): void {
|
||||
BAND_COLORS = null
|
||||
}
|
||||
|
||||
function bandLabel(mhz: number): string {
|
||||
if (mhz >= 1000) {
|
||||
const ghz = mhz / 1000
|
||||
|
|
@ -125,7 +101,6 @@ export const ContactsMap = {
|
|||
this.bandGroups = new Map()
|
||||
this.lines = []
|
||||
this.dotLayer = L.layerGroup()
|
||||
this.themeObserver = null
|
||||
|
||||
// Callsign filter still roundtrips through LiveView (debounced) — it's
|
||||
// cross-cutting and fires rarely. Band toggles are purely client-side.
|
||||
|
|
@ -144,18 +119,6 @@ export const ContactsMap = {
|
|||
|
||||
this.wireControls()
|
||||
|
||||
// Re-color polylines when the theme toggles. Leaflet writes `stroke` as
|
||||
// an SVG attribute (which does not resolve CSS vars), so we re-read the
|
||||
// resolved --band-* values and call setStyle on each line.
|
||||
this.themeObserver = new MutationObserver(() => {
|
||||
invalidateBandColors()
|
||||
this.restyleLines()
|
||||
})
|
||||
this.themeObserver.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ["data-theme"]
|
||||
})
|
||||
|
||||
requestAnimationFrame(() => this.initMap())
|
||||
|
||||
fetch(fetchUrl)
|
||||
|
|
@ -174,16 +137,6 @@ export const ContactsMap = {
|
|||
|
||||
destroyed(this: ContactsMapHook) {
|
||||
this.unwireControls()
|
||||
if (this.themeObserver) {
|
||||
this.themeObserver.disconnect()
|
||||
this.themeObserver = null
|
||||
}
|
||||
},
|
||||
|
||||
restyleLines(this: ContactsMapHook) {
|
||||
for (const entry of this.lines) {
|
||||
entry.line.setStyle({ color: bandColor(entry.band) })
|
||||
}
|
||||
},
|
||||
|
||||
wireControls(this: ContactsMapHook) {
|
||||
|
|
|
|||
|
|
@ -202,6 +202,7 @@ defmodule MicrowavepropWeb.ContactMapLive do
|
|||
type="checkbox"
|
||||
checked
|
||||
data-band={band}
|
||||
data-band-color={band_color(band)}
|
||||
style={"accent-color:#{band_color(band)}"}
|
||||
/>
|
||||
<span
|
||||
|
|
@ -325,6 +326,7 @@ defmodule MicrowavepropWeb.ContactMapLive do
|
|||
type="checkbox"
|
||||
checked
|
||||
data-band={band}
|
||||
data-band-color={band_color(band)}
|
||||
style={"accent-color:#{band_color(band)}"}
|
||||
/>
|
||||
<span
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue