From 596baf55a24f73e66ac634ebc220b888bee3d841 Mon Sep 17 00:00:00 2001 From: Jinjing <6427696+AmethystLiang@users.noreply.github.com> Date: Fri, 22 May 2026 01:38:09 -0700 Subject: [PATCH] Keep git history graph sticky Squashed commit from make-git-graph-sticky-current-change. --- .../right-sidebar/GitHistoryPanel.tsx | 83 ++++++++++++------- .../right-sidebar/SourceControl.tsx | 41 ++++----- 2 files changed, 75 insertions(+), 49 deletions(-) diff --git a/src/renderer/src/components/right-sidebar/GitHistoryPanel.tsx b/src/renderer/src/components/right-sidebar/GitHistoryPanel.tsx index c2ef31106..5442ebe9e 100644 --- a/src/renderer/src/components/right-sidebar/GitHistoryPanel.tsx +++ b/src/renderer/src/components/right-sidebar/GitHistoryPanel.tsx @@ -19,6 +19,14 @@ export type GitHistoryPanelState = const DEFAULT_GIT_HISTORY_PANEL_HEIGHT = 256 const MIN_GIT_HISTORY_PANEL_HEIGHT = 96 const MAX_GIT_HISTORY_PANEL_HEIGHT = 520 +const MAX_GIT_HISTORY_PANEL_VIEWPORT_HEIGHT = '33vh' + +type GitHistoryResizeSession = { + startY: number + startHeight: number + previousCursor: string + previousUserSelect: string +} function clampGitHistoryPanelHeight(height: number): number { return Math.min(MAX_GIT_HISTORY_PANEL_HEIGHT, Math.max(MIN_GIT_HISTORY_PANEL_HEIGHT, height)) @@ -77,29 +85,14 @@ function GitHistoryRow({ const visibleRefs = refs.slice(0, 2) const hiddenRefs = refs.slice(2) const rowTooltip = item.message || item.subject - - return ( - ) } @@ -199,15 +215,16 @@ export function GitHistoryPanel({ const loading = state.status === 'loading' || state.status === 'refreshing' const count = result?.items.length ?? 0 const [panelHeight, setPanelHeight] = useState(DEFAULT_GIT_HISTORY_PANEL_HEIGHT) - const resizeSessionRef = useRef<{ startY: number; startHeight: number } | null>(null) + const resizeSessionRef = useRef(null) const stopResize = useCallback((): void => { - if (!resizeSessionRef.current) { + const session = resizeSessionRef.current + if (!session) { return } resizeSessionRef.current = null - document.body.style.cursor = '' - document.body.style.userSelect = '' + document.body.style.cursor = session.previousCursor + document.body.style.userSelect = session.previousUserSelect }, []) const handleResizePointerMove = useCallback((event: PointerEvent): void => { @@ -228,6 +245,7 @@ export function GitHistoryPanel({ window.removeEventListener('pointerup', stopResize) window.removeEventListener('pointercancel', stopResize) window.removeEventListener('blur', stopResize) + stopResize() } }, [handleResizePointerMove, stopResize]) @@ -237,7 +255,12 @@ export function GitHistoryPanel({ return } event.preventDefault() - resizeSessionRef.current = { startY: event.clientY, startHeight: panelHeight } + resizeSessionRef.current = { + startY: event.clientY, + startHeight: panelHeight, + previousCursor: document.body.style.cursor, + previousUserSelect: document.body.style.userSelect + } document.body.style.cursor = 'row-resize' document.body.style.userSelect = 'none' event.currentTarget.setPointerCapture(event.pointerId) @@ -263,7 +286,9 @@ export function GitHistoryPanel({ }, []) const expandedBodyClassName = 'overflow-y-auto scrollbar-sleek' - const expandedBodyStyle = { height: panelHeight } + const expandedBodyStyle = { + height: `min(${panelHeight}px, ${MAX_GIT_HISTORY_PANEL_VIEWPORT_HEIGHT})` + } return (
diff --git a/src/renderer/src/components/right-sidebar/SourceControl.tsx b/src/renderer/src/components/right-sidebar/SourceControl.tsx index 7d1d6e1f5..a7ee1d3f2 100644 --- a/src/renderer/src/components/right-sidebar/SourceControl.tsx +++ b/src/renderer/src/components/right-sidebar/SourceControl.tsx @@ -1285,6 +1285,8 @@ function SourceControlInner(): React.JSX.Element { }, [entries]) const normalizedFilter = filterQuery.toLowerCase() + const isGitHistoryVisible = + scope === 'all' && !normalizedFilter && Boolean(activeWorktreeId && worktreePath && !isFolder) const filteredGrouped = useMemo(() => { if (!normalizedFilter) { @@ -2955,7 +2957,8 @@ function SourceControlInner(): React.JSX.Element { !worktreePath || isFolder || !isBranchVisible || - !isGitHistoryExpanded + !isGitHistoryExpanded || + !isGitHistoryVisible ) { return } @@ -3010,6 +3013,7 @@ function SourceControlInner(): React.JSX.Element { isBranchVisible, isFolder, isGitHistoryExpanded, + isGitHistoryVisible, worktreePath ]) @@ -3033,7 +3037,7 @@ function SourceControlInner(): React.JSX.Element { useEffect(() => { // Why: history shells out to git. Defer the first load until the user // expands Graph so source control stays cheap for large/remote repos. - if (!isBranchVisible || !isGitHistoryExpanded) { + if (!isBranchVisible || !isGitHistoryExpanded || !isGitHistoryVisible) { return } void refreshGitHistoryRef.current() @@ -3043,6 +3047,7 @@ function SourceControlInner(): React.JSX.Element { isBranchVisible, isFolder, isGitHistoryExpanded, + isGitHistoryVisible, worktreePath ]) @@ -4136,24 +4141,20 @@ function SourceControlInner(): React.JSX.Element {
)} - {scope === 'all' && - !normalizedFilter && - activeWorktreeId && - worktreePath && - !isFolder && ( - // Why: the graph is reference context for the whole panel, so when - // file sections are short it should occupy the bottom, and when the - // pane scrolls it should remain docked as branch context. -
- toggleSection('history')} - onRefresh={() => void refreshGitHistory()} - onOpenCommit={(item) => void openHistoryCommitDiff(item)} - /> -
- )} + {isGitHistoryVisible && ( + // Why: the graph is reference context for the whole panel, so when + // file sections are short it should occupy the bottom, and when the + // pane scrolls it should remain docked as branch context. +
+ toggleSection('history')} + onRefresh={() => void refreshGitHistory()} + onOpenCommit={(item) => void openHistoryCommitDiff(item)} + /> +
+ )} {selectedKeys.size > 0 && (