Componentmedia
Audio Mini
Compact audio player with animated equalizer bars and duration counter.
Preview
Live Preview
CONCERT HALL ACOUSTICS
ORCHESTRA ROW C · SEAT 1201:1204:18
Installation
Tokens guide →Add to your project via CLI (zero dependencies, code you own):
npx bigbullui add audio-miniOr install the full npm package:
npm install bigbulluiUsage
import { AudioMini } from "@/components/ui/audio-mini";
<AudioMini title="CONCERT LIVE" artist="ORCHESTRA" duration="03:45" />Source code
audio-mini.tsxZero dependencies (only React + utils). Copy and paste directly into your project:
"use client";
import * as React from "react";
import { cn } from "./lib/utils";
export interface AudioMiniProps extends React.HTMLAttributes<HTMLDivElement> {
title?: string;
artist?: string;
duration?: string;
src?: string;
className?: string;
}
export function AudioMini({
title = "STAGE LIVE RECORDING",
artist = "ORCHESTRA ROW C",
duration = "03:45",
src,
className,
...props
}: AudioMiniProps) {
const [isPlaying, setIsPlaying] = React.useState(false);
const [progress, setProgress] = React.useState(25);
const audioRef = React.useRef<HTMLAudioElement>(null);
React.useEffect(() => {
let timer: NodeJS.Timeout;
if (isPlaying) {
timer = setInterval(() => {
setProgress((prev) => (prev >= 100 ? 0 : prev + 2));
}, 500);
}
return () => clearInterval(timer);
}, [isPlaying]);
const togglePlay = () => {
if (audioRef.current) {
if (isPlaying) {
audioRef.current.pause();
} else {
audioRef.current.play();
}
}
setIsPlaying(!isPlaying);
};
return (
<div
className={cn(
"inline-flex w-full max-w-sm flex-col gap-2.5 rounded-xl border-2 border-foreground bg-card p-4 shadow-sm outline-1 outline-dashed outline-offset-[-5px] font-mono select-none",
className
)}
{...props}
>
{src && <audio ref={audioRef} src={src} onEnded={() => setIsPlaying(false)} />}
<div className="flex items-center justify-between">
<div className="flex items-center gap-2 truncate">
<button
type="button"
onClick={togglePlay}
aria-label={isPlaying ? "Pause audio" : "Play audio"}
className="flex size-8 shrink-0 items-center justify-center rounded-sm border border-foreground bg-accent text-accent-foreground shadow-xs transition-transform hover:scale-105 active:scale-95 cursor-pointer"
>
<span className="text-xs font-bold">{isPlaying ? "❚❚" : "▶"}</span>
</button>
<div className="truncate">
<h4 className="truncate text-xs font-bold text-foreground uppercase">{title}</h4>
<span className="text-[10px] text-muted-foreground uppercase">{artist}</span>
</div>
</div>
{/* Equalizer Sound Waves */}
<div className="flex items-end gap-1 h-5 pl-2">
{[40, 80, 55, 100, 70].map((h, i) => (
<div
key={i}
style={{ height: isPlaying ? `${h}%` : "20%" }}
className={cn(
"w-1 rounded-xs bg-accent transition-all duration-300",
isPlaying && "animate-pulse"
)}
/>
))}
</div>
</div>
{/* Progress Track */}
<div className="space-y-1">
<div className="relative h-1.5 w-full overflow-hidden rounded-xs bg-secondary border border-border">
<div
style={{ width: `${progress}%` }}
className="h-full bg-foreground transition-all duration-300"
/>
</div>
<div className="flex justify-between text-[9px] text-muted-foreground">
<span>01:12</span>
<span>{duration}</span>
</div>
</div>
</div>
);
}
Props
| Prop | Type | Description |
|---|---|---|
| title | string | Audio track title. |
| artist | string | Artist or seat row label. |
| duration | string | Duration timestamp display. |
| src | string | Optional audio file URL. |