diff --git a/packages/app/src/components/left-sidebar.tsx b/packages/app/src/components/left-sidebar.tsx index 457d677b8..8c304ff8c 100644 --- a/packages/app/src/components/left-sidebar.tsx +++ b/packages/app/src/components/left-sidebar.tsx @@ -15,6 +15,7 @@ import { router, usePathname } from 'expo-router' import { usePanelStore } from '@/stores/panel-store' import { SidebarWorkspaceList } from './sidebar-workspace-list' import { SidebarAgentListSkeleton } from './sidebar-agent-list-skeleton' +import { useSidebarShortcutModel } from '@/hooks/use-sidebar-shortcut-model' import { useSidebarWorkspacesList } from '@/hooks/use-sidebar-workspaces-list' import { useSidebarAnimation } from '@/contexts/sidebar-animation-context' import { useTauriDragHandlers, useTrafficLightPadding } from '@/utils/tauri-window' @@ -124,6 +125,8 @@ export function LeftSidebar({ selectedAgentId: _selectedAgentId }: LeftSidebarPr serverId: activeServerId, enabled: isOpen, }) + const { collapsedProjectKeys, shortcutIndexByWorkspaceKey, toggleProjectCollapsed } = + useSidebarShortcutModel(projects) const { translateX, backdropOpacity, @@ -353,6 +356,9 @@ export function LeftSidebar({ selectedAgentId: _selectedAgentId }: LeftSidebarPr + onToggleProjectCollapsed: (projectKey: string) => void + shortcutIndexByWorkspaceKey: Map isRefreshing?: boolean onRefresh?: () => void onWorkspacePress?: () => void @@ -1196,6 +1198,9 @@ export function SidebarWorkspaceList({ isOpen = true, projects, serverId, + collapsedProjectKeys, + onToggleProjectCollapsed, + shortcutIndexByWorkspaceKey, isRefreshing = false, onRefresh, onWorkspacePress, @@ -1205,16 +1210,9 @@ export function SidebarWorkspaceList({ const isMobile = UnistylesRuntime.breakpoint === 'xs' || UnistylesRuntime.breakpoint === 'sm' const isNative = Platform.OS !== 'web' const pathname = usePathname() - const [collapsedProjectKeys, setCollapsedProjectKeys] = useState>(new Set()) const isTauri = getIsTauri() const altDown = useKeyboardShortcutsStore((state) => state.altDown) const cmdOrCtrlDown = useKeyboardShortcutsStore((state) => state.cmdOrCtrlDown) - const setSidebarShortcutWorkspaceTargets = useKeyboardShortcutsStore( - (state) => state.setSidebarShortcutWorkspaceTargets - ) - const setVisibleWorkspaceTargets = useKeyboardShortcutsStore( - (state) => state.setVisibleWorkspaceTargets - ) const showShortcutBadges = altDown || (isTauri && cmdOrCtrlDown) const getProjectOrder = useSidebarOrderStore((state) => state.getProjectOrder) @@ -1236,19 +1234,6 @@ export function SidebarWorkspaceList({ } }, [pathname]) - useEffect(() => { - setCollapsedProjectKeys((prev) => { - const validProjectKeys = new Set(projects.map((project) => project.projectKey)) - const next = new Set() - for (const key of prev) { - if (validProjectKeys.has(key)) { - next.add(key) - } - } - return next - }) - }, [projects]) - const projectIconRequests = useMemo(() => { if (!isOpen || !serverId) { return [] @@ -1316,44 +1301,6 @@ export function SidebarWorkspaceList({ return byProject }, [projectIconQueries, projectIconRequests, projects, serverId]) - const shortcutModel = useMemo( - () => - buildSidebarShortcutModel({ - projects, - collapsedProjectKeys, - }), - [collapsedProjectKeys, projects] - ) - - useEffect(() => { - setSidebarShortcutWorkspaceTargets(shortcutModel.shortcutTargets) - setVisibleWorkspaceTargets(shortcutModel.visibleTargets) - }, [ - setSidebarShortcutWorkspaceTargets, - setVisibleWorkspaceTargets, - shortcutModel.shortcutTargets, - shortcutModel.visibleTargets, - ]) - - useEffect(() => { - return () => { - setSidebarShortcutWorkspaceTargets([]) - setVisibleWorkspaceTargets([]) - } - }, [setSidebarShortcutWorkspaceTargets, setVisibleWorkspaceTargets]) - - const toggleProjectCollapsed = useCallback((projectKey: string) => { - setCollapsedProjectKeys((prev) => { - const next = new Set(prev) - if (next.has(projectKey)) { - next.delete(projectKey) - } else { - next.add(projectKey) - } - return next - }) - }, []) - const handleProjectDragEnd = useCallback( (reorderedProjects: SidebarProjectEntry[]) => { if (!serverId) { @@ -1437,9 +1384,9 @@ export function SidebarWorkspaceList({ serverId={serverId} activeWorkspaceSelection={activeWorkspaceSelection} showShortcutBadges={showShortcutBadges} - shortcutIndexByWorkspaceKey={shortcutModel.shortcutIndexByWorkspaceKey} + shortcutIndexByWorkspaceKey={shortcutIndexByWorkspaceKey} parentGestureRef={parentGestureRef} - onToggleCollapsed={() => toggleProjectCollapsed(item.projectKey)} + onToggleCollapsed={() => onToggleProjectCollapsed(item.projectKey)} onWorkspacePress={onWorkspacePress} onWorkspaceReorder={handleWorkspaceReorder} onCreateWorktree={handleCreateWorktree} @@ -1456,12 +1403,12 @@ export function SidebarWorkspaceList({ handleCreateWorktree, handleWorkspaceReorder, onWorkspacePress, + onToggleProjectCollapsed, parentGestureRef, projectIconByProjectKey, serverId, - shortcutModel.shortcutIndexByWorkspaceKey, + shortcutIndexByWorkspaceKey, showShortcutBadges, - toggleProjectCollapsed, isNative, ] ) diff --git a/packages/app/src/hooks/use-sidebar-shortcut-model.ts b/packages/app/src/hooks/use-sidebar-shortcut-model.ts new file mode 100644 index 000000000..0cee13679 --- /dev/null +++ b/packages/app/src/hooks/use-sidebar-shortcut-model.ts @@ -0,0 +1,71 @@ +import { useCallback, useEffect, useMemo, useState } from 'react' +import type { SidebarProjectEntry } from '@/hooks/use-sidebar-workspaces-list' +import { useKeyboardShortcutsStore } from '@/stores/keyboard-shortcuts-store' +import { buildSidebarShortcutModel } from '@/utils/sidebar-shortcuts' + +export function useSidebarShortcutModel(projects: SidebarProjectEntry[]) { + const [collapsedProjectKeys, setCollapsedProjectKeys] = useState>(new Set()) + const setSidebarShortcutWorkspaceTargets = useKeyboardShortcutsStore( + (state) => state.setSidebarShortcutWorkspaceTargets + ) + const setVisibleWorkspaceTargets = useKeyboardShortcutsStore( + (state) => state.setVisibleWorkspaceTargets + ) + + const shortcutModel = useMemo( + () => + buildSidebarShortcutModel({ + projects, + collapsedProjectKeys, + }), + [collapsedProjectKeys, projects] + ) + + useEffect(() => { + setCollapsedProjectKeys((prev) => { + const validProjectKeys = new Set(projects.map((project) => project.projectKey)) + const next = new Set() + for (const key of prev) { + if (validProjectKeys.has(key)) { + next.add(key) + } + } + return next + }) + }, [projects]) + + useEffect(() => { + setSidebarShortcutWorkspaceTargets(shortcutModel.shortcutTargets) + setVisibleWorkspaceTargets(shortcutModel.visibleTargets) + }, [ + setSidebarShortcutWorkspaceTargets, + setVisibleWorkspaceTargets, + shortcutModel.shortcutTargets, + shortcutModel.visibleTargets, + ]) + + useEffect(() => { + return () => { + setSidebarShortcutWorkspaceTargets([]) + setVisibleWorkspaceTargets([]) + } + }, [setSidebarShortcutWorkspaceTargets, setVisibleWorkspaceTargets]) + + const toggleProjectCollapsed = useCallback((projectKey: string) => { + setCollapsedProjectKeys((prev) => { + const next = new Set(prev) + if (next.has(projectKey)) { + next.delete(projectKey) + } else { + next.add(projectKey) + } + return next + }) + }, []) + + return { + collapsedProjectKeys, + shortcutIndexByWorkspaceKey: shortcutModel.shortcutIndexByWorkspaceKey, + toggleProjectCollapsed, + } +}