forked from BasedHardware/omi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSingleLocationMap.tsx
More file actions
115 lines (104 loc) · 4 KB
/
Copy pathSingleLocationMap.tsx
File metadata and controls
115 lines (104 loc) · 4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
'use client';
import { useEffect, useRef } from 'react';
import { MapContainer, TileLayer, Marker, Popup, useMap, ZoomControl } from 'react-leaflet';
import L from 'leaflet';
import { ExternalLink } from 'lucide-react';
// Create simple marker icon
function createMarkerIcon() {
return L.divIcon({
className: 'custom-marker',
html: `<div style="
width: 24px;
height: 24px;
background: #8B5CF6;
border: 2px solid white;
border-radius: 50%;
box-shadow: 0 2px 8px rgba(139, 92, 246, 0.4);
"></div>`,
iconSize: [24, 24],
iconAnchor: [12, 12],
popupAnchor: [0, -12],
});
}
interface SingleLocationMapProps {
latitude: number;
longitude: number;
address?: string | null;
height?: number | string;
className?: string;
}
// Component to set view and handle container resize
function SetView({ latitude, longitude }: { latitude: number; longitude: number }) {
const map = useMap();
const isMountedRef = useRef(true);
useEffect(() => {
isMountedRef.current = true;
// Stop any ongoing animations before setting view
map.stop();
map.setView([latitude, longitude], 15, { animate: false });
// Small delay to ensure container is properly sized
const timeout = setTimeout(() => {
if (isMountedRef.current) {
map.invalidateSize();
}
}, 100);
return () => {
isMountedRef.current = false;
clearTimeout(timeout);
// Stop animations on unmount to prevent errors
try {
map.stop();
} catch {
// Ignore - map already disposed
}
};
}, [map, latitude, longitude]);
return null;
}
export default function SingleLocationMap({
latitude,
longitude,
address,
height = 280,
className,
}: SingleLocationMapProps) {
const openStreetMapUrl = `https://www.openstreetmap.org/?mlat=${latitude}&mlon=${longitude}#map=15/${latitude}/${longitude}`;
return (
<div
className={className}
style={{ height: typeof height === 'number' ? `${height}px` : height, width: '100%' }}
>
<MapContainer
center={[latitude, longitude]}
zoom={15}
style={{ height: '100%', width: '100%' }}
scrollWheelZoom={false}
zoomControl={false}
className="z-0 [&_.leaflet-control-zoom]:!border-none [&_.leaflet-control-zoom]:!rounded-lg [&_.leaflet-control-zoom]:!bg-bg-tertiary/80 [&_.leaflet-control-zoom]:!backdrop-blur-sm [&_.leaflet-control-zoom-in]:!text-text-secondary [&_.leaflet-control-zoom-in]:!bg-transparent [&_.leaflet-control-zoom-in]:!border-none [&_.leaflet-control-zoom-in]:!w-8 [&_.leaflet-control-zoom-in]:!h-8 [&_.leaflet-control-zoom-in]:!leading-8 [&_.leaflet-control-zoom-out]:!text-text-secondary [&_.leaflet-control-zoom-out]:!bg-transparent [&_.leaflet-control-zoom-out]:!border-none [&_.leaflet-control-zoom-out]:!w-8 [&_.leaflet-control-zoom-out]:!h-8 [&_.leaflet-control-zoom-out]:!leading-8 hover:[&_.leaflet-control-zoom-in]:!text-text-primary hover:[&_.leaflet-control-zoom-out]:!text-text-primary"
>
<ZoomControl position="bottomright" />
<TileLayer
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
url="https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png"
/>
<SetView latitude={latitude} longitude={longitude} />
<Marker position={[latitude, longitude]} icon={createMarkerIcon()}>
<Popup className="dark-popup">
<div className="text-sm">
{address && <p className="font-medium text-gray-900 mb-2">{address}</p>}
<a
href={openStreetMapUrl}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1 text-xs text-text-secondary hover:text-text-primary transition-colors"
>
<ExternalLink className="w-3 h-3" />
<span>Open in maps</span>
</a>
</div>
</Popup>
</Marker>
</MapContainer>
</div>
);
}