diff --git a/frontend/src/components/MapView.tsx b/frontend/src/components/MapView.tsx index f7d3b29..84105d8 100644 --- a/frontend/src/components/MapView.tsx +++ b/frontend/src/components/MapView.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState, useMemo, useRef, useCallback } from 'react'; +import { Fragment, useEffect, useState, useMemo, useRef, useCallback } from 'react'; import { MapContainer, TileLayer, CircleMarker, Popup, useMap } from 'react-leaflet'; import type { LatLngBoundsExpression, CircleMarker as LeafletCircleMarker } from 'leaflet'; import 'leaflet/dist/leaflet.css'; @@ -13,18 +13,27 @@ interface MapViewProps { focusedKey?: string | null; } +const MAP_RECENCY_COLORS = { + recent: '#06b6d4', + today: '#2563eb', + stale: '#f59e0b', + old: '#64748b', +} as const; +const MAP_MARKER_STROKE = '#0f172a'; +const MAP_REPEATER_RING = '#f8fafc'; + // Calculate marker color based on how recently the contact was heard function getMarkerColor(lastSeen: number | null | undefined): string { - if (lastSeen == null) return '#9ca3af'; + if (lastSeen == null) return MAP_RECENCY_COLORS.old; const now = Date.now() / 1000; const age = now - lastSeen; const hour = 3600; const day = 86400; - if (age < hour) return '#22c55e'; // Bright green - less than 1 hour - if (age < day) return '#4ade80'; // Light green - less than 1 day - if (age < 3 * day) return '#a3e635'; // Yellow-green - less than 3 days - return '#9ca3af'; // Gray - older (up to 7 days) + if (age < hour) return MAP_RECENCY_COLORS.recent; + if (age < day) return MAP_RECENCY_COLORS.today; + if (age < 3 * day) return MAP_RECENCY_COLORS.stale; + return MAP_RECENCY_COLORS.old; } // Component to handle map bounds fitting @@ -147,16 +156,44 @@ export function MapView({ contacts, focusedKey }: MapViewProps) {
-
@@ -188,37 +225,40 @@ export function MapView({ contacts, focusedKey }: MapViewProps) { contact.last_seen != null ? formatTime(contact.last_seen) : 'Never heard by this server'; + const radius = isRepeater ? 10 : 7; return ( - setMarkerRef(contact.public_key, ref)} - center={[contact.lat!, contact.lon!]} - radius={isRepeater ? 10 : 7} - pathOptions={{ - color: isRepeater ? color : '#000', - fillColor: color, - fillOpacity: 0.8, - weight: isRepeater ? 0 : 1, - }} - > - -
-
- {isRepeater && ( - - )} - {displayName} + + setMarkerRef(contact.public_key, ref)} + center={[contact.lat!, contact.lon!]} + radius={radius} + pathOptions={{ + color: isRepeater ? MAP_REPEATER_RING : MAP_MARKER_STROKE, + fillColor: color, + fillOpacity: 0.9, + weight: isRepeater ? 3 : 2, + }} + > + +
+
+ {isRepeater && ( + + )} + {displayName} +
+
Last heard: {lastHeardLabel}
+
+ {contact.lat!.toFixed(5)}, {contact.lon!.toFixed(5)} +
-
Last heard: {lastHeardLabel}
-
- {contact.lat!.toFixed(5)}, {contact.lon!.toFixed(5)} -
-
- - + + + ); })}