Improve path page UX: prominent GPS button, share links
- "My Location" button with text label (was just an icon) - Two share buttons after results: - "Copy Link" — fixed coordinates, exact result - "Copy Link (use viewer's GPS)" — source=gps, dynamic per viewer - CopyLink JS hook copies full URL to clipboard with "Copied!" feedback
This commit is contained in:
parent
024735009b
commit
ba0d2541ca
3 changed files with 63 additions and 8 deletions
|
|
@ -35,7 +35,7 @@ import {ContactMap} from "./contact_map_hook"
|
||||||
import {ContactsMap} from "./contacts_map_hook"
|
import {ContactsMap} from "./contacts_map_hook"
|
||||||
import {ElevationProfile} from "./elevation_profile_hook"
|
import {ElevationProfile} from "./elevation_profile_hook"
|
||||||
import {WeatherMap} from "./weather_map_hook"
|
import {WeatherMap} from "./weather_map_hook"
|
||||||
import {LocateMe} from "./locate_me_hook"
|
import {LocateMe, CopyLink} from "./locate_me_hook"
|
||||||
|
|
||||||
const UtcClock = {
|
const UtcClock = {
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
@ -57,7 +57,7 @@ const csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute
|
||||||
const liveSocket = new LiveSocket("/live", Socket, {
|
const liveSocket = new LiveSocket("/live", Socket, {
|
||||||
longPollFallbackMs: 2500,
|
longPollFallbackMs: 2500,
|
||||||
params: initLiveStash({_csrf_token: csrfToken}),
|
params: initLiveStash({_csrf_token: csrfToken}),
|
||||||
hooks: {...colocatedHooks, PropagationMap, UtcClock, ContactMap, ContactsMap, ElevationProfile, WeatherMap, LocateMe},
|
hooks: {...colocatedHooks, PropagationMap, UtcClock, ContactMap, ContactsMap, ElevationProfile, WeatherMap, LocateMe, CopyLink},
|
||||||
})
|
})
|
||||||
|
|
||||||
// Show progress bar on live navigation and form submits
|
// Show progress bar on live navigation and form submits
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,16 @@
|
||||||
|
export const CopyLink = {
|
||||||
|
mounted() {
|
||||||
|
this.el.addEventListener("click", () => {
|
||||||
|
const url = window.location.origin + this.el.dataset.url
|
||||||
|
navigator.clipboard.writeText(url).then(() => {
|
||||||
|
const orig = this.el.innerHTML
|
||||||
|
this.el.innerHTML = '<span class="text-success">Copied!</span>'
|
||||||
|
setTimeout(() => { this.el.innerHTML = orig }, 1500)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const LocateMe = {
|
export const LocateMe = {
|
||||||
mounted() {
|
mounted() {
|
||||||
this.el.addEventListener("click", () => this.locate())
|
this.el.addEventListener("click", () => this.locate())
|
||||||
|
|
|
||||||
|
|
@ -470,6 +470,27 @@ defmodule MicrowavepropWeb.PathLive do
|
||||||
defp format_utc_hour(%DateTime{} = dt), do: Calendar.strftime(dt, "%H:%M")
|
defp format_utc_hour(%DateTime{} = dt), do: Calendar.strftime(dt, "%H:%M")
|
||||||
defp format_utc_hour(_), do: "?"
|
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 >= 1000, do: "#{format_number(mw / 1000)} W"
|
||||||
defp format_mw(mw) when mw >= 1, do: "#{format_number(mw)} mW"
|
defp format_mw(mw) when mw >= 1, do: "#{format_number(mw)} mW"
|
||||||
defp format_mw(mw), do: "#{format_number(mw * 1000)} uW"
|
defp format_mw(mw), do: "#{format_number(mw * 1000)} uW"
|
||||||
|
|
@ -488,25 +509,24 @@ defmodule MicrowavepropWeb.PathLive do
|
||||||
<form phx-submit="calculate" phx-change="update_form" class="bg-base-200 rounded-box p-4 mb-6">
|
<form phx-submit="calculate" phx-change="update_form" class="bg-base-200 rounded-box p-4 mb-6">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-4 items-end">
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-4 items-end">
|
||||||
<div class="fieldset">
|
<div class="fieldset">
|
||||||
<label class="label text-sm font-medium">Source (callsign or grid)</label>
|
<label class="label text-sm font-medium">Source</label>
|
||||||
<div class="flex gap-1">
|
<div class="flex gap-1">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="source"
|
name="source"
|
||||||
id="source-input"
|
id="source-input"
|
||||||
value={@source}
|
value={@source}
|
||||||
placeholder="W5ISP or EM13sf"
|
placeholder="W5ISP, EM13sf, or lat,lon"
|
||||||
class="input input-bordered flex-1"
|
class="input input-bordered flex-1"
|
||||||
required
|
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
id="locate-me"
|
id="locate-me"
|
||||||
phx-hook="LocateMe"
|
phx-hook="LocateMe"
|
||||||
class="btn btn-square btn-sm btn-ghost"
|
class="btn btn-sm btn-outline gap-1"
|
||||||
title="Use GPS location"
|
title="Use device GPS"
|
||||||
>
|
>
|
||||||
<.icon name="hero-map-pin" class="size-4" />
|
<.icon name="hero-map-pin" class="size-3.5" /> My Location
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -896,6 +916,28 @@ defmodule MicrowavepropWeb.PathLive do
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
<%!-- Share links --%>
|
||||||
|
<div class="flex flex-wrap gap-2 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
|
end
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue