diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index f26683ca7..01b9a7a60 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -9,6 +9,12 @@ import { Modals } from './components/Modals' import { ThemeProvider } from './contexts/ThemeContext' import { SidebarProvider } from '@/components/ui/sidebar' import { useModalStore } from './stores/modalStore' +import { useUIStore } from './stores/uiStore' +import { + RightPanel, + RightPanelHeader, + RightPanelContent, +} from './components/layout' function AppContent(): React.JSX.Element { const { @@ -31,6 +37,10 @@ function AppContent(): React.JSX.Element { const openModal = useModalStore((s) => s.openModal) + // UI state + const sidebarOpen = useUIStore((s) => s.sidebarOpen) + const setSidebarOpen = useUIStore((s) => s.setSidebarOpen) + // Default agent for new sessions const [defaultAgentId, setDefaultAgentId] = useState('opencode') @@ -73,7 +83,11 @@ function AppContent(): React.JSX.Element { )} {/* Main content */} - + {/* Sidebar */} {/* Main area */} -
+
{/* Status bar */}
+ + {/* Right panel - placeholder for future content */} + + + Details + + +
+

Right panel content

+
+
+
{/* Global modals */} diff --git a/src/renderer/src/components/StatusBar.tsx b/src/renderer/src/components/StatusBar.tsx index 33caf25bd..29d7e1a62 100644 --- a/src/renderer/src/components/StatusBar.tsx +++ b/src/renderer/src/components/StatusBar.tsx @@ -2,7 +2,8 @@ * Status bar component - shows session info and running status */ import type { MulticaSession } from '../../../shared/types' -import { SidebarTrigger, useSidebar } from '@/components/ui/sidebar' +import { useSidebar } from '@/components/ui/sidebar' +import { SidebarTrigger, RightPanelTrigger } from './layout' import { cn } from '@/lib/utils' interface StatusBarProps { @@ -43,12 +44,13 @@ export function StatusBar({ )} - {/* Right: Status */} + {/* Right: Status + Right panel trigger */}
+
) diff --git a/src/renderer/src/components/layout/RightPanel.tsx b/src/renderer/src/components/layout/RightPanel.tsx new file mode 100644 index 000000000..50b6f4328 --- /dev/null +++ b/src/renderer/src/components/layout/RightPanel.tsx @@ -0,0 +1,129 @@ +/** + * Layout components - panels and triggers + * Desktop only - hidden on mobile + */ +import * as React from 'react' +import { PanelLeftIcon, PanelRightIcon } from 'lucide-react' +import { cn } from '@/lib/utils' +import { Button } from '@/components/ui/button' +import { useUIStore } from '@/stores/uiStore' +import { useSidebar } from '@/components/ui/sidebar' + +const RIGHT_PANEL_WIDTH = '20rem' // 320px + +interface RightPanelProps { + children: React.ReactNode + className?: string +} + +export function RightPanel({ children, className }: RightPanelProps) { + const isOpen = useUIStore((s) => s.rightPanelOpen) + + return ( +
+
+ {children} +
+
+ ) +} + +// Trigger button - desktop only, secondary variant when panel is open +export function RightPanelTrigger({ + className, + ...props +}: React.ComponentProps) { + const isOpen = useUIStore((s) => s.rightPanelOpen) + const toggle = useUIStore((s) => s.toggleRightPanel) + + return ( + + ) +} + +// Sidebar trigger - uses uiStore, secondary variant when open +export function SidebarTrigger({ + className, + onClick, + ...props +}: React.ComponentProps) { + const { toggleSidebar } = useSidebar() + const isOpen = useUIStore((s) => s.sidebarOpen) + + return ( + + ) +} + +// Sub-components for consistent structure +export function RightPanelHeader({ + className, + ...props +}: React.ComponentProps<'div'>) { + return ( +
+ ) +} + +export function RightPanelContent({ + className, + ...props +}: React.ComponentProps<'div'>) { + return ( +
+ ) +} + +export function RightPanelFooter({ + className, + ...props +}: React.ComponentProps<'div'>) { + return ( +
+ ) +} diff --git a/src/renderer/src/components/layout/index.ts b/src/renderer/src/components/layout/index.ts new file mode 100644 index 000000000..e2441b2cf --- /dev/null +++ b/src/renderer/src/components/layout/index.ts @@ -0,0 +1,8 @@ +export { + RightPanel, + RightPanelTrigger, + RightPanelHeader, + RightPanelContent, + RightPanelFooter, + SidebarTrigger, +} from './RightPanel' diff --git a/src/renderer/src/stores/uiStore.ts b/src/renderer/src/stores/uiStore.ts new file mode 100644 index 000000000..4891dbfe5 --- /dev/null +++ b/src/renderer/src/stores/uiStore.ts @@ -0,0 +1,37 @@ +/** + * Global UI state management using Zustand + * Stores all UI-related state like panel visibility, etc. + */ +import { create } from 'zustand' +import { persist } from 'zustand/middleware' + +interface UIStore { + // Sidebar state + sidebarOpen: boolean + toggleSidebar: () => void + setSidebarOpen: (open: boolean) => void + + // Right panel state + rightPanelOpen: boolean + toggleRightPanel: () => void + setRightPanelOpen: (open: boolean) => void +} + +export const useUIStore = create()( + persist( + (set) => ({ + // Sidebar - default open + sidebarOpen: true, + toggleSidebar: () => set((state) => ({ sidebarOpen: !state.sidebarOpen })), + setSidebarOpen: (open) => set({ sidebarOpen: open }), + + // Right panel - default open + rightPanelOpen: true, + toggleRightPanel: () => set((state) => ({ rightPanelOpen: !state.rightPanelOpen })), + setRightPanelOpen: (open) => set({ rightPanelOpen: open }), + }), + { + name: 'ui-state', // localStorage key + } + ) +)