@@ -732,6 +732,26 @@ const App: React.FC = () => {
732732 const [ isDragging , setIsDragging ] = useState ( false ) ;
733733 const [ dragStart , setDragStart ] = useState ( { x : 0 , y : 0 } ) ;
734734
735+ // Lightbox control handlers - memoized for performance
736+ const handleLightboxShrink = useCallback ( ( ) => {
737+ setLightboxScale ( s => Math . max ( 0.25 , s - 0.25 ) ) ;
738+ } , [ ] ) ;
739+
740+ const handleLightboxReset = useCallback ( ( ) => {
741+ setLightboxScale ( 1 ) ;
742+ setLightboxOffset ( { x : 0 , y : 0 } ) ;
743+ } , [ ] ) ;
744+
745+ const handleLightboxEnlarge = useCallback ( ( ) => {
746+ setLightboxScale ( s => Math . min ( 4 , s + 0.25 ) ) ;
747+ } , [ ] ) ;
748+
749+ const handleLightboxClose = useCallback ( ( ) => {
750+ setLightboxImage ( null ) ;
751+ setLightboxOffset ( { x : 0 , y : 0 } ) ;
752+ setLightboxScale ( 1 ) ;
753+ } , [ ] ) ;
754+
735755 // Calculate actual list width from ratio (Moved up)
736756
737757
@@ -1099,7 +1119,7 @@ const App: React.FC = () => {
10991119 }
11001120 } , [ selectedIssue ] ) ;
11011121
1102- // Lightbox keyboard and wheel handlers
1122+ // Lightbox keyboard handlers
11031123 useEffect ( ( ) => {
11041124 if ( ! lightboxImage ) return ;
11051125
@@ -1127,21 +1147,10 @@ const App: React.FC = () => {
11271147 }
11281148 } ;
11291149
1130- const handleWheel = ( e : WheelEvent ) => {
1131- e . preventDefault ( ) ;
1132- if ( e . deltaY < 0 ) {
1133- setLightboxScale ( s => Math . min ( 4 , s + 0.1 ) ) ;
1134- } else {
1135- setLightboxScale ( s => Math . max ( 0.25 , s - 0.1 ) ) ;
1136- }
1137- } ;
1138-
11391150 window . addEventListener ( 'keydown' , handleKeyDown ) ;
1140- window . addEventListener ( 'wheel' , handleWheel , { passive : false } ) ;
11411151
11421152 return ( ) => {
11431153 window . removeEventListener ( 'keydown' , handleKeyDown ) ;
1144- window . removeEventListener ( 'wheel' , handleWheel ) ;
11451154 } ;
11461155 } , [ lightboxImage ] ) ;
11471156
@@ -2564,37 +2573,61 @@ const App: React.FC = () => {
25642573 { /* Modals & Overlays */ }
25652574 {
25662575 lightboxImage && (
2567- < div className = "image-lightbox-overlay" onClick = { ( ) => { setLightboxImage ( null ) ; setLightboxOffset ( { x : 0 , y : 0 } ) ; setLightboxScale ( 1 ) ; } }
2576+ < div
2577+ className = "image-lightbox-overlay"
2578+ onClick = { handleLightboxClose }
2579+ onWheel = { ( e ) => {
2580+ e . preventDefault ( ) ;
2581+ const delta = e . deltaY ;
2582+ if ( delta < 0 ) {
2583+ setLightboxScale ( s => Math . min ( 4 , s + 0.1 ) ) ;
2584+ } else {
2585+ setLightboxScale ( s => Math . max ( 0.25 , s - 0.1 ) ) ;
2586+ }
2587+ } }
25682588 onMouseMove = { ( e ) => {
25692589 if ( isDragging ) {
2570- setLightboxOffset ( o => ( {
2571- x : o . x + e . movementX ,
2572- y : o . y + e . movementY
2573- } ) ) ;
2590+ setLightboxOffset ( {
2591+ x : e . clientX - dragStart . x ,
2592+ y : e . clientY - dragStart . y
2593+ } ) ;
25742594 }
25752595 } }
25762596 onMouseUp = { ( ) => setIsDragging ( false ) }
25772597 onMouseLeave = { ( ) => setIsDragging ( false ) }
25782598 >
2579- < AuthenticatedImage
2580- src = { lightboxImage }
2581- alt = "Enlarged"
2582- fetchBlob = { ( u ) => vm . fetchImageBlob ( u ) }
2583- className = "image-lightbox-content"
2599+ < div
2600+ onClick = { ( e ) => e . stopPropagation ( ) }
2601+ onMouseDown = { ( e ) => {
2602+ e . preventDefault ( ) ;
2603+ e . stopPropagation ( ) ;
2604+ setIsDragging ( true ) ;
2605+ setDragStart ( { x : e . clientX - lightboxOffset . x , y : e . clientY - lightboxOffset . y } ) ;
2606+ } }
25842607 style = { {
2585- transform : `translate(${ lightboxOffset . x } px, ${ lightboxOffset . y } px) scale(${ lightboxScale } )` ,
25862608 cursor : isDragging ? 'grabbing' : 'grab' ,
25872609 userSelect : 'none' ,
2588- pointerEvents : 'auto'
2610+ display : 'inline-block' ,
2611+ transform : `translate(${ lightboxOffset . x } px, ${ lightboxOffset . y } px) scale(${ lightboxScale } )` ,
2612+ transformOrigin : 'center center'
25892613 } }
2590- onClick = { ( e ) => e . stopPropagation ( ) }
2591- onMouseDown = { ( e ) => { e . preventDefault ( ) ; e . stopPropagation ( ) ; setIsDragging ( true ) ; } }
2592- />
2614+ >
2615+ < AuthenticatedImage
2616+ src = { lightboxImage }
2617+ alt = "Enlarged"
2618+ fetchBlob = { ( u ) => vm . fetchImageBlob ( u ) }
2619+ className = "image-lightbox-content"
2620+ style = { {
2621+ pointerEvents : 'none' ,
2622+ display : 'block'
2623+ } }
2624+ />
2625+ </ div >
25932626 < div className = "image-lightbox-controls" onClick = { e => e . stopPropagation ( ) } >
2594- < button onClick = { ( ) => setLightboxScale ( s => Math . max ( 0.25 , s - 0.25 ) ) } > ➖ </ button >
2595- < button onClick = { ( ) => { setLightboxScale ( 1 ) ; setLightboxOffset ( { x : 0 , y : 0 } ) ; } } > 重置 </ button >
2596- < button onClick = { ( ) => setLightboxScale ( s => Math . min ( 4 , s + 0.25 ) ) } > ➕ </ button >
2597- < button onClick = { ( ) => { setLightboxImage ( null ) ; setLightboxOffset ( { x : 0 , y : 0 } ) ; setLightboxScale ( 1 ) ; } } > ✕</ button >
2627+ < button onClick = { handleLightboxShrink } > − </ button >
2628+ < button onClick = { handleLightboxReset } > ○ </ button >
2629+ < button onClick = { handleLightboxEnlarge } > + </ button >
2630+ < button onClick = { handleLightboxClose } > ✕</ button >
25982631 </ div >
25992632 </ div >
26002633 )
0 commit comments