{ "name": "ai-voice", "type": "registry:component", "dependencies": [ "motion", "lucide-react" ], "files": [ { "type": "registry:component", "content": "\"use client\";\n\n/**\n * @author: @kokonutui\n * @description: AI Voice\n * @version: 1.0.0\n * @date: 2025-06-26\n * @license: MIT\n * @website: https://kokonutui.com\n * @github: https://github.com/kokonut-labs/kokonutui\n */\n\nimport { Mic } from \"lucide-react\";\nimport { useEffect, useState } from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport default function AI_Voice() {\n const [submitted, setSubmitted] = useState(false);\n const [time, setTime] = useState(0);\n const [isClient, setIsClient] = useState(false);\n const [isDemo, setIsDemo] = useState(true);\n\n useEffect(() => {\n setIsClient(true);\n }, []);\n\n useEffect(() => {\n let intervalId: NodeJS.Timeout;\n\n if (submitted) {\n intervalId = setInterval(() => {\n setTime((t) => t + 1);\n }, 1000);\n } else {\n setTime(0);\n }\n\n return () => clearInterval(intervalId);\n }, [submitted]);\n\n const formatTime = (seconds: number) => {\n const mins = Math.floor(seconds / 60);\n const secs = seconds % 60;\n return `${mins.toString().padStart(2, \"0\")}:${secs\n .toString()\n .padStart(2, \"0\")}`;\n };\n\n /**\n * Remove that, only used for demo\n */\n useEffect(() => {\n if (!isDemo) return;\n\n let timeoutId: NodeJS.Timeout;\n const runAnimation = () => {\n setSubmitted(true);\n timeoutId = setTimeout(() => {\n setSubmitted(false);\n timeoutId = setTimeout(runAnimation, 1000);\n }, 3000);\n };\n\n const initialTimeout = setTimeout(runAnimation, 100);\n return () => {\n clearTimeout(timeoutId);\n clearTimeout(initialTimeout);\n };\n }, [isDemo]);\n\n const handleClick = () => {\n if (isDemo) {\n setIsDemo(false);\n setSubmitted(false);\n } else {\n setSubmitted((prev) => !prev);\n }\n };\n\n return (\n
\n {submitted ? \"Listening...\" : \"Click to speak\"}\n
\n