11import React , { useRef , useEffect , useCallback , useMemo } from "react" ;
22import { DiffMinimapProps , DiffRowOrCollapsed } from "../types" ;
33
4- const MINIMAP_WIDTH = 100 ;
54const ROW_HEIGHT = 20 ;
65const SEARCH_HIGHLIGHT_COLOR = "#ffd700" ;
76const CURRENT_MATCH_COLOR = "#ff4500" ;
@@ -10,11 +9,18 @@ const ADD_LINE_COLOR = "#4CAF50";
109const REMOVE_LINE_COLOR = "#F44336" ;
1110const MODIFY_LINE_COLOR = "#FFC107" ;
1211
12+ // const MINIMAP_HOVER_SCROLL_COLOR = "#2196f3cc";
13+ // const MINIMAP_SCROLL_COLOR = "#2196f380";
14+ 15+ const MINIMAP_HOVER_SCROLL_COLOR = "#7B7B7Bcc" ;
16+ const MINIMAP_SCROLL_COLOR = "#7B7B7B80" ;
17+ 1318export const DiffMinimap : React . FC < DiffMinimapProps > = ( {
1419 leftDiff,
1520 rightDiff,
1621 height,
1722 onScroll,
23+ miniMapWidth = 20 ,
1824 currentScrollTop,
1925 searchResults = [ ] ,
2026 currentMatchIndex = - 1 ,
@@ -59,47 +65,60 @@ export const DiffMinimap: React.FC<DiffMinimapProps> = ({
5965 ctx . fillRect ( x , y , width , ROW_HEIGHT ) ;
6066 } , [ ] ) ;
6167
62- const drawMinimap = useCallback ( ( ) => {
63- const canvas = canvasRef . current ;
64- if ( ! canvas ) return ;
65- 66- const ctx = canvas . getContext ( "2d" ) ;
67- if ( ! ctx ) return ;
68- 69- ctx . clearRect ( 0 , 0 , canvas . width , canvas . height ) ;
70- 71- const totalLines = Math . max ( leftDiff . length , rightDiff . length ) ;
68+ // Draw the differences -> This will be called in drawScrollBox method
69+ const drawDifferencesInMinimap = ( ctx : CanvasRenderingContext2D ) => {
7270 const scale = height / totalLines ;
7371
72+ if ( currentMatchIndex >= 0 && searchResults [ currentMatchIndex ] !== undefined ) {
73+ const y = searchResults [ currentMatchIndex ] * scale ;
74+ const lineHeight = Math . max ( 1 , scale ) ;
75+ ctx . fillStyle = CURRENT_MATCH_COLOR ;
76+ ctx . fillRect ( 0 , y , miniMapWidth , lineHeight ) ;
77+ }
78+ 7479 leftDiff . forEach ( ( line , index ) => {
7580 const y = index * scale ;
76- drawLine ( ctx , line , y , 0 , MINIMAP_WIDTH / 2 ) ;
81+ drawLine ( ctx , line , y , 0 , miniMapWidth / 2 ) ;
7782 } ) ;
7883
7984 rightDiff . forEach ( ( line , index ) => {
8085 const y = index * scale ;
81- drawLine ( ctx , line , y , MINIMAP_WIDTH / 2 , MINIMAP_WIDTH / 2 ) ;
86+ drawLine ( ctx , line , y , miniMapWidth / 2 , miniMapWidth / 2 ) ;
8287 } ) ;
8388
8489 searchResults . forEach ( ( index ) => {
8590 const y = index * scale ;
8691 const lineHeight = Math . max ( 1 , scale ) ;
8792 ctx . fillStyle = SEARCH_HIGHLIGHT_COLOR ;
88- ctx . fillRect ( 0 , y , MINIMAP_WIDTH , lineHeight ) ;
93+ ctx . fillRect ( 0 , y , miniMapWidth , lineHeight ) ;
8994 } ) ;
95+ } ;
9096
91- if ( currentMatchIndex >= 0 && searchResults [ currentMatchIndex ] !== undefined ) {
92- const y = searchResults [ currentMatchIndex ] * scale ;
93- const lineHeight = Math . max ( 1 , scale ) ;
94- ctx . fillStyle = CURRENT_MATCH_COLOR ;
95- ctx . fillRect ( 0 , y , MINIMAP_WIDTH , lineHeight ) ;
96- }
97- 97+ // Draw the scroll box and also differences in minimapo
98+ const drawScrollBox = ( ctx : CanvasRenderingContext2D , color : string ) => {
9899 const totalContentHeight = totalLines * ROW_HEIGHT ;
99100 const viewportTop = ( currentScrollTop / totalContentHeight ) * height ;
100- ctx . strokeStyle = "#2196F3" ;
101- ctx . lineWidth = 2 ;
102- ctx . strokeRect ( 0 , viewportTop , MINIMAP_WIDTH , viewportHeight ) ;
101+ 102+ drawDifferencesInMinimap ( ctx ) ;
103+ 104+ ctx . fillStyle = color ;
105+ ctx . fillRect ( 0 , viewportTop , miniMapWidth , viewportHeight ) ;
106+ } ;
107+ 108+ const drawMinimap = useCallback ( ( ) => {
109+ const canvas = canvasRef . current ;
110+ if ( ! canvas ) return ;
111+ 112+ const ctx = canvas . getContext ( "2d" ) ;
113+ if ( ! ctx ) return ;
114+ 115+ ctx . clearRect ( 0 , 0 , canvas . width , canvas . height ) ;
116+ 117+ if ( ! isDragging . current ) {
118+ drawScrollBox ( ctx , MINIMAP_SCROLL_COLOR ) ;
119+ } else {
120+ drawScrollBox ( ctx , MINIMAP_HOVER_SCROLL_COLOR ) ;
121+ }
103122 } , [ leftDiff , rightDiff , height , currentScrollTop , searchResults , currentMatchIndex , drawLine , viewportHeight ] ) ;
104123
105124 useEffect ( ( ) => {
@@ -116,6 +135,13 @@ export const DiffMinimap: React.FC<DiffMinimapProps> = ({
116135
117136 if ( height <= 0 || totalLines <= 0 ) return ;
118137
138+ const canvas = canvasRef . current ;
139+ if ( ! canvas ) return ;
140+ 141+ const ctx = canvas . getContext ( "2d" ) ;
142+ if ( ! ctx ) return ;
143+ drawScrollBox ( ctx , "rgba(33, 150, 243, 0.8)" ) ;
144+ 119145 const viewportCenter = relativeY - viewportHeight / 2 ;
120146 const scrollTop = ( viewportCenter / height ) * totalLines * ROW_HEIGHT ;
121147
@@ -128,15 +154,33 @@ export const DiffMinimap: React.FC<DiffMinimapProps> = ({
128154
129155 const handleMouseMove = useCallback (
130156 ( e : React . MouseEvent ) => {
131- if ( ! isDragging . current || ! containerRef . current ) return ;
132- 157+ if ( ! containerRef . current ) return ;
133158 const rect = containerRef . current . getBoundingClientRect ( ) ;
134- const relativeY = e . clientY - rect . top ;
159+ const relativeY = e . clientY - rect . top ; // e.client y - rect top (120)
160+ const viewportCenter = relativeY - viewportHeight / 2 ; // 0 when mouse is at the center of the drag square
161+ const scrollTop = ( viewportCenter / height ) * totalLines * ROW_HEIGHT ;
135162
136- if ( height <= 0 || totalLines <= 0 ) return ;
163+ const totalContentHeight = totalLines * ROW_HEIGHT ;
164+ const scrollSquareTop = ( currentScrollTop / totalContentHeight ) * height ;
137165
138- const viewportCenter = relativeY - viewportHeight / 2 ;
139- const scrollTop = ( viewportCenter / height ) * totalLines * ROW_HEIGHT ;
166+ const isHovering = relativeY > scrollSquareTop && relativeY < scrollSquareTop + viewportHeight ;
167+ 168+ const canvas = canvasRef . current ;
169+ 170+ drawMinimap ( ) ;
171+ 172+ if ( canvas ) {
173+ const ctx = canvas . getContext ( "2d" ) ;
174+ if ( ! ctx ) return ;
175+ if ( isHovering ) {
176+ // This is active when box is hovered
177+ drawScrollBox ( ctx , MINIMAP_HOVER_SCROLL_COLOR ) ;
178+ }
179+ }
180+ 181+ if ( ! isDragging . current ) return ;
182+ 183+ if ( height <= 0 || totalLines <= 0 ) return ;
140184
141185 if ( isNaN ( scrollTop ) || ! isFinite ( scrollTop ) ) return ;
142186
@@ -160,6 +204,18 @@ export const DiffMinimap: React.FC<DiffMinimapProps> = ({
160204 isDragging . current = false ;
161205 } , [ ] ) ;
162206
207+ const handleMouseLeave = ( ) => {
208+ const canvas = canvasRef . current ;
209+ if ( ! canvas ) return ;
210+ const ctx = canvas . getContext ( "2d" ) ;
211+ if ( ! ctx ) return ;
212+ 213+ if ( isDragging . current ) {
214+ isDragging . current = false ;
215+ }
216+ drawMinimap ( ) ; // resets full state
217+ } ;
218+ 163219 useEffect ( ( ) => {
164220 window . addEventListener ( "mouseup" , handleMouseUp ) ;
165221 return ( ) => window . removeEventListener ( "mouseup" , handleMouseUp ) ;
@@ -169,17 +225,18 @@ export const DiffMinimap: React.FC<DiffMinimapProps> = ({
169225 < div
170226 ref = { containerRef }
171227 style = { {
172- width : MINIMAP_WIDTH ,
228+ width : miniMapWidth ,
173229 height,
174230 position : "relative" ,
175231 cursor : "pointer" ,
176232 } }
177233 onMouseDown = { handleMouseDown }
178234 onMouseMove = { handleMouseMove }
235+ onMouseLeave = { handleMouseLeave }
179236 >
180237 < canvas
181238 ref = { canvasRef }
182- width = { MINIMAP_WIDTH }
239+ width = { miniMapWidth }
183240 height = { height }
184241 style = { {
185242 width : "100%" ,
0 commit comments