fix(terminal): add scroll area to worktree dropdown to prevent overflow (#1146)
* fix(terminal): add scroll area to worktree dropdown to prevent overflow Wrap worktree list in ScrollArea with max-height of 300px to handle cases with many worktrees without overflowing the screen. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(terminal): keep separator fixed above scrollable worktree list Move DropdownMenuSeparator outside ScrollArea so it remains visible when scrolling through many worktrees, maintaining visual distinction from the "Create New" item. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,7 @@ import {
|
|||||||
AlertDialogTitle,
|
AlertDialogTitle,
|
||||||
} from '../ui/alert-dialog';
|
} from '../ui/alert-dialog';
|
||||||
import { cn } from '../../lib/utils';
|
import { cn } from '../../lib/utils';
|
||||||
|
import { ScrollArea } from '../ui/scroll-area';
|
||||||
import { useProjectStore } from '../../stores/project-store';
|
import { useProjectStore } from '../../stores/project-store';
|
||||||
|
|
||||||
interface WorktreeSelectorProps {
|
interface WorktreeSelectorProps {
|
||||||
@@ -169,90 +170,91 @@ export function WorktreeSelector({
|
|||||||
{t('terminal:worktree.createNew')}
|
{t('terminal:worktree.createNew')}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|
||||||
{/* Separator and existing worktrees */}
|
{/* Fixed separator between "Create New" and scrollable content */}
|
||||||
{isLoading ? (
|
<DropdownMenuSeparator />
|
||||||
<>
|
|
||||||
<DropdownMenuSeparator />
|
{/* Scrollable content */}
|
||||||
|
<ScrollArea className="max-h-[300px]">
|
||||||
|
{isLoading ? (
|
||||||
<div className="flex items-center justify-center py-2">
|
<div className="flex items-center justify-center py-2">
|
||||||
<Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
|
<Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
|
||||||
</div>
|
</div>
|
||||||
</>
|
) : (
|
||||||
) : (
|
<>
|
||||||
<>
|
{/* Terminal Worktrees Section */}
|
||||||
{/* Terminal Worktrees Section */}
|
{worktrees.length > 0 && (
|
||||||
{worktrees.length > 0 && (
|
<>
|
||||||
<>
|
<div className="px-2 py-1.5 text-xs text-muted-foreground">
|
||||||
<DropdownMenuSeparator />
|
{t('terminal:worktree.existing')}
|
||||||
<div className="px-2 py-1.5 text-xs text-muted-foreground">
|
</div>
|
||||||
{t('terminal:worktree.existing')}
|
{worktrees.map((wt) => (
|
||||||
</div>
|
<DropdownMenuItem
|
||||||
{worktrees.map((wt) => (
|
key={wt.name}
|
||||||
<DropdownMenuItem
|
|
||||||
key={wt.name}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
setIsOpen(false);
|
|
||||||
onSelectWorktree(wt);
|
|
||||||
}}
|
|
||||||
className="text-xs group"
|
|
||||||
>
|
|
||||||
<FolderGit className="h-3 w-3 mr-2 text-amber-500/70 shrink-0" />
|
|
||||||
<div className="flex flex-col min-w-0 flex-1">
|
|
||||||
<span className="truncate font-medium">{wt.name}</span>
|
|
||||||
{wt.branchName && (
|
|
||||||
<span className="text-[10px] text-muted-foreground truncate">
|
|
||||||
{wt.branchName}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
setIsOpen(false);
|
||||||
setDeleteWorktree(wt);
|
onSelectWorktree(wt);
|
||||||
}}
|
}}
|
||||||
className="ml-2 p-1 rounded hover:bg-destructive/10 text-muted-foreground hover:text-destructive opacity-0 group-hover:opacity-100 transition-opacity shrink-0"
|
className="text-xs group"
|
||||||
title={t('common:delete')}
|
|
||||||
>
|
>
|
||||||
<Trash2 className="h-3 w-3" />
|
<FolderGit className="h-3 w-3 mr-2 text-amber-500/70 shrink-0" />
|
||||||
</button>
|
<div className="flex flex-col min-w-0 flex-1">
|
||||||
</DropdownMenuItem>
|
<span className="truncate font-medium">{wt.name}</span>
|
||||||
))}
|
{wt.branchName && (
|
||||||
</>
|
<span className="text-[10px] text-muted-foreground truncate">
|
||||||
)}
|
{wt.branchName}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
setDeleteWorktree(wt);
|
||||||
|
}}
|
||||||
|
className="ml-2 p-1 rounded hover:bg-destructive/10 text-muted-foreground hover:text-destructive opacity-0 group-hover:opacity-100 transition-opacity shrink-0"
|
||||||
|
title={t('common:delete')}
|
||||||
|
>
|
||||||
|
<Trash2 className="h-3 w-3" />
|
||||||
|
</button>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Task Worktrees Section */}
|
{/* Task Worktrees Section */}
|
||||||
{taskWorktrees.length > 0 && (
|
{taskWorktrees.length > 0 && (
|
||||||
<>
|
<>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<div className="px-2 py-1.5 text-xs text-muted-foreground">
|
<div className="px-2 py-1.5 text-xs text-muted-foreground">
|
||||||
{t('terminal:worktree.taskWorktrees')}
|
{t('terminal:worktree.taskWorktrees')}
|
||||||
</div>
|
</div>
|
||||||
{taskWorktrees.map((wt) => (
|
{taskWorktrees.map((wt) => (
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
key={wt.specName}
|
key={wt.specName}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
selectTaskWorktree(wt);
|
selectTaskWorktree(wt);
|
||||||
}}
|
}}
|
||||||
className="text-xs group"
|
className="text-xs group"
|
||||||
>
|
>
|
||||||
<ListTodo className="h-3 w-3 mr-2 text-cyan-500/70 shrink-0" />
|
<ListTodo className="h-3 w-3 mr-2 text-cyan-500/70 shrink-0" />
|
||||||
<div className="flex flex-col min-w-0 flex-1">
|
<div className="flex flex-col min-w-0 flex-1">
|
||||||
<span className="truncate font-medium">{wt.specName}</span>
|
<span className="truncate font-medium">{wt.specName}</span>
|
||||||
{wt.branch && (
|
{wt.branch && (
|
||||||
<span className="text-[10px] text-muted-foreground truncate">
|
<span className="text-[10px] text-muted-foreground truncate">
|
||||||
{wt.branch}
|
{wt.branch}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
</ScrollArea>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user