{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "music-player-apple",
  "title": "Apple Music Player",
  "description": "A music player component with a design inspired by Apple.",
  "registryDependencies": [
    "slider",
    "button"
  ],
  "files": [
    {
      "path": "registry/music-player/music-player-apple.tsx",
      "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\nimport { Slider } from \"@/components/ui/slider\";\nimport {\n  PauseIcon,\n  RepeatIcon,\n  ShuffleIcon,\n  SkipBackIcon,\n  SkipForwardIcon,\n  MusicIcon,\n  PlayIcon,\n  Repeat1Icon,\n} from \"lucide-react\";\nimport { useMusicPlayer, Song } from \"@/hooks/use-music-player\";\n\nexport default function MusicPlayerApple({ song }: { song: Song }) {\n  const {\n    isPlaying,\n    duration,\n    progressPercentage,\n    formattedCurrentTime,\n    formattedDuration,\n    isShuffling,\n    repeatMode,\n    togglePlayPause,\n    handleSliderChange,\n    toggleShuffle,\n    toggleRepeat,\n  } = useMusicPlayer({ song });\n\n  return (\n    <div className=\"md:max-w-lg w-full flex flex-col gap-2.5 bg-popover border rounded-xl p-4\">\n      <div className=\"flex items-start md:items-center flex-col md:flex-row gap-4 min-w-0\">\n        {song.album.image ? (\n          <img\n            src={song.album.image}\n            alt={`${song.name} by ${song.artists.join(\", \")}`}\n            className=\"size-full md:size-14 rounded-md object-cover\"\n            aria-hidden=\"true\"\n          />\n        ) : (\n          <div\n            className=\"size-full md:size-16 rounded-md bg-muted flex items-center justify-center\"\n            aria-hidden=\"true\"\n          >\n            <MusicIcon className=\"size-8 text-muted-foreground\" />\n          </div>\n        )}\n        <div className=\"w-full\">\n          <p className=\"text-lg font-semibold truncate\">{song.name}</p>\n          <p className=\"text-sm text-muted-foreground truncate\">\n            {song.artists.join(\", \")}\n          </p>\n        </div>\n        <div className=\"flex items-center justify-center gap-1 w-full\">\n          <Button\n            variant=\"ghost\"\n            size=\"icon\"\n            className={cn(\n              \"size-7 mr-1.5 rounded-full\",\n              isShuffling\n                ? \"text-apple hover:text-apple\"\n                : \"text-muted-foreground\",\n            )}\n            aria-label={`Shuffle ${isShuffling ? \"on\" : \"off\"}`}\n            onClick={toggleShuffle}\n          >\n            <ShuffleIcon className=\"size-3.5\" />\n          </Button>\n          <Button\n            variant=\"ghost\"\n            size=\"icon\"\n            className=\"size-8 rounded-full\"\n            aria-label=\"Skip backwords\"\n          >\n            <SkipBackIcon className=\"size-5\" />\n          </Button>\n          <Button\n            variant=\"ghost\"\n            size=\"icon\"\n            className=\"size-8 rounded-full\"\n            onClick={togglePlayPause}\n            aria-label={isPlaying ? \"Pause\" : \"Play\"}\n          >\n            {isPlaying ? (\n              <PauseIcon className=\"size-5 text-apple\" />\n            ) : (\n              <PlayIcon className=\"size-5 text-apple\" />\n            )}\n          </Button>\n          <Button\n            variant=\"ghost\"\n            size=\"icon\"\n            className=\"size-8 rounded-full\"\n            aria-label=\"Skip forward\"\n          >\n            <SkipForwardIcon className=\"size-5\" />\n          </Button>\n          <Button\n            variant=\"ghost\"\n            size=\"icon\"\n            className={cn(\n              \"size-7 ml-1.5 rounded-full\",\n              repeatMode !== \"off\"\n                ? \"text-apple hover:text-apple\"\n                : \"text-muted-foreground\",\n            )}\n            aria-label={`Repeat: ${repeatMode}`}\n            onClick={toggleRepeat}\n          >\n            {repeatMode === \"track\" ? (\n              <Repeat1Icon className=\"size-3.5\" />\n            ) : (\n              <RepeatIcon className=\"size-3.5\" />\n            )}\n          </Button>\n        </div>\n      </div>\n      <div className=\"flex mt-2 md:mt-0 items-center gap-2 relative\">\n        <span className=\"text-xs text-muted-foreground\">\n          {formattedCurrentTime}\n        </span>\n        <Slider\n          value={[progressPercentage]}\n          max={100}\n          step={1}\n          aria-label=\"Music progress slider\"\n          onValueChange={handleSliderChange}\n          disabled={duration === 0}\n          style={{ \"--primary\": \"var(--apple)\" } as React.CSSProperties}\n        />\n        <span className=\"text-xs text-muted-foreground\">\n          {formattedDuration}\n        </span>\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component"
    },
    {
      "path": "hooks/use-music-player.ts",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\nexport interface Song {\n  name: string;\n  artists: Array<string>;\n  album: { name: string; image: string };\n  duration: number; // Duration in seconds\n}\n\n// Helper function to format time from seconds to MM:SS\nexport const formatTime = (timeInSeconds: number): string => {\n  const minutes = Math.floor(timeInSeconds / 60);\n  const seconds = Math.floor(timeInSeconds % 60)\n    .toString()\n    .padStart(2, \"0\");\n  return `${minutes}:${seconds}`;\n};\n\nexport type RepeatMode = \"off\" | \"track\" | \"context\";\n\nexport interface UseMusicPlayerProps {\n  song: Song | null;\n}\n\nexport interface UseMusicPlayerReturn {\n  isPlaying: boolean;\n  currentTime: number;\n  duration: number;\n  progressPercentage: number;\n  formattedCurrentTime: string;\n  formattedDuration: string;\n  isShuffling: boolean;\n  repeatMode: RepeatMode;\n  togglePlayPause: () => void;\n  handleSliderChange: (value: number | readonly number[]) => void;\n  toggleShuffle: () => void;\n  toggleRepeat: () => void;\n  setIsPlaying: React.Dispatch<React.SetStateAction<boolean>>;\n  setCurrentTime: React.Dispatch<React.SetStateAction<number>>;\n}\n\nexport function useMusicPlayer({\n  song,\n}: UseMusicPlayerProps): UseMusicPlayerReturn {\n  const [isPlaying, setIsPlaying] = React.useState(false);\n  const [currentTime, setCurrentTime] = React.useState(0);\n  const [isShuffling, setIsShuffling] = React.useState(false);\n  const [repeatMode, setRepeatMode] = React.useState<RepeatMode>(\"off\");\n\n  const songDuration = song?.duration ?? 0;\n\n  // Effect to handle song playback timing\n  React.useEffect(() => {\n    if (!isPlaying || songDuration === 0) return;\n\n    const interval = setInterval(() => {\n      setCurrentTime((prevTime) => {\n        if (prevTime < songDuration - 1) {\n          return prevTime + 1;\n        }\n        if (repeatMode === \"track\") {\n          return 0; // Restart track\n        } else {\n          // For \"off\" and \"context\", we'd normally move to next song or stop.\n          // For now, just stop and set to duration.\n          // \"context\" repeat would be handled by a playlist manager.\n          setIsPlaying(false);\n          return songDuration;\n        }\n      });\n    }, 1000);\n\n    return () => {\n      clearInterval(interval);\n    };\n  }, [isPlaying, songDuration, repeatMode]);\n\n  React.useEffect(() => {\n    if (song) {\n      setCurrentTime(0); // Reset to beginning when song changes\n      setIsPlaying(true); // Autoplay new song\n    } else {\n      // No song, reset state\n      setCurrentTime(0);\n      setIsPlaying(false);\n    }\n  }, [song]);\n\n  const togglePlayPause = React.useCallback(() => {\n    if (!song) return;\n\n    if (currentTime >= songDuration && !isPlaying && songDuration > 0) {\n      setCurrentTime(0);\n      setIsPlaying(true);\n    } else {\n      setIsPlaying((prevIsPlaying) => !prevIsPlaying);\n    }\n  }, [currentTime, songDuration, isPlaying, song]);\n\n  const handleSliderChangeExternal = (value: number | readonly number[]) => {\n    if (!song) return;\n    const v = typeof value === \"number\" ? value : value[0];\n    const newTime = Math.floor((v / 100) * songDuration);\n    setCurrentTime(newTime);\n    if (!isPlaying && newTime < songDuration) {\n      setIsPlaying(true);\n    }\n  };\n\n  const progressPercentage =\n    songDuration > 0 ? (currentTime / songDuration) * 100 : 0;\n\n  const toggleShuffle = React.useCallback(() => {\n    setIsShuffling((prev) => !prev);\n  }, []);\n\n  const toggleRepeat = React.useCallback(() => {\n    setRepeatMode((prevMode) => {\n      if (prevMode === \"off\") return \"context\";\n      if (prevMode === \"context\") return \"track\";\n      return \"off\";\n    });\n  }, []);\n\n  return {\n    isPlaying,\n    currentTime,\n    duration: songDuration,\n    progressPercentage,\n    formattedCurrentTime: formatTime(currentTime),\n    formattedDuration: formatTime(songDuration),\n    isShuffling,\n    repeatMode,\n    togglePlayPause,\n    handleSliderChange: handleSliderChangeExternal,\n    toggleShuffle,\n    toggleRepeat,\n    setIsPlaying, // Exposing these if direct manipulation is needed\n    setCurrentTime, // Exposing these if direct manipulation is needed\n  };\n}\n",
      "type": "registry:hook"
    }
  ],
  "cssVars": {
    "light": {
      "apple": "oklch(0.68 0.1968 17.66)"
    }
  },
  "type": "registry:block"
}