"use client" import * as React from "react" import { cn } from "@/lib/utils" import { useEffect, useRef, useState } from "react" export interface FilmstripItem { src: string label: string } export interface FilmstripProps extends React.HTMLAttributes { items: FilmstripItem[] title?: string subtitle?: string } const Filmstrip = React.forwardRef( ({ className, items, title, subtitle, ...props }, ref) => { const containerRef = useRef(null) const trackRef = useRef(null) const [progress, setProgress] = useState(0) useEffect(() => { const container = containerRef.current const track = trackRef.current if (!container || !track) return const handleScroll = () => { const rect = container.getBoundingClientRect() const viewHeight = window.innerHeight const containerHeight = rect.height let scrollProgress = -rect.top / (containerHeight - viewHeight) scrollProgress = Math.min(Math.max(scrollProgress, 0), 1) setProgress(scrollProgress) const trackWidth = track.scrollWidth const maxTranslate = trackWidth - window.innerWidth track.style.transform = `translateX(${-maxTranslate * scrollProgress}px)` } window.addEventListener("scroll", handleScroll, { passive: true }) handleScroll() return () => window.removeEventListener("scroll", handleScroll) }, []) return (
{ // @ts-ignore - assigning to ref.current is needed for ref merging containerRef.current = node if (typeof ref === "function") ref(node) else if (ref) { // @ts-ignore ref.current = node } }} className={cn("h-[300vh] relative", className)} {...props} >
{(title || subtitle) && (
{subtitle && ( {subtitle} )} {title &&

{title}

}
)}
{items.map((item, index) => (
{item.label}
))}
) }, ) Filmstrip.displayName = "Filmstrip" export { Filmstrip }