mirror of
https://github.com/stablyai/orca.git
synced 2026-09-28 08:02:43 +00:00
feat(cmd-j): compact palette location layout
This commit is contained in:
@@ -1,15 +1,14 @@
|
||||
import type React from 'react'
|
||||
import { Smartphone } from 'lucide-react'
|
||||
import { CommandItem } from '@/components/ui/command'
|
||||
import { RepoBadgeMark } from '@/components/repo/RepoBadgeLabel'
|
||||
import { getPaletteHostBadge } from '@/components/cmd-j/palette-host-badge'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import type { BrowserPaletteItem, SimulatorPaletteItem } from './worktree-jump-palette-model'
|
||||
import type { WorktreeJumpPaletteController } from './use-worktree-jump-palette-controller'
|
||||
import {
|
||||
HighlightedText,
|
||||
PaletteHostBadgeChip,
|
||||
PaletteLocationChip,
|
||||
PaletteOpenTabPrimaryLine,
|
||||
PaletteRowShortcutBadge
|
||||
} from './worktree-jump-palette-primitives'
|
||||
@@ -67,8 +66,6 @@ export function WorktreeJumpPaletteSimulatorRow({
|
||||
secondaryText={result.secondaryText}
|
||||
secondaryRanges={result.secondaryRanges}
|
||||
secondaryMatches={result.secondaryMatches}
|
||||
worktreeName={result.worktreeName}
|
||||
worktreeRanges={result.worktreeRanges}
|
||||
sessionAge={simulatorSessionAge}
|
||||
leadingBadges={
|
||||
<>
|
||||
@@ -94,16 +91,15 @@ export function WorktreeJumpPaletteSimulatorRow({
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-1.5">
|
||||
<div className="flex min-w-0 max-w-[40%] items-center justify-end gap-1.5">
|
||||
<PaletteHostBadgeChip badge={simulatorHostBadge} />
|
||||
{simulatorRepoName && (
|
||||
<span className="inline-flex max-w-[180px] items-center gap-1.5 rounded-md border border-border bg-muted px-2 py-1 text-[11px] font-semibold leading-none text-foreground">
|
||||
<RepoBadgeMark color={simulatorRepo?.badgeColor} />
|
||||
<span className="truncate">
|
||||
<HighlightedText text={simulatorRepoName} matchRanges={result.repoRanges} />
|
||||
</span>
|
||||
</span>
|
||||
)}
|
||||
<PaletteLocationChip
|
||||
repoName={simulatorRepoName}
|
||||
repoRanges={result.repoRanges}
|
||||
repoColor={simulatorRepo?.badgeColor}
|
||||
worktreeName={result.worktreeName}
|
||||
worktreeRanges={result.worktreeRanges}
|
||||
/>
|
||||
<PaletteRowShortcutBadge
|
||||
index={controller.recentTabShortcutIndexByItem.get(entry)}
|
||||
modifierKeys={controller.digitShortcutModifiers}
|
||||
@@ -165,8 +161,6 @@ export function WorktreeJumpPaletteBrowserRow({
|
||||
secondaryText={result.secondaryText}
|
||||
secondaryRanges={result.secondaryRanges}
|
||||
secondaryMatches={result.secondaryMatches}
|
||||
worktreeName={result.worktreeName}
|
||||
worktreeRanges={result.worktreeRanges}
|
||||
sessionAge={browserSessionAge}
|
||||
leadingBadges={
|
||||
<>
|
||||
@@ -187,16 +181,15 @@ export function WorktreeJumpPaletteBrowserRow({
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-1.5">
|
||||
<div className="flex min-w-0 max-w-[40%] items-center justify-end gap-1.5">
|
||||
<PaletteHostBadgeChip badge={browserHostBadge} />
|
||||
{browserRepoName && (
|
||||
<span className="inline-flex max-w-[180px] items-center gap-1.5 rounded-md border border-border bg-muted px-2 py-1 text-[11px] font-semibold leading-none text-foreground">
|
||||
<RepoBadgeMark color={browserRepo?.badgeColor} />
|
||||
<span className="truncate">
|
||||
<HighlightedText text={browserRepoName} matchRanges={result.repoRanges} />
|
||||
</span>
|
||||
</span>
|
||||
)}
|
||||
<PaletteLocationChip
|
||||
repoName={browserRepoName}
|
||||
repoRanges={result.repoRanges}
|
||||
repoColor={browserRepo?.badgeColor}
|
||||
worktreeName={result.worktreeName}
|
||||
worktreeRanges={result.worktreeRanges}
|
||||
/>
|
||||
<PaletteRowShortcutBadge
|
||||
index={controller.recentTabShortcutIndexByItem.get(entry)}
|
||||
modifierKeys={controller.digitShortcutModifiers}
|
||||
|
||||
@@ -448,8 +448,13 @@ describe('WorktreeJumpPalette interleaved primary sections', () => {
|
||||
const title = row?.querySelector('[data-slot="palette-open-tab-title"]')
|
||||
const worktree = row?.querySelector('[data-slot="palette-open-tab-worktree"]')
|
||||
expect(title?.textContent).toBe(longTitle)
|
||||
expect(title?.classList.contains('flex-auto')).toBe(true)
|
||||
expect(title?.classList.contains('min-w-0')).toBe(true)
|
||||
expect(title?.classList.contains('shrink-0')).toBe(false)
|
||||
expect(worktree?.textContent).toBe('user-support')
|
||||
const locationChip = worktree?.closest('[data-slot="palette-location-chip"]')
|
||||
expect(locationChip).not.toBeNull()
|
||||
expect(locationChip?.parentElement?.classList.contains('max-w-[40%]')).toBe(true)
|
||||
expect(locationChip?.parentElement?.classList.contains('min-w-0')).toBe(true)
|
||||
expect(worktree?.compareDocumentPosition(title ?? document.createElement('span'))).toBe(
|
||||
Node.DOCUMENT_POSITION_PRECEDING
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { cleanup, render, type RenderResult, screen } from '@testing-library/react'
|
||||
import { afterEach, expect, it } from 'vitest'
|
||||
import { TooltipProvider } from '@/components/ui/tooltip'
|
||||
import { PaletteOpenTabPrimaryLine } from './worktree-jump-palette-primitives'
|
||||
import { PaletteLocationChip, PaletteOpenTabPrimaryLine } from './worktree-jump-palette-primitives'
|
||||
|
||||
afterEach(() => cleanup())
|
||||
|
||||
@@ -18,8 +18,6 @@ function renderPrimaryLine(
|
||||
secondaryText="src/app.ts"
|
||||
secondaryRanges={[]}
|
||||
secondaryMatches={secondaryMatches}
|
||||
worktreeName="Workspace"
|
||||
worktreeRanges={[]}
|
||||
/>
|
||||
</TooltipProvider>
|
||||
)
|
||||
@@ -45,3 +43,92 @@ it('renders no badge when every secondary match is already shown', () => {
|
||||
|
||||
expect(screen.queryByText(/^\+\d+$/)).toBeNull()
|
||||
})
|
||||
|
||||
it('elides a deep path from the head so the matched tail stays visible', () => {
|
||||
const path = '/Users/me/projects/orca/new-create-button-design/proposals/create-button.html'
|
||||
const start = path.indexOf('create-butt')
|
||||
const { container } = render(
|
||||
<TooltipProvider>
|
||||
<PaletteOpenTabPrimaryLine
|
||||
title="Design"
|
||||
titleRanges={[]}
|
||||
secondaryText={path}
|
||||
secondaryRanges={[{ start, end: start + 'create-butt'.length }]}
|
||||
/>
|
||||
</TooltipProvider>
|
||||
)
|
||||
|
||||
const secondary = container.querySelector('[data-slot="palette-open-tab-secondary"]')
|
||||
expect(secondary?.textContent).toBe(path)
|
||||
const [head, tail] = Array.from(secondary?.children ?? [])
|
||||
expect(head?.textContent).toBe('/Users/me/projects/orca')
|
||||
expect(tail?.textContent).toBe('/new-create-button-design/proposals/create-button.html')
|
||||
expect(tail?.querySelector('.font-semibold')?.textContent).toBe('create-butt')
|
||||
})
|
||||
|
||||
it('folds the worktree into the repo chip and drops it when it repeats the repo name', () => {
|
||||
const { container, rerender } = render(
|
||||
<TooltipProvider>
|
||||
<PaletteLocationChip
|
||||
repoName="orca"
|
||||
repoRanges={[]}
|
||||
worktreeName="new-create-button-design"
|
||||
worktreeRanges={[]}
|
||||
/>
|
||||
</TooltipProvider>
|
||||
)
|
||||
expect(container.querySelector('[data-slot="palette-location-chip"]')?.textContent).toBe(
|
||||
'orca·new-create-button-design'
|
||||
)
|
||||
const chip = container.querySelector('[data-slot="palette-location-chip"]')
|
||||
const repo = container.querySelector('[data-slot="palette-location-repo"]')
|
||||
const worktree = container.querySelector('[data-slot="palette-open-tab-worktree"]')
|
||||
expect(chip?.className).toContain('overflow-hidden')
|
||||
expect(chip?.className).toContain('min-w-0')
|
||||
expect(repo?.className).toContain('max-w-[55%]')
|
||||
expect(repo?.className).toContain('min-w-[3ch]')
|
||||
expect(worktree?.className).toContain('min-w-[3ch]')
|
||||
expect(worktree?.getAttribute('data-state')).toBeNull()
|
||||
expect(worktree?.getAttribute('tabindex')).toBeNull()
|
||||
|
||||
rerender(
|
||||
<TooltipProvider>
|
||||
<PaletteLocationChip
|
||||
repoName="orca"
|
||||
repoRanges={[]}
|
||||
worktreeName="orca"
|
||||
worktreeRanges={[{ start: 0, end: 4 }]}
|
||||
/>
|
||||
</TooltipProvider>
|
||||
)
|
||||
expect(container.querySelector('[data-slot="palette-location-chip"]')?.textContent).toBe('orca')
|
||||
expect(
|
||||
container.querySelector('[data-slot="palette-location-repo"] .font-semibold')?.textContent
|
||||
).toBe('orca')
|
||||
})
|
||||
|
||||
it('keeps a short title at its natural width so the session age stays beside it', () => {
|
||||
const { container } = render(
|
||||
<TooltipProvider>
|
||||
<PaletteOpenTabPrimaryLine
|
||||
title="Terminal 1"
|
||||
titleRanges={[]}
|
||||
secondaryText=""
|
||||
secondaryRanges={[]}
|
||||
sessionAge="2d"
|
||||
/>
|
||||
</TooltipProvider>
|
||||
)
|
||||
|
||||
const title = container.querySelector('[data-slot="palette-open-tab-title"]')
|
||||
expect(title?.className).toContain('min-w-0')
|
||||
expect(title?.className).not.toContain('shrink-0')
|
||||
})
|
||||
|
||||
it('caps the title only when it shares the line with secondary text', () => {
|
||||
const { container } = renderPrimaryLine([])
|
||||
|
||||
const title = container.querySelector('[data-slot="palette-open-tab-title"]')
|
||||
expect(title?.className).toContain('max-w-[62%]')
|
||||
expect(title?.className).toContain('shrink-0')
|
||||
})
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import React, { useLayoutEffect, useRef, useState } from 'react'
|
||||
import React from 'react'
|
||||
import { ShortcutKeyCombo } from '@/components/ShortcutKeyCombo'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import type { PaletteHostBadge } from '@/components/cmd-j/palette-host-badge'
|
||||
import type { MatchRange, PaletteSearchResult } from '@/lib/worktree-palette-search'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
import type { Worktree } from '../../../shared/worktree/types'
|
||||
import { resolveWorktreeBranchLabel } from '@/lib/worktree-default-display-name'
|
||||
import { splitPathHeadForElision } from '@/lib/path-head-elision'
|
||||
import { RepoBadgeMark } from '@/components/repo/RepoBadgeLabel'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const NO_SECONDARY_MATCHES: readonly { text: string; ranges: readonly MatchRange[] }[] = []
|
||||
|
||||
@@ -67,14 +68,48 @@ export function HighlightedText({
|
||||
return <>{parts}</>
|
||||
}
|
||||
|
||||
function PaletteOpenTabSecondaryText({
|
||||
text,
|
||||
ranges
|
||||
}: {
|
||||
text: string
|
||||
ranges: readonly MatchRange[]
|
||||
}): React.JSX.Element {
|
||||
const split = splitPathHeadForElision(text, ranges)
|
||||
const content = split ? (
|
||||
<span
|
||||
data-slot="palette-open-tab-secondary"
|
||||
className="flex min-w-0 items-baseline overflow-hidden font-mono text-[11px] text-muted-foreground/80"
|
||||
>
|
||||
<span className="min-w-0 shrink-[999] truncate">{split.head}</span>
|
||||
<span className="min-w-0 shrink truncate">
|
||||
<HighlightedText text={split.tail} matchRanges={split.tailRanges} />
|
||||
</span>
|
||||
</span>
|
||||
) : (
|
||||
<span
|
||||
data-slot="palette-open-tab-secondary"
|
||||
className="min-w-0 truncate font-mono text-[11px] text-muted-foreground/80"
|
||||
>
|
||||
<HighlightedText text={text} matchRanges={ranges} />
|
||||
</span>
|
||||
)
|
||||
return (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>{content}</TooltipTrigger>
|
||||
<TooltipContent side="top" sideOffset={4} className="max-w-96 break-all">
|
||||
{text}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
export function PaletteOpenTabPrimaryLine({
|
||||
title,
|
||||
titleRanges,
|
||||
secondaryText,
|
||||
secondaryRanges,
|
||||
secondaryMatches = NO_SECONDARY_MATCHES,
|
||||
worktreeName,
|
||||
worktreeRanges,
|
||||
sessionAge,
|
||||
leadingBadges
|
||||
}: {
|
||||
@@ -83,13 +118,10 @@ export function PaletteOpenTabPrimaryLine({
|
||||
secondaryText: string
|
||||
secondaryRanges: readonly MatchRange[]
|
||||
secondaryMatches?: readonly { text: string; ranges: readonly MatchRange[] }[]
|
||||
worktreeName: string
|
||||
worktreeRanges: readonly MatchRange[]
|
||||
sessionAge?: string
|
||||
leadingBadges?: React.ReactNode
|
||||
}): React.JSX.Element {
|
||||
const showSecondary = secondaryText.trim().length > 0
|
||||
const showWorktree = worktreeName.trim().length > 0
|
||||
const additionalSecondaryMatches = secondaryMatches.filter(
|
||||
(match) => match.text && match.text !== secondaryText
|
||||
)
|
||||
@@ -98,7 +130,10 @@ export function PaletteOpenTabPrimaryLine({
|
||||
<div className="flex min-w-0 items-center gap-2 overflow-hidden">
|
||||
<span
|
||||
data-slot="palette-open-tab-title"
|
||||
className="min-w-0 flex-auto truncate text-[14px] font-semibold tracking-[-0.01em] text-foreground"
|
||||
className={cn(
|
||||
'truncate text-[14px] font-semibold tracking-[-0.01em] text-foreground',
|
||||
showSecondary ? 'max-w-[62%] shrink-0' : 'min-w-0'
|
||||
)}
|
||||
>
|
||||
<HighlightedText text={title} matchRanges={titleRanges} />
|
||||
</span>
|
||||
@@ -116,12 +151,7 @@ export function PaletteOpenTabPrimaryLine({
|
||||
) : null}
|
||||
{leadingBadges}
|
||||
{showSecondary ? (
|
||||
<>
|
||||
<span className="shrink-0 text-muted-foreground/45">·</span>
|
||||
<span className="min-w-0 truncate text-[12px] font-medium text-muted-foreground/92">
|
||||
<HighlightedText text={secondaryText} matchRanges={secondaryRanges} />
|
||||
</span>
|
||||
</>
|
||||
<PaletteOpenTabSecondaryText text={secondaryText} ranges={secondaryRanges} />
|
||||
) : null}
|
||||
{additionalSecondaryMatches.length ? (
|
||||
<>
|
||||
@@ -154,85 +184,76 @@ export function PaletteOpenTabPrimaryLine({
|
||||
</Tooltip>
|
||||
</>
|
||||
) : null}
|
||||
{showWorktree ? (
|
||||
<>
|
||||
<span className="shrink-0 text-muted-foreground/45">·</span>
|
||||
<span
|
||||
data-slot="palette-open-tab-worktree"
|
||||
className="min-w-0 truncate text-[12px] font-medium text-muted-foreground/92"
|
||||
>
|
||||
<HighlightedText text={worktreeName} matchRanges={worktreeRanges} />
|
||||
</span>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function resolveOpenTabWorktreeRailTooltip({
|
||||
isBranch,
|
||||
truncated,
|
||||
name
|
||||
export function PaletteLocationChip({
|
||||
repoName,
|
||||
repoRanges,
|
||||
repoColor,
|
||||
worktreeName,
|
||||
worktreeRanges,
|
||||
className
|
||||
}: {
|
||||
isBranch: boolean
|
||||
truncated: boolean
|
||||
name: string
|
||||
}): string {
|
||||
if (truncated) {
|
||||
return name
|
||||
}
|
||||
return isBranch
|
||||
? translate('auto.components.WorktreeJumpPalette.paletteOpenTabBranch', 'Branch name')
|
||||
: translate('auto.components.WorktreeJumpPalette.paletteOpenTabWorkspace', 'Workspace name')
|
||||
}
|
||||
|
||||
export function PaletteOpenTabWorktreeRailLabel({
|
||||
name,
|
||||
matchRanges,
|
||||
worktree,
|
||||
className,
|
||||
slot = 'palette-open-tab-worktree'
|
||||
}: {
|
||||
name: string
|
||||
matchRanges: readonly MatchRange[]
|
||||
worktree?: Pick<Worktree, 'branch'> | null
|
||||
repoName: string
|
||||
repoRanges: readonly MatchRange[]
|
||||
repoColor?: string
|
||||
worktreeName: string
|
||||
worktreeRanges: readonly MatchRange[]
|
||||
className?: string
|
||||
slot?: string
|
||||
}): React.JSX.Element | null {
|
||||
const [truncated, setTruncated] = useState(false)
|
||||
const labelRef = useRef<HTMLSpanElement | null>(null)
|
||||
useLayoutEffect(() => {
|
||||
const node = labelRef.current
|
||||
if (!node) {
|
||||
setTruncated(false)
|
||||
return
|
||||
}
|
||||
const updateTruncated = (): void => {
|
||||
const next = node.scrollWidth > node.clientWidth
|
||||
setTruncated((current) => (current === next ? current : next))
|
||||
}
|
||||
updateTruncated()
|
||||
if (typeof ResizeObserver === 'undefined') {
|
||||
return
|
||||
}
|
||||
const observer = new ResizeObserver(updateTruncated)
|
||||
observer.observe(node)
|
||||
return () => observer.disconnect()
|
||||
}, [name])
|
||||
if (name.trim().length === 0) {
|
||||
const showRepo = repoName.trim().length > 0
|
||||
const repeatedName = showRepo && worktreeName === repoName
|
||||
const showWorktree = worktreeName.trim().length > 0 && !repeatedName
|
||||
if (!showRepo && !showWorktree) {
|
||||
return null
|
||||
}
|
||||
const isBranch = worktree != null && name === resolveWorktreeBranchLabel(worktree)
|
||||
const tooltip = resolveOpenTabWorktreeRailTooltip({ isBranch, truncated, name })
|
||||
const repoMatchRanges = repeatedName
|
||||
? [...repoRanges, ...worktreeRanges].sort((left, right) => left.start - right.start)
|
||||
: repoRanges
|
||||
const label = [showRepo ? repoName : '', showWorktree ? worktreeName : '']
|
||||
.filter(Boolean)
|
||||
.join(' · ')
|
||||
const chip = (
|
||||
<span
|
||||
data-slot="palette-location-chip"
|
||||
className={cn(
|
||||
'inline-flex min-w-0 max-w-[260px] items-center gap-1.5 overflow-hidden rounded-md border border-border bg-muted px-2 py-1 text-[11px] font-semibold leading-none text-foreground',
|
||||
className
|
||||
)}
|
||||
>
|
||||
{showRepo ? (
|
||||
<>
|
||||
<RepoBadgeMark color={repoColor} />
|
||||
<span
|
||||
className={cn('min-w-0 truncate', showWorktree && 'min-w-[3ch] max-w-[55%]')}
|
||||
data-slot="palette-location-repo"
|
||||
>
|
||||
<HighlightedText text={repoName} matchRanges={repoMatchRanges} />
|
||||
</span>
|
||||
</>
|
||||
) : null}
|
||||
{showRepo && showWorktree ? (
|
||||
<span aria-hidden className="shrink-0 text-muted-foreground/50">
|
||||
·
|
||||
</span>
|
||||
) : null}
|
||||
{showWorktree ? (
|
||||
<span
|
||||
data-slot="palette-open-tab-worktree"
|
||||
className="min-w-[3ch] truncate font-medium text-muted-foreground"
|
||||
>
|
||||
<HighlightedText text={worktreeName} matchRanges={worktreeRanges} />
|
||||
</span>
|
||||
) : null}
|
||||
</span>
|
||||
)
|
||||
return (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span ref={labelRef} data-slot={slot} tabIndex={-1} className={className}>
|
||||
<HighlightedText text={name} matchRanges={matchRanges} />
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" sideOffset={6} className="max-w-80 break-all">
|
||||
{tooltip}
|
||||
<TooltipTrigger asChild>{chip}</TooltipTrigger>
|
||||
<TooltipContent side="top" sideOffset={4} className="max-w-96 break-all">
|
||||
{label}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)
|
||||
|
||||
@@ -3,15 +3,14 @@ import { FileText, SquareTerminal } from 'lucide-react'
|
||||
import { AgentIcon } from '@/lib/agent-catalog'
|
||||
import { CommandItem } from '@/components/ui/command'
|
||||
import { PaletteRecentTabStatusDot } from '@/components/cmd-j/palette-live-status'
|
||||
import { RepoBadgeMark } from '@/components/repo/RepoBadgeLabel'
|
||||
import { getPaletteHostBadge } from '@/components/cmd-j/palette-host-badge'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import type { WorkspaceTabPaletteItem } from './worktree-jump-palette-model'
|
||||
import type { WorktreeJumpPaletteController } from './use-worktree-jump-palette-controller'
|
||||
import {
|
||||
HighlightedText,
|
||||
PaletteHostBadgeChip,
|
||||
PaletteLocationChip,
|
||||
PaletteOpenTabPrimaryLine,
|
||||
PaletteRowShortcutBadge
|
||||
} from './worktree-jump-palette-primitives'
|
||||
@@ -76,8 +75,6 @@ export function WorktreeJumpPaletteWorkspaceTabRow({
|
||||
secondaryText={result.secondaryText}
|
||||
secondaryRanges={result.secondaryRanges}
|
||||
secondaryMatches={result.secondaryMatches}
|
||||
worktreeName={result.worktreeName}
|
||||
worktreeRanges={result.worktreeRanges}
|
||||
sessionAge={sessionAge}
|
||||
leadingBadges={
|
||||
<>
|
||||
@@ -103,16 +100,15 @@ export function WorktreeJumpPaletteWorkspaceTabRow({
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-1.5">
|
||||
<div className="flex min-w-0 max-w-[40%] items-center justify-end gap-1.5">
|
||||
<PaletteHostBadgeChip badge={workspaceTabHostBadge} />
|
||||
{workspaceTabRepoName && (
|
||||
<span className="inline-flex max-w-[180px] items-center gap-1.5 rounded-md border border-border bg-muted px-2 py-1 text-[11px] font-semibold leading-none text-foreground">
|
||||
<RepoBadgeMark color={workspaceTabRepo?.badgeColor} />
|
||||
<span className="truncate">
|
||||
<HighlightedText text={workspaceTabRepoName} matchRanges={result.repoRanges} />
|
||||
</span>
|
||||
</span>
|
||||
)}
|
||||
<PaletteLocationChip
|
||||
repoName={workspaceTabRepoName}
|
||||
repoRanges={result.repoRanges}
|
||||
repoColor={workspaceTabRepo?.badgeColor}
|
||||
worktreeName={result.worktreeName}
|
||||
worktreeRanges={result.worktreeRanges}
|
||||
/>
|
||||
<PaletteRowShortcutBadge
|
||||
index={controller.recentTabShortcutIndexByItem.get(entry)}
|
||||
modifierKeys={controller.digitShortcutModifiers}
|
||||
|
||||
Reference in New Issue
Block a user