Vendor Leaflet 1.9.4 (JS, CSS, marker images) and wire it into the esbuild/Tailwind asset pipeline. Create MapLive with band selector buttons, auto-refresh, and a colocated JS hook that renders propagation scores as color-coded circle markers with a legend. Stub Propagation context and BandConfig modules provide the data interface for the scoring pipeline. Add nav bar with links to Map, QSOs, and Submit pages.
96 lines
2.6 KiB
Elixir
96 lines
2.6 KiB
Elixir
defmodule MicrowavepropWeb.MapLive do
|
|
@moduledoc false
|
|
use MicrowavepropWeb, :live_view
|
|
|
|
alias Microwaveprop.Propagation
|
|
alias Microwaveprop.Propagation.BandConfig
|
|
|
|
@default_band 10_000
|
|
@refresh_interval_ms to_timeout(minute: 5)
|
|
|
|
@impl true
|
|
def mount(_params, _session, socket) do
|
|
bands = BandConfig.all_bands()
|
|
scores = Propagation.latest_scores(@default_band)
|
|
valid_time = Propagation.latest_valid_time()
|
|
|
|
if connected?(socket) do
|
|
Process.send_after(self(), :refresh, @refresh_interval_ms)
|
|
end
|
|
|
|
{:ok,
|
|
assign(socket,
|
|
page_title: "Propagation Map",
|
|
bands: bands,
|
|
selected_band: @default_band,
|
|
scores: scores,
|
|
valid_time: valid_time
|
|
)}
|
|
end
|
|
|
|
@impl true
|
|
def handle_event("select_band", %{"value" => band_str}, socket) do
|
|
band = String.to_integer(band_str)
|
|
scores = Propagation.latest_scores(band)
|
|
|
|
socket =
|
|
socket
|
|
|> assign(:selected_band, band)
|
|
|> assign(:scores, scores)
|
|
|> push_event("update_scores", %{scores: scores})
|
|
|
|
{:noreply, socket}
|
|
end
|
|
|
|
@impl true
|
|
def handle_info(:refresh, socket) do
|
|
scores = Propagation.latest_scores(socket.assigns.selected_band)
|
|
valid_time = Propagation.latest_valid_time()
|
|
Process.send_after(self(), :refresh, @refresh_interval_ms)
|
|
|
|
socket =
|
|
socket
|
|
|> assign(:scores, scores)
|
|
|> assign(:valid_time, valid_time)
|
|
|> push_event("update_scores", %{scores: scores})
|
|
|
|
{:noreply, socket}
|
|
end
|
|
|
|
@impl true
|
|
def render(assigns) do
|
|
~H"""
|
|
<Layouts.app flash={@flash}>
|
|
<div class="flex flex-col h-[calc(100vh-4rem)]">
|
|
<div class="flex items-center gap-4 p-3 bg-base-200 rounded-t-lg flex-wrap">
|
|
<h2 class="text-lg font-bold">Propagation Map</h2>
|
|
<div class="flex gap-1 flex-wrap">
|
|
<button
|
|
:for={band <- @bands}
|
|
phx-click="select_band"
|
|
value={band.freq_mhz}
|
|
class={[
|
|
"btn btn-sm",
|
|
if(@selected_band == band.freq_mhz, do: "btn-primary", else: "btn-ghost")
|
|
]}
|
|
>
|
|
{band.label}
|
|
</button>
|
|
</div>
|
|
<div :if={@valid_time} class="ml-auto text-sm text-base-content/60">
|
|
Updated: {Calendar.strftime(@valid_time, "%Y-%m-%d %H:%M UTC")}
|
|
</div>
|
|
</div>
|
|
<div
|
|
id="propagation-map"
|
|
phx-hook="PropagationMap"
|
|
phx-update="ignore"
|
|
data-scores={Jason.encode!(@scores)}
|
|
class="flex-1 rounded-b-lg z-0"
|
|
>
|
|
</div>
|
|
</div>
|
|
</Layouts.app>
|
|
"""
|
|
end
|
|
end
|