Skip to content
Source
Sign inSign up

ThreadCommandSubtitle.tsx

111 lines3.9 KB

1import type { ProviderDriverKind } from "@t3tools/contracts";
2import { FolderGit2Icon, FolderIcon, GitBranchIcon } from "lucide-react";
3import { ProjectFavicon, type ProjectFaviconProject } from "./ProjectFavicon";
4import { ProviderInstanceIcon } from "./chat/ProviderInstanceIcon";
5import { cn } from "~/lib/utils";
6​
7import { MiddleTruncate } from "./ui/middle-truncate";
8​
9export type ThreadCommandSubtitleVariant =
10 | "favicon-workspace-harness"
11 | "favicon-workspace"
12 | "favicon-branch-harness";
13​
14const THREAD_COMMAND_SUBTITLE_VARIANT: ThreadCommandSubtitleVariant = "favicon-workspace-harness";
15​
16export const COMMAND_PALETTE_META_ICON_CLASS = "size-3 shrink-0 text-muted-foreground/70";
17​
18export function CommandPaletteMetaDot() {
19 return <span className="shrink-0 text-muted-foreground/50">·</span>;
21​
22function WorkspaceIcon(props: { variant: ThreadCommandSubtitleVariant; isWorktree: boolean }) {
23 if (props.isWorktree) {
24 return <FolderGit2Icon className={COMMAND_PALETTE_META_ICON_CLASS} aria-hidden />;
25 }
26 if (props.variant === "favicon-branch-harness") {
27 return <GitBranchIcon className={COMMAND_PALETTE_META_ICON_CLASS} aria-hidden />;
28 }
29 return <FolderIcon className={COMMAND_PALETTE_META_ICON_CLASS} aria-hidden />;
31​
32export function ThreadCommandSubtitle(props: {
33 project: ProjectFaviconProject | null;
34 projectTitle: string | null;
35 environmentLabel?: string | null;
36 branch: string | null;
37 worktreePath: string | null;
38 isCurrent: boolean;
39 driverKind?: ProviderDriverKind | null;
40 providerDisplayName?: string | null;
41 acpRegistryAgentId?: string | undefined;
42 acpRegistryIconUrl?: string | undefined;
43 variant?: ThreadCommandSubtitleVariant;
44 className?: string;
45}) {
46 const variant = props.variant ?? THREAD_COMMAND_SUBTITLE_VARIANT;
47 const isWorktree = props.worktreePath != null && props.worktreePath.trim().length > 0;
48 const showHarness =
49 variant !== "favicon-workspace" && props.driverKind != null && props.providerDisplayName;
50​
51 const projectLabel = props.projectTitle?.trim() || null;
52 const branchLabel = props.branch?.trim() || null;
53​
54 if (!projectLabel && !branchLabel && !props.isCurrent && !showHarness) {
55 return null;
56 }
57​
58 return (
59 <span
60 className={cn(
61 "inline-flex min-w-0 max-w-full items-center gap-1 text-xs text-muted-foreground/70",
62 props.className,
63 )}
64 >
65 {projectLabel ? (
66 <span className="inline-flex min-w-0 items-center gap-1">
67 {props.project ? (
68 <ProjectFavicon project={props.project} className="size-3 shrink-0" />
69 ) : null}
70 <span className="min-w-0 truncate">{projectLabel}</span>
71 {props.environmentLabel ? (
72 <>
73 <CommandPaletteMetaDot />
74 <span className="shrink-0">{props.environmentLabel}</span>
75 </>
76 ) : null}
77 </span>
78 ) : null}
79​
80 {branchLabel ? (
81 <>
82 {projectLabel ? <CommandPaletteMetaDot /> : null}
83 <span className="inline-flex min-w-0 items-center gap-1">
84 <WorkspaceIcon variant={variant} isWorktree={isWorktree} />
85 <MiddleTruncate value={branchLabel} />
86 </span>
87 </>
88 ) : null}
89​
90 {showHarness && props.driverKind ? (
91 <>
92 {projectLabel || branchLabel ? <CommandPaletteMetaDot /> : null}
93 <ProviderInstanceIcon
94 driverKind={props.driverKind}
95 displayName={props.providerDisplayName ?? props.driverKind}
96 acpRegistryAgentId={props.acpRegistryAgentId}
97 acpRegistryIconUrl={props.acpRegistryIconUrl}
98 iconClassName="size-3 shrink-0 opacity-70"
99 />
100 </>
101 ) : null}
102​
103 {props.isCurrent ? (
104 <>
105 {projectLabel || branchLabel || showHarness ? <CommandPaletteMetaDot /> : null}
106 <span className="shrink-0">Current thread</span>
107 </>
108 ) : null}
109 </span>
110 );