{"name":"assistant-ui-thread","type":"registry:block","dependencies":["@assistant-ui/react","@assistant-ui/react-ui","lucide-react","@assistant-ui/react-markdown"],"registryDependencies":["button","https://r.assistant-ui.com/tooltip-icon-button.json","https://r.assistant-ui.com/markdown-text.json","https://r.assistant-ui.com/tool-fallback.json","https://r.assistant-ui.com/attachment.json"],"files":[{"path":"components/assistant-ui/thread.tsx","content":"\"use client\";\n\nimport {\n  ArrowUpIcon,\n  BotIcon,\n  CheckIcon,\n  ChevronLeftIcon,\n  ChevronRightIcon,\n  CopyIcon,\n  DownloadIcon,\n  LoaderIcon,\n  PencilIcon,\n  RefreshCwIcon,\n  SquareIcon,\n  ThumbsDownIcon,\n  ThumbsUpIcon,\n  UserIcon,\n} from \"lucide-react\";\nimport {\n  ActionBarPrimitive,\n  AuiIf,\n  BranchPickerPrimitive,\n  ComposerPrimitive,\n  ErrorPrimitive,\n  MessagePrimitive,\n  ThreadPrimitive,\n} from \"@assistant-ui/react\";\nimport \"@assistant-ui/react-markdown/styles/dot.css\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { TooltipIconButton } from \"@/components/assistant-ui/tooltip-icon-button\";\nimport { MarkdownText } from \"@/components/assistant-ui/markdown-text\";\nimport { ToolFallback } from \"@/components/assistant-ui/tool-fallback\";\nimport {\n  ComposerAddAttachment,\n  ComposerAttachments,\n  UserMessageAttachments,\n} from \"@/components/assistant-ui/attachment\";\nimport { cn } from \"@/lib/utils\";\nexport function Thread() {\n  return (\n    <ThreadPrimitive.Root\n      className=\"flex h-full flex-col bg-background text-base\"\n      style={{\n        \"--thread-max-width\": \"48rem\",\n        \"--accent-color\": \"#10a37f\",\n        \"--accent-foreground\": \"#ffffff\",\n      }}\n    >\n      <ThreadPrimitive.Viewport\n        turnAnchor=\"top\"\n        className=\"relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll scroll-smooth px-4 pt-4\"\n      >\n        <AuiIf condition={(s) => s.thread.isEmpty}>\n          <ThreadWelcome />\n        </AuiIf>\n\n        <ThreadPrimitive.Messages\n          components={{\n            UserMessage,\n            EditComposer,\n            AssistantMessage,\n          }}\n        />\n\n        <ThreadPrimitive.ViewportFooter className=\"sticky bottom-0 mx-auto mt-auto flex w-full max-w-[var(--thread-max-width)] flex-col gap-4 overflow-visible rounded-t-3xl bg-background pb-4\">\n          \n          <Composer />\n        </ThreadPrimitive.ViewportFooter>\n      </ThreadPrimitive.Viewport>\n    </ThreadPrimitive.Root>\n  );\n}\nfunction ThreadWelcome() {\n  return (\n    <div className=\"mx-auto my-auto flex w-full max-w-[var(--thread-max-width)] flex-grow flex-col\">\n      <div className=\"flex w-full flex-grow flex-col items-center justify-center\">\n        <div className=\"flex size-full flex-col justify-center px-8\">\n          <div className=\"text-2xl font-semibold\">Hello there!</div>\n          <div className=\"text-2xl text-muted-foreground/65\">\n            How can I help you today?\n          </div>\n        </div>\n      </div>\n      \n    </div>\n  );\n}\n\nfunction Composer() {\n  return (\n    <ComposerPrimitive.Root className=\"relative flex w-full flex-col\">\n      <ComposerPrimitive.AttachmentDropzone className=\"flex w-full flex-col rounded-3xl border border-input bg-background px-1 pt-2 outline-none transition-shadow has-[textarea:focus-visible]:border-ring has-[textarea:focus-visible]:ring-2 has-[textarea:focus-visible]:ring-ring/20 data-[dragging=true]:border-ring data-[dragging=true]:border-dashed data-[dragging=true]:bg-accent/50\">\n        <ComposerAttachments />\n        <ComposerPrimitive.Input\n          placeholder=\"Send a message...\"\n          className=\"mb-1 max-h-32 min-h-14 w-full resize-none bg-transparent px-4 pt-2 pb-3 text-sm outline-none placeholder:text-muted-foreground focus-visible:ring-0\"\n          rows={1}\n          autoFocus\n          aria-label=\"Message input\"\n        />\n        <ComposerAction />\n      </ComposerPrimitive.AttachmentDropzone>\n    </ComposerPrimitive.Root>\n  );\n}\n\nfunction ComposerAction() {\n  return (\n    <div className=\"relative mx-2 mb-2 flex items-center justify-between\">\n      <ComposerAddAttachment />\n\n      <AuiIf condition={(s) => !s.thread.isRunning}>\n        <ComposerPrimitive.Send asChild>\n          <TooltipIconButton\n            tooltip=\"Send message\"\n            side=\"bottom\"\n            type=\"submit\"\n            variant=\"default\"\n            size=\"icon\"\n            className=\"size-8 rounded-full\"\n            style={{\n              backgroundColor: \"var(--accent-color)\",\n              color: \"var(--accent-foreground)\",\n            }}\n            aria-label=\"Send message\"\n          >\n            <ArrowUpIcon className=\"size-4\" />\n          </TooltipIconButton>\n        </ComposerPrimitive.Send>\n      </AuiIf>\n\n      <AuiIf condition={(s) => s.thread.isRunning}>\n        <ComposerPrimitive.Cancel asChild>\n          <Button\n            type=\"button\"\n            variant=\"default\"\n            size=\"icon\"\n            className=\"size-8 rounded-full\"\n            style={{\n              backgroundColor: \"var(--accent-color)\",\n              color: \"var(--accent-foreground)\",\n            }}\n            aria-label=\"Stop generating\"\n          >\n            <SquareIcon className=\"size-3 fill-current\" />\n          </Button>\n        </ComposerPrimitive.Cancel>\n      </AuiIf>\n    </div>\n  );\n}\n\nfunction UserMessage() {\n  return (\n    <MessagePrimitive.Root\n      className=\"mx-auto grid w-full max-w-[var(--thread-max-width)] auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] content-start gap-y-2 px-2 py-4 fade-in slide-in-from-bottom-1 animate-in duration-150\"\n      data-role=\"user\"\n    >\n      <UserMessageAttachments />\n\n      <div className=\"relative col-start-2 min-w-0\">\n        <div className=\"rounded-3xl bg-muted px-4 py-2.5 break-words text-foreground\">\n          <MessagePrimitive.Parts />\n        </div>\n        <div className=\"absolute top-1/2 left-0 -translate-x-full -translate-y-1/2 pr-2\">\n          <UserActionBar />\n        </div>\n      </div>\n\n      <BranchPicker className=\"col-span-full col-start-1 row-start-3 -mr-1 justify-end\" />\n    </MessagePrimitive.Root>\n  );\n}\n\nfunction UserActionBar() {\n  return (\n    <ActionBarPrimitive.Root\n      hideWhenRunning\n      autohide=\"not-last\"\n      className=\"flex flex-col items-end\"\n    >\n      <ActionBarPrimitive.Edit asChild>\n        <TooltipIconButton tooltip=\"Edit\" className=\"p-4\">\n          <PencilIcon />\n        </TooltipIconButton>\n      </ActionBarPrimitive.Edit>\n    </ActionBarPrimitive.Root>\n  );\n}\n\nfunction EditComposer() {\n  return (\n    <MessagePrimitive.Root className=\"mx-auto flex w-full max-w-[var(--thread-max-width)] flex-col px-2 py-3\">\n      <ComposerPrimitive.Root className=\"ml-auto flex w-full max-w-[85%] flex-col rounded-3xl bg-muted\">\n        <ComposerPrimitive.Input\n          className=\"min-h-14 w-full resize-none bg-transparent p-4 text-foreground text-sm outline-none\"\n          autoFocus\n        />\n        <div className=\"mx-3 mb-3 flex items-center gap-2 self-end\">\n          <ComposerPrimitive.Cancel asChild>\n            <Button variant=\"ghost\" size=\"sm\">Cancel</Button>\n          </ComposerPrimitive.Cancel>\n          <ComposerPrimitive.Send asChild>\n            <Button size=\"sm\">Update</Button>\n          </ComposerPrimitive.Send>\n        </div>\n      </ComposerPrimitive.Root>\n    </MessagePrimitive.Root>\n  );\n}\n\nfunction AssistantMessage() {\n  return (\n    <MessagePrimitive.Root\n      className=\"relative mx-auto w-full max-w-[var(--thread-max-width)] py-4 fade-in slide-in-from-bottom-1 animate-in duration-150\"\n      data-role=\"assistant\"\n    >\n      <div className=\"flex size-8 shrink-0 items-center justify-center rounded-full bg-primary/10\">\n        <BotIcon className=\"size-4\" />\n      </div>\n      <div className=\"break-words px-2 leading-relaxed text-foreground\">\n        <MessagePrimitive.Parts\n          components={{\n            Text: MarkdownText,\n            tools: { Fallback: ToolFallback },\n          }}\n        />\n        <MessageError />\n        <AuiIf condition={(s) => s.thread.isRunning && s.message.content.length === 0}>\n          <div className=\"flex items-center gap-2 text-muted-foreground\">\n            <LoaderIcon className=\"size-4 animate-spin\" />\n            <span className=\"text-sm\">Thinking...</span>\n          </div>\n        </AuiIf>\n      </div>\n\n      <div className=\"mt-1 ml-2 flex min-h-6 items-center\">\n        <BranchPicker />\n        <AssistantActionBar />\n      </div>\n      \n    </MessagePrimitive.Root>\n  );\n}\n\nfunction MessageError() {\n  return (\n    <MessagePrimitive.Error>\n      <ErrorPrimitive.Root className=\"mt-2 rounded-md border border-destructive bg-destructive/10 p-3 text-destructive text-sm dark:bg-destructive/5 dark:text-red-200\">\n        <ErrorPrimitive.Message className=\"line-clamp-2\" />\n      </ErrorPrimitive.Root>\n    </MessagePrimitive.Error>\n  );\n}\n\nfunction AssistantActionBar() {\n  return (\n    <ActionBarPrimitive.Root\n      hideWhenRunning\n      autohide=\"not-last\"\n      className=\"-ml-1 flex gap-1 text-muted-foreground\"\n    >\n      <ActionBarPrimitive.Copy asChild>\n        <TooltipIconButton tooltip=\"Copy\">\n          <AuiIf condition={(s) => s.message.isCopied}>\n            <CheckIcon />\n          </AuiIf>\n          <AuiIf condition={(s) => !s.message.isCopied}>\n            <CopyIcon />\n          </AuiIf>\n        </TooltipIconButton>\n      </ActionBarPrimitive.Copy>\n      <ActionBarPrimitive.ExportMarkdown asChild>\n        <TooltipIconButton tooltip=\"Export as Markdown\">\n          <DownloadIcon />\n        </TooltipIconButton>\n      </ActionBarPrimitive.ExportMarkdown>\n      <ActionBarPrimitive.Reload asChild>\n        <TooltipIconButton tooltip=\"Refresh\">\n          <RefreshCwIcon />\n        </TooltipIconButton>\n      </ActionBarPrimitive.Reload>\n      \n      <ActionBarPrimitive.FeedbackPositive asChild>\n        <TooltipIconButton tooltip=\"Good response\">\n          <ThumbsUpIcon />\n        </TooltipIconButton>\n      </ActionBarPrimitive.FeedbackPositive>\n      <ActionBarPrimitive.FeedbackNegative asChild>\n        <TooltipIconButton tooltip=\"Bad response\">\n          <ThumbsDownIcon />\n        </TooltipIconButton>\n      </ActionBarPrimitive.FeedbackNegative>\n    </ActionBarPrimitive.Root>\n  );\n}\n\nfunction BranchPicker({ className, ...rest }: { className?: string }) {\n  return (\n    <BranchPickerPrimitive.Root\n      hideWhenSingleBranch\n      className={cn(\"mr-2 -ml-2 inline-flex items-center text-xs text-muted-foreground\", className)}\n      {...rest}\n    >\n      <BranchPickerPrimitive.Previous asChild>\n        <TooltipIconButton tooltip=\"Previous\">\n          <ChevronLeftIcon />\n        </TooltipIconButton>\n      </BranchPickerPrimitive.Previous>\n      <span className=\"font-medium\">\n        <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />\n      </span>\n      <BranchPickerPrimitive.Next asChild>\n        <TooltipIconButton tooltip=\"Next\">\n          <ChevronRightIcon />\n        </TooltipIconButton>\n      </BranchPickerPrimitive.Next>\n    </BranchPickerPrimitive.Root>\n  );\n}","type":"registry:component"}],"cssVars":{"light":{"--aui-accent":"#10a37f","--aui-accent-foreground":"#ffffff","--aui-background":"#ffffff","--aui-foreground":"#0d0d0d","--aui-muted-foreground":"#6e6e6e","--aui-border":"#e5e5e5","--aui-user-message":"#f7f7f8","--aui-composer":"#f7f7f8","--aui-max-width":"48rem","--aui-border-radius":"1.5rem","--aui-font-family":"system-ui"},"dark":{"--aui-accent":"#ffffff","--aui-accent-foreground":"#000000","--aui-background":"#212121","--aui-foreground":"#ececec","--aui-muted-foreground":"#9b9b9b","--aui-border":"#424242","--aui-user-message":"#2f2f2f","--aui-composer":"#2f2f2f","--aui-max-width":"48rem","--aui-border-radius":"1.5rem","--aui-font-family":"system-ui"}}}