import { RefreshCwIcon } from "lucide-react"; import type { ReactNode } from "react"; import { threadSyncLabel, type ThreadSyncPhase } from "../../threadSync"; import { cn } from "~/lib/utils"; import { NoticeText } from "./ComposerBannerStack"; /** A line of thread state for the end of the timeline. */ export interface ThreadNowItem { readonly id: string; readonly icon: ReactNode; readonly title: ReactNode; readonly description?: ReactNode; readonly actions?: ReactNode; } /** Matches ThreadStatusLine, so every line at the end of the timeline reads as one family. */ const lineClassName = cn( "mx-auto flex w-full min-w-0 max-w-(--chat-content-max-width) items-center gap-1.5 px-1 pb-2 text-xs text-muted-foreground [&_svg]:size-3.5 [&_svg]:shrink-0", // A details button must not make its line taller than the others. "[&_[data-slot=popover-trigger]]:-my-1.5", // Inline actions keep their text size but get a finger-sized hit area on touch. "pointer-coarse:[&_[data-slot=inline-button]]:relative pointer-coarse:[&_[data-slot=inline-button]]:after:absolute pointer-coarse:[&_[data-slot=inline-button]]:after:-inset-x-1.5 pointer-coarse:[&_[data-slot=inline-button]]:after:-inset-y-3.5", "transition-opacity duration-150 ease-out starting:opacity-0 motion-reduce:transition-none", ); /** One line of thread state at the end of the timeline: icon, title, detail, then actions. */ function ThreadNowLine({ item, announce = false, }: { readonly item: ThreadNowItem; /** Announces the line when it appears; only for something that needs the user. */ readonly announce?: boolean; }) { return (