diff --git a/ui/goose2/scripts/check-file-sizes.mjs b/ui/goose2/scripts/check-file-sizes.mjs index a80012b342..559bd719c0 100644 --- a/ui/goose2/scripts/check-file-sizes.mjs +++ b/ui/goose2/scripts/check-file-sizes.mjs @@ -11,9 +11,9 @@ const EXCEPTIONS = { "Temporary allowance while project creation, home/chat handoff, session-history routing, and drag-drop wiring remain in the shell.", }, "src/features/sidebar/ui/SidebarProjectsSection.tsx": { - limit: 545, + limit: 560, justification: - "Added drag-and-drop handlers for moving chats between projects.", + "Drag-and-drop handlers plus activeProjectId highlight for draft-in-project sessions.", }, "src/features/chat/ui/ChatView.tsx": { limit: 505, @@ -21,8 +21,9 @@ const EXCEPTIONS = { "Added useSessionAutoTitle hook call for smart session naming.", }, "src/features/sidebar/ui/Sidebar.tsx": { - limit: 575, - justification: "Added search-as-you-type filtering for sidebar sessions.", + limit: 580, + justification: + "Search-as-you-type filtering plus draft-aware sidebar highlight logic.", }, "src-tauri/src/services/acp/manager.rs": { limit: 520, diff --git a/ui/goose2/src/features/sidebar/ui/Sidebar.tsx b/ui/goose2/src/features/sidebar/ui/Sidebar.tsx index e1f604e444..2fdbbf1738 100644 --- a/ui/goose2/src/features/sidebar/ui/Sidebar.tsx +++ b/ui/goose2/src/features/sidebar/ui/Sidebar.tsx @@ -260,12 +260,8 @@ export function Sidebar({ return () => window.removeEventListener("keydown", handler); }, []); - const toggleProject = (projectId: string) => { - setExpandedProjects((prev) => ({ - ...prev, - [projectId]: !prev[projectId], - })); - }; + const toggleProject = (projectId: string) => + setExpandedProjects((prev) => ({ ...prev, [projectId]: !prev[projectId] })); const navRef = useRef(null); const homeRef = useRef(null); @@ -279,12 +275,20 @@ export function Sidebar({ updateActiveRect, } = useSidebarHighlight(navRef); - // Update active rect when activeView/activeSessionId changes + // Drafts aren't in the sidebar — highlight project row or clear highlight. + const activeDraft = activeSessionId + ? sessions.find((s) => s.id === activeSessionId && s.draft) + : undefined; + const activeProjectId = activeDraft?.projectId ?? null; + + // Position the sliding highlight based on what's active. + // Non-draft sessions and draft-in-project are handled by ref callbacks. useEffect(() => { - if (activeSessionId) { + if (activeDraft) { + if (!activeProjectId) updateActiveRect(null); return; } - + if (activeSessionId) return; if (activeView === "home") { updateActiveRect(homeRef.current); } else if (activeView && navItemRefs.current[activeView]) { @@ -292,17 +296,27 @@ export function Sidebar({ } else { updateActiveRect(null); } - }, [activeSessionId, activeView, updateActiveRect]); + }, [ + activeSessionId, + activeDraft, + activeProjectId, + activeView, + updateActiveRect, + ]); - // Callback for SidebarProjectsSection to register active session refs + // Ref callbacks to position the highlight on active session or project row. const activeSessionRefCallback = useCallback( (el: HTMLElement | null) => { - if (activeSessionId && el) { - updateActiveRect(el); - } + if (activeSessionId && el) updateActiveRect(el); }, [activeSessionId, updateActiveRect], ); + const activeProjectRefCallback = useCallback( + (el: HTMLElement | null) => { + if (activeProjectId && el) updateActiveRect(el); + }, + [activeProjectId, updateActiveRect], + ); return (
)} diff --git a/ui/goose2/src/features/sidebar/ui/SidebarProjectsSection.tsx b/ui/goose2/src/features/sidebar/ui/SidebarProjectsSection.tsx index ff025e01d1..5b7d842e47 100644 --- a/ui/goose2/src/features/sidebar/ui/SidebarProjectsSection.tsx +++ b/ui/goose2/src/features/sidebar/ui/SidebarProjectsSection.tsx @@ -46,6 +46,7 @@ interface SidebarProjectsSectionProps { labelTransition: string; labelVisible: boolean; activeSessionId?: string | null; + activeProjectId?: string | null; onNavigate?: (view: AppView) => void; onSelectSession?: (sessionId: string) => void; onNewChatInProject?: (projectId: string) => void; @@ -58,6 +59,7 @@ interface SidebarProjectsSectionProps { onMoveToProject?: (sessionId: string, projectId: string | null) => void; onItemMouseEnter?: (e: React.MouseEvent) => void; activeSessionRefCallback?: (el: HTMLElement | null) => void; + activeProjectRefCallback?: (el: HTMLElement | null) => void; } function ItemMenu({ label, @@ -112,6 +114,7 @@ function ProjectSection({ isExpanded, toggleProject, activeSessionId, + activeProjectId, onSelectSession, onNewChatInProject, onNavigate, @@ -122,12 +125,14 @@ function ProjectSection({ onMoveToProject, onItemMouseEnter, activeSessionRefCallback, + activeProjectRefCallback, }: { project: ProjectInfo; projectChats: TabInfo[]; isExpanded: boolean; toggleProject: (projectId: string) => void; activeSessionId?: string | null; + activeProjectId?: string | null; onSelectSession?: (sessionId: string) => void; onNewChatInProject?: (projectId: string) => void; onNavigate?: (view: AppView) => void; @@ -138,6 +143,7 @@ function ProjectSection({ onMoveToProject?: (sessionId: string, projectId: string | null) => void; onItemMouseEnter?: (e: React.MouseEvent) => void; activeSessionRefCallback?: (el: HTMLElement | null) => void; + activeProjectRefCallback?: (el: HTMLElement | null) => void; }) { const [showAll, setShowAll] = useState(false); const [dragOver, setDragOver] = useState(false); @@ -180,7 +186,12 @@ function ProjectSection({ onDrop={handleDrop} > {/* Project row */} -
+