diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js
index b7e6d17..fe2de8f 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js
@@ -3755,7 +3755,7 @@ const decodeContactPaths = new Map();
const mapMarkers = new Set();
const DEFAULT_MAP_SOURCE_FILTER = { ais: true, vdes: true, aprs: true, bookmark: false, ft8: true, wspr: true };
const mapFilter = { ...DEFAULT_MAP_SOURCE_FILTER };
-const mapLocatorFilter = { phase: "type", bands: new Set() };
+const mapLocatorFilter = { phase: "band", bands: new Set() };
let mapSearchFilter = "";
const APRS_TRACK_MAX_POINTS = 64;
const AIS_TRACK_MAX_POINTS = 64;
@@ -4303,11 +4303,30 @@ function renderMapLocatorPhaseRow(container, phase) {
}
}
+function renderMapBandLegend(items) {
+ const legendEl = document.getElementById("map-band-legend");
+ if (!legendEl) return;
+ const bandItems = Array.isArray(items) ? items : [];
+ if (bandItems.length === 0) {
+ legendEl.classList.add("is-empty");
+ legendEl.innerHTML = "";
+ return;
+ }
+ legendEl.classList.remove("is-empty");
+ const rows = bandItems
+ .map((item) => {
+ const label = escapeMapHtml(item.label);
+ const color = escapeMapHtml(item.color);
+ return `${label}`;
+ })
+ .join("");
+ legendEl.innerHTML = `
Band Colors
${rows}
`;
+}
+
function rebuildMapLocatorFilters() {
const phaseEl = document.getElementById("map-locator-phase");
const choiceEl = document.getElementById("map-locator-choice-filter");
const choiceLabelEl = document.getElementById("map-locator-choice-label");
- if (!phaseEl || !choiceEl || !choiceLabelEl) return;
const availableSources = new Set();
if (aisMarkers.size > 0) availableSources.add("ais");
@@ -4360,6 +4379,9 @@ function rebuildMapLocatorFilters() {
const bandItems = Array.from(bandMap.values())
.sort((a, b) => (b.sortHz - a.sortHz) || a.label.localeCompare(b.label));
+ renderMapBandLegend(bandItems);
+ if (!phaseEl || !choiceEl || !choiceLabelEl) return;
+
renderMapLocatorPhaseRow(phaseEl, mapLocatorFilter.phase);
if (mapLocatorFilter.phase === "band") {
choiceLabelEl.textContent = "Visible Bands";
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html
index 5752f0f..f733d17 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html
@@ -698,6 +698,7 @@
+
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css
index 2778a55..b862205 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css
@@ -1314,6 +1314,61 @@ small { color: var(--text-muted); }
border-color: color-mix(in srgb, var(--accent-green) 34%, var(--border-light));
color: var(--text-heading);
}
+.map-band-legend {
+ position: absolute;
+ left: 0.7rem;
+ bottom: 0.7rem;
+ z-index: 410;
+ display: flex;
+ flex-direction: column;
+ gap: 0.45rem;
+ width: min(14rem, calc(100% - 5.8rem));
+ max-height: min(40%, 18rem);
+ padding: 0.65rem 0.7rem;
+ border-radius: 0.8rem;
+ border: 1px solid color-mix(in srgb, var(--border-light) 74%, transparent);
+ background: color-mix(in srgb, var(--card-bg) 78%, transparent);
+ box-shadow: 0 16px 30px rgba(0, 0, 0, 0.2);
+ backdrop-filter: blur(14px);
+ -webkit-backdrop-filter: blur(14px);
+ overflow: auto;
+}
+.map-band-legend.is-empty {
+ display: none;
+}
+.map-band-legend-title {
+ font-size: 0.72rem;
+ font-weight: 800;
+ letter-spacing: 0.1em;
+ text-transform: uppercase;
+ color: var(--text-muted);
+}
+.map-band-legend-list {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(5.4rem, 1fr));
+ gap: 0.35rem 0.55rem;
+}
+.map-band-legend-item {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.4rem;
+ min-width: 0;
+}
+.map-band-legend-swatch {
+ flex: 0 0 auto;
+ width: 0.78rem;
+ height: 0.78rem;
+ border-radius: 999px;
+ background: var(--legend-color, var(--accent-green));
+ box-shadow: 0 0 0 1px color-mix(in srgb, var(--legend-color, var(--accent-green)) 44%, rgba(255, 255, 255, 0.18));
+}
+.map-band-legend-text {
+ min-width: 0;
+ font-size: 0.76rem;
+ font-weight: 700;
+ color: var(--text);
+ white-space: nowrap;
+}
#map-stage:fullscreen,
#map-stage:-webkit-full-screen,
#map-stage.map-fake-fullscreen {
@@ -2321,6 +2376,17 @@ button:focus-visible, input:focus-visible, select:focus-visible {
top: 0.55rem;
right: 0.55rem;
}
+ .map-band-legend {
+ left: 0.55rem;
+ bottom: 0.55rem;
+ width: min(12rem, calc(100% - 1.1rem));
+ max-height: min(36%, 13rem);
+ padding: 0.55rem 0.6rem;
+ border-radius: 0.7rem;
+ }
+ .map-band-legend-list {
+ grid-template-columns: repeat(auto-fit, minmax(4.8rem, 1fr));
+ }
.map-locator-filter-group {
align-items: stretch;
}