import Track from "./Track"; import "./Album.css"; import type { Album, Track as TrackType } from "../../album"; import { useLayoutEffect, useMemo, useRef, useState } from "react"; export default function Album({ album, dismissAlbum, play, nowPlaying }: { album: Album; dismissAlbum: () => void, play: (i: number) => void, nowPlaying: TrackType }) { const titleViewportRef = useRef(null); const titleTextRef = useRef(null); const [isMarquee, setIsMarquee] = useState(false); const [marqueeDistancePx, setMarqueeDistancePx] = useState(0); // Tunables (constant px/sec + visible gap between repeats) const marqueeGapPx = 96; const marqueeSpeedPxPerSec = 60; useLayoutEffect(() => { const viewportEl = titleViewportRef.current; const textEl = titleTextRef.current; if (!viewportEl || !textEl) return; let raf = 0; const measure = () => { cancelAnimationFrame(raf); raf = requestAnimationFrame(() => { const viewportWidth = viewportEl.clientWidth; const textWidth = textEl.scrollWidth; const shouldMarquee = textWidth > viewportWidth + 1; setIsMarquee(shouldMarquee); setMarqueeDistancePx(shouldMarquee ? textWidth + marqueeGapPx : 0); }); }; measure(); const ro = new ResizeObserver(measure); ro.observe(viewportEl); // Fonts can load after first paint and change measurements. void (document as unknown as { fonts?: { ready: Promise } }).fonts?.ready.then(measure); return () => { cancelAnimationFrame(raf); ro.disconnect(); }; }, [album.title]); const marqueeStyle = useMemo(() => { if (!isMarquee) return undefined; const durationSec = marqueeSpeedPxPerSec > 0 ? marqueeDistancePx / marqueeSpeedPxPerSec : 0; return { ["--marquee-gap" as never]: `${marqueeGapPx}px`, ["--marquee-distance" as never]: `${marqueeDistancePx}px`, ["--marquee-duration" as never]: `${durationSec}s`, }; }, [isMarquee, marqueeDistancePx]); return (

{album.title} {isMarquee ? ( {album.title} ) : null}

{album.artistName} {album.releaseDate.year ? ' • ' + album.releaseDate.year : ''} {/* TODO: .toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" }) */}

{album.tracks.map((t, i) => ( ))}
); }