- Remove Layouts.app wrapper so map fills entire viewport - Replace band buttons with daisyUI dropdown selector - Overlay controls (home button, band picker, timestamp) on top-left - Keep Leaflet's standard zoom controls
118 lines
3.2 KiB
Elixir
118 lines
3.2 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
|
|
|
|
defp selected_label(bands, selected_band) do
|
|
case Enum.find(bands, &(&1.freq_mhz == selected_band)) do
|
|
nil -> "Select Band"
|
|
band -> band.label
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def render(assigns) do
|
|
~H"""
|
|
<div class="relative w-screen h-screen">
|
|
<%!-- Full-page map --%>
|
|
<div
|
|
id="propagation-map"
|
|
phx-hook="PropagationMap"
|
|
phx-update="ignore"
|
|
data-scores={Jason.encode!(@scores)}
|
|
class="absolute inset-0 z-0"
|
|
>
|
|
</div>
|
|
|
|
<%!-- Top-left controls overlay --%>
|
|
<div class="absolute top-3 left-14 z-[1000] flex items-center gap-2">
|
|
<.link navigate="/" class="btn btn-sm bg-base-100/90 shadow border-base-300">
|
|
<.icon name="hero-home" class="size-4" />
|
|
</.link>
|
|
|
|
<div class="dropdown">
|
|
<div tabindex="0" role="button" class="btn btn-sm bg-base-100/90 shadow border-base-300">
|
|
<.icon name="hero-signal" class="size-4" />
|
|
{selected_label(@bands, @selected_band)}
|
|
<.icon name="hero-chevron-down" class="size-3" />
|
|
</div>
|
|
<ul
|
|
tabindex="0"
|
|
class="dropdown-content menu bg-base-100 rounded-box shadow-lg w-44 mt-1 p-1"
|
|
>
|
|
<li :for={band <- @bands}>
|
|
<button
|
|
phx-click="select_band"
|
|
value={band.freq_mhz}
|
|
class={[if(@selected_band == band.freq_mhz, do: "active")]}
|
|
>
|
|
{band.label}
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div :if={@valid_time} class="badge badge-ghost bg-base-100/90 shadow text-xs">
|
|
{Calendar.strftime(@valid_time, "%H:%M UTC")}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<Layouts.flash_group flash={@flash} />
|
|
"""
|
|
end
|
|
end
|