-
- {txCount} stations hearing you
-
- {stats.txBands.length > 0 && (
-
- Bands: {stats.txBands.join(', ')}
-
- )}
- {stats.txModes.length > 0 && (
-
- Modes: {stats.txModes.slice(0, 3).join(', ')}
-
- )}
+ {/* Reports list - matches DX Cluster style */}
+ {error ? (
+
+ β οΈ Temporarily unavailable
+
+ ) : loading && reports.length === 0 ? (
+
+ ) : reports.length === 0 ? (
+
+ No {activeTab === 'tx' ? 'reception reports' : 'stations heard'}
+
+ ) : (
+
+ {reports.slice(0, 20).map((report, i) => {
+ const freqMHz = report.freqMHz || (report.freq ? (report.freq / 1000000).toFixed(3) : '?');
+ const color = getFreqColor(freqMHz);
+ const displayCall = activeTab === 'tx' ? report.receiver : report.sender;
+ const grid = activeTab === 'tx' ? report.receiverGrid : report.senderGrid;
+
+ return (
+
onShowOnMap && report.lat && report.lon && onShowOnMap(report)}
+ style={{
+ display: 'grid',
+ gridTemplateColumns: '55px 1fr auto',
+ gap: '6px',
+ padding: '4px 6px',
+ borderRadius: '3px',
+ marginBottom: '2px',
+ background: i % 2 === 0 ? 'rgba(255,255,255,0.03)' : 'transparent',
+ cursor: report.lat && report.lon ? 'pointer' : 'default',
+ transition: 'background 0.15s',
+ borderLeft: '2px solid transparent'
+ }}
+ onMouseEnter={(e) => e.currentTarget.style.background = 'rgba(68, 136, 255, 0.15)'}
+ onMouseLeave={(e) => e.currentTarget.style.background = i % 2 === 0 ? 'rgba(255,255,255,0.03)' : 'transparent'}
+ >
+
+ {freqMHz}
-
- )}
-
- {/* Reports list */}
-
- {reports.slice(0, 25).map((report, idx) => (
-
onShowOnMap && report.lat && report.lon && onShowOnMap(report)}
- style={{
- display: 'grid',
- gridTemplateColumns: '1fr auto auto auto',
- gap: '8px',
- padding: '6px 8px',
- background: 'var(--bg-tertiary)',
- borderRadius: '4px',
- fontSize: '0.75rem',
- cursor: report.lat && report.lon ? 'pointer' : 'default',
- alignItems: 'center'
- }}
- >
-
-
- {activeTab === 'tx' ? report.receiver : report.sender}
-
- {(activeTab === 'tx' ? report.receiverGrid : report.senderGrid) && (
-
- {activeTab === 'tx' ? report.receiverGrid : report.senderGrid}
-
- )}
-
-
-
- {report.freqMHz} {report.band}
-
-
-
- {report.mode}
-
-
-
- {report.snr !== null && (
-
- {report.snr > 0 ? '+' : ''}{report.snr}dB
-
- )}
+
+ {displayCall}
+ {grid && {grid}}
+
+
+ {report.mode}
+ {report.snr !== null && report.snr !== undefined && (
= 0 ? '#4ade80' : report.snr >= -10 ? '#fbbf24' : '#f97316',
+ fontWeight: '600'
}}>
- {formatAge(report.age)}
+ {report.snr > 0 ? '+' : ''}{report.snr}
-
+ )}
+
+ {formatAge(report.age)}
+
- ))}
-
-
- {reports.length > 25 && (
-
- Showing 25 of {reports.length} reports
- )}
- >
- )}
-
-
- {/* Footer with last update */}
- {lastUpdate && (
-
- Updated: {lastUpdate.toLocaleTimeString()}
+ );
+ })}
)}
diff --git a/src/components/WorldMap.jsx b/src/components/WorldMap.jsx
index 6ad138d..7a349e8 100644
--- a/src/components/WorldMap.jsx
+++ b/src/components/WorldMap.jsx
@@ -21,11 +21,13 @@ export const WorldMap = ({
dxPaths,
dxFilters,
satellites,
+ pskReporterSpots,
showDXPaths,
showDXLabels,
onToggleDXLabels,
showPOTA,
showSatellites,
+ showPSKReporter,
onToggleSatellites,
hoveredSpot
}) => {
@@ -44,6 +46,7 @@ export const WorldMap = ({
const dxPathsMarkersRef = useRef([]);
const satMarkersRef = useRef([]);
const satTracksRef = useRef([]);
+ const pskMarkersRef = useRef([]);
// Load map style from localStorage
const getStoredMapSettings = () => {
@@ -416,6 +419,55 @@ export const WorldMap = ({
}
}, [satellites, showSatellites]);
+ // Update PSKReporter markers
+ useEffect(() => {
+ if (!mapInstanceRef.current) return;
+ const map = mapInstanceRef.current;
+
+ pskMarkersRef.current.forEach(m => map.removeLayer(m));
+ pskMarkersRef.current = [];
+
+ if (showPSKReporter && pskReporterSpots && pskReporterSpots.length > 0 && deLocation) {
+ pskReporterSpots.forEach(spot => {
+ if (spot.lat && spot.lon) {
+ const displayCall = spot.receiver || spot.sender;
+ const freqMHz = spot.freqMHz || (spot.freq ? (spot.freq / 1000000).toFixed(3) : '?');
+ const bandColor = getBandColor(parseFloat(freqMHz));
+
+ // Draw line from DE to spot location
+ const points = getGreatCirclePoints(
+ [deLocation.lat, deLocation.lon],
+ [spot.lat, spot.lon],
+ 50
+ );
+
+ const line = L.polyline(points, {
+ color: bandColor,
+ weight: 1.5,
+ opacity: 0.5,
+ dashArray: '4, 4'
+ }).addTo(map);
+ pskMarkersRef.current.push(line);
+
+ // Add small dot marker at spot location
+ const circle = L.circleMarker([spot.lat, spot.lon], {
+ radius: 4,
+ fillColor: bandColor,
+ color: '#fff',
+ weight: 1,
+ opacity: 0.9,
+ fillOpacity: 0.8
+ }).bindPopup(`
+
${displayCall}
+ ${spot.mode} @ ${freqMHz} MHz
+ ${spot.snr !== null ? `SNR: ${spot.snr > 0 ? '+' : ''}${spot.snr} dB` : ''}
+ `).addTo(map);
+ pskMarkersRef.current.push(circle);
+ }
+ });
+ }
+ }, [pskReporterSpots, showPSKReporter, deLocation]);
+
return (