[feat](trx-frontend-http): clicking APRS bar coords navigates to Map

Add window.navigateToAprsMap(lat, lon) which activates the Map tab
and pans to the given position at zoom 13. APRS bar frames that carry
a position render a clickable coordinate button that calls this
function. Button is styled inline with the frame text.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
2026-03-01 14:49:04 +01:00
parent 8ffe73c539
commit 37966ea29a
3 changed files with 24 additions and 1 deletions
@@ -2469,6 +2469,24 @@ function aprsSymbolIcon(symbolTable, symbolCode) {
}); });
} }
window.navigateToAprsMap = function(lat, lon) {
// Activate the map tab
document.querySelectorAll(".tab-bar .tab").forEach((t) => t.classList.remove("active"));
const mapTabBtn = document.querySelector(".tab-bar .tab[data-tab='map']");
if (mapTabBtn) mapTabBtn.classList.add("active");
document.querySelectorAll(".tab-panel").forEach((p) => (p.style.display = "none"));
const mapPanel = document.getElementById("tab-map");
if (mapPanel) mapPanel.style.display = "";
initAprsMap();
sizeAprsMapToViewport();
if (aprsMap) {
setTimeout(() => {
aprsMap.invalidateSize();
aprsMap.setView([lat, lon], 13);
}, 50);
}
};
window.aprsMapAddStation = function(call, lat, lon, info, symbolTable, symbolCode) { window.aprsMapAddStation = function(call, lat, lon, info, symbolTable, symbolCode) {
if (!aprsMap) initAprsMap(); if (!aprsMap) initAprsMap();
if (!aprsMap) return; if (!aprsMap) return;
@@ -118,7 +118,10 @@ function updateAprsBar() {
const call = `<span class="aprs-bar-call">${escapeMapHtml(pkt.srcCall)}</span>`; const call = `<span class="aprs-bar-call">${escapeMapHtml(pkt.srcCall)}</span>`;
const dest = escapeMapHtml(pkt.destCall || ""); const dest = escapeMapHtml(pkt.destCall || "");
const info = escapeMapHtml(pkt.info || ""); const info = escapeMapHtml(pkt.info || "");
html += `<div class="aprs-bar-frame">${ts}${call}>${dest}: ${info}</div>`; const posHtml = pkt.lat != null && pkt.lon != null
? ` <button class="aprs-bar-pos" onclick="window.navigateToAprsMap(${pkt.lat},${pkt.lon})">${pkt.lat.toFixed(4)}, ${pkt.lon.toFixed(4)}</button>`
: "";
html += `<div class="aprs-bar-frame">${ts}${call}>${dest}: ${info}${posHtml}</div>`;
} }
aprsBarOverlay.innerHTML = html; aprsBarOverlay.innerHTML = html;
aprsBarOverlay.style.display = "flex"; aprsBarOverlay.style.display = "flex";
@@ -984,6 +984,8 @@ small { color: var(--text-muted); }
.aprs-symbol { display: inline-block; width: 24px; height: 24px; background-size: 384px 192px; vertical-align: middle; margin-right: 0.3rem; } .aprs-symbol { display: inline-block; width: 24px; height: 24px; background-size: 384px 192px; vertical-align: middle; margin-right: 0.3rem; }
.aprs-pos { color: var(--accent-green); text-decoration: none; margin-left: 0.3rem; font-size: 0.8rem; } .aprs-pos { color: var(--accent-green); text-decoration: none; margin-left: 0.3rem; font-size: 0.8rem; }
.aprs-pos:hover { text-decoration: underline; } .aprs-pos:hover { text-decoration: underline; }
.aprs-bar-pos { background: none; border: none; padding: 0; margin-left: 0.4em; font-family: inherit; font-size: inherit; color: var(--accent-green); cursor: pointer; }
.aprs-bar-pos:hover { text-decoration: underline; }
.aprs-byte { color: var(--accent-yellow); background: rgba(255, 214, 0, 0.12); border: 1px solid rgba(255, 214, 0, 0.25); border-radius: 4px; padding: 0 0.2rem; margin: 0 0.1rem; font-size: 0.78em; } .aprs-byte { color: var(--accent-yellow); background: rgba(255, 214, 0, 0.12); border: 1px solid rgba(255, 214, 0, 0.25); border-radius: 4px; padding: 0 0.2rem; margin: 0 0.1rem; font-size: 0.78em; }
.ft8-controls { display: flex; gap: 0.6rem; align-items: center; margin-bottom: 0.75rem; } .ft8-controls { display: flex; gap: 0.6rem; align-items: center; margin-bottom: 0.75rem; }
.ft8-filter { .ft8-filter {