liveview links
This commit is contained in:
parent
bb82e46822
commit
142900c759
12 changed files with 214 additions and 54 deletions
|
|
@ -446,9 +446,9 @@ defmodule AprsmeWeb.CoreComponents do
|
|||
~H"""
|
||||
<div class="navbar bg-base-200 shadow-lg">
|
||||
<div class="navbar-start">
|
||||
<a href="/" class="btn btn-ghost text-xl font-bold text-primary">
|
||||
<.link navigate="/" class="btn btn-ghost text-xl font-bold text-primary">
|
||||
aprs.me
|
||||
</a>
|
||||
</.link>
|
||||
</div>
|
||||
<div class="navbar-center hidden lg:flex">
|
||||
<.navigation variant={:horizontal} />
|
||||
|
|
@ -751,14 +751,14 @@ defmodule AprsmeWeb.CoreComponents do
|
|||
~H"""
|
||||
<%= if @variant == :horizontal do %>
|
||||
<ul class="menu menu-horizontal px-1">
|
||||
<li><a href="/" class="link link-hover">Home</a></li>
|
||||
<li><a href="/api" class="link link-hover">API</a></li>
|
||||
<li><a href="/about" class="link link-hover">About</a></li>
|
||||
<li><.link navigate="/" class="text-gray-900 hover:text-gray-700">Home</.link></li>
|
||||
<li><.link navigate="/api" class="text-gray-900 hover:text-gray-700">API</.link></li>
|
||||
<li><.link navigate="/about" class="text-gray-900 hover:text-gray-700">About</.link></li>
|
||||
</ul>
|
||||
<% else %>
|
||||
<li><a href="/" class="link link-hover">Home</a></li>
|
||||
<li><a href="/api" class="link link-hover">API</a></li>
|
||||
<li><a href="/about" class="link link-hover">About</a></li>
|
||||
<li><.link navigate="/" class="text-gray-900 hover:text-gray-700">Home</.link></li>
|
||||
<li><.link navigate="/api" class="text-gray-900 hover:text-gray-700">API</.link></li>
|
||||
<li><.link navigate="/about" class="text-gray-900 hover:text-gray-700">About</.link></li>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,7 +4,13 @@ defmodule AprsmeWeb.Layouts do
|
|||
|
||||
embed_templates "layouts/*"
|
||||
|
||||
def body_class(_assigns) do
|
||||
["bg-base-100 antialiased"]
|
||||
def body_class(assigns) do
|
||||
base_classes = ["bg-base-100 antialiased"]
|
||||
|
||||
if Map.get(assigns, :map_page, false) do
|
||||
base_classes ++ ["map-page"]
|
||||
else
|
||||
base_classes
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,174 @@
|
|||
<style>
|
||||
/* Map page specific styles */
|
||||
body.map-page header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.map-page main {
|
||||
padding: 0;
|
||||
max-width: none;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body.map-page main > div {
|
||||
max-width: none;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body.map-page .phx-main {
|
||||
position: relative;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body.map-page div[data-phx-main="true"] {
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Full page map for APRS home page and callsign pages */
|
||||
body.map-page #aprs-map {
|
||||
position: fixed !important;
|
||||
top: 0 !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
bottom: 0 !important;
|
||||
height: 100vh !important;
|
||||
width: 100vw !important;
|
||||
z-index: 1 !important;
|
||||
transition: right 0.3s ease-in-out !important;
|
||||
}
|
||||
|
||||
/* Desktop slideover behavior for map */
|
||||
@media (min-width: 1024px) {
|
||||
body.map-page #aprs-map.slideover-open {
|
||||
right: 352px !important;
|
||||
}
|
||||
|
||||
body.map-page #aprs-map.slideover-closed {
|
||||
right: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile slideover behavior for map */
|
||||
@media (max-width: 1023px) {
|
||||
body.map-page #aprs-map {
|
||||
right: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Slideover toggle button styles */
|
||||
body.map-page .slideover-toggle {
|
||||
position: fixed !important;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
z-index: 1001;
|
||||
background: white;
|
||||
border: 2px solid rgba(0, 0, 0, 0.2);
|
||||
border-radius: 8px;
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
transition: all 0.2s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
body.map-page .slideover-toggle:hover {
|
||||
background: #f8fafc;
|
||||
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
body.map-page .slideover-toggle:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
/* Hide toggle on desktop when slideover is open */
|
||||
@media (min-width: 1024px) {
|
||||
body.map-page .slideover-toggle.slideover-open {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile toggle adjustments */
|
||||
@media (max-width: 1023px) {
|
||||
body.map-page .slideover-toggle {
|
||||
right: 15px;
|
||||
top: 15px;
|
||||
padding: 12px;
|
||||
border-radius: 50%;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Slideover panel responsive styles */
|
||||
body.map-page .slideover-panel {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 100vh;
|
||||
width: 352px;
|
||||
background: white;
|
||||
box-shadow: -4px 0 24px rgba(0, 0, 0, 0.15);
|
||||
z-index: 1000;
|
||||
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Desktop slideover behavior */
|
||||
@media (min-width: 1024px) {
|
||||
body.map-page .slideover-panel.slideover-open {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
body.map-page .slideover-panel.slideover-closed {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile slideover behavior */
|
||||
@media (max-width: 1023px) {
|
||||
body.map-page .slideover-panel {
|
||||
width: 100vw;
|
||||
max-width: 400px;
|
||||
box-shadow: -8px 0 32px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
body.map-page .slideover-panel.slideover-open {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
body.map-page .slideover-panel.slideover-closed {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile panel improvements */
|
||||
@media (max-width: 1023px) {
|
||||
body.map-page .slideover-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
/* Improve scrolling on mobile */
|
||||
@media (max-width: 1023px) {
|
||||
body.map-page .slideover-panel {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
|
||||
body.map-page .slideover-panel .flex-1 {
|
||||
min-height: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<.header />
|
||||
<main class="min-h-screen bg-base-100">
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ defmodule AprsmeWeb.MapLive.CallsignView do
|
|||
alias AprsmeWeb.MapLive.MapHelpers
|
||||
alias AprsmeWeb.MapLive.PacketUtils
|
||||
|
||||
@layout {AprsmeWeb.Layouts, :map}
|
||||
|
||||
@default_center %{lat: 39.0, lng: -98.0}
|
||||
@default_zoom 4
|
||||
@default_replay_speed 1.0
|
||||
|
|
@ -61,7 +63,8 @@ defmodule AprsmeWeb.MapLive.CallsignView do
|
|||
latest_symbol_table_id: "/",
|
||||
latest_symbol_code: ">",
|
||||
# Flag to track if latest marker was already pushed
|
||||
latest_marker_pushed: false
|
||||
latest_marker_pushed: false,
|
||||
map_page: true
|
||||
)
|
||||
|
||||
if connected?(socket) do
|
||||
|
|
@ -656,9 +659,11 @@ defmodule AprsmeWeb.MapLive.CallsignView do
|
|||
<div class="callsign-title">{@callsign}</div>
|
||||
|
||||
<div class="nav-links">
|
||||
<a href="/" class="nav-link">← Back to Map</a>
|
||||
<a href="/packets" class="nav-link">All Packets</a>
|
||||
<a href={"/packets/#{String.downcase(@callsign)}"} class="nav-link">{@callsign} Packets</a>
|
||||
<.link navigate="/" class="nav-link">← Back to Map</.link>
|
||||
<.link navigate="/packets" class="nav-link">All Packets</.link>
|
||||
<.link navigate={"/packets/#{String.downcase(@callsign)}"} class="nav-link">
|
||||
{@callsign} Packets
|
||||
</.link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ defmodule AprsmeWeb.MapLive.Index do
|
|||
alias AprsmeWeb.MapLive.PacketUtils
|
||||
alias Phoenix.LiveView.Socket
|
||||
|
||||
@layout {AprsmeWeb.Layouts, :map}
|
||||
|
||||
@default_center %{lat: 39.8283, lng: -98.5795}
|
||||
@default_zoom 5
|
||||
|
||||
|
|
@ -54,7 +56,8 @@ defmodule AprsmeWeb.MapLive.Index do
|
|||
historical_hours: "1",
|
||||
packet_age_threshold: one_hour_ago,
|
||||
slideover_open: true,
|
||||
deployed_at: deployed_at
|
||||
deployed_at: deployed_at,
|
||||
map_page: true
|
||||
)}
|
||||
end
|
||||
|
||||
|
|
@ -774,7 +777,7 @@ defmodule AprsmeWeb.MapLive.Index do
|
|||
<form phx-change="update_trail_duration" class="relative">
|
||||
<select
|
||||
name="trail_duration"
|
||||
class="w-full px-4 py-3 border border-slate-300 rounded-xl shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 text-sm bg-white appearance-none transition-all duration-200 hover:border-slate-400"
|
||||
class="w-full px-4 py-3 border border-slate-300 rounded-xl shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 text-sm bg-white text-gray-900 appearance-none transition-all duration-200 hover:border-slate-400"
|
||||
>
|
||||
<option value="1" selected={@trail_duration == "1"}>1 Hour</option>
|
||||
<option value="6" selected={@trail_duration == "6"}>6 Hours</option>
|
||||
|
|
@ -799,17 +802,6 @@ defmodule AprsmeWeb.MapLive.Index do
|
|||
</svg>
|
||||
</div>
|
||||
</form>
|
||||
<p class="text-xs text-slate-500 flex items-center space-x-1">
|
||||
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<span>How long should position trails be displayed</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Historical Data -->
|
||||
|
|
@ -828,7 +820,7 @@ defmodule AprsmeWeb.MapLive.Index do
|
|||
<form phx-change="update_historical_hours" class="relative">
|
||||
<select
|
||||
name="historical_hours"
|
||||
class="w-full px-4 py-3 border border-slate-300 rounded-xl shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 text-sm bg-white appearance-none transition-all duration-200 hover:border-slate-400"
|
||||
class="w-full px-4 py-3 border border-slate-300 rounded-xl shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 text-sm bg-white text-gray-900 appearance-none transition-all duration-200 hover:border-slate-400"
|
||||
>
|
||||
<option value="1" selected={@historical_hours == "1"}>1 Hour</option>
|
||||
<option value="3" selected={@historical_hours == "3"}>3 Hours</option>
|
||||
|
|
@ -852,17 +844,6 @@ defmodule AprsmeWeb.MapLive.Index do
|
|||
</svg>
|
||||
</div>
|
||||
</form>
|
||||
<p class="text-xs text-slate-500 flex items-center space-x-1">
|
||||
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<span>How many hours of historical packets to load</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Navigation -->
|
||||
|
|
|
|||
|
|
@ -199,14 +199,14 @@ defmodule AprsmeWeb.MapLive.PacketUtils do
|
|||
|
||||
weather_link_html =
|
||||
if has_weather_packets?(packet_info.callsign) do
|
||||
~s( <a href="/weather/#{packet_info.callsign}" class="aprs-info-link">weather charts</a>)
|
||||
~s( <.link navigate="/weather/#{packet_info.callsign}" class="aprs-info-link">weather charts</.link>)
|
||||
else
|
||||
""
|
||||
end
|
||||
|
||||
"""
|
||||
<div class="aprs-popup">
|
||||
<div class="aprs-callsign"><strong><a href="/#{packet_info.callsign}">#{packet_info.callsign}</a></strong> <a href="/info/#{packet_info.callsign}" class="aprs-info-link">info</a>#{weather_link_html}</div>
|
||||
<div class="aprs-callsign"><strong><.link navigate="/#{packet_info.callsign}">#{packet_info.callsign}</.link></strong> <.link navigate="/info/#{packet_info.callsign}" class="aprs-info-link">info</.link>#{weather_link_html}</div>
|
||||
#{comment_html}
|
||||
#{timestamp_html}
|
||||
</div>
|
||||
|
|
@ -234,7 +234,7 @@ defmodule AprsmeWeb.MapLive.PacketUtils do
|
|||
|
||||
"""
|
||||
<div class="aprs-popup" data-timestamp="#{cache_buster}">
|
||||
<div class="aprs-callsign"><strong><a href="/#{sender}">#{sender}</a></strong> <a href="/info/#{sender}" class="aprs-info-link">info</a> <a href="/weather/#{sender}" class="aprs-info-link">weather charts</a></div>
|
||||
<div class="aprs-callsign"><strong><.link navigate="/#{sender}">#{sender}</.link></strong> <.link navigate="/info/#{sender}" class="aprs-info-link">info</.link> <.link navigate="/weather/#{sender}" class="aprs-info-link">weather charts</.link></div>
|
||||
<div class="aprs-comment">Weather Report</div>
|
||||
#{timestamp_html}
|
||||
<hr style="margin-top: 4px; margin-bottom: 4px;">
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ defmodule AprsmeWeb.UserConfirmationInstructionsLive do
|
|||
</.simple_form>
|
||||
|
||||
<p>
|
||||
<.link href={~p"/users/register"}>Register</.link>
|
||||
| <.link href={~p"/users/log_in"}>Log in</.link>
|
||||
<.link navigate={~p"/users/register"}>Register</.link>
|
||||
| <.link navigate={~p"/users/log_in"}>Log in</.link>
|
||||
</p>
|
||||
"""
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ defmodule AprsmeWeb.UserConfirmationLive do
|
|||
</.simple_form>
|
||||
|
||||
<p class="text-center mt-4">
|
||||
<.link href={~p"/users/register"}>Register</.link>
|
||||
| <.link href={~p"/users/log_in"}>Log in</.link>
|
||||
<.link navigate={~p"/users/register"}>Register</.link>
|
||||
| <.link navigate={~p"/users/log_in"}>Log in</.link>
|
||||
</p>
|
||||
</div>
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ defmodule AprsmeWeb.UserForgotPasswordLive do
|
|||
</:actions>
|
||||
</.simple_form>
|
||||
<p class="text-center mt-4">
|
||||
<.link href={~p"/users/register"}>Register</.link>
|
||||
| <.link href={~p"/users/log_in"}>Log in</.link>
|
||||
<.link navigate={~p"/users/register"}>Register</.link>
|
||||
| <.link navigate={~p"/users/log_in"}>Log in</.link>
|
||||
</p>
|
||||
</div>
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ defmodule AprsmeWeb.UserLoginLive do
|
|||
|
||||
<:actions :let={f}>
|
||||
<.input field={{f, :remember_me}} type="checkbox" label="Keep me logged in" />
|
||||
<.link href={~p"/users/reset_password"} class="text-sm font-semibold">
|
||||
<.link navigate={~p"/users/reset_password"} class="text-sm font-semibold">
|
||||
Forgot your password?
|
||||
</.link>
|
||||
</:actions>
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ defmodule AprsmeWeb.UserResetPasswordLive do
|
|||
</.simple_form>
|
||||
|
||||
<p class="text-center mt-4">
|
||||
<.link href={~p"/users/register"}>Register</.link>
|
||||
| <.link href={~p"/users/log_in"}>Log in</.link>
|
||||
<.link navigate={~p"/users/register"}>Register</.link>
|
||||
| <.link navigate={~p"/users/log_in"}>Log in</.link>
|
||||
</p>
|
||||
</div>
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -39,9 +39,6 @@ defmodule AprsmeWeb.Router do
|
|||
live "/about", AboutLive, :index
|
||||
live "/api", ApiDocsLive, :index
|
||||
live "/info/:callsign", InfoLive.Show, :show
|
||||
end
|
||||
|
||||
live_session :map_pages, layout: {AprsmeWeb.Layouts, :map} do
|
||||
live "/", MapLive.Index, :index
|
||||
live "/:callsign", MapLive.CallsignView, :index
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue