mirror of https://github.com/usememos/memos.git
73 lines
2.1 KiB
TypeScript
73 lines
2.1 KiB
TypeScript
import { DivIcon, LatLng } from "leaflet";
|
|
import { MapPinIcon } from "lucide-react";
|
|
import { useEffect, useState } from "react";
|
|
import ReactDOMServer from "react-dom/server";
|
|
import { MapContainer, Marker, TileLayer, useMapEvents } from "react-leaflet";
|
|
|
|
const markerIcon = new DivIcon({
|
|
className: "relative border-none",
|
|
html: ReactDOMServer.renderToString(<MapPinIcon className="absolute bottom-1/2 -left-1/2" fill="pink" size={24} />),
|
|
});
|
|
|
|
interface MarkerProps {
|
|
position: LatLng | undefined;
|
|
onChange: (position: LatLng) => void;
|
|
readonly?: boolean;
|
|
}
|
|
|
|
const LocationMarker = (props: MarkerProps) => {
|
|
const [position, setPosition] = useState(props.position);
|
|
|
|
const map = useMapEvents({
|
|
click(e) {
|
|
if (props.readonly) {
|
|
return;
|
|
}
|
|
|
|
setPosition(e.latlng);
|
|
map.locate();
|
|
// Call the parent onChange function.
|
|
props.onChange(e.latlng);
|
|
},
|
|
locationfound() {},
|
|
});
|
|
|
|
useEffect(() => {
|
|
map.attributionControl.setPrefix("");
|
|
map.attributionControl.addAttribution("<a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a>");
|
|
map.locate();
|
|
}, []);
|
|
|
|
// Keep marker and map in sync with external position updates
|
|
useEffect(() => {
|
|
if (props.position) {
|
|
setPosition(props.position);
|
|
map.setView(props.position);
|
|
} else {
|
|
setPosition(undefined);
|
|
}
|
|
}, [props.position, map]);
|
|
|
|
return position === undefined ? null : <Marker position={position} icon={markerIcon}></Marker>;
|
|
};
|
|
|
|
interface MapProps {
|
|
readonly?: boolean;
|
|
latlng?: LatLng;
|
|
onChange?: (position: LatLng) => void;
|
|
}
|
|
|
|
const DEFAULT_CENTER_LAT_LNG = new LatLng(48.8584, 2.2945);
|
|
|
|
const LeafletMap = (props: MapProps) => {
|
|
const position = props.latlng || DEFAULT_CENTER_LAT_LNG;
|
|
return (
|
|
<MapContainer className="w-full h-72" center={position} zoom={13} scrollWheelZoom={false}>
|
|
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
|
|
<LocationMarker position={position} readonly={props.readonly} onChange={props.onChange ? props.onChange : () => {}} />
|
|
</MapContainer>
|
|
);
|
|
};
|
|
|
|
export default LeafletMap;
|