{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "ai-01",
  "type": "registry:block",
  "title": "AI Chat with Voice Input",
  "description": "A ai chat with voice input block.",
  "author": "ephraim duncan <https://ephraimduncan.com>",
  "registryDependencies": [
    "button",
    "dropdown-menu",
    "textarea"
  ],
  "dependencies": [
    "@tabler/icons-react"
  ],
  "files": [
    {
      "path": "content/components/ai/ai-01.tsx",
      "type": "registry:component",
      "target": "components/ai-01.tsx",
      "content": "\"use client\";\n\nimport type React from \"react\";\n\nimport { Button } from \"@/components/ui/button\";\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuGroup,\n  DropdownMenuItem,\n  DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport { Textarea } from \"@/components/ui/textarea\";\nimport { cn } from \"@/lib/utils\";\nimport {\n  IconMicrophone,\n  IconPaperclip,\n  IconPlus,\n  IconSearch,\n  IconSend,\n  IconSparkles,\n  IconWaveSine,\n} from \"@tabler/icons-react\";\nimport { useRef, useState } from \"react\";\n\nexport default function Ai01() {\n  const [message, setMessage] = useState(\"\");\n  const [isExpanded, setIsExpanded] = useState(false);\n  const textareaRef = useRef<HTMLTextAreaElement>(null);\n  const fileInputRef = useRef<HTMLInputElement>(null);\n\n  const handleSubmit = (e: React.FormEvent) => {\n    e.preventDefault();\n\n    if (message.trim()) {\n      setMessage(\"\");\n      setIsExpanded(false);\n\n      if (textareaRef.current) {\n        textareaRef.current.style.height = \"auto\";\n      }\n    }\n  };\n\n  const handleTextareaChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n    setMessage(e.target.value);\n\n    if (textareaRef.current) {\n      textareaRef.current.style.height = \"auto\";\n      textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`;\n    }\n\n    setIsExpanded(e.target.value.length > 100 || e.target.value.includes(\"\\n\"));\n  };\n\n  const handleKeyDown = (e: React.KeyboardEvent) => {\n    if (e.key === \"Enter\" && !e.shiftKey) {\n      e.preventDefault();\n      handleSubmit(e as any);\n    }\n  };\n\n  return (\n    <div className=\"w-full\">\n      <h1 className=\"text-balance mb-8 mx-auto max-w-2xl text-center text-2xl font-semibold leading-9 text-foreground px-1 text-pretty whitespace-pre-wrap\">\n        How can I help you today?\n      </h1>\n\n      <form onSubmit={handleSubmit} className=\"group/composer w-full\">\n        <input\n          ref={fileInputRef}\n          type=\"file\"\n          multiple\n          className=\"sr-only\"\n          onChange={(e) => {}}\n        />\n\n        <div\n          className={cn(\n            \"w-full max-w-2xl mx-auto bg-transparent dark:bg-muted/50 cursor-text overflow-clip bg-clip-padding p-2.5 shadow-lg border border-border transition-[border-radius] duration-200 ease-out\",\n            isExpanded\n              ? \"rounded-3xl grid [grid-template-columns:1fr] [grid-template-rows:auto_1fr_auto] [grid-template-areas:'header'_'primary'_'footer']\"\n              : \"rounded-3xl grid [grid-template-columns:auto_1fr_auto] [grid-template-rows:auto_1fr_auto] [grid-template-areas:'header_header_header'_'leading_primary_trailing'_'._footer_.']\"\n          )}\n        >\n          <div\n            className={cn(\n              \"flex min-h-14 items-center overflow-x-hidden px-1.5\",\n              {\n                \"px-2 py-1 mb-0\": isExpanded,\n                \"-my-2.5\": !isExpanded,\n              }\n            )}\n            style={{ gridArea: \"primary\" }}\n          >\n            <div className=\"flex-1 overflow-auto max-h-52\">\n              <Textarea\n                ref={textareaRef}\n                value={message}\n                onChange={handleTextareaChange}\n                onKeyDown={handleKeyDown}\n                placeholder=\"Ask anything\"\n                className=\"min-h-0 resize-none rounded-none border-0 p-0 text-base placeholder:text-muted-foreground focus-visible:ring-0 focus-visible:ring-offset-0 scrollbar-thin dark:bg-transparent\"\n                rows={1}\n              />\n            </div>\n          </div>\n\n          <div\n            className={cn(\"flex\", { hidden: isExpanded })}\n            style={{ gridArea: \"leading\" }}\n          >\n            <DropdownMenu>\n              <DropdownMenuTrigger asChild>\n                <Button\n                  type=\"button\"\n                  variant=\"ghost\"\n                  size=\"icon\"\n                  className=\"rounded-full hover:bg-accent outline-none ring-0\"\n                  aria-label=\"Add attachments\"\n                >\n                  <IconPlus className=\"size-6 text-muted-foreground\" />\n                </Button>\n              </DropdownMenuTrigger>\n\n              <DropdownMenuContent\n                align=\"start\"\n                className=\"max-w-xs rounded-2xl p-1.5\"\n              >\n                <DropdownMenuGroup className=\"space-y-1\">\n                  <DropdownMenuItem\n                    className=\"rounded-md\"\n                    onClick={() => fileInputRef.current?.click()}\n                  >\n                    <IconPaperclip size={20} className=\"opacity-60\" />\n                    Add photos & files\n                  </DropdownMenuItem>\n                  <DropdownMenuItem\n                    className=\"rounded-md\"\n                    onClick={() => {}}\n                  >\n                    <div className=\"flex items-center gap-2\">\n                      <IconSparkles size={20} className=\"opacity-60\" />\n                      Agent mode\n                    </div>\n                  </DropdownMenuItem>\n                  <DropdownMenuItem\n                    className=\"rounded-md\"\n                    onClick={() => {}}\n                  >\n                    <IconSearch size={20} className=\"opacity-60\" />\n                    Deep Research\n                  </DropdownMenuItem>\n                </DropdownMenuGroup>\n              </DropdownMenuContent>\n            </DropdownMenu>\n          </div>\n\n          <div\n            className=\"flex items-center gap-2\"\n            style={{ gridArea: isExpanded ? \"footer\" : \"trailing\" }}\n          >\n            <div className=\"ms-auto flex items-center gap-1.5\">\n              <Button\n                type=\"button\"\n                variant=\"ghost\"\n                size=\"icon\"\n                className=\"rounded-full hover:bg-accent\"\n                aria-label=\"Record audio message\"\n              >\n                <IconMicrophone className=\"size-5 text-muted-foreground\" />\n              </Button>\n\n              <Button\n                type=\"button\"\n                variant=\"ghost\"\n                size=\"icon\"\n                className=\"h-9 w-9 rounded-full hover:bg-accent relative\"\n                aria-label=\"Audio visualization\"\n              >\n                <IconWaveSine className=\"size-5 text-muted-foreground\" />\n              </Button>\n\n              {message.trim() && (\n                <Button\n                  type=\"submit\"\n                  size=\"icon\"\n                  className=\"rounded-full\"\n                  aria-label=\"Send message\"\n                >\n                  <IconSend className=\"size-5\" />\n                </Button>\n              )}\n            </div>\n          </div>\n        </div>\n      </form>\n    </div>\n  );\n}\n"
    }
  ],
  "categories": [
    "ai"
  ]
}