diff --git a/src/features/git/components/GitDiffViewer.tsx b/src/features/git/components/GitDiffViewer.tsx index cef9dbfa3..778c64150 100644 --- a/src/features/git/components/GitDiffViewer.tsx +++ b/src/features/git/components/GitDiffViewer.tsx @@ -127,6 +127,8 @@ export function GitDiffViewer({ const listRef = useRef(null); const lastScrolledPathRef = useRef(null); const activePathRef = useRef(null); + const ignoreActivePathUntilRef = useRef(0); + const lastSelectionFromScrollRef = useRef(false); const poolOptions = useMemo(() => ({ workerFactory }), []); const highlighterOptions = useMemo( () => ({ theme: { dark: "pierre-dark", light: "pierre-light" } }), @@ -163,13 +165,18 @@ export function GitDiffViewer({ if (!selectedPath) { return; } - if (lastScrolledPathRef.current === selectedPath) { + const shouldSkipScroll = + lastSelectionFromScrollRef.current && + lastScrolledPathRef.current === selectedPath; + if (shouldSkipScroll) { + lastSelectionFromScrollRef.current = false; return; } const index = indexByPath.get(selectedPath); if (index === undefined) { return; } + ignoreActivePathUntilRef.current = Date.now() + 250; rowVirtualizer.scrollToIndex(index, { align: "start" }); lastScrolledPathRef.current = selectedPath; }, [selectedPath, indexByPath, rowVirtualizer]); @@ -187,26 +194,39 @@ export function GitDiffViewer({ const updateActivePath = () => { frameId = null; + if (Date.now() < ignoreActivePathUntilRef.current) { + return; + } const items = rowVirtualizer.getVirtualItems(); if (!items.length) { return; } const scrollTop = container.scrollTop; - const targetOffset = scrollTop + 8; - let activeItem = items[0]; - for (const item of items) { - if (item.start <= targetOffset) { - activeItem = item; - } else { - break; + const canScroll = container.scrollHeight > container.clientHeight; + const isAtBottom = + canScroll && + scrollTop + container.clientHeight >= container.scrollHeight - 4; + let nextPath: string | undefined; + if (isAtBottom) { + nextPath = diffs[diffs.length - 1]?.path; + } else { + const targetOffset = scrollTop + 8; + let activeItem = items[0]; + for (const item of items) { + if (item.start <= targetOffset) { + activeItem = item; + } else { + break; + } } + nextPath = diffs[activeItem.index]?.path; } - const nextPath = diffs[activeItem.index]?.path; if (!nextPath || nextPath === activePathRef.current) { return; } activePathRef.current = nextPath; lastScrolledPathRef.current = nextPath; + lastSelectionFromScrollRef.current = true; onActivePathChange(nextPath); }; diff --git a/src/features/workspaces/hooks/useWorkspaceSelection.ts b/src/features/workspaces/hooks/useWorkspaceSelection.ts index d559a0b2f..b5316acbf 100644 --- a/src/features/workspaces/hooks/useWorkspaceSelection.ts +++ b/src/features/workspaces/hooks/useWorkspaceSelection.ts @@ -36,6 +36,7 @@ export function useWorkspaceSelection({ const selectWorkspace = useCallback( (workspaceId: string) => { + setSelectedDiffPath(null); const target = workspaces.find((entry) => entry.id === workspaceId); if (target?.settings.sidebarCollapsed) { void updateWorkspaceSettings(workspaceId, { @@ -52,6 +53,7 @@ export function useWorkspaceSelection({ isCompact, setActiveTab, setActiveWorkspaceId, + setSelectedDiffPath, updateWorkspaceSettings, workspaces, ], @@ -59,11 +61,12 @@ export function useWorkspaceSelection({ const selectHome = useCallback(() => { exitDiffView(); + setSelectedDiffPath(null); setActiveWorkspaceId(null); if (isCompact) { setActiveTab("projects"); } - }, [exitDiffView, isCompact, setActiveTab, setActiveWorkspaceId]); + }, [exitDiffView, isCompact, setActiveTab, setActiveWorkspaceId, setSelectedDiffPath]); return { exitDiffView, selectWorkspace, selectHome }; }