first commit

This commit is contained in:
lendry
2026-06-24 14:37:15 +03:00
commit 995adeedd4
188 changed files with 28810 additions and 0 deletions

View File

@@ -0,0 +1,102 @@
'use client';
import { useEffect, useRef } from 'react';
import L from 'leaflet';
const DEFAULT_CENTER = { lat: 55.7558, lng: 37.6173 };
let iconsFixed = false;
function fixLeafletIcons() {
if (iconsFixed || typeof window === 'undefined') return;
iconsFixed = true;
L.Icon.Default.mergeOptions({
iconUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png',
iconRetinaUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon-2x.png',
shadowUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
}
export function AddressMapPicker({
latitude,
longitude,
onPick
}: {
latitude?: number;
longitude?: number;
onPick: (lat: number, lng: number) => void;
}) {
const mapRef = useRef<HTMLDivElement>(null);
const mapInstance = useRef<L.Map | null>(null);
const markerRef = useRef<L.Marker | null>(null);
const onPickRef = useRef(onPick);
useEffect(() => {
onPickRef.current = onPick;
}, [onPick]);
useEffect(() => {
fixLeafletIcons();
if (!mapRef.current || mapInstance.current) return;
const lat = latitude ?? DEFAULT_CENTER.lat;
const lng = longitude ?? DEFAULT_CENTER.lng;
const map = L.map(mapRef.current, { zoomControl: true }).setView([lat, lng], latitude != null ? 16 : 11);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);
const marker = L.marker([lat, lng], { draggable: true }).addTo(map);
const emitPick = (nextLat: number, nextLng: number) => {
onPickRef.current(nextLat, nextLng);
};
marker.on('dragend', () => {
const position = marker.getLatLng();
emitPick(position.lat, position.lng);
});
map.on('click', (event) => {
marker.setLatLng(event.latlng);
emitPick(event.latlng.lat, event.latlng.lng);
});
mapInstance.current = map;
markerRef.current = marker;
const resizeObserver = new ResizeObserver(() => {
map.invalidateSize();
});
resizeObserver.observe(mapRef.current);
return () => {
resizeObserver.disconnect();
map.remove();
mapInstance.current = null;
markerRef.current = null;
};
}, []);
useEffect(() => {
if (!markerRef.current || !mapInstance.current) return;
if (latitude == null || longitude == null) return;
const latLng = L.latLng(latitude, longitude);
markerRef.current.setLatLng(latLng);
mapInstance.current.setView(latLng, Math.max(mapInstance.current.getZoom(), 15));
}, [latitude, longitude]);
return (
<div className="overflow-hidden rounded-2xl border border-[#eceef4]">
<div ref={mapRef} className="h-[280px] w-full" />
<p className="border-t border-[#eceef4] bg-[#fafbfd] px-4 py-2 text-xs text-[#667085]">
Нажмите на карту или перетащите маркер, чтобы указать адрес
</p>
</div>
);
}