{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "audio-player",
  "title": "Audio Player",
  "description": "A custom audio player component.",
  "dependencies": [
    "motion",
    "lucide-react"
  ],
  "registryDependencies": [
    "button"
  ],
  "files": [
    {
      "path": "registry/ui/audio-player.tsx",
      "content": "\"use client\"\nimport React, { useRef, useState } from \"react\"\nimport { Button } from \"@/components/ui/button\" // Registry\nimport {\n  Play,\n  Pause,\n  SkipBack,\n  SkipForward,\n  Shuffle,\n  Repeat,\n} from \"lucide-react\"\nimport { motion, AnimatePresence } from \"motion/react\"\nimport { cn } from \"@/lib/utils\"\n\nconst formatTime = (seconds: number) => {\n  const minutes = Math.floor(seconds / 60)\n  const remainingSeconds = Math.floor(seconds % 60)\n  return `${minutes}:${remainingSeconds.toString().padStart(2, \"0\")}`\n}\n\nconst CustomSlider = ({\n  value,\n  onChange,\n  className,\n}: {\n  value: number\n  onChange: (value: number) => void\n  className?: string\n}) => {\n  return (\n    <motion.div\n      className={cn(\n        \"bg-secondary relative h-1 w-full cursor-pointer rounded-full\",\n        className,\n      )}\n      onClick={(e) => {\n        const rect = e.currentTarget.getBoundingClientRect()\n        const x = e.clientX - rect.left\n        const percentage = (x / rect.width) * 100\n        onChange(Math.min(Math.max(percentage, 0), 100))\n      }}\n    >\n      <motion.div\n        className=\"bg-primary absolute top-0 left-0 h-full rounded-full\"\n        style={{ width: `${value}%` }}\n        initial={{ width: 0 }}\n        animate={{ width: `${value}%` }}\n        transition={{ type: \"spring\", stiffness: 300, damping: 30 }}\n      />\n    </motion.div>\n  )\n}\n\nconst AudioPlayer = ({\n  src,\n  cover,\n  title,\n}: {\n  src: string\n  cover?: string\n  title?: string\n}) => {\n  const audioRef = useRef<HTMLAudioElement>(null)\n  const [isPlaying, setIsPlaying] = useState(false)\n  const [progress, setProgress] = useState(0)\n  const [currentTime, setCurrentTime] = useState(0)\n  const [duration, setDuration] = useState(0)\n  const [isShuffle, setIsShuffle] = useState(false)\n  const [isRepeat, setIsRepeat] = useState(false)\n\n  const togglePlay = () => {\n    if (audioRef.current) {\n      if (isPlaying) {\n        audioRef.current.pause()\n      } else {\n        audioRef.current.play()\n      }\n      setIsPlaying(!isPlaying)\n    }\n  }\n\n  const handleTimeUpdate = () => {\n    if (audioRef.current) {\n      const progress =\n        (audioRef.current.currentTime / audioRef.current.duration) * 100\n      setProgress(isFinite(progress) ? progress : 0)\n      setCurrentTime(audioRef.current.currentTime)\n      setDuration(audioRef.current.duration)\n    }\n  }\n\n  const handleSeek = (value: number) => {\n    if (audioRef.current && audioRef.current.duration) {\n      const time = (value / 100) * audioRef.current.duration\n      if (isFinite(time)) {\n        audioRef.current.currentTime = time\n        setProgress(value)\n      }\n    }\n  }\n\n  const handleShuffle = () => {\n    setIsShuffle(!isShuffle)\n  }\n\n  const handleRepeat = () => {\n    setIsRepeat(!isRepeat)\n  }\n\n  return (\n    <AnimatePresence>\n      <motion.div\n        className=\"bg-card border-border relative mx-auto flex h-auto w-[280px] flex-col overflow-hidden rounded-3xl border p-3 shadow-sm backdrop-blur-sm\"\n        initial={{ opacity: 0, filter: \"blur(10px)\" }}\n        animate={{ opacity: 1, filter: \"blur(0px)\" }}\n        exit={{ opacity: 0, filter: \"blur(10px)\" }}\n        transition={{\n          duration: 0.3,\n          ease: \"easeInOut\",\n          delay: 0.1,\n          type: \"spring\",\n        }}\n        layout\n      >\n        <audio\n          ref={audioRef}\n          onTimeUpdate={handleTimeUpdate}\n          src={src}\n          className=\"hidden\"\n        />\n        <motion.div\n          className=\"relative flex flex-col\"\n          layout\n          animate={{ opacity: 1 }}\n          transition={{ duration: 0.3, ease: \"easeInOut\" }}\n        >\n          {/* Cover */}\n          {cover && (\n            <motion.div className=\"bg-muted relative h-[180px] w-full overflow-hidden rounded-[16px]\">\n              <img\n                src={cover}\n                alt=\"cover\"\n                className=\"h-full w-full object-cover\"\n              />\n            </motion.div>\n          )}\n\n          <motion.div className=\"flex w-full flex-col gap-y-2\">\n            {/* Title */}\n            {title && (\n              <motion.h3 className=\"text-card-foreground mt-1 text-center text-base font-bold\">\n                {title}\n              </motion.h3>\n            )}\n\n            {/* Slider */}\n            <motion.div className=\"flex flex-col gap-y-1\">\n              <CustomSlider\n                value={progress}\n                onChange={handleSeek}\n                className=\"w-full\"\n              />\n              <div className=\"flex items-center justify-between\">\n                <span className=\"text-muted-foreground text-sm\">\n                  {formatTime(currentTime)}\n                </span>\n                <span className=\"text-muted-foreground text-sm\">\n                  {formatTime(duration)}\n                </span>\n              </div>\n            </motion.div>\n\n            {/* Controls */}\n            <motion.div className=\"flex w-full items-center justify-center\">\n              <div className=\"bg-background border-border flex w-fit items-center gap-2 rounded-[16px] border p-2\">\n                <motion.div\n                  whileHover={{ scale: 1.1 }}\n                  whileTap={{ scale: 0.9 }}\n                >\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon\"\n                    onClick={(e: React.MouseEvent) => {\n                      e.stopPropagation()\n                      handleShuffle()\n                    }}\n                    className={cn(\n                      \"text-foreground hover:bg-accent hover:text-accent-foreground h-8 w-8 rounded-full\",\n                      isShuffle && \"bg-accent text-accent-foreground\",\n                    )}\n                  >\n                    <Shuffle className=\"h-5 w-5\" />\n                  </Button>\n                </motion.div>\n                <motion.div\n                  whileHover={{ scale: 1.1 }}\n                  whileTap={{ scale: 0.9 }}\n                >\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon\"\n                    onClick={(e: React.MouseEvent) => e.stopPropagation()}\n                    className=\"text-foreground hover:bg-accent hover:text-accent-foreground h-8 w-8 rounded-full\"\n                  >\n                    <SkipBack className=\"h-5 w-5\" />\n                  </Button>\n                </motion.div>\n                <motion.div\n                  whileHover={{ scale: 1.1 }}\n                  whileTap={{ scale: 0.9 }}\n                >\n                  <Button\n                    onClick={(e: React.MouseEvent) => {\n                      e.stopPropagation()\n                      togglePlay()\n                    }}\n                    variant=\"ghost\"\n                    size=\"icon\"\n                    className=\"text-foreground hover:bg-accent hover:text-accent-foreground h-8 w-8 rounded-full\"\n                  >\n                    {isPlaying ? (\n                      <Pause className=\"h-5 w-5\" />\n                    ) : (\n                      <Play className=\"h-5 w-5\" />\n                    )}\n                  </Button>\n                </motion.div>\n                <motion.div\n                  whileHover={{ scale: 1.1 }}\n                  whileTap={{ scale: 0.9 }}\n                >\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon\"\n                    onClick={(e: React.MouseEvent) => e.stopPropagation()}\n                    className=\"text-foreground hover:bg-accent hover:text-accent-foreground h-8 w-8 rounded-full\"\n                  >\n                    <SkipForward className=\"h-5 w-5\" />\n                  </Button>\n                </motion.div>\n                <motion.div\n                  whileHover={{ scale: 1.1 }}\n                  whileTap={{ scale: 0.9 }}\n                >\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon\"\n                    onClick={(e: React.MouseEvent) => {\n                      e.stopPropagation()\n                      handleRepeat()\n                    }}\n                    className={cn(\n                      \"text-foreground hover:bg-accent hover:text-accent-foreground h-8 w-8 rounded-full\",\n                      isRepeat && \"bg-accent text-accent-foreground\",\n                    )}\n                  >\n                    <Repeat className=\"h-5 w-5\" />\n                  </Button>\n                </motion.div>\n              </div>\n            </motion.div>\n          </motion.div>\n        </motion.div>\n      </motion.div>\n    </AnimatePresence>\n  )\n}\n\nexport default AudioPlayer\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}