65 lines
2.0 KiB
TypeScript
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; |