refactor: improve PR display and interaction in worktree components

- Updated WorktreeActionsDropdown to use DropdownMenuItem for better interaction with PR links.
- Enhanced WorktreeTab to include hover and active states for buttons, and improved accessibility with updated titles and aria-labels.
- Ensured PR URLs are safely opened only if they exist, enhancing user experience and preventing errors.
This commit is contained in:
Cody Seibert
2025-12-19 20:46:23 -05:00
parent ec7c2892c2
commit bb5f68c2f0
2 changed files with 19 additions and 10 deletions

View File

@@ -185,13 +185,18 @@ export function WorktreeActionsDropdown({
{/* Show PR info and Address Comments button if PR exists */} {/* Show PR info and Address Comments button if PR exists */}
{!worktree.isMain && hasPR && worktree.pr && ( {!worktree.isMain && hasPR && worktree.pr && (
<> <>
<DropdownMenuLabel className="text-xs flex items-center gap-2"> <DropdownMenuItem
<GitPullRequest className="w-3 h-3" /> onClick={() => {
window.open(worktree.pr!.url, "_blank");
}}
className="text-xs"
>
<GitPullRequest className="w-3 h-3 mr-2" />
PR #{worktree.pr.number} PR #{worktree.pr.number}
<span className="ml-auto text-[10px] bg-green-500/20 text-green-600 px-1.5 py-0.5 rounded"> <span className="ml-auto text-[10px] bg-green-500/20 text-green-600 px-1.5 py-0.5 rounded uppercase">
{worktree.pr.state} {worktree.pr.state}
</span> </span>
</DropdownMenuLabel> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
onClick={() => { onClick={() => {
// Convert stored PR info to the full PRInfo format for the handler // Convert stored PR info to the full PRInfo format for the handler

View File

@@ -157,7 +157,7 @@ export function WorktreeTab({
className={cn( className={cn(
"ml-1.5 inline-flex items-center gap-1 rounded-full border px-1.5 py-0.5 text-[10px] font-medium transition-colors", "ml-1.5 inline-flex items-center gap-1 rounded-full border px-1.5 py-0.5 text-[10px] font-medium transition-colors",
"focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-1 focus:ring-offset-background", "focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-1 focus:ring-offset-background",
"appearance-none cursor-pointer", // Reset button appearance but keep cursor "appearance-none cursor-pointer hover:opacity-80 active:opacity-70", // Reset button appearance but keep cursor, add hover/active states
prStateClasses prStateClasses
)} )}
style={{ style={{
@@ -165,24 +165,28 @@ export function WorktreeTab({
backgroundImage: "none", backgroundImage: "none",
boxShadow: "none", boxShadow: "none",
}} }}
title={prLabel} title={`${prLabel} - Click to open`}
aria-label={prLabel} aria-label={`${prLabel} - Click to open pull request`}
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); // Prevent triggering worktree selection e.stopPropagation(); // Prevent triggering worktree selection
window.open(worktree.pr.url, "_blank", "noopener,noreferrer"); if (worktree.pr?.url) {
window.open(worktree.pr.url, "_blank", "noopener,noreferrer");
}
}} }}
onKeyDown={(e) => { onKeyDown={(e) => {
// Prevent event from bubbling to parent button // Prevent event from bubbling to parent button
e.stopPropagation(); e.stopPropagation();
if (e.key === "Enter" || e.key === " ") { if (e.key === "Enter" || e.key === " ") {
e.preventDefault(); e.preventDefault();
window.open(worktree.pr.url, "_blank", "noopener,noreferrer"); if (worktree.pr?.url) {
window.open(worktree.pr.url, "_blank", "noopener,noreferrer");
}
} }
}} }}
> >
<GitPullRequest className={cn("w-3 h-3", getStatusColorClass())} aria-hidden="true" /> <GitPullRequest className={cn("w-3 h-3", getStatusColorClass())} aria-hidden="true" />
<span aria-hidden="true" className={isSelected ? "text-foreground font-semibold" : ""}> <span aria-hidden="true" className={isSelected ? "text-foreground font-semibold" : ""}>
#{worktree.pr.number} PR #{worktree.pr.number}
</span> </span>
<span className={cn("capitalize", getStatusColorClass())} aria-hidden="true"> <span className={cn("capitalize", getStatusColorClass())} aria-hidden="true">
{prState} {prState}