diff --git a/ui/desktop/src/components/Layout/AppLayout.tsx b/ui/desktop/src/components/Layout/AppLayout.tsx index bc03d5e270..6b3533ee5b 100644 --- a/ui/desktop/src/components/Layout/AppLayout.tsx +++ b/ui/desktop/src/components/Layout/AppLayout.tsx @@ -1,6 +1,6 @@ -import React, { useState, createContext, useContext, useCallback } from 'react'; +import React, { useState, createContext, useContext, useCallback, useEffect } from 'react'; import { Outlet, useNavigate, useLocation } from 'react-router-dom'; -import { AppWindowMac, AppWindow, ChevronDown, ChevronUp } from 'lucide-react'; +import { AppWindowMac, AppWindow, ChevronDown, ChevronUp, ChevronLeft, ChevronRight } from 'lucide-react'; import { Button } from '../ui/button'; import { SidebarProvider } from '../ui/sidebar'; import { SidecarProvider, useSidecar } from '../SidecarLayout'; @@ -13,14 +13,17 @@ import DocumentEditor from '../DocumentEditor'; import WebViewer from '../WebViewer'; import { TopNavigation } from './TopNavigation'; +import { NavigationPosition } from '../settings/app/NavigationPositionSelector'; // Create context for navigation state const NavigationContext = createContext<{ isNavExpanded: boolean; setIsNavExpanded: (expanded: boolean) => void; + navigationPosition: NavigationPosition; }>({ isNavExpanded: false, - setIsNavExpanded: () => {} + setIsNavExpanded: () => {}, + navigationPosition: 'top' }); export const useNavigation = () => useContext(NavigationContext); @@ -36,6 +39,21 @@ const AppLayoutContent: React.FC = ({ setIsGoosehintsModalOpen } const safeIsMacOS = (window?.electron?.platform || 'darwin') === 'darwin'; const sidecar = useSidecar(); const [isNavExpanded, setIsNavExpanded] = useState(false); + const [navigationPosition, setNavigationPosition] = useState(() => { + const stored = localStorage.getItem('navigation_position'); + return (stored as NavigationPosition) || 'top'; + }); + + // Listen for navigation position changes + useEffect(() => { + const handlePositionChange = (e: Event) => { + const customEvent = e as CustomEvent<{ position: NavigationPosition }>; + setNavigationPosition(customEvent.detail.position); + }; + + window.addEventListener('navigation-position-changed', handlePositionChange); + return () => window.removeEventListener('navigation-position-changed', handlePositionChange); + }, []); // Bento box state management const [bentoBoxContainers, setBentoBoxContainers] = useState([]); @@ -268,52 +286,82 @@ const AppLayoutContent: React.FC = ({ setIsGoosehintsModalOpen } return () => window.removeEventListener('open-sidecar-localhost', handler); }, [sidecar]); + // Determine layout direction based on navigation position + const isHorizontalNav = navigationPosition === 'top' || navigationPosition === 'bottom'; + const flexDirection = isHorizontalNav ? 'flex-col' : 'flex-row'; + + // Render the main content area + const mainContent = ( +
+
+ {panels.length > 0 ? ( + useMultiPanel && panels.length > 1 ? ( + } + panels={panels} + layoutMode={layoutMode} + onLayoutModeChange={handleLayoutModeChange} + onPanelResize={handlePanelResize} + onPanelReorder={handlePanelReorder} + initialLeftWidth={chatWidth} + className="h-full" + /> + ) : ( + } + rightContent={ + + } + initialLeftWidth={chatWidth} + minLeftWidth={30} + maxLeftWidth={80} + onResize={setChatWidth} + className="h-full" + floatingRight={true} + /> + ) + ) : ( + + )} +
+
+ ); + + // Render navigation component + const navigationComponent = ( + + ); + return ( - -
- {/* Top Navigation Bar */} - + +
+ {/* Navigation placement based on position */} + {navigationPosition === 'top' && navigationComponent} + {navigationPosition === 'left' && navigationComponent} {/* Main Content Area */} -
- {panels.length > 0 ? ( - useMultiPanel && panels.length > 1 ? ( - } - panels={panels} - layoutMode={layoutMode} - onLayoutModeChange={handleLayoutModeChange} - onPanelResize={handlePanelResize} - onPanelReorder={handlePanelReorder} - initialLeftWidth={chatWidth} - className="h-full" - /> - ) : ( - } - rightContent={ - - } - initialLeftWidth={chatWidth} - minLeftWidth={30} - maxLeftWidth={80} - onResize={setChatWidth} - className="h-full" - floatingRight={true} - /> - ) - ) : ( - - )} -
+ {mainContent} - {/* Control Buttons - floating in top right */} -
+ {/* Navigation placement for bottom and right */} + {navigationPosition === 'bottom' && navigationComponent} + {navigationPosition === 'right' && navigationComponent} + + {/* Control Buttons - position based on nav location */} +
+ ))} +
+ ); +}