diff --git a/packages/ui/src/components/layout/ContextPanel.tsx b/packages/ui/src/components/layout/ContextPanel.tsx index 8df72d98..93cbf102 100644 --- a/packages/ui/src/components/layout/ContextPanel.tsx +++ b/packages/ui/src/components/layout/ContextPanel.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { RiCloseLine, RiFullscreenExitLine, RiFullscreenLine } from '@remixicon/react'; import { Button } from '@/components/ui/button'; -import { DiffView, FilesView } from '@/components/views'; +import { DiffView, FilesView, PlanView } from '@/components/views'; import { useEffectiveDirectory } from '@/hooks/useEffectiveDirectory'; import { cn } from '@/lib/utils'; import { useFilesViewTabsStore } from '@/stores/useFilesViewTabsStore'; @@ -145,7 +145,7 @@ export const ContextPanel: React.FC = () => { const activeFilePath = useFilesViewTabsStore((state) => (directoryKey ? (state.byRoot[directoryKey]?.selectedPath ?? null) : null)); - const panelTitle = panelState?.mode === 'diff' ? 'Diff' : panelState?.mode === 'file' ? 'File' : panelState?.mode === 'context' ? 'Context' : 'Panel'; + const panelTitle = panelState?.mode === 'diff' ? 'Diff' : panelState?.mode === 'file' ? 'File' : panelState?.mode === 'context' ? 'Context' : panelState?.mode === 'plan' ? 'Plan' : 'Panel'; const effectivePath = panelState?.mode === 'file' ? (activeFilePath ?? panelState?.targetPath ?? null) : panelState?.mode === 'context' ? null : (panelState?.targetPath ?? null); const pathLabel = getRelativePathLabel(effectivePath, effectiveDirectory); @@ -155,7 +155,9 @@ export const ContextPanel: React.FC = () => { ? : panelState?.mode === 'context' ? - : null; + : panelState?.mode === 'plan' + ? + : null; const header = (
diff --git a/packages/ui/src/components/layout/Header.tsx b/packages/ui/src/components/layout/Header.tsx index 5929a237..2eae3616 100644 --- a/packages/ui/src/components/layout/Header.tsx +++ b/packages/ui/src/components/layout/Header.tsx @@ -142,6 +142,7 @@ export const Header: React.FC = () => { const toggleBottomTerminal = useUIStore((state) => state.toggleBottomTerminal); const toggleRightSidebar = useUIStore((state) => state.toggleRightSidebar); const openContextOverview = useUIStore((state) => state.openContextOverview); + const openContextPlan = useUIStore((state) => state.openContextPlan); const closeContextPanel = useUIStore((state) => state.closeContextPanel); const contextPanelByDirectory = useUIStore((state) => state.contextPanelByDirectory); const setSettingsDialogOpen = useUIStore((state) => state.setSettingsDialogOpen); @@ -917,6 +918,30 @@ export const Header: React.FC = () => { return Boolean(panelState?.isOpen && panelState.mode === 'context'); }, [contextPanelByDirectory, openDirectory]); + const handleOpenContextPlan = React.useCallback(() => { + const directory = normalize(openDirectory || ''); + if (!directory) { + return; + } + + const panelState = contextPanelByDirectory[directory]; + if (panelState?.isOpen && panelState.mode === 'plan') { + closeContextPanel(directory); + return; + } + + openContextPlan(directory); + }, [closeContextPanel, contextPanelByDirectory, openContextPlan, openDirectory]); + + const isContextPlanActive = React.useMemo(() => { + const directory = normalize(openDirectory || ''); + if (!directory) { + return false; + } + const panelState = contextPanelByDirectory[directory]; + return Boolean(panelState?.isOpen && panelState.mode === 'plan'); + }, [contextPanelByDirectory, openDirectory]); + const headerIconButtonClass = 'app-region-no-drag inline-flex h-9 w-9 items-center justify-center gap-2 p-2 rounded-md typography-ui-label font-medium text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary disabled:pointer-events-none disabled:opacity-50 hover:text-foreground hover:bg-interactive-hover transition-colors'; const desktopPaddingClass = React.useMemo(() => { @@ -1644,6 +1669,23 @@ export const Header: React.FC = () => { percentIconClassName="h-5 w-5" /> )} + {showPlanTab && ( + + + + + +

Plan

+
+
+ )} void; openContextFile: (directory: string, filePath: string) => void; openContextOverview: (directory: string) => void; + openContextPlan: (directory: string) => void; closeContextPanel: (directory: string) => void; toggleContextPanelExpanded: (directory: string) => void; setContextPanelWidth: (directory: string, width: number) => void; @@ -549,6 +550,29 @@ export const useUIStore = create()( }); }, + openContextPlan: (directory) => { + const normalizedDirectory = normalizeDirectoryPath((directory || '').trim()); + if (!normalizedDirectory) { + return; + } + + set((state) => { + const prev = state.contextPanelByDirectory[normalizedDirectory]; + const current = touchContextPanelState(prev); + const byDirectory = { + ...state.contextPanelByDirectory, + [normalizedDirectory]: { + ...current, + isOpen: true, + mode: 'plan' as const, + targetPath: null, + }, + }; + + return { contextPanelByDirectory: clampContextPanelRoots(byDirectory, 20) }; + }); + }, + closeContextPanel: (directory) => { const normalizedDirectory = normalizeDirectoryPath((directory || '').trim()); if (!normalizedDirectory) {