diff --git a/src/renderer/src/components/sidebar/WorktreeCard.quick-actions.test.tsx b/src/renderer/src/components/sidebar/WorktreeCard.quick-actions.test.tsx index e6fb3c5f2f1..34a544e1c7a 100644 --- a/src/renderer/src/components/sidebar/WorktreeCard.quick-actions.test.tsx +++ b/src/renderer/src/components/sidebar/WorktreeCard.quick-actions.test.tsx @@ -189,6 +189,23 @@ describe('WorktreeCard quick actions', () => { expect(markup).toContain('tabindex="0"') }) + it('does not reserve an empty metadata row for detached git worktrees', () => { + worktreeCardProperties = [] + + const markup = renderToStaticMarkup( + + ) + + expect(markup).toContain('orca') + expect(markup).not.toContain('data-worktree-card-meta-row=""') + expect(markup).toContain('tabindex="0"') + }) + it('omits the repeated branch metadata row when compact cards are enabled', () => { worktreeCardProperties = [] settings = { experimentalCompactWorktreeCards: true } diff --git a/src/renderer/src/components/sidebar/WorktreeCard.tsx b/src/renderer/src/components/sidebar/WorktreeCard.tsx index 2d40c6c3bbb..90fc73bfcb4 100644 --- a/src/renderer/src/components/sidebar/WorktreeCard.tsx +++ b/src/renderer/src/components/sidebar/WorktreeCard.tsx @@ -584,7 +584,8 @@ const WorktreeCard = React.memo(function WorktreeCard({ const cacheTtlMs = useAppStore((s) => s.settings?.promptCacheTtlMs ?? 0) const showInlineRepoBadge = compactCards && !!repo && !hideRepoBadge && !isFolder const showRepoBadgeInMetaRow = !compactCards && !!repo && !hideRepoBadge - const showBranch = !isFolder && (!compactCards || branch !== worktree.displayName) + const showBranch = + !isFolder && branch.length > 0 && (!compactCards || branch !== worktree.displayName) // Why: rebases already surface in source control; keep dense cards from // carrying a persistent rebase chip while preserving other interruption cues. const showConflictOperationBadge = @@ -598,9 +599,20 @@ const WorktreeCard = React.memo(function WorktreeCard({ const showTitleRowUnread = compactCards && showUnreadQuickAction && !showStatus const showTitleRowPrimary = compactCards && worktree.isMainWorktree && !isFolder const showMetaRowDetails = !compactCards && (hasDetails || hasPorts) - // Why: detailed layout is the user's explicit choice to reserve a scannable - // metadata lane; compact layout only opens that lane for transient state. - const hasMetaRow = !compactCards || hasMetadataBadge || cacheStartedAt != null + // Why: detailed cards need a stable metadata lane only when it has content. + // Detached git worktrees can have no branch text, and grouped project + // views hide the repo badge; don't reserve a blank metadata lane in that case. + const hasDetailedMetaRowContent = Boolean( + (showRepoBadgeInMetaRow && repo) || + isFolder || + showBranch || + showConflictOperationBadge || + cacheStartedAt != null || + showMetaRowDetails + ) + const hasMetaRow = compactCards + ? hasMetadataBadge || cacheStartedAt != null + : hasDetailedMetaRowContent const showHeaderActions = showTitleRowUnread || showTitleRowPrimary || showDeleteQuickAction const showBranchIdentityHover = compactCards && showBranch // Why: sidebar rows need a small surface inset, while their content remains