Spaces:
Runtime error
Runtime error
Commit
·
1170a8f
1
Parent(s):
a93666a
Add a split view, one for maps, one for wiki
Browse files- frontend/src/components/Map.js +158 -26
frontend/src/components/Map.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
| 1 |
-
import React, { useState, useEffect,
|
| 2 |
// useCallback
|
| 3 |
} from 'react';
|
| 4 |
import { MapContainer, TileLayer,
|
| 5 |
useMapEvents,
|
| 6 |
Marker,
|
| 7 |
Popup ,
|
| 8 |
-
|
| 9 |
} from 'react-leaflet';
|
| 10 |
import L from 'leaflet';
|
| 11 |
import 'leaflet/dist/leaflet.css';
|
|
@@ -31,9 +31,58 @@ const ClickHandler = ({ onMapClick }) => {
|
|
| 31 |
const BACKEND_URL = process.env.BACKEND_URL || 'http://localhost:8004';
|
| 32 |
console.log(BACKEND_URL);
|
| 33 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
const Map = ( { onMapClick, searchQuery } ) => {
|
| 35 |
const [markerPosition, setMarkerPosition] = useState([0,0]);
|
| 36 |
const [wikiContent, setWikiContent] = useState(null);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
const fetchWiki = async (pageName) => {
|
| 38 |
try{
|
| 39 |
const res = await fetch(`${BACKEND_URL}/wiki/${pageName}`);
|
|
@@ -54,31 +103,114 @@ const Map = ( { onMapClick, searchQuery } ) => {
|
|
| 54 |
}
|
| 55 |
}, [searchQuery]);
|
| 56 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
return (
|
| 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 |
|
|
|
|
| 1 |
+
import React, { useState, useEffect, useRef
|
| 2 |
// useCallback
|
| 3 |
} from 'react';
|
| 4 |
import { MapContainer, TileLayer,
|
| 5 |
useMapEvents,
|
| 6 |
Marker,
|
| 7 |
Popup ,
|
| 8 |
+
useMap
|
| 9 |
} from 'react-leaflet';
|
| 10 |
import L from 'leaflet';
|
| 11 |
import 'leaflet/dist/leaflet.css';
|
|
|
|
| 31 |
const BACKEND_URL = process.env.BACKEND_URL || 'http://localhost:8004';
|
| 32 |
console.log(BACKEND_URL);
|
| 33 |
|
| 34 |
+
const ResizeHandler = ({ trigger }) => {
|
| 35 |
+
const map = useMap();
|
| 36 |
+
useEffect(() => {
|
| 37 |
+
map.invalidateSize();
|
| 38 |
+
}, [trigger, map]);
|
| 39 |
+
return null;
|
| 40 |
+
};
|
| 41 |
const Map = ( { onMapClick, searchQuery } ) => {
|
| 42 |
const [markerPosition, setMarkerPosition] = useState([0,0]);
|
| 43 |
const [wikiContent, setWikiContent] = useState(null);
|
| 44 |
+
const [panelSize, setPanelSize] = useState('half');
|
| 45 |
+
const [wikiWidth, setWikiWidth] = useState(50);
|
| 46 |
+
const isDragging = useRef(false);
|
| 47 |
+
const startX = useRef(0);
|
| 48 |
+
const startWidth = useRef(0);
|
| 49 |
+
const containerRef = useRef(null);
|
| 50 |
+
|
| 51 |
+
const handleMouseDown = (e) => {
|
| 52 |
+
isDragging.current = true;
|
| 53 |
+
startX.current = e.clientX;
|
| 54 |
+
startWidth.current = wikiWidth;
|
| 55 |
+
document.body.style.cursor = 'col-resize';
|
| 56 |
+
document.body.style.userSelect = 'none';
|
| 57 |
+
};
|
| 58 |
+
|
| 59 |
+
const handleMouseMove = (e) => {
|
| 60 |
+
if (!isDragging.current || !containerRef.current) return;
|
| 61 |
+
|
| 62 |
+
const containerWidth = containerRef.current.offsetWidth;
|
| 63 |
+
const deltaX = e.clientX - startX.current;
|
| 64 |
+
const newWidth = Math.max(20, Math.min(80, startWidth.current + (deltaX / containerWidth * 100)));
|
| 65 |
+
|
| 66 |
+
setWikiWidth(newWidth);
|
| 67 |
+
};
|
| 68 |
+
|
| 69 |
+
const handleMouseUp = () => {
|
| 70 |
+
isDragging.current = false;
|
| 71 |
+
document.body.style.cursor = '';
|
| 72 |
+
document.body.style.userSelect = '';
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
useEffect(() => {
|
| 76 |
+
document.addEventListener('mousemove', handleMouseMove);
|
| 77 |
+
document.addEventListener('mouseup', handleMouseUp);
|
| 78 |
+
|
| 79 |
+
return () => {
|
| 80 |
+
document.removeEventListener('mousemove', handleMouseMove);
|
| 81 |
+
document.removeEventListener('mouseup', handleMouseUp);
|
| 82 |
+
};
|
| 83 |
+
}, []);
|
| 84 |
+
|
| 85 |
+
|
| 86 |
const fetchWiki = async (pageName) => {
|
| 87 |
try{
|
| 88 |
const res = await fetch(`${BACKEND_URL}/wiki/${pageName}`);
|
|
|
|
| 103 |
}
|
| 104 |
}, [searchQuery]);
|
| 105 |
|
| 106 |
+
const togglePanel = () => {
|
| 107 |
+
setPanelSize(prev => {
|
| 108 |
+
if (prev === 'half') return 'half';
|
| 109 |
+
if (prev === 'full') return 'half';
|
| 110 |
+
return 'half';
|
| 111 |
+
});
|
| 112 |
+
};
|
| 113 |
+
|
| 114 |
return (
|
| 115 |
+
<div ref={containerRef} style={{ display: 'flex', height: '100vh', width: '100%', overflow: 'hidden' }}>
|
| 116 |
+
{panelSize !== 'closed' && (
|
| 117 |
+
<>
|
| 118 |
+
<div style={{
|
| 119 |
+
width: `${wikiWidth}%`,
|
| 120 |
+
height: '100%',
|
| 121 |
+
overflow: 'auto',
|
| 122 |
+
padding: '20px',
|
| 123 |
+
backgroundColor: 'white',
|
| 124 |
+
boxShadow: '2px 0 5px rgba(0,0,0,0.1)',
|
| 125 |
+
zIndex: 1000,
|
| 126 |
+
flexShrink: 0
|
| 127 |
+
}}>
|
| 128 |
+
<div style={{ marginBottom: '20px' }}>
|
| 129 |
+
<h2>{wikiContent?.title || 'Search for a location'}</h2>
|
| 130 |
+
</div>
|
| 131 |
+
{wikiContent ? (
|
| 132 |
+
<div>
|
| 133 |
+
<p>{wikiContent.content}</p>
|
| 134 |
+
</div>
|
| 135 |
+
) : (
|
| 136 |
+
<p>Search for a location to see Wikipedia content</p>
|
| 137 |
+
)}
|
| 138 |
+
</div>
|
| 139 |
+
<div
|
| 140 |
+
onMouseDown={handleMouseDown}
|
| 141 |
+
style={{
|
| 142 |
+
width: '8px',
|
| 143 |
+
height: '100%',
|
| 144 |
+
backgroundColor: '#f0f0f0',
|
| 145 |
+
cursor: 'col-resize',
|
| 146 |
+
position: 'relative',
|
| 147 |
+
zIndex: 1001,
|
| 148 |
+
display: 'flex',
|
| 149 |
+
alignItems: 'center',
|
| 150 |
+
justifyContent: 'center',
|
| 151 |
+
flexShrink: 0
|
| 152 |
+
}}
|
| 153 |
+
>
|
| 154 |
+
<div style={{
|
| 155 |
+
width: '2px',
|
| 156 |
+
height: '40px',
|
| 157 |
+
backgroundColor: '#ccc',
|
| 158 |
+
borderRadius: '1px'
|
| 159 |
+
}} />
|
| 160 |
+
</div>
|
| 161 |
+
</>
|
| 162 |
+
)}
|
| 163 |
+
<div style={{
|
| 164 |
+
flex: 1,
|
| 165 |
+
height: '100%',
|
| 166 |
+
position: 'relative',
|
| 167 |
+
minWidth: 0,
|
| 168 |
+
overflow: 'hidden'
|
| 169 |
+
}}>
|
| 170 |
+
<MapContainer
|
| 171 |
+
center={markerPosition}
|
| 172 |
+
zoom={2}
|
| 173 |
+
style={{ height: '100%', width: '100%', position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 }}
|
| 174 |
+
>
|
| 175 |
+
<ResizeHandler trigger={wikiWidth} />
|
| 176 |
+
<TileLayer
|
| 177 |
+
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
| 178 |
+
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
| 179 |
+
/>
|
| 180 |
+
<ClickHandler onMapClick={onMapClick}/>
|
| 181 |
+
<Marker position={markerPosition}>
|
| 182 |
+
<Popup minWidth={250}>
|
| 183 |
+
{wikiContent ? (
|
| 184 |
+
<>
|
| 185 |
+
<strong>{wikiContent.title}</strong><br />
|
| 186 |
+
<p style={{ fontSize: '12px' }}>{wikiContent.content}</p>
|
| 187 |
+
</>
|
| 188 |
+
) : (
|
| 189 |
+
"Search for a location to see information"
|
| 190 |
+
)}
|
| 191 |
+
</Popup>
|
| 192 |
+
</Marker>
|
| 193 |
+
</MapContainer>
|
| 194 |
+
{panelSize === 'closed' && (
|
| 195 |
+
<button
|
| 196 |
+
onClick={togglePanel}
|
| 197 |
+
style={{
|
| 198 |
+
position: 'absolute',
|
| 199 |
+
top: '10px',
|
| 200 |
+
left: '10px',
|
| 201 |
+
zIndex: 1000,
|
| 202 |
+
padding: '5px 10px',
|
| 203 |
+
backgroundColor: 'white',
|
| 204 |
+
border: '1px solid #ccc',
|
| 205 |
+
borderRadius: '4px',
|
| 206 |
+
cursor: 'pointer'
|
| 207 |
+
}}
|
| 208 |
+
>
|
| 209 |
+
Show Wikipedia
|
| 210 |
+
</button>
|
| 211 |
+
)}
|
| 212 |
+
</div>
|
| 213 |
+
</div>
|
| 214 |
);
|
| 215 |
};
|
| 216 |
|