diff --git a/ui/desktop/src/components/Layout/AppLayout.tsx b/ui/desktop/src/components/Layout/AppLayout.tsx index 7f7c778c2c4b..301e777063fc 100644 --- a/ui/desktop/src/components/Layout/AppLayout.tsx +++ b/ui/desktop/src/components/Layout/AppLayout.tsx @@ -1,11 +1,11 @@ import React from 'react'; import { Outlet, useNavigate, useLocation } from 'react-router-dom'; -import AppSidebar from '../GooseSidebar/AppSidebar'; -import GlobalBackground from '../GlobalBackground'; import { View, ViewOptions } from '../../App'; import { AppWindowMac, AppWindow } from 'lucide-react'; import { Button } from '../ui/button'; -import { Sidebar, SidebarInset, SidebarProvider, SidebarTrigger, useSidebar } from '../ui/sidebar'; +import { SidebarProvider, useSidebar } from '../ui/sidebar'; +import GlobalBackground from '../GlobalBackground'; +import PillSideNav from '../PillSideNav'; interface AppLayoutProps { setIsGoosehintsModalOpen?: (isOpen: boolean) => void; @@ -18,10 +18,6 @@ const AppLayoutContent: React.FC = ({ setIsGoosehintsModalOpen } const safeIsMacOS = (window?.electron?.platform || 'darwin') === 'darwin'; const { isMobile, openMobile } = useSidebar(); - // Calculate padding based on sidebar state and macOS - const headerPadding = safeIsMacOS ? 'pl-21' : 'pl-4'; - // const headerPadding = ''; - // Hide buttons when mobile sheet is showing const shouldHideButtons = isMobile && openMobile; @@ -69,11 +65,6 @@ const AppLayoutContent: React.FC = ({ setIsGoosehintsModalOpen } } }; - const handleSelectSession = async (sessionId: string) => { - // Navigate to chat with session data - navigate('/', { state: { sessionId } }); - }; - const handleNewWindow = () => { window.electron.createChatWindow( undefined, @@ -83,17 +74,22 @@ const AppLayoutContent: React.FC = ({ setIsGoosehintsModalOpen } return (
- {/* Global background with aggressive blur for chat sections */} - + {/* Global background */} + + + {/* Floating pill navigation in center */} +
+
+ +
+
+ {/* New Window button in top right */} {!shouldHideButtons && ( -
- +
)} - - - - + + {/* Main Content */} +
- +
); }; diff --git a/ui/desktop/src/components/PillSideNav.tsx b/ui/desktop/src/components/PillSideNav.tsx new file mode 100644 index 000000000000..a9d046bcbed3 --- /dev/null +++ b/ui/desktop/src/components/PillSideNav.tsx @@ -0,0 +1,126 @@ +import React, { useState } from 'react'; +import { useNavigate, useLocation } from 'react-router-dom'; +import { cn } from '../utils'; +import { + Home as HomeIcon, + MessageSquare as ChatIcon, + Clock as ClockIcon, + FileText as FileIcon, + Puzzle as PuzzleIcon, + Settings as SettingsIcon, + History as HistoryIcon, + ChevronRight as ChevronRightIcon, + X as CloseIcon +} from 'lucide-react'; + +interface NavItemProps { + icon: React.ReactNode; + label: string; + path: string; + isActive?: boolean; + onClick: () => void; +} + +const NavItem: React.FC = ({ + icon, + label, + isActive = false, + onClick +}) => { + return ( + + ); +}; + +export const PillSideNav: React.FC = () => { + const navigate = useNavigate(); + const location = useLocation(); + const currentPath = location.pathname; + const [isExpanded, setIsExpanded] = useState(false); + + const handleNavigation = (path: string) => { + navigate(path); + setIsExpanded(false); + }; + + // Navigation items configuration + const navItems = [ + { icon: , label: 'Home', path: '/' }, + { icon: , label: 'Chat', path: '/pair' }, + { icon: , label: 'History', path: '/sessions' }, + { icon: , label: 'Recipes', path: '/recipes' }, + { icon: , label: 'Settings', path: '/settings' }, + ]; + + // Find the current active item + const activeItem = navItems.find(item => item.path === currentPath) || navItems[0]; + + // Get current mode label + const currentModeLabel = activeItem.label; + + return ( +
+ {/* Collapsed Pill */} + {!isExpanded && ( +
setIsExpanded(true)} + > + {currentModeLabel} +
+ )} + + {/* Expanded Navigation */} + {isExpanded && ( +
+
+ {/* Header with close button */} +
+ Navigation + +
+ + {/* Navigation Items */} +
+ {navItems.map((item) => ( + handleNavigation(item.path)} + /> + ))} +
+
+
+ )} +
+ ); +}; + +export default PillSideNav; diff --git a/ui/desktop/src/components/pair.tsx b/ui/desktop/src/components/pair.tsx index ff7f1ac43050..8172d5388cac 100644 --- a/ui/desktop/src/components/pair.tsx +++ b/ui/desktop/src/components/pair.tsx @@ -60,15 +60,66 @@ export default function Pair({ // Get recipe configuration and parameter handling const { initialPrompt: recipeInitialPrompt } = useRecipeManager(chat.messages, location.state); + // Get sidebar state for background adjustments + const { state: currentSidebarState } = useSidebar(); + const isSidebarCollapsed = currentSidebarState === 'collapsed'; + // Override backgrounds to allow our gradient to show through useEffect(() => { - // Override SidebarInset background + // Target the specific SidebarInset component with the complex class const sidebarInset = document.querySelector('[data-slot="sidebar-inset"]') as HTMLElement; if (sidebarInset) { sidebarInset.style.background = 'transparent'; + sidebarInset.style.backgroundColor = 'transparent'; + // Remove the bg-background class that might be causing the issue + sidebarInset.classList.remove('bg-background'); + // Add bg-transparent class + sidebarInset.classList.add('bg-transparent'); + } + + // Target the sidebar element itself + const sidebar = document.querySelector('[data-slot="sidebar"]') as HTMLElement; + if (sidebar) { + // Add a style to make sure it doesn't block our background + sidebar.style.pointerEvents = 'auto'; + sidebar.style.zIndex = '20'; + // Make the sidebar background transparent + sidebar.style.background = 'transparent'; + sidebar.style.backgroundColor = 'transparent'; + } + + // Target the sidebar wrapper + const sidebarWrapper = document.querySelector('[data-slot="sidebar-wrapper"]') as HTMLElement; + if (sidebarWrapper) { + sidebarWrapper.style.background = 'transparent'; + sidebarWrapper.style.backgroundColor = 'transparent'; + } + + // Target the sidebar container + const sidebarContainer = document.querySelector('[data-slot="sidebar-container"]') as HTMLElement; + if (sidebarContainer) { + sidebarContainer.style.background = 'transparent'; + sidebarContainer.style.backgroundColor = 'transparent'; + } + + // Target the sidebar inner + const sidebarInner = document.querySelector('[data-slot="sidebar-inner"]') as HTMLElement; + if (sidebarInner) { + // Keep the sidebar's own background but make sure it doesn't extend + sidebarInner.style.width = '100%'; + sidebarInner.style.height = '100%'; } - // Apply reduced blur effect to ChatInput (same as Hub but less aggressive) + // Override MainPanelLayout background + const mainPanels = document.querySelectorAll('.bg-background-default, .bg-background-muted') as NodeListOf; + mainPanels.forEach(panel => { + if (panel) { + panel.style.background = 'transparent'; + panel.style.backgroundColor = 'transparent'; + } + }); + + // Override ChatInput background to be transparent with glass effect const chatInputContainer = document.querySelector('[data-drop-zone="true"]') as HTMLElement; if (chatInputContainer) { chatInputContainer.style.background = 'rgba(255, 255, 255, 0.05)'; @@ -82,7 +133,37 @@ export default function Pair({ return () => { if (sidebarInset) { sidebarInset.style.background = ''; + sidebarInset.style.backgroundColor = ''; + sidebarInset.classList.remove('bg-transparent'); + // Restore the original class if needed + if (!sidebarInset.classList.contains('bg-background')) { + sidebarInset.classList.add('bg-background'); + } + } + if (sidebar) { + sidebar.style.pointerEvents = ''; + sidebar.style.zIndex = ''; + sidebar.style.background = ''; + sidebar.style.backgroundColor = ''; + } + if (sidebarWrapper) { + sidebarWrapper.style.background = ''; + sidebarWrapper.style.backgroundColor = ''; } + if (sidebarContainer) { + sidebarContainer.style.background = ''; + sidebarContainer.style.backgroundColor = ''; + } + if (sidebarInner) { + sidebarInner.style.width = ''; + sidebarInner.style.height = ''; + } + mainPanels.forEach(panel => { + if (panel) { + panel.style.background = ''; + panel.style.backgroundColor = ''; + } + }); if (chatInputContainer) { chatInputContainer.style.background = ''; chatInputContainer.style.backdropFilter = ''; @@ -91,7 +172,7 @@ export default function Pair({ chatInputContainer.style.border = ''; } }; - }); + }, []); // Handle recipe loading from recipes view - reset chat if needed useEffect(() => { @@ -222,8 +303,11 @@ export default function Pair({ // Custom main layout props to override background completely const customMainLayoutProps = { - backgroundColor: '', // Remove any background class - style: { backgroundColor: 'transparent' }, // Force transparent background with inline style + backgroundColor: 'transparent', // Use transparent instead of empty string + style: { + backgroundColor: 'transparent', + background: 'transparent' + }, // Force transparent background with inline style }; // Custom content before messages @@ -232,13 +316,25 @@ export default function Pair({ }; return ( -
- {/* Use GlobalBackground to respect user's selected background */} - - +
+ {/* Image background implementation */} +
+ + {/* Optional overlay for better text readability */} +
+ {/* Centered chat content */} -
-
+
+