1- import React , { useRef , useEffect } from 'react'
1+ import React , { useRef , useEffect , useState } from 'react'
22import { useAppStore } from '@/stores/appStore'
33import { useAllProjectApis } from '@/hooks/useApis'
44import { METHOD_COLORS } from '@/types'
@@ -7,6 +7,18 @@ export function TabsBar() {
77 const { openTabs, activeTabId, setActiveTab, closeTab, currentProjectId, apiDrafts } = useAppStore ( )
88 const { data : allApis } = useAllProjectApis ( currentProjectId )
99 const containerRef = useRef < HTMLDivElement > ( null )
10+ const [ ctx , setCtx ] = useState < { x : number ; y : number ; tabId : string } | null > ( null )
11+
12+ useEffect ( ( ) => {
13+ const handleEscape = ( e : KeyboardEvent ) => { if ( e . key === 'Escape' ) setCtx ( null ) }
14+ const handleClick = ( ) => setCtx ( null )
15+ window . addEventListener ( 'keydown' , handleEscape )
16+ window . addEventListener ( 'click' , handleClick )
17+ return ( ) => {
18+ window . removeEventListener ( 'keydown' , handleEscape )
19+ window . removeEventListener ( 'click' , handleClick )
20+ }
21+ } , [ ] )
1022
1123 // Scroll active tab into view
1224 useEffect ( ( ) => {
@@ -46,6 +58,10 @@ export function TabsBar() {
4658 onMouseDown = { ( e ) => {
4759 if ( e . button === 1 ) closeTab ( tab . id ) // Middle click to close
4860 } }
61+ onContextMenu = { ( e ) => {
62+ e . preventDefault ( )
63+ setCtx ( { x : e . clientX , y : e . clientY , tabId : tab . id } )
64+ } }
4965 style = { {
5066 display : 'flex' ,
5167 alignItems : 'center' ,
@@ -144,6 +160,55 @@ export function TabsBar() {
144160 </ div >
145161 )
146162 } ) }
163+
164+ { ctx && (
165+ < div
166+ style = { {
167+ position : 'fixed' ,
168+ top : ctx . y ,
169+ left : ctx . x ,
170+ background : '#1F1F1F' ,
171+ border : '1px solid #2A2A2A' ,
172+ borderRadius : '6px' ,
173+ padding : '4px' ,
174+ display : 'flex' ,
175+ flexDirection : 'column' ,
176+ gap : '2px' ,
177+ zIndex : 1000 ,
178+ boxShadow : '0 4px 12px rgba(0,0,0,0.5)' ,
179+ minWidth : '160px'
180+ } }
181+ onClick = { e => e . stopPropagation ( ) }
182+ >
183+ < button
184+ className = "ctx-menu-item"
185+ onClick = { ( ) => { closeTab ( ctx . tabId ) ; setCtx ( null ) } }
186+ style = { { display : 'flex' , alignItems : 'center' , padding : '6px 12px' , fontSize : '12px' , color : '#E5E5E5' , background : 'transparent' , border : 'none' , borderRadius : '4px' , cursor : 'pointer' , textAlign : 'left' , transition : '150ms ease' } }
187+ onMouseEnter = { e => e . currentTarget . style . background = '#2A2A2A' }
188+ onMouseLeave = { e => e . currentTarget . style . background = 'transparent' }
189+ >
190+ Close Tab
191+ </ button >
192+ < button
193+ className = "ctx-menu-item"
194+ onClick = { ( ) => { useAppStore . getState ( ) . closeOtherTabs ( ctx . tabId ) ; setCtx ( null ) } }
195+ style = { { display : 'flex' , alignItems : 'center' , padding : '6px 12px' , fontSize : '12px' , color : '#E5E5E5' , background : 'transparent' , border : 'none' , borderRadius : '4px' , cursor : 'pointer' , textAlign : 'left' , transition : '150ms ease' } }
196+ onMouseEnter = { e => e . currentTarget . style . background = '#2A2A2A' }
197+ onMouseLeave = { e => e . currentTarget . style . background = 'transparent' }
198+ >
199+ Close Other Tabs
200+ </ button >
201+ < button
202+ className = "ctx-menu-item"
203+ onClick = { ( ) => { useAppStore . getState ( ) . closeAllTabs ( ) ; setCtx ( null ) } }
204+ style = { { display : 'flex' , alignItems : 'center' , padding : '6px 12px' , fontSize : '12px' , color : '#EF4444' , background : 'transparent' , border : 'none' , borderRadius : '4px' , cursor : 'pointer' , textAlign : 'left' , transition : '150ms ease' } }
205+ onMouseEnter = { e => e . currentTarget . style . background = '#2A2A2A' }
206+ onMouseLeave = { e => e . currentTarget . style . background = 'transparent' }
207+ >
208+ Close All Tabs
209+ </ button >
210+ </ div >
211+ ) }
147212 </ div >
148213 )
149214}
0 commit comments