import React, { useEffect, useState } from 'react'; import { IpcRendererEvent } from 'electron'; import { Outlet, useLocation } from 'react-router-dom'; import { motion } from 'framer-motion'; import { Menu, PanelLeft } from 'lucide-react'; import { defineMessages, useIntl } from '../../i18n'; import { Button } from '../ui/button'; import ChatSessionsContainer from '../ChatSessionsContainer'; import { useChatContext } from '../../contexts/ChatContext'; import { NavigationProvider, useNavigationContext } from './NavigationContext'; import { Navigation } from './NavigationPanel'; import { NAV_DIMENSIONS, Z_INDEX } from './constants'; import { cn } from '../../utils'; import { UserInput } from '../../types/message'; const i18n = defineMessages({ openNavigation: { id: 'appLayout.openNavigation', defaultMessage: 'Open navigation', }, collapseNavigation: { id: 'appLayout.collapseNavigation', defaultMessage: 'Collapse navigation', }, }); interface AppLayoutContentProps { activeSessions: Array<{ sessionId: string; initialMessage?: UserInput; noAutoSubmit?: boolean; }>; } const AppLayoutContent: React.FC = ({ activeSessions }) => { const intl = useIntl(); const location = useLocation(); const safeIsMacOS = (window?.electron?.platform || 'darwin') === 'darwin'; const chatContext = useChatContext(); const isOnPairRoute = location.pathname === '/pair'; const [isFullScreen, setIsFullScreen] = useState(false); useEffect(() => { if (!safeIsMacOS) return; window.electron .getIsFullScreen() .then(setIsFullScreen) .catch(() => {}); const handler = (_event: IpcRendererEvent, ...args: unknown[]) => { setIsFullScreen(Boolean(args[0])); }; window.electron.on('fullscreen-change', handler); return () => window.electron.off('fullscreen-change', handler); }, [safeIsMacOS]); const { isNavExpanded, setIsNavExpanded } = useNavigationContext(); if (!chatContext) { throw new Error('AppLayoutContent must be used within ChatProvider'); } const { setChat } = chatContext; const needsTrafficLightInset = safeIsMacOS && !isFullScreen; const headerPadding = needsTrafficLightInset ? 'pl-[96px]' : 'pl-4'; const headerTop = needsTrafficLightInset ? 'top-[14px]' : 'top-[11px]'; const navToggleTitle = intl.formatMessage( isNavExpanded ? i18n.collapseNavigation : i18n.openNavigation ); return (
{/* Main content with navigation. Shared white canvas; the sidebar is a rounded outlined card floating on it with breathing room. */}
{/* Main content — no border / no card; just flows on the canvas. */}
{/* Always render ChatSessionsContainer to keep SSE connections alive. When navigating away from /pair, hide it with CSS */}
); }; interface AppLayoutProps { activeSessions: Array<{ sessionId: string; initialMessage?: UserInput; noAutoSubmit?: boolean; }>; } export const AppLayout: React.FC = ({ activeSessions }) => { return ( ); };