60 lines
1.7 KiB
TypeScript
60 lines
1.7 KiB
TypeScript
"use client";
|
||
|
||
import { motion } from "framer-motion";
|
||
import { cn } from "@/lib/utils";
|
||
|
||
/**
|
||
* Animated audio wave bars — used in the minimized player pill
|
||
* and the "Now Playing" button.
|
||
*
|
||
* @param paused – when true the bars flatten to a static state
|
||
* @param colorClassName – Tailwind color class for the bars (default: "bg-current")
|
||
* @param className – additional classes on the container
|
||
* @param barCount – number of bars (default: 4)
|
||
* @param size – "sm" (10px tall) | "md" (12px tall, default) | "lg" (16px tall)
|
||
*/
|
||
export function AudioWaveAnimation({
|
||
paused = false,
|
||
colorClassName = "bg-current",
|
||
className,
|
||
barCount = 4,
|
||
size = "md",
|
||
}: {
|
||
paused?: boolean;
|
||
colorClassName?: string;
|
||
className?: string;
|
||
barCount?: number;
|
||
size?: "sm" | "md" | "lg";
|
||
}) {
|
||
const config = {
|
||
sm: { height: 10, minH: 2, barW: "w-[2px]", containerH: "h-2.5" },
|
||
md: { height: 12, minH: 3, barW: "w-[3px]", containerH: "h-3" },
|
||
lg: { height: 16, minH: 3, barW: "w-[3px]", containerH: "h-4" },
|
||
}[size];
|
||
|
||
return (
|
||
<div
|
||
className={cn("flex items-end gap-[2px]", config.containerH, className)}
|
||
>
|
||
{Array.from({ length: barCount }, (_, i) => (
|
||
<motion.div
|
||
key={i}
|
||
className={cn(config.barW, "rounded-full", colorClassName)}
|
||
animate={{
|
||
height: paused
|
||
? config.minH
|
||
: [config.minH, config.height, config.minH],
|
||
}}
|
||
transition={{
|
||
duration: 0.8,
|
||
repeat: paused ? 0 : Infinity,
|
||
repeatType: "mirror",
|
||
ease: "easeInOut",
|
||
delay: i * 0.15,
|
||
}}
|
||
/>
|
||
))}
|
||
</div>
|
||
);
|
||
}
|