@@ -52,9 +52,11 @@ const SidebarContainer: React.FC<SidebarContainerProps> = ({
5252 "bg-separator border-l border-border-light flex flex-col overflow-hidden flex-shrink-0" ,
5353 customWidth ? "" : "transition-[width] duration-200" ,
5454 collapsed && "sticky right-0 z-10 shadow-[-2px_0_4px_rgba(0,0,0,0.2)]" ,
55- "max-md:border-l-0 max-md:border-t max-md:border-border-light" ,
56- collapsed && "max-md:w-0 max-md:absolute max-md:bottom-0" ,
57- ! collapsed && "max-md:w-full max-md:relative max-md:max-h-[50vh]"
55+ // Mobile: slide in from right (similar to left sidebar pattern)
56+ "max-md:fixed max-md:right-0 max-md:top-0 max-md:h-screen max-md:transition-transform max-md:duration-300" ,
57+ collapsed && "max-md:translate-x-full max-md:shadow-none" ,
58+ ! collapsed &&
59+ "max-md:translate-x-0 max-md:w-full max-md:max-w-md max-md:z-[999] max-md:shadow-[-2px_0_8px_rgba(0,0,0,0.5)] max-md:border-l max-md:border-border-light"
5860 ) }
5961 style = { { width } }
6062 role = { role }
@@ -186,112 +188,161 @@ const RightSidebarComponent: React.FC<RightSidebarProps> = ({
186188 const verticalMeter = showMeter ? < VerticalTokenMeter data = { verticalMeterData } /> : null ;
187189
188190 return (
189- < SidebarContainer
190- collapsed = { showCollapsed }
191- wide = { selectedTab === "review" && ! width } // Auto-wide only if not drag-resizing
192- customWidth = { width } // Drag-resized width from AIView (Review tab only)
193- role = "complementary"
194- aria-label = "Workspace insights"
195- >
196- { /* Full view when not collapsed */ }
197- < div className = { cn ( "flex-row h-full" , ! showCollapsed ? "flex" : "hidden" ) } >
198- { /* Render meter when Review tab is active */ }
199- { selectedTab === "review" && (
200- < div className = "bg-separator border-border-light flex w-5 shrink-0 flex-col border-r" >
201- { verticalMeter }
202- </ div >
203- ) }
191+ < >
192+ { /* FAB - Floating Action Button for mobile, only visible when collapsed */ }
193+ { showCollapsed && (
194+ < button
195+ onClick = { ( ) => setShowCollapsed ( false ) }
196+ title = { `Open ${ selectedTab } panel` }
197+ aria-label = { `Open ${ selectedTab } panel` }
198+ className = { cn (
199+ "hidden max-md:flex fixed bottom-20 right-4 z-[998]" ,
200+ "w-12 h-12 bg-accent border border-accent rounded-full cursor-pointer" ,
201+ "items-center justify-center text-white text-lg transition-all duration-200" ,
202+ "shadow-[0_4px_12px_rgba(0,0,0,0.4)]" ,
203+ "hover:bg-accent-hover hover:scale-105" ,
204+ "active:scale-95"
205+ ) }
206+ >
207+ { selectedTab === "costs" ? "💰" : "📋" }
208+ </ button >
209+ ) }
204210
205- { /* Render resize handle to right of meter when Review tab is active */ }
206- { selectedTab === "review" && onStartResize && (
207- < div
208- className = { cn (
209- "w-1 flex-shrink-0 z-10 transition-[background] duration-150" ,
210- "bg-border-light cursor-col-resize hover:bg-accent" ,
211- isResizing && "bg-accent"
212- ) }
213- onMouseDown = { ( e ) => onStartResize ( e as unknown as React . MouseEvent ) }
214- />
215- ) }
211+ { /* Backdrop overlay - only on mobile when sidebar is expanded */ }
212+ { ! showCollapsed && (
213+ < div
214+ className = "hidden max-md:block fixed inset-0 bg-black/50 z-[998] backdrop-blur-sm"
215+ onClick = { ( ) => setShowCollapsed ( true ) }
216+ aria-hidden = "true"
217+ />
218+ ) }
216219
217- < div className = "flex min-w-0 flex-1 flex-col" >
218- < div
219- className = "bg-background-secondary border-border flex border-b [&>*]:flex-1"
220- role = "tablist"
221- aria-label = "Metadata views"
222- >
223- < TooltipWrapper inline >
224- < button
225- className = { cn (
226- "w-full py-2.5 px-[15px] border-none border-solid cursor-pointer font-primary text-[13px] font-medium transition-all duration-200" ,
227- selectedTab === "costs"
228- ? "text-white bg-separator border-b-2 border-b-plan-mode"
229- : "bg-transparent text-secondary border-b-2 border-b-transparent hover:bg-background-secondary hover:text-foreground"
230- ) }
231- onClick = { ( ) => setSelectedTab ( "costs" ) }
232- id = { costsTabId }
233- role = "tab"
234- type = "button"
235- aria-selected = { selectedTab === "costs" }
236- aria-controls = { costsPanelId }
237- >
238- Costs
239- </ button >
240- < Tooltip className = "tooltip" position = "bottom" align = "center" >
241- { formatKeybind ( KEYBINDS . COSTS_TAB ) }
242- </ Tooltip >
243- </ TooltipWrapper >
244- < TooltipWrapper inline >
220+ < SidebarContainer
221+ collapsed = { showCollapsed }
222+ wide = { selectedTab === "review" && ! width } // Auto-wide only if not drag-resizing
223+ customWidth = { width } // Drag-resized width from AIView (Review tab only)
224+ role = "complementary"
225+ aria-label = "Workspace insights"
226+ >
227+ { /* Full view when not collapsed */ }
228+ < div className = { cn ( "flex-row h-full" , ! showCollapsed ? "flex" : "hidden" ) } >
229+ { /* Render meter when Review tab is active */ }
230+ { selectedTab === "review" && (
231+ < div className = "bg-separator border-border-light flex w-5 shrink-0 flex-col border-r" >
232+ { verticalMeter }
233+ </ div >
234+ ) }
235+
236+ { /* Render resize handle to right of meter when Review tab is active */ }
237+ { selectedTab === "review" && onStartResize && (
238+ < div
239+ className = { cn (
240+ "w-1 flex-shrink-0 z-10 transition-[background] duration-150" ,
241+ "bg-border-light cursor-col-resize hover:bg-accent" ,
242+ isResizing && "bg-accent"
243+ ) }
244+ onMouseDown = { ( e ) => onStartResize ( e as unknown as React . MouseEvent ) }
245+ />
246+ ) }
247+
248+ < div className = "flex min-w-0 flex-1 flex-col" >
249+ < div
250+ className = "bg-background-secondary border-border flex border-b [&>*]:flex-1 relative"
251+ role = "tablist"
252+ aria-label = "Metadata views"
253+ >
254+ { /* Close button - only visible on mobile */ }
245255 < button
256+ onClick = { ( ) => setShowCollapsed ( true ) }
257+ title = "Close panel"
258+ aria-label = "Close panel"
246259 className = { cn (
247- "w-full py-2.5 px-[15px] border-none border-solid cursor-pointer font-primary text-[13px] font-medium transition-all duration-200" ,
248- selectedTab === "review"
249- ? "text-white bg-separator border-b-2 border-b-plan-mode"
250- : "bg-transparent text-secondary border-b-2 border-b-transparent hover:bg-background-secondary hover:text-foreground"
260+ "hidden max-md:flex absolute top-2 right-2 z-10" ,
261+ "w-8 h-8 bg-separator border border-border-light rounded cursor-pointer" ,
262+ "items-center justify-center text-foreground transition-all duration-200" ,
263+ "hover:bg-hover hover:border-bg-light" ,
264+ "active:scale-95"
251265 ) }
252- onClick = { ( ) => setSelectedTab ( "review" ) }
253- id = { reviewTabId }
254- role = "tab"
255- type = "button"
256- aria-selected = { selectedTab === "review" }
257- aria-controls = { reviewPanelId }
258266 >
259- Review
267+ ✕
260268 </ button >
261- < Tooltip className = "tooltip" position = "bottom" align = "center" >
262- { formatKeybind ( KEYBINDS . REVIEW_TAB ) }
263- </ Tooltip >
264- </ TooltipWrapper >
265- </ div >
266- < div
267- className = { cn ( "flex-1 overflow-y-auto" , selectedTab === "review" ? "p-0" : "p-[15px]" ) }
268- >
269- { selectedTab === "costs" && (
270- < div role = "tabpanel" id = { costsPanelId } aria-labelledby = { costsTabId } >
271- < CostsTab workspaceId = { workspaceId } />
272- </ div >
273- ) }
274- { selectedTab === "review" && (
275- < div
276- role = "tabpanel"
277- id = { reviewPanelId }
278- aria-labelledby = { reviewTabId }
279- className = "h-full"
280- >
281- < ReviewPanel
282- workspaceId = { workspaceId }
283- workspacePath = { workspacePath }
284- onReviewNote = { onReviewNote }
285- focusTrigger = { focusTrigger }
286- />
287- </ div >
288- ) }
269+
270+ < TooltipWrapper inline >
271+ < button
272+ className = { cn (
273+ "w-full py-2.5 px-[15px] border-none border-solid cursor-pointer font-primary text-[13px] font-medium transition-all duration-200" ,
274+ selectedTab === "costs"
275+ ? "text-white bg-separator border-b-2 border-b-plan-mode"
276+ : "bg-transparent text-secondary border-b-2 border-b-transparent hover:bg-background-secondary hover:text-foreground"
277+ ) }
278+ onClick = { ( ) => setSelectedTab ( "costs" ) }
279+ id = { costsTabId }
280+ role = "tab"
281+ type = "button"
282+ aria-selected = { selectedTab === "costs" }
283+ aria-controls = { costsPanelId }
284+ >
285+ Costs
286+ </ button >
287+ < Tooltip className = "tooltip" position = "bottom" align = "center" >
288+ { formatKeybind ( KEYBINDS . COSTS_TAB ) }
289+ </ Tooltip >
290+ </ TooltipWrapper >
291+ < TooltipWrapper inline >
292+ < button
293+ className = { cn (
294+ "w-full py-2.5 px-[15px] border-none border-solid cursor-pointer font-primary text-[13px] font-medium transition-all duration-200" ,
295+ selectedTab === "review"
296+ ? "text-white bg-separator border-b-2 border-b-plan-mode"
297+ : "bg-transparent text-secondary border-b-2 border-b-transparent hover:bg-background-secondary hover:text-foreground"
298+ ) }
299+ onClick = { ( ) => setSelectedTab ( "review" ) }
300+ id = { reviewTabId }
301+ role = "tab"
302+ type = "button"
303+ aria-selected = { selectedTab === "review" }
304+ aria-controls = { reviewPanelId }
305+ >
306+ Review
307+ </ button >
308+ < Tooltip className = "tooltip" position = "bottom" align = "center" >
309+ { formatKeybind ( KEYBINDS . REVIEW_TAB ) }
310+ </ Tooltip >
311+ </ TooltipWrapper >
312+ </ div >
313+ < div
314+ className = { cn (
315+ "flex-1 overflow-y-auto" ,
316+ selectedTab === "review" ? "p-0" : "p-[15px]"
317+ ) }
318+ >
319+ { selectedTab === "costs" && (
320+ < div role = "tabpanel" id = { costsPanelId } aria-labelledby = { costsTabId } >
321+ < CostsTab workspaceId = { workspaceId } />
322+ </ div >
323+ ) }
324+ { selectedTab === "review" && (
325+ < div
326+ role = "tabpanel"
327+ id = { reviewPanelId }
328+ aria-labelledby = { reviewTabId }
329+ className = "h-full"
330+ >
331+ < ReviewPanel
332+ workspaceId = { workspaceId }
333+ workspacePath = { workspacePath }
334+ onReviewNote = { onReviewNote }
335+ focusTrigger = { focusTrigger }
336+ />
337+ </ div >
338+ ) }
339+ </ div >
289340 </ div >
290341 </ div >
291- </ div >
292- { /* Render meter in collapsed view when sidebar is collapsed */ }
293- < div className = { cn ( "h-full" , showCollapsed ? "flex" : "hidden" ) } > { verticalMeter } </ div >
294- </ SidebarContainer >
342+ { /* Render meter in collapsed view when sidebar is collapsed */ }
343+ < div className = { cn ( "h-full" , showCollapsed ? "flex" : "hidden" ) } > { verticalMeter } </ div >
344+ </ SidebarContainer >
345+ </ >
295346 ) ;
296347} ;
297348
0 commit comments