diff --git a/apps/web/src/components/BranchToolbarBranchSelector.tsx b/apps/web/src/components/BranchToolbarBranchSelector.tsx index 3bab1315ee8b..9ca02389b192 100644 --- a/apps/web/src/components/BranchToolbarBranchSelector.tsx +++ b/apps/web/src/components/BranchToolbarBranchSelector.tsx @@ -59,6 +59,7 @@ import { useLinkedThreadPullRequest, } from "./ThreadStatusIndicators"; import { Button } from "./ui/button"; +import { ComposerControl } from "./chat/ComposerControl"; import { Switch } from "./ui/switch"; import { getVirtualizedScrollFadeClassName } from "./ui/scroll-area"; import { @@ -790,7 +791,7 @@ export function BranchToolbarBranchSelector({ data-composer-context-control > } badge={prBadge} number={prNumber} url={prUrl} diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx index 95f0e062d8e0..3ec0f981d386 100644 --- a/apps/web/src/components/Sidebar.tsx +++ b/apps/web/src/components/Sidebar.tsx @@ -221,7 +221,7 @@ import { } from "../providerInstances"; import { useThreadRunningTerminalIds } from "../state/terminalSessions"; import { stackedThreadToast, toastManager } from "./ui/toast"; -import { Button } from "./ui/button"; +import { Button, InlineButton } from "./ui/button"; import { Combobox, ComboboxEmpty, @@ -1510,7 +1510,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: { const prBadge = prBadgeShape?.kind === "stack" || pr || currentLinkedPr ? ( } badge={prBadgeShape} number={pr?.number ?? currentLinkedPr?.number} url={pr?.url ?? currentLinkedPr?.url} diff --git a/apps/web/src/components/ThreadStatusIndicators.tsx b/apps/web/src/components/ThreadStatusIndicators.tsx index 8b27b74fd0a5..29020f4975a3 100644 --- a/apps/web/src/components/ThreadStatusIndicators.tsx +++ b/apps/web/src/components/ThreadStatusIndicators.tsx @@ -15,8 +15,8 @@ import { type ThreadPullRequestBadge, } from "@t3tools/shared/threadPullRequests"; import { FolderGit2Icon, TerminalIcon } from "lucide-react"; -import { useMemo, type MouseEvent } from "react"; -import { Button, InlineButton } from "./ui/button"; +import { useRender } from "@base-ui/react/use-render"; +import { useMemo, type MouseEvent, type ReactElement } from "react"; import { cn } from "../lib/utils"; import { useEnvironment, usePrimaryEnvironmentId } from "../state/environments"; import { EnvironmentMachineIcon } from "./EnvironmentMachineIcon"; @@ -191,9 +191,14 @@ export function resolveThreadPullRequestBadgePresentation({ }; } -/** The complete linked-PR control shared by the sidebar and composer footer. */ +/** + * The linked-PR badge shared by the sidebar and composer footer. The badge owns what it shows: + * the state glyph and number at the meta size, in the state's color. The caller owns the control + * it sits in through `render` (an inline link in a sidebar row, a toolbar control in the + * composer), and the badge fills in the link or stack button behavior. + */ export function ThreadPullRequestBadgeControl({ - variant, + render, badge, number, url, @@ -201,7 +206,7 @@ export function ThreadPullRequestBadgeControl({ onOpenStack, onOpenPullRequest, }: { - variant: "underline" | "ghost"; + render: ReactElement<{ render?: useRender.RenderProp }>; badge: ThreadPullRequestBadge | null; number?: number | undefined; url?: string | undefined; @@ -211,53 +216,65 @@ export function ThreadPullRequestBadgeControl({ }) { const presentation = resolveThreadPullRequestBadgePresentation({ badge, number, url, status }); if (presentation === null) return null; - const isStack = badge?.kind === "stack"; - const content = ( - <> - - {presentation.text} - + return ( + ); - const linkProps = isStack - ? { - onClick: (event: MouseEvent) => { - event.preventDefault(); - event.stopPropagation(); - onOpenStack(); - }, +} + +function PullRequestBadge({ + render, + presentation, + isStack, + url, + onOpenStack, + onOpenPullRequest, +}: { + render: ReactElement<{ render?: useRender.RenderProp }>; + presentation: NonNullable>; + isStack: boolean; + url: string | undefined; + onOpenStack: () => void; + onOpenPullRequest: (event: MouseEvent) => void; +}) { + const onClick = isStack + ? (event: MouseEvent) => { + event.preventDefault(); + event.stopPropagation(); + onOpenStack(); } - : { onClick: onOpenPullRequest }; + : onOpenPullRequest; const element = isStack ? (