Keep source=gps in URL when GPS is used, single copy link, fix unicode

- GPS button sets source_is_gps flag, URL stays source=gps
- Form shows resolved coordinates but URL preserves gps intent
- Single "Copy Link" button copies current URL (includes gps if used)
- Fix unicode escapes in HEEx: use Elixir interpolation for subscripts
This commit is contained in:
Graham McIntire 2026-04-07 13:56:36 -05:00
parent 44d0c3d1ed
commit 15ff056a2a
2 changed files with 21 additions and 43 deletions

View file

@ -1,8 +1,7 @@
export const CopyLink = {
mounted() {
this.el.addEventListener("click", () => {
const url = window.location.origin + this.el.dataset.url
navigator.clipboard.writeText(url).then(() => {
navigator.clipboard.writeText(window.location.href).then(() => {
const orig = this.el.innerHTML
this.el.innerHTML = '<span class="text-success">Copied!</span>'
setTimeout(() => { this.el.innerHTML = orig }, 1500)

View file

@ -50,7 +50,8 @@ defmodule MicrowavepropWeb.PathLive do
dst_height_ft: "30",
tx_power_dbm: "20",
src_gain_dbi: "30",
dst_gain_dbi: "30"
dst_gain_dbi: "30",
source_is_gps: false
)}
end
@ -58,16 +59,19 @@ defmodule MicrowavepropWeb.PathLive do
def handle_params(params, _uri, socket) do
p = Map.merge(@defaults, Map.take(params, @url_params))
is_gps = p["source"] == "gps"
socket =
assign(socket,
source: p["source"],
source: if(is_gps, do: socket.assigns.source, else: p["source"]),
destination: p["destination"],
band: p["band"],
src_height_ft: p["src_height_ft"],
dst_height_ft: p["dst_height_ft"],
tx_power_dbm: p["tx_power_dbm"],
src_gain_dbi: p["src_gain_dbi"],
dst_gain_dbi: p["dst_gain_dbi"]
dst_gain_dbi: p["dst_gain_dbi"],
source_is_gps: is_gps
)
# If source=gps, request device location via JS
@ -156,19 +160,25 @@ defmodule MicrowavepropWeb.PathLive do
{:compute_path, params["source"], params["destination"], String.to_integer(params["band"]), station_params}
)
url_params = params |> Map.take(@url_params) |> Enum.reject(fn {_k, v} -> v == "" end) |> Map.new()
url_params =
params
|> Map.take(@url_params)
|> then(fn p -> if socket.assigns.source_is_gps, do: Map.put(p, "source", "gps"), else: p end)
|> Enum.reject(fn {_k, v} -> v == "" end)
|> Map.new()
{:noreply, push_patch(socket, to: ~p"/path?#{url_params}", replace: true)}
end
def handle_event("gps_location", %{"lat" => lat, "lon" => lon}, socket) do
source = "#{Float.round(lat / 1, 6)},#{Float.round(lon / 1, 6)}"
coords = "#{Float.round(lat / 1, 6)},#{Float.round(lon / 1, 6)}"
# Replace gps with actual coords in URL and trigger calculation
socket = assign(socket, source: source, result: nil)
# Show coords in the input but keep source=gps in the URL
socket = assign(socket, source: coords, source_is_gps: true, result: nil)
url_params =
%{
"source" => source,
"source" => "gps",
"destination" => socket.assigns.destination,
"band" => socket.assigns.band,
"src_height_ft" => socket.assigns.src_height_ft,
@ -470,27 +480,6 @@ defmodule MicrowavepropWeb.PathLive do
defp format_utc_hour(%DateTime{} = dt), do: Calendar.strftime(dt, "%H:%M")
defp format_utc_hour(_), do: "?"
defp share_url(result, mode) do
source =
case mode do
:gps -> "gps"
:fixed -> "#{Float.round(result.source.lat, 4)},#{Float.round(result.source.lon, 4)}"
end
params = %{
"source" => source,
"destination" => result.destination.label,
"band" => to_string(result.band_mhz),
"src_height_ft" => to_string(result.station_params.src_height_ft),
"dst_height_ft" => to_string(result.station_params.dst_height_ft),
"tx_power_dbm" => to_string(result.station_params.tx_power_dbm),
"src_gain_dbi" => to_string(result.station_params.src_gain_dbi),
"dst_gain_dbi" => to_string(result.station_params.dst_gain_dbi)
}
"/path?" <> URI.encode_query(params)
end
defp format_mw(mw) when mw >= 1000, do: "#{format_number(mw / 1000)} W"
defp format_mw(mw) when mw >= 1, do: "#{format_number(mw)} mW"
defp format_mw(mw), do: "#{format_number(mw * 1000)} uW"
@ -917,26 +906,16 @@ defmodule MicrowavepropWeb.PathLive do
</div>
<% end %>
<%!-- Share links --%>
<div class="flex flex-wrap gap-2 mb-6">
<%!-- Share link --%>
<div class="mb-6">
<button
type="button"
phx-hook="CopyLink"
id="copy-link"
data-url={share_url(@result, :fixed)}
class="btn btn-sm btn-outline gap-1"
>
<.icon name="hero-link" class="size-3.5" /> Copy Link
</button>
<button
type="button"
phx-hook="CopyLink"
id="copy-gps-link"
data-url={share_url(@result, :gps)}
class="btn btn-sm btn-outline gap-1"
>
<.icon name="hero-map-pin" class="size-3.5" /> Copy Link (use viewer's GPS)
</button>
</div>
"""
end