@@ -67,6 +67,7 @@ const MapPage = () => {
6767 const defaultLinePathsRef = useRef < [ number , number ] [ ] [ ] > ( [ ] ) ;
6868 const pendingPinkMarkerRef = useRef < L . Marker | null > ( null ) ;
6969 const pendingMemorialMarkerRef = useRef < L . Marker | null > ( null ) ;
70+ const centralSiteRef = useRef < PendingSite | null > ( null ) ;
7071
7172 useEffect ( ( ) => {
7273 activeProjectRef . current = activeProject ;
@@ -76,6 +77,10 @@ const MapPage = () => {
7677 activeMemorialTypeRef . current = activeMemorialType ;
7778 } , [ activeMemorialType ] ) ;
7879
80+ useEffect ( ( ) => {
81+ centralSiteRef . current = centralSite ;
82+ } , [ centralSite ] ) ;
83+
7984 useEffect ( ( ) => {
8085 const bootstrap = async ( ) => {
8186 try {
@@ -140,6 +145,12 @@ const MapPage = () => {
140145 setPendingPinkTarget ( { lat : e . latlng . lat , lng : e . latlng . lng } ) ;
141146 return ;
142147 }
148+ if ( activeMemorialTypeRef . current === "central" && centralSiteRef . current ) {
149+ if ( ! confirm ( "ניתן לבחור רק אנדרטה מרכזית אחת. האם להחליף את הקיימת?" ) ) {
150+ return ;
151+ }
152+ setCentralSite ( null ) ;
153+ }
143154 setPendingMemorialTarget ( {
144155 lat : e . latlng . lat ,
145156 lng : e . latlng . lng ,
@@ -320,6 +331,65 @@ const MapPage = () => {
320331 } ;
321332 const isEntryModalOpen = Boolean ( pendingPinkTarget || pendingMemorialTarget ) ;
322333
334+ const ghostRef = useRef < HTMLDivElement | null > ( null ) ;
335+
336+ const handleToolbarDragStart = ( e : React . PointerEvent , type : "central" | "local" ) => {
337+ const startX = e . clientX ;
338+ const startY = e . clientY ;
339+ let dragging = false ;
340+ const iconSrc = type === "central" ? regionalMemorialIconUrl : localMemorialIconUrl ;
341+
342+ const onMove = ( ev : PointerEvent ) => {
343+ if ( ! dragging ) {
344+ const dx = ev . clientX - startX ;
345+ const dy = ev . clientY - startY ;
346+ if ( dx * dx + dy * dy < 25 ) return ;
347+ dragging = true ;
348+ const ghost = document . createElement ( "div" ) ;
349+ ghost . style . cssText = "position:fixed;pointer-events:none;z-index:10000;opacity:0.85;transform:translate(-50%,-50%)" ;
350+ const img = document . createElement ( "img" ) ;
351+ img . src = iconSrc ;
352+ img . style . cssText = "width:40px;height:40px;filter:drop-shadow(0 2px 6px rgba(0,0,0,0.4))" ;
353+ ghost . appendChild ( img ) ;
354+ document . body . appendChild ( ghost ) ;
355+ ghostRef . current = ghost ;
356+ }
357+ if ( ghostRef . current ) {
358+ ghostRef . current . style . left = `${ ev . clientX } px` ;
359+ ghostRef . current . style . top = `${ ev . clientY } px` ;
360+ }
361+ } ;
362+
363+ const onUp = ( ev : PointerEvent ) => {
364+ document . removeEventListener ( "pointermove" , onMove ) ;
365+ document . removeEventListener ( "pointerup" , onUp ) ;
366+ if ( ghostRef . current ) {
367+ ghostRef . current . remove ( ) ;
368+ ghostRef . current = null ;
369+ }
370+ if ( ! dragging || ! mapRef . current ) return ;
371+
372+ const mapEl = document . getElementById ( "map" ) ;
373+ if ( ! mapEl ) return ;
374+ const rect = mapEl . getBoundingClientRect ( ) ;
375+ const x = ev . clientX - rect . left ;
376+ const y = ev . clientY - rect . top ;
377+ if ( x < 0 || y < 0 || x > rect . width || y > rect . height ) return ;
378+
379+ const latlng = mapRef . current . containerPointToLatLng ( [ x , y ] ) ;
380+
381+ if ( type === "central" && centralSiteRef . current ) {
382+ if ( ! confirm ( "ניתן לבחור רק אנדרטה מרכזית אחת. האם להחליף את הקיימת?" ) ) return ;
383+ setCentralSite ( null ) ;
384+ }
385+
386+ setPendingMemorialTarget ( { lat : latlng . lat , lng : latlng . lng , type } ) ;
387+ } ;
388+
389+ document . addEventListener ( "pointermove" , onMove ) ;
390+ document . addEventListener ( "pointerup" , onUp ) ;
391+ } ;
392+
323393 const handleClearPink = ( ) => {
324394 if ( pinkNodes . length === 0 ) return ;
325395 if ( ! confirm ( "למחוק את כל נקודות הקו הוורוד?" ) ) return ;
@@ -490,14 +560,15 @@ const MapPage = () => {
490560 type = "button"
491561 className = { `memorial-toolbar-section ${ activeMemorialType === "central" ? "memorial-toolbar-active" : "" } ` }
492562 onClick = { ( ) => setActiveMemorialType ( "central" ) }
563+ onPointerDown = { ( e ) => handleToolbarDragStart ( e , "central" ) }
493564 >
494565 < div className = "memorial-toolbar-drag-item" >
495- < img src = { regionalMemorialIconUrl } alt = "" className = "memorial-toolbar-icon" />
566+ < img src = { regionalMemorialIconUrl } alt = "" className = "memorial-toolbar-icon" draggable = { false } />
496567 </ div >
497568 < div className = "memorial-toolbar-item-text" >
498569 < span className = "memorial-toolbar-item-label" > אנדרטה מרכזית אזורית</ span >
499570 < span className = "memorial-toolbar-item-value" >
500- { centralSite ? centralSite . name || "—" : "ניתן לבחור אחת בלבד " }
571+ { centralSite ? centralSite . name || "—" : "גררו למפה או לחצו " }
501572 </ span >
502573 </ div >
503574 </ button >
@@ -508,13 +579,14 @@ const MapPage = () => {
508579 type = "button"
509580 className = { `memorial-toolbar-section ${ activeMemorialType === "local" ? "memorial-toolbar-active" : "" } ` }
510581 onClick = { ( ) => setActiveMemorialType ( "local" ) }
582+ onPointerDown = { ( e ) => handleToolbarDragStart ( e , "local" ) }
511583 >
512584 < div className = "memorial-toolbar-drag-item" >
513- < img src = { localMemorialIconUrl } alt = "" className = "memorial-toolbar-icon" />
585+ < img src = { localMemorialIconUrl } alt = "" className = "memorial-toolbar-icon" draggable = { false } />
514586 </ div >
515587 < div className = "memorial-toolbar-item-text" >
516588 < span className = "memorial-toolbar-item-label" > אנדרטות מקומיות ({ localSites . length } )</ span >
517- < span className = "memorial-toolbar-item-value" > לחצו על המפה להוספה </ span >
589+ < span className = "memorial-toolbar-item-value" > גררו למפה או לחצו </ span >
518590 </ div >
519591 </ button >
520592
0 commit comments