I'm new to gsap and I want to create timeline animation like this (I've attached the images below) where if I scroll, current section should fade away and next section should fade in (changing the state of timeline on the left side too). To make the pages 100vh (which is requirement in my case) I've used overflow: none property but the scrolltrigger doesn't works if the page scroll is hidden. If I hide it, it doesn't work.
so far I've written this code.
import { useEffect, useRef, useState } from "react";
import { StepTimleline, TextCard, Wrapper } from "./Common/ReusableObj";
import { features } from "./Common/Data";
import { Grid, Tab, Typography, Tabs, Box, Stack } from "@mui/material";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { Link } from "react-router-dom";
gsap.registerPlugin(ScrollTrigger);
export default function Features() {
const [isActive, setIsActive] = useState(null);
const [isTabActive, setIsTabActive] = useState("#section-1");
useEffect(() => {
setIsActive(location.pathname);
}, [location]);
useEffect(() => {
gsap.to(".section-1", {
scrollTrigger: {
trigger: ".section-1",
toggleActions: "play none none reverse",
},
y: -600,
});
gsap.to(".section-2", {
scrollTrigger: {
trigger: ".section-2",
toggleActions: "play none none reverse",
},
y: -500,
});
gsap.to(".section-3", {
scrollTrigger: {
trigger: ".section-3",
toggleActions: "play none none reverse",
},
y: -500,
});
gsap.to(".section-4", {
scrollTrigger: {
trigger: ".section-4",
toggleActions: "play none none reverse",
},
y: -500,
});
}, []);
return (
<>
<Wrapper
sx={{
height: "auto",
}}
className={
isActive === "/"
? "res-height wrapper-center border-box"
: "wrapper-center border-box"
}
>
<StepTimleline
className="steps-timeline features"
sx={{ alignSelf: "center", marginTop: { xs: "6rem", md: 0 } }}
>
<Stack className="steps" spacing={3}>
{features.map((item, index) => (
<Link
key={index}
className={
isTabActive === `#section-${index + 1}` ? "active" : ""
}
href={`#section-${index + 1}`}
to={`#section-${index + 1}`}
onClick={() => {
setIsTabActive(`#section-${index + 1}`);
}}
></Link>
))}
</Stack>
<Stack>
{features.map((item, index) =>
index % 2 == 0 ? (
<Box
key={index}
id={`#section-${index + 1}`}
className={`section-${
index + 1
} sections justify-content-center`}
ref={imgRef}
>
<Grid
container
sx={{
height: { md: "auto", lg: "-webkit-fill-available" },
}}
>
<Grid
item
xs={12}
md={6}
className="d-flex align-items-center justify-content-center"
>
<TextCard>
<Typography className="section-title">
{item.sectionTitle}
</Typography>
<Typography className="section-text">
{item.content}
</Typography>
</TextCard>
</Grid>
<Grid
item
xs={12}
md={6}
sx={{ marginTop: { xs: "1rem", md: 0 } }}
className="d-flex align-items-center justify-content-center"
>
<img src={item.img} alt="goddess" loading="lazy" />
</Grid>
</Grid>
</Box>
) : (
<Box
key={index}
id={`section-${index + 1}`}
className={`section-${
index + 1
} sections justify-content-center`}
ref={imgRef}
>
<Grid
container
sx={{
height: { md: "auto", lg: "-webkit-fill-available" },
}}
>
<Grid
item
xs={12}
md={6}
className="d-flex align-items-center justify-content-center"
sx={{
marginTop: { xs: "1rem", md: 0 },
order: { xs: "2", md: "1" },
}}
>
<img src={item.img} alt="fruit" loading="lazy" />
</Grid>
<Grid
item
xs={12}
md={6}
className="d-flex align-items-center justify-content-center"
sx={{
order: { xs: "1", md: "2" },
}}
>
<TextCard>
<Typography className="section-title">
{item.sectionTitle}
</Typography>
<Typography className="section-text">
{item.content}
</Typography>
</TextCard>
</Grid>
</Grid>
</Box>
)
)}
</Stack>
</StepTimleline>
</Wrapper>
</>
);
}
Style component
export const StepTimleline = styled(Box)`
width: -webkit-fill-available;
overflow: hidden;
&.features {
height: calc(100vh - 20vh);
img {
width: 636.12px;
height: 585.27px;
@media (max-width: 1200px) {
width: 550px;
height: 550px;
}
@media (max-width: 900px) {
width: 496px;
height: 472px;
}
@media (max-width: 500px) {
width: 296px;
height: 272px;
}
}
}
.steps {
position: sticky;
top: 0;
left: 0;
align-items: end;
float: inline-start;
z-index: 1;
a.active {
background: linear-gradient(180deg, #c798ff 1.28%, #8824b6 101.28%);
box-shadow: 0px 0px 8px 0px #b05bec;
opacity: 1;
}
a {
width: 4px;
background: #b87cd4;
opacity: 0.15;
}
}
.sections:nth-of-type(odd) {
display: flex;
opacity: 1;
transition: all 2s ease-in;
}
.sections:nth-of-type(even) {
display: flex;
opacity: 1;
transition: all 2s ease-in;
}
@media (max-width: 900px) {
.res-btn button {
width: 288px;
height: 63px;
img {
width: 288px;
height: 63px;
}
}
.footer {
position: absolute;
}
}
`;
(https://i.stack.imgur.com/WCHai.png) (https://i.stack.imgur.com/mZFQW.png)