diff --git a/config.example.json b/config.example.json index 8c7549a..cbd82f9 100644 --- a/config.example.json +++ b/config.example.json @@ -36,8 +36,7 @@ "SJC": "San Jose, US", "SFO": "San Francisco, US", "OAK": "Oakland, US", - "MRY": "Monterey, US", - "LAR": "Los Angeles, US" + "MRY": "Monterey, US" }, "cacheTTL": { "stats": 10, diff --git a/public/index.html b/public/index.html index 608548d..6354d74 100644 --- a/public/index.html +++ b/public/index.html @@ -22,7 +22,7 @@ - + - - + + - - + + diff --git a/public/live.js b/public/live.js index 67add0e..c9cf816 100644 --- a/public/live.js +++ b/public/live.js @@ -908,8 +908,8 @@ const topNav = document.querySelector('.top-nav'); if (topNav) { topNav.style.position = 'fixed'; topNav.style.width = '100%'; topNav.style.zIndex = '1100'; } _navCleanup = { timeout: null, fn: null, pinned: false }; - // Add pin button to nav - if (topNav) { + // Add pin button to nav (guard against duplicate) + if (topNav && !document.getElementById('navPinBtn')) { const pinBtn = document.createElement('button'); pinBtn.id = 'navPinBtn'; pinBtn.className = 'nav-pin-btn'; @@ -1466,6 +1466,8 @@ if (appEl) appEl.style.height = ''; const topNav = document.querySelector('.top-nav'); if (topNav) { topNav.classList.remove('nav-autohide'); topNav.style.position = ''; topNav.style.width = ''; topNav.style.zIndex = ''; } + const existingPin = document.getElementById('navPinBtn'); + if (existingPin) existingPin.remove(); if (_navCleanup) { clearTimeout(_navCleanup.timeout); const livePage = document.querySelector('.live-page'); diff --git a/public/map.js b/public/map.js index 4051131..3e0fc58 100644 --- a/public/map.js +++ b/public/map.js @@ -105,10 +105,21 @@ try { const v = JSON.parse(savedView); initCenter = [v.lat, v.lng]; initZoom = v.zoom; } catch {} } map = L.map('leaflet-map', { zoomControl: true }).setView(initCenter, initZoom); - L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { - attribution: '© OpenStreetMap', + + const DARK_TILES = 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png'; + const LIGHT_TILES = 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png'; + const isDark = document.documentElement.getAttribute('data-theme') === 'dark' || + (document.documentElement.getAttribute('data-theme') !== 'light' && window.matchMedia('(prefers-color-scheme: dark)').matches); + const tileLayer = L.tileLayer(isDark ? DARK_TILES : LIGHT_TILES, { + attribution: '© OpenStreetMap © CartoDB', maxZoom: 19, }).addTo(map); + const _mapThemeObs = new MutationObserver(function () { + const dark = document.documentElement.getAttribute('data-theme') === 'dark' || + (document.documentElement.getAttribute('data-theme') !== 'light' && window.matchMedia('(prefers-color-scheme: dark)').matches); + tileLayer.setUrl(dark ? DARK_TILES : LIGHT_TILES); + }); + _mapThemeObs.observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] }); // Save position on move map.on('moveend', () => { diff --git a/public/observers.js b/public/observers.js index c942dfc..9dbe58d 100644 --- a/public/observers.js +++ b/public/observers.js @@ -113,7 +113,7 @@ ${o.iata ? `${o.iata}` : '—'} ${timeAgo(o.last_seen)} ${(o.packet_count || 0).toLocaleString()} - ${sparkBar(o.packetsLastHour || 0, maxPktsHr)} + ${sparkBar(o.packetsLastHour || 0, maxPktsHr)} ${uptimeStr(o.first_seen)} `; }).join('')} diff --git a/public/packets.js b/public/packets.js index 4fc139e..72ca31e 100644 --- a/public/packets.js +++ b/public/packets.js @@ -598,10 +598,11 @@ try { const d = JSON.parse(p.decoded_json || '{}'); const pathHops = JSON.parse(p.path_json || '[]'); - // Check if any node key in decoded data or path matches - return (d.pubkey && allKeys.has(d.pubkey)) || - (d.to && allKeys.has(d.to)) || - (d.from && allKeys.has(d.from)) || + return (d.pubKey && allKeys.has(d.pubKey)) || + (d.srcPubKey && allKeys.has(d.srcPubKey)) || + (d.destPubKey && allKeys.has(d.destPubKey)) || + (d.srcHash && allKeys.has(d.srcHash)) || + (d.destHash && allKeys.has(d.destHash)) || pathHops.some(h => allKeys.has(h)); } catch { return false; } });