{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "team-ai-room",
  "title": "Team AI Room",
  "description": "Collaborative AI workspace for team members with shared conversations.",
  "registryDependencies": [
    "ai-message",
    "avatar",
    "badge",
    "card",
    "empty",
    "input-group"
  ],
  "files": [
    {
      "path": "registry/new-york/blocks/team/team-ai-room.tsx",
      "content": "\"use client\";\n\nimport { Bot, Loader2, Send, Users } from \"lucide-react\";\nimport { useRef, useState } from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport AIMessageComponent from \"@/registry/new-york/blocks/ai/ai-message\";\nimport {\n  Avatar,\n  AvatarFallback,\n  AvatarImage,\n} from \"@/registry/new-york/ui/avatar\";\nimport { Badge } from \"@/registry/new-york/ui/badge\";\nimport {\n  Card,\n  CardContent,\n  CardDescription,\n  CardHeader,\n  CardTitle,\n} from \"@/registry/new-york/ui/card\";\nimport {\n  Empty,\n  EmptyDescription,\n  EmptyHeader,\n  EmptyMedia,\n  EmptyTitle,\n} from \"@/registry/new-york/ui/empty\";\nimport {\n  InputGroup,\n  InputGroupAddon,\n  InputGroupButton,\n  InputGroupTextarea,\n} from \"@/registry/new-york/ui/input-group\";\n\nexport interface Participant {\n  id: string;\n  name: string;\n  avatar?: string;\n  isTyping?: boolean;\n  cursorPosition?: number;\n}\n\nexport interface AIMessage {\n  id: string;\n  role: \"user\" | \"assistant\";\n  content: string;\n  author?: {\n    id: string;\n    name: string;\n    avatar?: string;\n  };\n  timestamp: Date;\n}\n\nexport interface TeamAIRoomProps {\n  roomName?: string;\n  participants?: Participant[];\n  messages?: AIMessage[];\n  currentUserId?: string;\n  onSendMessage?: (content: string) => Promise<void>;\n  onTyping?: (isTyping: boolean) => void;\n  className?: string;\n  isStreaming?: boolean;\n}\n\nfunction formatTime(date: Date): string {\n  return new Intl.DateTimeFormat(\"en-US\", {\n    hour: \"numeric\",\n    minute: \"2-digit\",\n  }).format(date);\n}\n\nfunction getInitials(name: string): string {\n  return name\n    .split(\" \")\n    .map((n) => n[0])\n    .join(\"\")\n    .toUpperCase()\n    .slice(0, 2);\n}\n\nexport default function TeamAIRoom({\n  roomName = \"Shared AI Workspace\",\n  participants = [],\n  messages = [],\n  currentUserId,\n  onSendMessage,\n  onTyping,\n  className,\n  isStreaming = false,\n}: TeamAIRoomProps) {\n  const [input, setInput] = useState(\"\");\n  const [isSending, setIsSending] = useState(false);\n  const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n  const handleSend = async () => {\n    if (!input.trim() || isSending) return;\n\n    const content = input.trim();\n    setInput(\"\");\n    setIsSending(true);\n\n    try {\n      await onSendMessage?.(content);\n    } catch (error) {\n      setInput(content);\n    } finally {\n      setIsSending(false);\n      textareaRef.current?.focus();\n    }\n  };\n\n  const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n    if ((e.metaKey || e.ctrlKey) && e.key === \"Enter\") {\n      e.preventDefault();\n      handleSend();\n    }\n  };\n\n  const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n    setInput(e.target.value);\n    onTyping?.(e.target.value.length > 0);\n  };\n\n  const typingParticipants = participants.filter((p) => p.isTyping);\n\n  return (\n    <Card className={cn(\"flex h-[700px] flex-col shadow-xs\", className)}>\n      <CardHeader className=\"shrink-0\">\n        <div className=\"flex items-center justify-between gap-4\">\n          <div className=\"flex min-w-0 flex-1 flex-col gap-2\">\n            <CardTitle>{roomName}</CardTitle>\n            <CardDescription>\n              Collaborative AI workspace with shared context\n            </CardDescription>\n          </div>\n          <div className=\"flex shrink-0 items-center gap-2\">\n            <div className=\"flex -space-x-2\">\n              {participants.slice(0, 3).map((participant) => (\n                <Avatar\n                  className=\"size-8 border-2 border-background\"\n                  key={participant.id}\n                >\n                  <AvatarImage\n                    alt={participant.name}\n                    src={participant.avatar}\n                  />\n                  <AvatarFallback className=\"text-xs\">\n                    {getInitials(participant.name)}\n                  </AvatarFallback>\n                </Avatar>\n              ))}\n              {participants.length > 3 && (\n                <div className=\"flex size-8 items-center justify-center rounded-full border-2 border-background bg-muted\">\n                  <span className=\"text-muted-foreground text-xs\">\n                    +{participants.length - 3}\n                  </span>\n                </div>\n              )}\n            </div>\n            <Badge variant=\"secondary\">\n              <Users className=\"mr-1 size-3\" />\n              {participants.length}\n            </Badge>\n          </div>\n        </div>\n      </CardHeader>\n      <CardContent className=\"flex min-h-0 flex-1 flex-col gap-0 overflow-hidden\">\n        {/* Messages */}\n        <div className=\"flex-1 overflow-y-auto py-4\">\n          {messages.length === 0 ? (\n            <Empty>\n              <EmptyHeader>\n                <EmptyMedia variant=\"icon\">\n                  <Bot className=\"size-6\" />\n                </EmptyMedia>\n                <EmptyTitle>Start collaborating</EmptyTitle>\n                <EmptyDescription>\n                  Ask questions and work together with AI\n                </EmptyDescription>\n              </EmptyHeader>\n            </Empty>\n          ) : (\n            <div className=\"flex flex-col gap-6\">\n              {messages.map((message) => {\n                if (message.role === \"user\") {\n                  return (\n                    <div className=\"flex items-start gap-3\" key={message.id}>\n                      <Avatar className=\"size-8 shrink-0\">\n                        <AvatarImage\n                          alt={message.author?.name || \"User\"}\n                          src={message.author?.avatar}\n                        />\n                        <AvatarFallback className=\"text-xs\">\n                          {message.author\n                            ? getInitials(message.author.name)\n                            : \"U\"}\n                        </AvatarFallback>\n                      </Avatar>\n                      <div className=\"flex min-w-0 flex-1 flex-col gap-2\">\n                        <div className=\"flex items-center gap-2\">\n                          <span className=\"font-medium text-sm\">\n                            {message.author?.name || \"User\"}\n                          </span>\n                          <span className=\"text-muted-foreground text-xs\">\n                            {formatTime(message.timestamp)}\n                          </span>\n                        </div>\n                        <div className=\"max-w-[80%] rounded-lg bg-muted px-3 py-2\">\n                          <p className=\"wrap-break-word whitespace-pre-wrap text-sm\">\n                            {message.content}\n                          </p>\n                        </div>\n                      </div>\n                    </div>\n                  );\n                }\n\n                return (\n                  <div className=\"flex items-start gap-3\" key={message.id}>\n                    <div className=\"flex size-8 shrink-0 items-center justify-center rounded-full bg-primary/10\">\n                      <Bot className=\"size-4 text-primary\" />\n                    </div>\n                    <div className=\"flex min-w-0 flex-1 flex-col gap-2\">\n                      <div className=\"rounded-lg border bg-card p-4\">\n                        <AIMessageComponent\n                          className=\"shadow-none\"\n                          content={message.content}\n                          isStreaming={\n                            isStreaming &&\n                            message.id === messages[messages.length - 1]?.id\n                          }\n                        />\n                      </div>\n                      <span className=\"text-muted-foreground text-xs\">\n                        {formatTime(message.timestamp)}\n                      </span>\n                    </div>\n                  </div>\n                );\n              })}\n              {typingParticipants.length > 0 && (\n                <div className=\"flex items-center gap-2 text-muted-foreground text-sm\">\n                  <Loader2 className=\"size-4 animate-spin\" />\n                  <span>\n                    {typingParticipants.map((p) => p.name).join(\", \")} typing…\n                  </span>\n                </div>\n              )}\n            </div>\n          )}\n        </div>\n\n        {/* Input */}\n        <div className=\"shrink-0 rounded-lg bg-muted/30 p-4\">\n          <div className=\"flex items-center\">\n            <div className=\"relative flex min-w-0 flex-1 flex-col gap-2.5\">\n              <InputGroup>\n                <InputGroupTextarea\n                  className=\"min-h-[52px] resize-none pr-12\"\n                  onChange={handleInputChange}\n                  onKeyDown={handleKeyDown}\n                  placeholder=\"Ask AI anything…\"\n                  ref={textareaRef}\n                  rows={1}\n                  value={input}\n                />\n                <InputGroupAddon align=\"inline-end\">\n                  <InputGroupButton\n                    aria-busy={isSending}\n                    className=\"size-9\"\n                    data-loading={isSending}\n                    disabled={!input.trim() || isSending}\n                    onClick={handleSend}\n                    type=\"button\"\n                  >\n                    {isSending ? (\n                      <Loader2 className=\"size-4 animate-spin\" />\n                    ) : (\n                      <Send className=\"size-4\" />\n                    )}\n                  </InputGroupButton>\n                </InputGroupAddon>\n              </InputGroup>\n              <div className=\"flex items-center justify-between px-1\">\n                <span className=\"text-muted-foreground text-xs\">\n                  ⌘ + Enter to send\n                </span>\n                {input.trim() && (\n                  <span className=\"text-muted-foreground text-xs\">\n                    {input.length} character{input.length !== 1 ? \"s\" : \"\"}\n                  </span>\n                )}\n              </div>\n            </div>\n          </div>\n        </div>\n      </CardContent>\n    </Card>\n  );\n}\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "block",
    "team"
  ],
  "type": "registry:ui"
}