136 lines
7.0 KiB
TypeScript
136 lines
7.0 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import styles from './index.module.css';
|
|
import TopTabs from './TopTabs';
|
|
import { useLocation } from 'react-router-dom';
|
|
import ScrollReveal from '@/components/ScrollReveal';
|
|
import { Swiper, SwiperSlide } from 'swiper/react';
|
|
import { Autoplay, Pagination } from 'swiper/modules';
|
|
import 'swiper/css';
|
|
import 'swiper/css/pagination';
|
|
|
|
type Data = {
|
|
tabItems: {
|
|
icon?: string;
|
|
tabName?: string;
|
|
contentTitle?: string;
|
|
contentSubtitle?: string;
|
|
contentText?: string;
|
|
content?: string;
|
|
/** 以 mockData 为准;传 string[] 时为右侧轮播 */
|
|
sideImage?: string | string[];
|
|
path?: string;
|
|
items?: { label: string }[];
|
|
}[]
|
|
backgroundImage?: string;
|
|
titleDirection?: 'row' | 'column';
|
|
}
|
|
|
|
function sideImageToSlides(sideImage: string | string[] | undefined): string[] {
|
|
if (Array.isArray(sideImage)) return sideImage.filter(Boolean);
|
|
if (sideImage) return [sideImage];
|
|
return [];
|
|
}
|
|
|
|
export default function TopTabsSection({ data, className }: { data: Data, className?: string }) {
|
|
const location = useLocation();
|
|
const hash = location.hash;
|
|
const hashId = decodeURIComponent(hash.replace('#', ''));
|
|
const [activeIndex, setActiveIndex] = useState(0);
|
|
|
|
useEffect(() => {
|
|
if (hashId && data.tabItems) {
|
|
const index = data.tabItems.findIndex((item) => item.tabName === hashId);
|
|
if (index !== -1) {
|
|
setActiveIndex(index);
|
|
}
|
|
}
|
|
}, [hashId, data.tabItems])
|
|
|
|
const sideSlides = sideImageToSlides(data.tabItems[activeIndex]?.sideImage);
|
|
|
|
return (
|
|
<section className={`${styles.topTabsSection} ${className}`} style={{ backgroundImage: `url(${data.backgroundImage})` }}>
|
|
<div aria-hidden="true">
|
|
{data.tabItems.map((item) => (
|
|
<div key={item.tabName} id={item.tabName} style={{ height: 0, overflow: "hidden" }} />
|
|
))}
|
|
</div>
|
|
<TopTabs data={data} activeIndex={activeIndex} setActiveIndex={setActiveIndex} />
|
|
<div className={styles.topTabsContent}>
|
|
{
|
|
data.tabItems[activeIndex]?.items && (data.tabItems[activeIndex]?.items as any).length > 0 ?
|
|
<ul className={styles.topTabsContentItems}>
|
|
{
|
|
(data.tabItems[activeIndex]?.items as any).map((item: { label: string }) => (
|
|
<li key={item.label} className={styles.topTabsContentItem}>
|
|
<span>{item.label}</span>
|
|
</li>
|
|
))
|
|
}
|
|
</ul> : (
|
|
<>
|
|
<div className={styles.topTabsContentLeft}>
|
|
<div className={styles.topTabsContentLeftHead}>
|
|
{
|
|
<ScrollReveal preset="slideRight" delay={0.3} >
|
|
{
|
|
data.tabItems[activeIndex].icon && (
|
|
<img src={data.tabItems[activeIndex].icon} alt="" style={{ width: '6.25rem', height: '6.25rem', marginRight: '1.25rem' }} />
|
|
)
|
|
}
|
|
</ScrollReveal>
|
|
}
|
|
<div className={`${styles.topTabsContentLeftTitle} ${data.titleDirection === 'column' ? styles.columnCenter : ''}`}>
|
|
<ScrollReveal preset="slideUp" delay={0.5} duration={1.1}>
|
|
<div className={styles.topTabsContentLeftTitleMain}>{data.tabItems[activeIndex].contentTitle}</div>
|
|
</ScrollReveal>
|
|
<ScrollReveal preset="slideUp" delay={0.7} duration={1.1}>
|
|
<div className={styles.topTabsContentLeftTitleSub}>{data.tabItems[activeIndex].contentSubtitle}</div>
|
|
</ScrollReveal>
|
|
</div>
|
|
</div>
|
|
<ScrollReveal preset="slideUp" delay={0.9} duration={1.1}>
|
|
<p className={`${styles.topTabsContentLeftDesc} normal-p`}
|
|
|
|
dangerouslySetInnerHTML={{ __html: data.tabItems[activeIndex].contentText ?? data.tabItems[activeIndex].content as any }}
|
|
>
|
|
{/* {data.tabItems[activeIndex].contentText ?? data.tabItems[activeIndex].content} */}
|
|
</p>
|
|
</ScrollReveal>
|
|
</div>
|
|
<div className={styles.topTabsContentRight}>
|
|
<ScrollReveal preset="slideLeft" delay={0.5} >
|
|
{sideSlides.length > 1 ? (
|
|
<Swiper
|
|
className={styles.sideImageSwiper}
|
|
modules={[Autoplay, Pagination]}
|
|
slidesPerView={1}
|
|
spaceBetween={0}
|
|
loop
|
|
allowTouchMove
|
|
autoplay={{
|
|
delay: 4500,
|
|
disableOnInteraction: false,
|
|
}}
|
|
pagination={{ clickable: true }}
|
|
>
|
|
{sideSlides.map((src, i) => (
|
|
<SwiperSlide key={`${src}-${i}`}>
|
|
<img src={src} alt="" />
|
|
</SwiperSlide>
|
|
))}
|
|
</Swiper>
|
|
) : (
|
|
<img src={sideSlides[0] || sideSlides as any} alt="" />
|
|
)}
|
|
</ScrollReveal>
|
|
</div>
|
|
</>
|
|
)
|
|
}
|
|
|
|
</div>
|
|
</section>
|
|
)
|
|
}
|