Audio Player
zyeon/audio-playerFreeComponent
A minimal token-styled audio player card — play/pause, seek, and mm:ss time over a native <audio> element.
See it running
Open the demo on zyeon
ui.zyeon.ai/r/audio-playerInstall it
npx shadcn@latest add https://ui.zyeon.ai/r/audio-player.jsonSource
1"use client"23import * as React from "react"4import { Pause, Play } from "lucide-react"5import { cn } from "@/lib/utils"67export interface AudioPlayerProps extends React.HTMLAttributes<HTMLDivElement> {8 /** Audio file URL. */9 src: string10 /** Optional label rendered above the seek bar (podcast episode, track name, sender…). */11 title?: string12 /** Native <audio> preload hint. */13 preload?: "none" | "metadata"14}1516function formatTime(seconds: number) {17 if (!Number.isFinite(seconds) || seconds < 0) return "0:00"18 const m = Math.floor(seconds / 60)19 const s = Math.floor(seconds % 60)20 return `${m}:${s.toString().padStart(2, "0")}`21}2223export const AudioPlayer = React.forwardRef<HTMLDivElement, AudioPlayerProps>(24 ({ src, title, preload = "metadata", className, ...props }, ref) => {25 const audioRef = React.useRef<HTMLAudioElement | null>(null)26 const [playing, setPlaying] = React.useState(false)27 const [currentTime, setCurrentTime] = React.useState(0)28 const [duration, setDuration] = React.useState(0)29 const [error, setError] = React.useState(false)3031 // src 变化(播放列表复用同一实例)时重置全部派生状态:否则上一首的32 // error/进度会残留,坏源之后的好源永远被禁用。渲染期 adjust-state 模式。33 const [prevSrc, setPrevSrc] = React.useState(src)34 if (prevSrc !== src) {35 setPrevSrc(src)36 setPlaying(false)37 setCurrentTime(0)38 setDuration(0)39 setError(false)40 }4142 // Unmounting mid-playback shouldn't leave the clip running in the background.43 React.useEffect(() => {44 const audio = audioRef.current45 return () => audio?.pause()46 }, [])4748 const togglePlay = () => {49 const audio = audioRef.current50 if (!audio || error) return51 if (audio.paused) {52 audio.play().catch(() => setError(true))53 } else {54 audio.pause()55 }56 }5758 const handleSeek = (e: React.ChangeEvent<HTMLInputElement>) => {59 const next = Number(e.target.value)60 if (audioRef.current) audioRef.current.currentTime = next61 setCurrentTime(next)62 }6364 const progress = duration > 0 ? (currentTime / duration) * 100 : 06566 return (67 <div68 className={cn("flex items-center gap-3 rounded-xl border bg-card px-4 py-3", className)}69 ref={ref}70 {...props}71 >72 <audio73 onEnded={() => {74 setPlaying(false)75 setCurrentTime(0)76// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from zyeon
All 517 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | zyeon | Components | Free | 1 dep | |
| Activity Heatmapactivity-heatmap | zyeon | Components | Paid | 1 dep · 2 files | |
| Address Formaddress-form | zyeon | Components | Paid | 1 dep | |
| Agent Graphagent-graph | zyeon | Components | Free | 2 deps · 2 files | |
| Agent Handoffagent-handoff | zyeon | Components | Free | 1 dep | |
| Agent Inboxagent-inbox | zyeon | Components | Free | 2 deps · 2 files | |
| Agent Permissionsagent-permissions | zyeon | Components | Free | 2 deps · 2 files | |
| Agent Planagent-plan | zyeon | Components | Free | 2 deps · 2 files |
