// 横向手风琴组件 import { useEffect, useRef, useState } from 'react'; import { motion, useInView, type Variants } from 'motion/react'; import styles from './index.module.css'; import { Link } from 'react-router-dom'; import { scrollToWithLenis } from '@/utils/lenis'; const contentItemVariants: Variants = { hidden: { opacity: 0, x: 80 }, visible: { opacity: 1, x: 0 }, }; const FALLBACK_GRADIENT = "linear-gradient(0deg, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.5) 100%)"; type Data = { title?: string; items: { title: string; subtitle?: string; content?: string; links?: { text: string; path: string; }[]; /** 以 mockData 为准,优先使用 backgroundImage */ backgroundImage?: string; image?: string; }[]; } type Props = { data: Data; placement?: 'top' | 'bottom'; } export default function RowAccordion({ data, placement='bottom' }: Props) { const [activeIndex, setActiveIndex] = useState(0); const containerRef = useRef(null); const isInView = useInView(containerRef, { once: true, margin: "0px 0px -30% 0px" }); useEffect(() => { if (isInView && containerRef.current) { const rect = containerRef.current.getBoundingClientRect(); scrollToWithLenis(window.scrollY + rect.top, { duration: 3 }); } }, [isInView]); const getToPath = (link: { text: string; path: string }) => { return link.path.includes("{id}") ? link.path.replace("{id}", link.text) : link.path; } return (
{data.items.map((item, index) => (
))}
{ data.title && (
{data.title}
) }
{data.items.map((item, index) => ( setActiveIndex(index)} initial="hidden" whileInView="visible" viewport={{ once: true, amount: 0.2 }} variants={contentItemVariants} transition={{ duration: 0.6, delay: 0.3 + index * 0.12, ease: [0.25, 0.46, 0.45, 0.94], }} >
{item.title}
{item.subtitle &&
{item.subtitle}
} { (item.content || (item.links || []).length > 0) && (
{item.content && (
{item.content}
)} {item.links && (
{item.links?.map((link) => ( {link.text} ))}
)}
) }
))}
); }