nex_music/components/LyricsPanel.tsx

65 lines
2.0 KiB
TypeScript

import React, { useEffect, useRef } from 'react';
import { LyricLine } from '../types';
interface LyricsPanelProps {
lyrics: LyricLine[];
currentTime: number;
}
const LyricsPanel: React.FC<LyricsPanelProps> = ({ lyrics, currentTime }) => {
const containerRef = useRef<HTMLDivElement>(null);
const activeIndex = lyrics.findIndex((line, i) => {
const nextLine = lyrics[i + 1];
return currentTime >= line.time && (!nextLine || currentTime < nextLine.time);
});
useEffect(() => {
if (activeIndex !== -1 && containerRef.current) {
const activeElement = containerRef.current.children[activeIndex] as HTMLElement;
if (activeElement) {
// Calculate scroll position to center the active element
const containerHeight = containerRef.current.clientHeight;
const elementTop = activeElement.offsetTop;
const elementHeight = activeElement.clientHeight;
containerRef.current.scrollTo({
top: elementTop - containerHeight / 2 + elementHeight / 2,
behavior: 'smooth'
});
}
}
}, [activeIndex]);
if (lyrics.length === 0) {
return (
<div className="flex items-center justify-center h-full text-neutral-500 italic">
<p>No lyrics available for this track.</p>
</div>
);
}
return (
<div
ref={containerRef}
className="h-full w-full overflow-y-auto no-scrollbar py-[50vh] text-center px-4"
>
{lyrics.map((line, index) => {
const isActive = index === activeIndex;
return (
<div
key={index}
className={`transition-all duration-500 ease-out py-3 origin-center ${
isActive
? 'text-amber-400 text-2xl md:text-3xl font-bold opacity-100 scale-105'
: 'text-neutral-400 text-lg md:text-xl font-medium opacity-40 blur-[0.5px]'
}`}
>
{line.text}
</div>
);
})}
</div>
);
};
export default LyricsPanel;