用GSAP重新创建滑块并进行反应

发布于 2025-01-19 07:23:32 字数 8489 浏览 0 评论 0原文

我正在尝试使用React和GSAP重新创建此代码epen,我一直在尝试重新创建它几个小时,甚至不知道从哪里开始。我不想在该编码epen中以相同的方式创建各节,而是想从一系列对象中形成细节,这意味着仅创建一个组件就可以使其干燥。我对反应很陌生,我想知道如何从Vanillajs的角度看待这种反应。我已经知道发生了什么事,我也在React中创建了它,但是我想要一种我的代码最小的情况,并且一系列对象形成一个组件,使其更具动态性,以便我可以单击它以获取有关有关的更多信息each section that comes in.

HTML

<div class="slider">
  
  <div class="slider__slide slider__slide--1">
    <div class="slider__img slider__img--1"></div>
    <div class="slider__text slider__text--1">
      <h1 class="slider__header">Rejuvenate your, true self.</h1>
      <a href="ign.com" class="cta">discover</a>
    </div>
  </div>
  
  <div class="slider__slide slider__slide--2">
    <div class="slider__img slider__img--2"></div>
    <div class="slider__text slider__text--2">
      <h1 class="slider__header">Professonial, trust-worthy, and compassionate.</h1>
      <a href="google.com" class="cta">learn more</a>
    </div>
  </div>
  
    <div class="slider__slide slider__slide--3">
    <div class="slider__img slider__img--3"></div>
    <div class="slider__text slider__text--3">
      <h1 class="slider__header">Trust in us.</h1>
      <a href="youtube.com" class="cta">learn more</a>
    </div>
  </div>
  
  <div class="slider__slide slider__slide--4">
    <div class="slider__img slider__img--4"></div>
    <div class="slider__text slider__text--4">
      <h1 class="slider__header">What we do.</h1>
      <a href="tsn.ca" class="cta">discover</a>
    </div>
  </div>
  
  <div class="slider__navigation">
    <div class="slider__count slider__count--top">
      <p class="count count--top count--top-1">01</p>
      <p class="count count--top count--top-2">02</p>
      <p class="count count--top count--top-3">03</p>      
      <p class="count count--top count--top-4">04</p>
    </div>
    
    <div class="slider__bar">
      <div id="sliderBarDynamic" class="slider__bar--dynamic"></div>
      <div class="slider__bar--static"></div>
    </div>
    
     <div class="slider__count slider__count--bottom">
      <p class="count count--bottom count--bottom-1">02</p>
      <p class="count count--bottom count--bottom-2">03</p>
      <p class="count count--bottom count--bottom-3">04</p>      
      <p class="count count--bottom count--bottom-3">01</p>
    </div>
  </div>
  
</div>

CSS

@import url('https://fonts.googleapis.com/css2?family=Gilda+Display&family=Roboto&display=swap');

*,
*::before,
*::after{
padding:0;
margin:0;
box-sizing:inherit;
}

html{
font-size:16px;
box-sizing:border-box;
}

body{
font-family: 'Roboto', sans-serif;
color:#444444;
font-weight: 300;
line-height: 1.6;
}

img{
max-width:100%;
}

h1{
  font-size: 100px;
  color: #fff;
  font-family: 'Gilda Display', serif;
  font-weight: 300;
  line-height: 1;
}

h2{

}


h3{

}


P{
  color: #fff;
}

a{
text-decoration:none;
color:#ffffff;
  font-size: 24px;
}

ul{
list-style-type:none;
}



// Slider 
.slider{
  width: 100%;
  height: 100vh;
  overflow: hidden;
  position: relative;
  
  &__slide{
    width: 100%;
    height: 100%;
    display: flex;
    
    position: absolute;
    top: 0;
    left:0;
    
    &--1{
      z-index: 4;
    }
    
    &--2{
      z-index: 3;
    }
    
    &--3{
      z-index: 2;
    }
    
    &--4{
      z-index: 1;
    }
  }
  
  &__img{
    width: 100%;
    height: 100%;
    position: absolute;
    z-index: -1;
    background-size: cover;
    background-repeat: no-repeat;
    background-position: 50% 50%;
    
    &--1{
      background-image: url('https://i.postimg.cc/Y0T3F1tc/about-landing.jpg');
    }
    
    &--2{
      background-image: url('https://i.postimg.cc/FHHyKWyf/i-Stock-1148043788.jpg');
    }
    
    &--3{
      background-image: url('https://i.postimg.cc/tTqp06QH/i-Stock-1064136816.jpg');
    }
    
    &--4{
      background-image: url('https://i.postimg.cc/435R13K2/i-Stock-1179976698.jpg');
    }
  }
  
  &__text{
    align-self: flex-end;
    padding: 0 0 5vw 15vh;
    opacity: 0;
    width: 80%;
    max-width: 1005px;
    
    .slider__header{
      margin-bottom: 40px;
      text-transform: capitalize;
    }
    
    .cta{
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 6px;
      margin-left: 65px;
      position: relative;
      
      &:before{
        content: '';
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
        left: -55px;
        width: 40px;
        height: 1px;
        background-color: white;
      }
    }
  }
  
  // Slider Navigation
  &__navigation{
    width: 21px;
    height: 400px;
    position: fixed;
    top: 50%;
    transform: translateY(-50%);
    left: calc(100% - 5vw);
    z-index: 10;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
  }
  
  .count--top{
    
      position: absolute;
      top: 0;
      left: 0;
    
    // position:
  }
  
  .count{
    opacity: 0;
  }
  
  .count:first-child{
    opacity: 1;
  }
  
  .count--bottom{
    position: absolute;
    bottom: 0;
    left: 0;
  }
  
  &__bar{
    width: 2px;
    height: 250px;
    position: relative;
    
    &--dynamic{
      width: 100%;
      height: 100%;
      background-color: #FF69B4;
      transform-origin: top center;
      
      position: absolute;
      top: 0;
      left: 0;
      z-index: 2;
    }
    
    &--static{
      width: 100%;
      height: 100%;
      background-color: darkgrey;
      
      position: absolute;
      top: 0;
      left: 0;
    }
  }
}
// Slider end

Javascript

/*
*/

// timeline to control animations everytime the timeline restarts/repeats
let tlRepeat = gsap.timeline();

// Need first slides elements - img and text to animate on each repeat of timeline
let repeatBeginning = ()=>{
  gsap.set(bgImage[0], {opacity: 0, scale: 1.2, webkitFilter:"blur(" + 6 + "px)"})  

 tlRepeat
  .add("slide1-in")
  .fromTo([countTop[0], countBottom[0]], {opacity: 0}, {duration: 0.3, opacity: 1, ease: "Power2.easeIn"}, "slide1-in")  
  .to(bgImage[0], {duration: 1.8, scale: 1, opacity: 1, webkitFilter:"blur(" + 0 + "px)"}, "slide1-in")
  .fromTo(text[0], {opacity: 0, x: -30, ease: "Power2.easeIn"}, {duration: 0.8, opacity: 1, x: 0}, "-=1")


}

// On start animations
// let onStartSlide1Animations = ()=>{
//     // gsap.to(text[0], {duration: 0.7, opacity: 1, x: -15, ease: "Power2.easeIn"})
// }

// Variables
let slides = document.querySelectorAll('.slider__slide'),
    dynamicBar = document.querySelector('#sliderBarDynamic'),
    countTop = document.querySelectorAll(".count--top"),
    countBottom = document.querySelectorAll(".count--bottom"),
    bgImage = document.querySelectorAll(".slider__img"),
    text = document.querySelectorAll(".slider__text"),
    tl = gsap.timeline({repeat: 0, delay: 1, paused: false, onRepeat: repeatBeginning});
    
// Push all text back and only make first one visible
gsap.set(text, {x: -30});
gsap.set(text[0], {opacity: 1});


// Animate slide's elements but not the first one. 
// Make first slide's elements animate when timeline is repeating, 
// Follow the flow of rest of the slide's animations
slides.forEach((slide, i) =>{
  
  tl
    .fromTo(dynamicBar, {scaleY: 0}, {duration: 1.4, scaleY: 1}, "+=2")
    .set(dynamicBar, {transformOrigin: "bottom center"})
    .to(dynamicBar, {duration: 1, scaleY: 0}, "+=0.4")
    .set(dynamicBar, {transformOrigin: "top center"})
    .add("elements-in-out")
    .to([countTop[i], countBottom[i]], {opacity: 0}, "elements-in-out")  
    .to([countTop[i+1], countBottom[i+1]], {opacity: 1}, "elements-in-out")
    .to(bgImage[i], {duration: 0.2, opacity: 0}, "elements-in-out")
    .set(bgImage[i+1], {scale: 1.2, webkitFilter:"blur(" + 6 + "px)"}, "elements-in-out")
    .to(bgImage[i+1], {duration: 1.8, scale: 1, webkitFilter:"blur(" + 0 + "px)"}, "elements-in-out")
    .to(text[i], {duration: 0.3, opacity: 0}, "elements-in-out")
    .to(text[i+1], {duration: 0.8, opacity: 1, x: 0}, "-=1")
})

I am trying to recreate this codepen with react and gsap on here and i have been trying to recreate this for some hours now and do not even know where to start from. i do not want to create the sections the same way in that codepen but rather form the details from an array of objects meaning creating just once component making it DRY. i am fairly new to react and i would like know how to do something like that in react, looking at it from vanillajs perspective. i already know what is going on and i also created it like this in react but i want a situation where i have minimal code and the an array of objects forms one component making it more dynamic so i can click on it to get more information about each section that comes in.

HTML

<div class="slider">
  
  <div class="slider__slide slider__slide--1">
    <div class="slider__img slider__img--1"></div>
    <div class="slider__text slider__text--1">
      <h1 class="slider__header">Rejuvenate your, true self.</h1>
      <a href="ign.com" class="cta">discover</a>
    </div>
  </div>
  
  <div class="slider__slide slider__slide--2">
    <div class="slider__img slider__img--2"></div>
    <div class="slider__text slider__text--2">
      <h1 class="slider__header">Professonial, trust-worthy, and compassionate.</h1>
      <a href="google.com" class="cta">learn more</a>
    </div>
  </div>
  
    <div class="slider__slide slider__slide--3">
    <div class="slider__img slider__img--3"></div>
    <div class="slider__text slider__text--3">
      <h1 class="slider__header">Trust in us.</h1>
      <a href="youtube.com" class="cta">learn more</a>
    </div>
  </div>
  
  <div class="slider__slide slider__slide--4">
    <div class="slider__img slider__img--4"></div>
    <div class="slider__text slider__text--4">
      <h1 class="slider__header">What we do.</h1>
      <a href="tsn.ca" class="cta">discover</a>
    </div>
  </div>
  
  <div class="slider__navigation">
    <div class="slider__count slider__count--top">
      <p class="count count--top count--top-1">01</p>
      <p class="count count--top count--top-2">02</p>
      <p class="count count--top count--top-3">03</p>      
      <p class="count count--top count--top-4">04</p>
    </div>
    
    <div class="slider__bar">
      <div id="sliderBarDynamic" class="slider__bar--dynamic"></div>
      <div class="slider__bar--static"></div>
    </div>
    
     <div class="slider__count slider__count--bottom">
      <p class="count count--bottom count--bottom-1">02</p>
      <p class="count count--bottom count--bottom-2">03</p>
      <p class="count count--bottom count--bottom-3">04</p>      
      <p class="count count--bottom count--bottom-3">01</p>
    </div>
  </div>
  
</div>

CSS

@import url('https://fonts.googleapis.com/css2?family=Gilda+Display&family=Roboto&display=swap');

*,
*::before,
*::after{
padding:0;
margin:0;
box-sizing:inherit;
}

html{
font-size:16px;
box-sizing:border-box;
}

body{
font-family: 'Roboto', sans-serif;
color:#444444;
font-weight: 300;
line-height: 1.6;
}

img{
max-width:100%;
}

h1{
  font-size: 100px;
  color: #fff;
  font-family: 'Gilda Display', serif;
  font-weight: 300;
  line-height: 1;
}

h2{

}


h3{

}


P{
  color: #fff;
}

a{
text-decoration:none;
color:#ffffff;
  font-size: 24px;
}

ul{
list-style-type:none;
}



// Slider 
.slider{
  width: 100%;
  height: 100vh;
  overflow: hidden;
  position: relative;
  
  &__slide{
    width: 100%;
    height: 100%;
    display: flex;
    
    position: absolute;
    top: 0;
    left:0;
    
    &--1{
      z-index: 4;
    }
    
    &--2{
      z-index: 3;
    }
    
    &--3{
      z-index: 2;
    }
    
    &--4{
      z-index: 1;
    }
  }
  
  &__img{
    width: 100%;
    height: 100%;
    position: absolute;
    z-index: -1;
    background-size: cover;
    background-repeat: no-repeat;
    background-position: 50% 50%;
    
    &--1{
      background-image: url('https://i.postimg.cc/Y0T3F1tc/about-landing.jpg');
    }
    
    &--2{
      background-image: url('https://i.postimg.cc/FHHyKWyf/i-Stock-1148043788.jpg');
    }
    
    &--3{
      background-image: url('https://i.postimg.cc/tTqp06QH/i-Stock-1064136816.jpg');
    }
    
    &--4{
      background-image: url('https://i.postimg.cc/435R13K2/i-Stock-1179976698.jpg');
    }
  }
  
  &__text{
    align-self: flex-end;
    padding: 0 0 5vw 15vh;
    opacity: 0;
    width: 80%;
    max-width: 1005px;
    
    .slider__header{
      margin-bottom: 40px;
      text-transform: capitalize;
    }
    
    .cta{
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 6px;
      margin-left: 65px;
      position: relative;
      
      &:before{
        content: '';
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
        left: -55px;
        width: 40px;
        height: 1px;
        background-color: white;
      }
    }
  }
  
  // Slider Navigation
  &__navigation{
    width: 21px;
    height: 400px;
    position: fixed;
    top: 50%;
    transform: translateY(-50%);
    left: calc(100% - 5vw);
    z-index: 10;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
  }
  
  .count--top{
    
      position: absolute;
      top: 0;
      left: 0;
    
    // position:
  }
  
  .count{
    opacity: 0;
  }
  
  .count:first-child{
    opacity: 1;
  }
  
  .count--bottom{
    position: absolute;
    bottom: 0;
    left: 0;
  }
  
  &__bar{
    width: 2px;
    height: 250px;
    position: relative;
    
    &--dynamic{
      width: 100%;
      height: 100%;
      background-color: #FF69B4;
      transform-origin: top center;
      
      position: absolute;
      top: 0;
      left: 0;
      z-index: 2;
    }
    
    &--static{
      width: 100%;
      height: 100%;
      background-color: darkgrey;
      
      position: absolute;
      top: 0;
      left: 0;
    }
  }
}
// Slider end

Javascript

/*
*/

// timeline to control animations everytime the timeline restarts/repeats
let tlRepeat = gsap.timeline();

// Need first slides elements - img and text to animate on each repeat of timeline
let repeatBeginning = ()=>{
  gsap.set(bgImage[0], {opacity: 0, scale: 1.2, webkitFilter:"blur(" + 6 + "px)"})  

 tlRepeat
  .add("slide1-in")
  .fromTo([countTop[0], countBottom[0]], {opacity: 0}, {duration: 0.3, opacity: 1, ease: "Power2.easeIn"}, "slide1-in")  
  .to(bgImage[0], {duration: 1.8, scale: 1, opacity: 1, webkitFilter:"blur(" + 0 + "px)"}, "slide1-in")
  .fromTo(text[0], {opacity: 0, x: -30, ease: "Power2.easeIn"}, {duration: 0.8, opacity: 1, x: 0}, "-=1")


}

// On start animations
// let onStartSlide1Animations = ()=>{
//     // gsap.to(text[0], {duration: 0.7, opacity: 1, x: -15, ease: "Power2.easeIn"})
// }

// Variables
let slides = document.querySelectorAll('.slider__slide'),
    dynamicBar = document.querySelector('#sliderBarDynamic'),
    countTop = document.querySelectorAll(".count--top"),
    countBottom = document.querySelectorAll(".count--bottom"),
    bgImage = document.querySelectorAll(".slider__img"),
    text = document.querySelectorAll(".slider__text"),
    tl = gsap.timeline({repeat: 0, delay: 1, paused: false, onRepeat: repeatBeginning});
    
// Push all text back and only make first one visible
gsap.set(text, {x: -30});
gsap.set(text[0], {opacity: 1});


// Animate slide's elements but not the first one. 
// Make first slide's elements animate when timeline is repeating, 
// Follow the flow of rest of the slide's animations
slides.forEach((slide, i) =>{
  
  tl
    .fromTo(dynamicBar, {scaleY: 0}, {duration: 1.4, scaleY: 1}, "+=2")
    .set(dynamicBar, {transformOrigin: "bottom center"})
    .to(dynamicBar, {duration: 1, scaleY: 0}, "+=0.4")
    .set(dynamicBar, {transformOrigin: "top center"})
    .add("elements-in-out")
    .to([countTop[i], countBottom[i]], {opacity: 0}, "elements-in-out")  
    .to([countTop[i+1], countBottom[i+1]], {opacity: 1}, "elements-in-out")
    .to(bgImage[i], {duration: 0.2, opacity: 0}, "elements-in-out")
    .set(bgImage[i+1], {scale: 1.2, webkitFilter:"blur(" + 6 + "px)"}, "elements-in-out")
    .to(bgImage[i+1], {duration: 1.8, scale: 1, webkitFilter:"blur(" + 0 + "px)"}, "elements-in-out")
    .to(text[i], {duration: 0.3, opacity: 0}, "elements-in-out")
    .to(text[i+1], {duration: 0.8, opacity: 1, x: 0}, "-=1")
})

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

软甜啾 2025-01-26 07:23:32

因此,首先,为了在ReactJ中重新想象任何HTML摘要,请尝试在片段中查找smilarities / Repetation。一旦这样做,您就可以将要分开的要点分开为单独的组成部分,以及它们如何将它们联系在一起。

现在,仅通过查看HTML片段,我们就可以看到幻灯片正在重复,因此可以将其保存为单独的组件。我们还看到,每个幻灯片都显示一个唯一的标题和段落文本,并且具有配色方案。因此,为了使我们的幻灯片组件动态,我们可以将它们作为支架传递给组件。

因此,我们的数据创建整个slider component(由slide's组成)看起来像这样:

const sliderData = [
    {
        id: '1',
        headerText: `I'm the first Box`,
        paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
            elit. Integer lacinia dui lectus. Donec scelerisque ipsum
            diam, ac mattis orci pellentesque eget. `,
        buttonText: 'Check Now',
        colors: {
            sliderBox: '#500033',
            sliderIllustration: '#FF0077',
            sliderInner: 'rgba(255, 0, 119, 0.4)',
            sliderButton: '#FF0077',
        },
    },
    ...
]

接下来,我们注意到,某些UI是使用CSS创建的,此主要是导致整个片段是静态的。因此,为了实现动态性,我们根据所获得的数据在组件中使用了一些样式。这样:

<style
    dangerouslySetInnerHTML={{
        __html: [
        `
            .slider {
                display: flex;
                width: ${sliderData.length * 100}%; /*(this value in css was static 500%, to rendered only 5 slides)*/
                height: 55rem;
                transition: all 0.25s ease-in;
                transform: translateX(0);
            }

            .trail {
                bottom: 5%;
                left: 50%;
                transform: translateX(-50%);
                width: 60%;
                display: grid;
                grid-template-columns: repeat(${sliderData.length}, 1fr); /*this value was also static in css to display only 5 bars/pages.*/
                gap: 1rem;
                text-align: center;
                font-size: 1.5rem;
            }`,
        ].join('\n'),
    }}
></style>

此外,每个幻灯片都被分配了一个静态类,例如box1,box2 ... etc。因此,这些样式需要为每个幻灯片渲染:(

<style
    dangerouslySetInnerHTML={{
        __html: [
            `.slider .box${data.id} {
                background-color: ${data.colors.sliderBox};
            }
            .slider .box${data.id} .illustration .inner {
                background-color: ${data.colors.sliderIllustration};
            }
            .slider .box${data.id} .illustration .inner::after, .slider .box${data.id} .illustration .inner::before {
                background-color: ${data.colors.sliderInner};
            }
            .slider .box${data.id} button {
                background-color: ${data.colors.sliderButton};
            }`,
        ].join('\n'),
    }}
></style>

请注意,上面的摘要中的对象data对应于我们的数组中的对象sliderdata,可以使整个塑造整个变形滑块组件)。

一旦准备好了UI,引入GSAP动画就很简单了。首先,我们为GSAP在动画过程中使用的UI元素创建了refs

接下来,我们触发了动画,就像您在Plain JavaScript中的方式一样。这里唯一的区别是,我们在加载功能组件(空依赖量阵列)后在usefect挂钩中执行它们。

此外,还有一些硬编码的东西使五个幻灯片动画。我们通过引入LET Ratio = 100 / SliderData.length < / code>

整个组件:

import React, { useEffect, useRef } from 'react'
import './styleNew.css'
import { gsap } from 'gsap'

const sliderData = [
  {
    id: '1',
    headerText: `I'm the first Box`,
    paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
        elit. Integer lacinia dui lectus. Donec scelerisque ipsum
        diam, ac mattis orci pellentesque eget. `,
    buttonText: 'Check Now',
    colors: {
      sliderBox: '#500033',
      sliderIllustration: '#FF0077',
      sliderInner: 'rgba(255, 0, 119, 0.4)',
      sliderButton: '#FF0077',
    },
  },
  {
    id: '2',
    headerText: `I'm the second Box`,
    paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
        elit. Integer lacinia dui lectus. Donec scelerisque ipsum
        diam, ac mattis orci pellentesque eget. `,
    buttonText: 'Check Now',
    colors: {
      sliderBox: '#000050',
      sliderIllustration: '#0033FF',
      sliderInner: 'rgba(0, 51, 255, 0.4)',
      sliderButton: '#0033FF',
    },
  },
  {
    id: '3',
    headerText: `I'm the third Box`,
    paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
        elit. Integer lacinia dui lectus. Donec scelerisque ipsum
        diam, ac mattis orci pellentesque eget. `,
    buttonText: 'Check Now',
    colors: {
      sliderBox: '#00501D',
      sliderIllustration: '#00FF44',
      sliderInner: 'rgba(0, 255, 68, 0.4)',
      sliderButton: '#00FF44',
    },
  },
  {
    id: '4',
    headerText: `I'm the fourth Box`,
    paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
        elit. Integer lacinia dui lectus. Donec scelerisque ipsum
        diam, ac mattis orci pellentesque eget. `,
    buttonText: 'Check Now',
    colors: {
      sliderBox: '#554D00',
      sliderIllustration: '#FF4E00',
      sliderInner: 'rgba(255, 78, 0, 0.4)',
      sliderButton: '#FF4E00',
    },
  },
  {
    id: '5',
    headerText: `I'm the fifth Box`,
    paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
        elit. Integer lacinia dui lectus. Donec scelerisque ipsum
        diam, ac mattis orci pellentesque eget. `,
    buttonText: 'Check Now',
    colors: {
      sliderBox: '#300050',
      sliderIllustration: '#8000FF',
      sliderInner: 'rgba(128, 0, 255, 0.4)',
      sliderButton: '#8000FF',
    },
  },
  {
    id: '6',
    headerText: `I'm the sixth Box`,
    paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
        elit. Integer lacinia dui lectus. Donec scelerisque ipsum
        diam, ac mattis orci pellentesque eget. `,
    buttonText: 'Check Now',
    colors: {
      sliderBox: '#000050',
      sliderIllustration: '#0033FF',
      sliderInner: 'rgba(0, 51, 255, 0.4)',
      sliderButton: '#0033FF',
    },
  },
  {
    id: '7',
    headerText: `I'm the seventh Box`,
    paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
        elit. Integer lacinia dui lectus. Donec scelerisque ipsum
        diam, ac mattis orci pellentesque eget. `,
    buttonText: 'Check Now',
    colors: {
      sliderBox: '#00501D',
      sliderIllustration: '#00FF44',
      sliderInner: 'rgba(0, 255, 68, 0.4)',
      sliderButton: '#00FF44',
    },
  },
  {
    id: '8',
    headerText: `I'm the eighth Box`,
    paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
        elit. Integer lacinia dui lectus. Donec scelerisque ipsum
        diam, ac mattis orci pellentesque eget. `,
    buttonText: 'Check Now',
    colors: {
      sliderBox: '#554D00',
      sliderIllustration: '#FF4E00',
      sliderInner: 'rgba(255, 78, 0, 0.4)',
      sliderButton: '#FF4E00',
    },
  },
  {
    id: '9',
    headerText: `I'm the ninth Box`,
    paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
        elit. Integer lacinia dui lectus. Donec scelerisque ipsum
        diam, ac mattis orci pellentesque eget. `,
    buttonText: 'Check Now',
    colors: {
      sliderBox: '#300050',
      sliderIllustration: '#8000FF',
      sliderInner: 'rgba(128, 0, 255, 0.4)',
      sliderButton: '#8000FF',
    },
  },
]

export default function SliderNew() {
  const slider = useRef(undefined)
  const prevButton = useRef(undefined)
  const nextButton = useRef(undefined)
  const trail = useRef([])

  useEffect(() => {
    console.log('sliders', slider)
    console.log('trail', trail)
    console.log('nextButton.current', nextButton.current)
    console.log('prevButton.current', prevButton.current)
    startGsapAnimations()
  }, [])

  const startGsapAnimations = () => {
    // Transform value
    let value = 0
    // trail index number
    let trailValue = 0
    // interval (Duration)
    let interval = 10000

    let ratio = 100 / sliderData.length

    const tl = gsap.timeline({
      defaults: { duration: 0.6, ease: 'power2.inOut' },
    })
    tl.from('.bg', { x: '-100%', opacity: 0 })
      .from('p', { opacity: 0 }, '-=0.3')
      .from('h1', { opacity: 0, y: '30px' }, '-=0.3')
      .from('button', { opacity: 0, y: '-40px' }, '-=0.8')

    // function to restart animation
    const animate = () => tl.restart()

    const slide = (condition) => {
      // CLear interval
      clearInterval(start)
      // update value and trailValue
      condition === 'increase' ? initiateINC() : initiateDEC()
      // move slide
      move(value, trailValue)
      // Restart Animation
      animate()
      // start interal for slides back
      start = setInterval(() => slide('increase'), interval)
    }

    // function for increase(forward, next) configuration
    const initiateINC = () => {
      // Remove active from all trails
      sliderData.forEach((_item, index) =>
        trail[index].classList.remove('active'),
      )
      // increase transform value
      //   console.log('initialInc~value', value)
      //   console.log('initialInc~calc', (sliderData.length - 1) * ratio)
      //   console.log(
      //     'initialInc~eq',
      //     Math.round(value) === Math.round((sliderData.length - 1) * ratio),
      //   )
      Math.round(value) === Math.round((sliderData.length - 1) * ratio)
        ? (value = 0)
        : (value += ratio)
      // update trailValue based on value
      trailUpdate()
    }

    // function for decrease(backward, previous) configuration
    const initiateDEC = () => {
      // Remove active from all trails
      sliderData.forEach((_item, index) =>
        trail[index].classList.remove('active'),
      )
      // decrease transform value
      Math.round(value) === 0
        ? (value = (sliderData.length - 1) * ratio)
        : (value -= ratio)
      // update trailValue based on value
      trailUpdate()
    }

    // function to transform slide
    const move = (S, T) => {
      // transform slider
      slider.current.style.transform = `translateX(-${S}%)`
      //add active class to the current trail
      console.log('trail', T)
      trail[Math.round(T)].classList.add('active')
    }

    const trailUpdate = () => {
      trailValue = value / ratio
      console.log('trailUpdate', trailValue)
    }

    // Start interval for slides
    let start = setInterval(() => slide('increase'), interval)

    nextButton.current.addEventListener('click', () => slide('increase'))
    prevButton.current.addEventListener('click', () => slide('decrease'))

    const clickCheck = (e) => {
      // CLear interval
      clearInterval(start)
      // Get selected trail
      const check = e.target

      // remove active class from all trails
      sliderData.forEach((_item, index) => {
        trail[index].classList.remove('active')
        if (check === trail[index]) {
          value = index * ratio
        }
      })

      // add active class
      check.classList.add('active')

      // update trail based on value
      trailUpdate()
      // transfrom slide
      move(value, trailValue)
      // start animation
      animate()
      // start interval
      start = setInterval(() => slide('increase'), interval)
    }

    // Add function to all trails
    sliderData.forEach((_item, index) =>
      trail[index].addEventListener('click', (ev) => clickCheck(ev)),
    )
  }

  return (
    <>
      <style
        dangerouslySetInnerHTML={{
          __html: [
            `
              .slider {
                display: flex;
                width: ${sliderData.length * 100}%;
                height: 55rem;
                transition: all 0.25s ease-in;
                transform: translateX(0);
              }
              
              .trail {
                bottom: 5%;
                left: 50%;
                transform: translateX(-50%);
                width: 60%;
                display: grid;
                grid-template-columns: repeat(${sliderData.length}, 1fr);
                gap: 1rem;
                text-align: center;
                font-size: 1.5rem;
              }`,
          ].join('\n'),
        }}
      ></style>
      <div className="container">
        <div className="slider" ref={slider}>
          {sliderData.map((item, index) => (
            <Slide key={index} data={item} />
          ))}
        </div>
        <Svg
          ref={prevButton}
          compClass="prev"
          compTransform="translate(0 91) rotate(-90)"
        />
        <Svg
          ref={nextButton}
          compClass="next"
          compTransform="translate(56.898) rotate(90)"
        />
        <div className="trail">
          {sliderData.map((item, index) => (
            <div
              ref={(ref) => {
                trail[index] = ref
              }}
              key={index}
              className={index == 0 ? `box${item.id} active` : `box${item.id}`}
            >
              {item.id}
            </div>
          ))}
        </div>
      </div>
    </>
  )
}

function Slide(props) {
  const { data } = props
  return (
    <>
      <style
        dangerouslySetInnerHTML={{
          __html: [
            `.slider .box${data.id} {
                background-color: ${data.colors.sliderBox};
              }
              .slider .box${data.id} .illustration .inner {
                background-color: ${data.colors.sliderIllustration};
              }
              .slider .box${data.id} .illustration .inner::after, .slider .box${data.id} .illustration .inner::before {
                background-color: ${data.colors.sliderInner};
              }
              .slider .box${data.id} button {
                background-color: ${data.colors.sliderButton};
              }`,
          ].join('\n'),
        }}
      ></style>
      <div className={`box${data.id} box`}>
        <div className="bg"></div>
        <div className="details">
          <h1>{data.headerText}</h1>
          <p>{data.paragraphText}</p>
          <button>{data.buttonText}</button>
        </div>

        <div className="illustration">
          <div className="inner"></div>
        </div>
      </div>
    </>
  )
}

const Svg = React.forwardRef((props, ref) => {
  console.log('Svg', props)
  return (
    <svg
      ref={ref}
      xmlns="http://www.w3.org/2000/svg"
      width="56.898"
      height="91"
      className={props.compClass}
      viewBox="0 0 56.898 91"
    >
      <path
        fill="#fff"
        d="M45.5,0,91,56.9,48.452,24.068,0,56.9Z"
        transform={props.compTransform}
      ></path>
    </svg>
  )
})

stylenew.css:

*,
*:before,
*:after {
  margin: 0;
  padding: 0;
  box-sizing: inherit;
}

html {
  box-sizing: border-box;
  font-family: "Roboto", sans-serif;
  font-size: 62.5%;
}
@media only screen and (max-width: 800px) {
  html {
    font-size: 57%;
  }
}

body {
  background-color: #000;
  color: #fff;
  padding: 8rem;
}
@media only screen and (max-width: 1000px) {
  body {
    padding: 0;
  }
}

.container {
  position: relative;
  overflow: hidden;
  border-radius: 5rem;
}
@media only screen and (max-width: 1000px) {
  .container {
    border-radius: 0;
  }
}

@media only screen and (max-width: 1000px) {
  .slider {
    height: 100vh;
  }
}
.slider .box {
  height: 100%;
  width: 100%;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  align-items: center;
  overflow: hidden;
  position: relative;
}
@media only screen and (max-width: 650px) {
  .slider .box {
    grid-template-columns: 1fr;
    grid-template-rows: repeat(2, 1fr);
  }
}
.slider .box .bg {
  padding: 2rem;
  background-color: rgba(0, 0, 0, 0.2);
  width: 55%;
  transform: skewX(7deg);
  position: absolute;
  height: 100%;
  left: -10%;
  padding-left: 20rem;
  transform-origin: 0 100%;
}
@media only screen and (max-width: 800px) {
  .slider .box .bg {
    width: 65%;
  }
}
@media only screen and (max-width: 650px) {
  .slider .box .bg {
    width: 100%;
    left: 0;
    bottom: 0;
    height: 54%;
    transform: skewX(0deg);
  }
}
.slider .box .bg::before {
  content: "";
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0;
  top: 0;
  background-color: inherit;
  pointer-events: none;
  transform: skewX(10deg);
}
@media only screen and (max-width: 650px) {
  .slider .box .bg::before {
    width: 120%;
    bottom: 0;
    transform: skewX(0deg);
  }
}
.slider .box .details {
  padding: 5rem;
  padding-left: 10rem;
  z-index: 100;
  grid-column: 1/span 1;
  grid-row: 1/-1;
}
@media only screen and (max-width: 650px) {
  .slider .box .details {
    grid-row: 2/span 1;
    grid-column: 1/-1;
    text-align: center;
    padding: 2rem;
    transform: translateY(-9rem);
  }
}
.slider .box .details h1 {
  font-size: 3.5rem;
  font-weight: 500;
  margin-bottom: 0.5rem;
}
.slider .box .details p {
  display: inline-block;
  font-size: 1.3rem;
  color: #B5B4B4;
  margin-bottom: 2rem;
  margin-right: 5rem;
}
@media only screen and (max-width: 800px) {
  .slider .box .details p {
    margin-right: 0;
  }
}
.slider .box .details button {
  padding: 1rem 3rem;
  color: #fff;
  border-radius: 2rem;
  outline: none;
  border: none;
  cursor: pointer;
  transition: all 0.3s ease;
}
.slider .box .details button:hover {
  opacity: 0.8;
}
.slider .box .details button:focus {
  outline: none;
  border: none;
}

.slider .illustration {
  grid-column: 2/-1;
  grid-row: 1/-1;
  justify-self: center;
}
@media only screen and (max-width: 650px) {
  .slider .illustration {
    grid-row: 1/span 1;
    grid-column: 1/-1;
    display: flex;
    justify-content: center;
    align-items: center;
  }
}
.slider .illustration div {
  height: 25rem;
  width: 18rem;
  border-radius: 3rem;
  background-color: #FF0077;
  position: relative;
  transform: skewX(-10deg);
}
@media only screen and (max-width: 800px) {
  .slider .illustration div {
    height: 20rem;
    width: 15rem;
  }
}
.slider .illustration div::after, .slider .illustration div::before {
  content: "";
  position: absolute;
  height: 100%;
  width: 100%;
  border-radius: 3rem;
  top: 0;
  left: 0;
}
.slider .illustration div::after {
  transform: translate(4rem, -1rem);
}
.slider .illustration div::before {
  transform: translate(2rem, -2rem);
}

.prev,
.next,
.trail {
  z-index: 10000;
  position: absolute;
}

.prev,
.next {
  width: 4rem;
  cursor: pointer;
  opacity: 0.2;
  transition: all 0.3s ease;
}
@media only screen and (max-width: 650px) {
  .prev,
.next {
    display: none;
  }
}
.prev:hover,
.next:hover {
  opacity: 1;
}

.prev {
  top: 50%;
  left: 2%;
  transform: translateY(-50%);
}

.next {
  top: 50%;
  right: 2%;
  transform: translateY(-50%);
}


@media only screen and (max-width: 650px) {
  .trail {
    width: 90%;
    bottom: 13%;
  }
}
.trail div {
  padding: 2rem;
  border-top: 3px solid #fff;
  cursor: pointer;
  opacity: 0.3;
  transition: all 0.3s ease;
}
.trail div:hover {
  opacity: 0.6;
}
@media only screen and (max-width: 650px) {
  .trail div {
    padding: 1rem;
  }
}

.active {
  opacity: 1 !important;
}

So first off, in order to re-imagine any html snippet in terms of ReactJS, try and look for smilarities / repetation with in the snippet. Once you do that you would kind of get the gist of what can be seperated out as individual components and how it all ties together.

Now, just by looking at the html snippet, we can see that the slides are repeating, thus they can be kept as a seperate component. We also see that each slide displays a unique heading and paragraph text and also has a color scheme. So in order to make our Slide component dynamic, we can pass these as props to the component.

So our data that creates the whole Slider component (composed of Slide's) looks something like this:

const sliderData = [
    {
        id: '1',
        headerText: `I'm the first Box`,
        paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
            elit. Integer lacinia dui lectus. Donec scelerisque ipsum
            diam, ac mattis orci pellentesque eget. `,
        buttonText: 'Check Now',
        colors: {
            sliderBox: '#500033',
            sliderIllustration: '#FF0077',
            sliderInner: 'rgba(255, 0, 119, 0.4)',
            sliderButton: '#FF0077',
        },
    },
    ...
]

Next we notice, some of the UI was created using CSS, and this mainly caused the whole snippet to be static. So in order to achieve dynamicity we rendered some styles with in the component(s) based on the data we are getting. Like this:

<style
    dangerouslySetInnerHTML={{
        __html: [
        `
            .slider {
                display: flex;
                width: ${sliderData.length * 100}%; /*(this value in css was static 500%, to rendered only 5 slides)*/
                height: 55rem;
                transition: all 0.25s ease-in;
                transform: translateX(0);
            }

            .trail {
                bottom: 5%;
                left: 50%;
                transform: translateX(-50%);
                width: 60%;
                display: grid;
                grid-template-columns: repeat(${sliderData.length}, 1fr); /*this value was also static in css to display only 5 bars/pages.*/
                gap: 1rem;
                text-align: center;
                font-size: 1.5rem;
            }`,
        ].join('\n'),
    }}
></style>

Moreover, each slide was assigned a static class like box1, box2... etc. Therefore these styles need to be rendered for each slide like this:

<style
    dangerouslySetInnerHTML={{
        __html: [
            `.slider .box${data.id} {
                background-color: ${data.colors.sliderBox};
            }
            .slider .box${data.id} .illustration .inner {
                background-color: ${data.colors.sliderIllustration};
            }
            .slider .box${data.id} .illustration .inner::after, .slider .box${data.id} .illustration .inner::before {
                background-color: ${data.colors.sliderInner};
            }
            .slider .box${data.id} button {
                background-color: ${data.colors.sliderButton};
            }`,
        ].join('\n'),
    }}
></style>

(Notice that the object data in the above snippet corresponds to the object in our array sliderData that shapes up the whole slider component).

Once we have our UI ready, introducing GSAP animations was simple. First we created refs to the UI elements that were being used by GSAP in the animation process.

Next up, we triggered the animations just like how you would in plain javascript. The only difference here is that we executed them in the useEffect hook that runs once the functional component is loaded (empty dependancy array).

Moreover there were a few hard-coded stuff that animated just the five slides. Which we made dynamic by introducing let ratio = 100 / sliderData.length

The whole component:

import React, { useEffect, useRef } from 'react'
import './styleNew.css'
import { gsap } from 'gsap'

const sliderData = [
  {
    id: '1',
    headerText: `I'm the first Box`,
    paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
        elit. Integer lacinia dui lectus. Donec scelerisque ipsum
        diam, ac mattis orci pellentesque eget. `,
    buttonText: 'Check Now',
    colors: {
      sliderBox: '#500033',
      sliderIllustration: '#FF0077',
      sliderInner: 'rgba(255, 0, 119, 0.4)',
      sliderButton: '#FF0077',
    },
  },
  {
    id: '2',
    headerText: `I'm the second Box`,
    paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
        elit. Integer lacinia dui lectus. Donec scelerisque ipsum
        diam, ac mattis orci pellentesque eget. `,
    buttonText: 'Check Now',
    colors: {
      sliderBox: '#000050',
      sliderIllustration: '#0033FF',
      sliderInner: 'rgba(0, 51, 255, 0.4)',
      sliderButton: '#0033FF',
    },
  },
  {
    id: '3',
    headerText: `I'm the third Box`,
    paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
        elit. Integer lacinia dui lectus. Donec scelerisque ipsum
        diam, ac mattis orci pellentesque eget. `,
    buttonText: 'Check Now',
    colors: {
      sliderBox: '#00501D',
      sliderIllustration: '#00FF44',
      sliderInner: 'rgba(0, 255, 68, 0.4)',
      sliderButton: '#00FF44',
    },
  },
  {
    id: '4',
    headerText: `I'm the fourth Box`,
    paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
        elit. Integer lacinia dui lectus. Donec scelerisque ipsum
        diam, ac mattis orci pellentesque eget. `,
    buttonText: 'Check Now',
    colors: {
      sliderBox: '#554D00',
      sliderIllustration: '#FF4E00',
      sliderInner: 'rgba(255, 78, 0, 0.4)',
      sliderButton: '#FF4E00',
    },
  },
  {
    id: '5',
    headerText: `I'm the fifth Box`,
    paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
        elit. Integer lacinia dui lectus. Donec scelerisque ipsum
        diam, ac mattis orci pellentesque eget. `,
    buttonText: 'Check Now',
    colors: {
      sliderBox: '#300050',
      sliderIllustration: '#8000FF',
      sliderInner: 'rgba(128, 0, 255, 0.4)',
      sliderButton: '#8000FF',
    },
  },
  {
    id: '6',
    headerText: `I'm the sixth Box`,
    paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
        elit. Integer lacinia dui lectus. Donec scelerisque ipsum
        diam, ac mattis orci pellentesque eget. `,
    buttonText: 'Check Now',
    colors: {
      sliderBox: '#000050',
      sliderIllustration: '#0033FF',
      sliderInner: 'rgba(0, 51, 255, 0.4)',
      sliderButton: '#0033FF',
    },
  },
  {
    id: '7',
    headerText: `I'm the seventh Box`,
    paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
        elit. Integer lacinia dui lectus. Donec scelerisque ipsum
        diam, ac mattis orci pellentesque eget. `,
    buttonText: 'Check Now',
    colors: {
      sliderBox: '#00501D',
      sliderIllustration: '#00FF44',
      sliderInner: 'rgba(0, 255, 68, 0.4)',
      sliderButton: '#00FF44',
    },
  },
  {
    id: '8',
    headerText: `I'm the eighth Box`,
    paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
        elit. Integer lacinia dui lectus. Donec scelerisque ipsum
        diam, ac mattis orci pellentesque eget. `,
    buttonText: 'Check Now',
    colors: {
      sliderBox: '#554D00',
      sliderIllustration: '#FF4E00',
      sliderInner: 'rgba(255, 78, 0, 0.4)',
      sliderButton: '#FF4E00',
    },
  },
  {
    id: '9',
    headerText: `I'm the ninth Box`,
    paragraphText: `Lorem ipsum dolor sit amet, consectetur adipiscing 
        elit. Integer lacinia dui lectus. Donec scelerisque ipsum
        diam, ac mattis orci pellentesque eget. `,
    buttonText: 'Check Now',
    colors: {
      sliderBox: '#300050',
      sliderIllustration: '#8000FF',
      sliderInner: 'rgba(128, 0, 255, 0.4)',
      sliderButton: '#8000FF',
    },
  },
]

export default function SliderNew() {
  const slider = useRef(undefined)
  const prevButton = useRef(undefined)
  const nextButton = useRef(undefined)
  const trail = useRef([])

  useEffect(() => {
    console.log('sliders', slider)
    console.log('trail', trail)
    console.log('nextButton.current', nextButton.current)
    console.log('prevButton.current', prevButton.current)
    startGsapAnimations()
  }, [])

  const startGsapAnimations = () => {
    // Transform value
    let value = 0
    // trail index number
    let trailValue = 0
    // interval (Duration)
    let interval = 10000

    let ratio = 100 / sliderData.length

    const tl = gsap.timeline({
      defaults: { duration: 0.6, ease: 'power2.inOut' },
    })
    tl.from('.bg', { x: '-100%', opacity: 0 })
      .from('p', { opacity: 0 }, '-=0.3')
      .from('h1', { opacity: 0, y: '30px' }, '-=0.3')
      .from('button', { opacity: 0, y: '-40px' }, '-=0.8')

    // function to restart animation
    const animate = () => tl.restart()

    const slide = (condition) => {
      // CLear interval
      clearInterval(start)
      // update value and trailValue
      condition === 'increase' ? initiateINC() : initiateDEC()
      // move slide
      move(value, trailValue)
      // Restart Animation
      animate()
      // start interal for slides back
      start = setInterval(() => slide('increase'), interval)
    }

    // function for increase(forward, next) configuration
    const initiateINC = () => {
      // Remove active from all trails
      sliderData.forEach((_item, index) =>
        trail[index].classList.remove('active'),
      )
      // increase transform value
      //   console.log('initialInc~value', value)
      //   console.log('initialInc~calc', (sliderData.length - 1) * ratio)
      //   console.log(
      //     'initialInc~eq',
      //     Math.round(value) === Math.round((sliderData.length - 1) * ratio),
      //   )
      Math.round(value) === Math.round((sliderData.length - 1) * ratio)
        ? (value = 0)
        : (value += ratio)
      // update trailValue based on value
      trailUpdate()
    }

    // function for decrease(backward, previous) configuration
    const initiateDEC = () => {
      // Remove active from all trails
      sliderData.forEach((_item, index) =>
        trail[index].classList.remove('active'),
      )
      // decrease transform value
      Math.round(value) === 0
        ? (value = (sliderData.length - 1) * ratio)
        : (value -= ratio)
      // update trailValue based on value
      trailUpdate()
    }

    // function to transform slide
    const move = (S, T) => {
      // transform slider
      slider.current.style.transform = `translateX(-${S}%)`
      //add active class to the current trail
      console.log('trail', T)
      trail[Math.round(T)].classList.add('active')
    }

    const trailUpdate = () => {
      trailValue = value / ratio
      console.log('trailUpdate', trailValue)
    }

    // Start interval for slides
    let start = setInterval(() => slide('increase'), interval)

    nextButton.current.addEventListener('click', () => slide('increase'))
    prevButton.current.addEventListener('click', () => slide('decrease'))

    const clickCheck = (e) => {
      // CLear interval
      clearInterval(start)
      // Get selected trail
      const check = e.target

      // remove active class from all trails
      sliderData.forEach((_item, index) => {
        trail[index].classList.remove('active')
        if (check === trail[index]) {
          value = index * ratio
        }
      })

      // add active class
      check.classList.add('active')

      // update trail based on value
      trailUpdate()
      // transfrom slide
      move(value, trailValue)
      // start animation
      animate()
      // start interval
      start = setInterval(() => slide('increase'), interval)
    }

    // Add function to all trails
    sliderData.forEach((_item, index) =>
      trail[index].addEventListener('click', (ev) => clickCheck(ev)),
    )
  }

  return (
    <>
      <style
        dangerouslySetInnerHTML={{
          __html: [
            `
              .slider {
                display: flex;
                width: ${sliderData.length * 100}%;
                height: 55rem;
                transition: all 0.25s ease-in;
                transform: translateX(0);
              }
              
              .trail {
                bottom: 5%;
                left: 50%;
                transform: translateX(-50%);
                width: 60%;
                display: grid;
                grid-template-columns: repeat(${sliderData.length}, 1fr);
                gap: 1rem;
                text-align: center;
                font-size: 1.5rem;
              }`,
          ].join('\n'),
        }}
      ></style>
      <div className="container">
        <div className="slider" ref={slider}>
          {sliderData.map((item, index) => (
            <Slide key={index} data={item} />
          ))}
        </div>
        <Svg
          ref={prevButton}
          compClass="prev"
          compTransform="translate(0 91) rotate(-90)"
        />
        <Svg
          ref={nextButton}
          compClass="next"
          compTransform="translate(56.898) rotate(90)"
        />
        <div className="trail">
          {sliderData.map((item, index) => (
            <div
              ref={(ref) => {
                trail[index] = ref
              }}
              key={index}
              className={index == 0 ? `box${item.id} active` : `box${item.id}`}
            >
              {item.id}
            </div>
          ))}
        </div>
      </div>
    </>
  )
}

function Slide(props) {
  const { data } = props
  return (
    <>
      <style
        dangerouslySetInnerHTML={{
          __html: [
            `.slider .box${data.id} {
                background-color: ${data.colors.sliderBox};
              }
              .slider .box${data.id} .illustration .inner {
                background-color: ${data.colors.sliderIllustration};
              }
              .slider .box${data.id} .illustration .inner::after, .slider .box${data.id} .illustration .inner::before {
                background-color: ${data.colors.sliderInner};
              }
              .slider .box${data.id} button {
                background-color: ${data.colors.sliderButton};
              }`,
          ].join('\n'),
        }}
      ></style>
      <div className={`box${data.id} box`}>
        <div className="bg"></div>
        <div className="details">
          <h1>{data.headerText}</h1>
          <p>{data.paragraphText}</p>
          <button>{data.buttonText}</button>
        </div>

        <div className="illustration">
          <div className="inner"></div>
        </div>
      </div>
    </>
  )
}

const Svg = React.forwardRef((props, ref) => {
  console.log('Svg', props)
  return (
    <svg
      ref={ref}
      xmlns="http://www.w3.org/2000/svg"
      width="56.898"
      height="91"
      className={props.compClass}
      viewBox="0 0 56.898 91"
    >
      <path
        fill="#fff"
        d="M45.5,0,91,56.9,48.452,24.068,0,56.9Z"
        transform={props.compTransform}
      ></path>
    </svg>
  )
})

The styleNew.css:

*,
*:before,
*:after {
  margin: 0;
  padding: 0;
  box-sizing: inherit;
}

html {
  box-sizing: border-box;
  font-family: "Roboto", sans-serif;
  font-size: 62.5%;
}
@media only screen and (max-width: 800px) {
  html {
    font-size: 57%;
  }
}

body {
  background-color: #000;
  color: #fff;
  padding: 8rem;
}
@media only screen and (max-width: 1000px) {
  body {
    padding: 0;
  }
}

.container {
  position: relative;
  overflow: hidden;
  border-radius: 5rem;
}
@media only screen and (max-width: 1000px) {
  .container {
    border-radius: 0;
  }
}

@media only screen and (max-width: 1000px) {
  .slider {
    height: 100vh;
  }
}
.slider .box {
  height: 100%;
  width: 100%;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  align-items: center;
  overflow: hidden;
  position: relative;
}
@media only screen and (max-width: 650px) {
  .slider .box {
    grid-template-columns: 1fr;
    grid-template-rows: repeat(2, 1fr);
  }
}
.slider .box .bg {
  padding: 2rem;
  background-color: rgba(0, 0, 0, 0.2);
  width: 55%;
  transform: skewX(7deg);
  position: absolute;
  height: 100%;
  left: -10%;
  padding-left: 20rem;
  transform-origin: 0 100%;
}
@media only screen and (max-width: 800px) {
  .slider .box .bg {
    width: 65%;
  }
}
@media only screen and (max-width: 650px) {
  .slider .box .bg {
    width: 100%;
    left: 0;
    bottom: 0;
    height: 54%;
    transform: skewX(0deg);
  }
}
.slider .box .bg::before {
  content: "";
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0;
  top: 0;
  background-color: inherit;
  pointer-events: none;
  transform: skewX(10deg);
}
@media only screen and (max-width: 650px) {
  .slider .box .bg::before {
    width: 120%;
    bottom: 0;
    transform: skewX(0deg);
  }
}
.slider .box .details {
  padding: 5rem;
  padding-left: 10rem;
  z-index: 100;
  grid-column: 1/span 1;
  grid-row: 1/-1;
}
@media only screen and (max-width: 650px) {
  .slider .box .details {
    grid-row: 2/span 1;
    grid-column: 1/-1;
    text-align: center;
    padding: 2rem;
    transform: translateY(-9rem);
  }
}
.slider .box .details h1 {
  font-size: 3.5rem;
  font-weight: 500;
  margin-bottom: 0.5rem;
}
.slider .box .details p {
  display: inline-block;
  font-size: 1.3rem;
  color: #B5B4B4;
  margin-bottom: 2rem;
  margin-right: 5rem;
}
@media only screen and (max-width: 800px) {
  .slider .box .details p {
    margin-right: 0;
  }
}
.slider .box .details button {
  padding: 1rem 3rem;
  color: #fff;
  border-radius: 2rem;
  outline: none;
  border: none;
  cursor: pointer;
  transition: all 0.3s ease;
}
.slider .box .details button:hover {
  opacity: 0.8;
}
.slider .box .details button:focus {
  outline: none;
  border: none;
}

.slider .illustration {
  grid-column: 2/-1;
  grid-row: 1/-1;
  justify-self: center;
}
@media only screen and (max-width: 650px) {
  .slider .illustration {
    grid-row: 1/span 1;
    grid-column: 1/-1;
    display: flex;
    justify-content: center;
    align-items: center;
  }
}
.slider .illustration div {
  height: 25rem;
  width: 18rem;
  border-radius: 3rem;
  background-color: #FF0077;
  position: relative;
  transform: skewX(-10deg);
}
@media only screen and (max-width: 800px) {
  .slider .illustration div {
    height: 20rem;
    width: 15rem;
  }
}
.slider .illustration div::after, .slider .illustration div::before {
  content: "";
  position: absolute;
  height: 100%;
  width: 100%;
  border-radius: 3rem;
  top: 0;
  left: 0;
}
.slider .illustration div::after {
  transform: translate(4rem, -1rem);
}
.slider .illustration div::before {
  transform: translate(2rem, -2rem);
}

.prev,
.next,
.trail {
  z-index: 10000;
  position: absolute;
}

.prev,
.next {
  width: 4rem;
  cursor: pointer;
  opacity: 0.2;
  transition: all 0.3s ease;
}
@media only screen and (max-width: 650px) {
  .prev,
.next {
    display: none;
  }
}
.prev:hover,
.next:hover {
  opacity: 1;
}

.prev {
  top: 50%;
  left: 2%;
  transform: translateY(-50%);
}

.next {
  top: 50%;
  right: 2%;
  transform: translateY(-50%);
}


@media only screen and (max-width: 650px) {
  .trail {
    width: 90%;
    bottom: 13%;
  }
}
.trail div {
  padding: 2rem;
  border-top: 3px solid #fff;
  cursor: pointer;
  opacity: 0.3;
  transition: all 0.3s ease;
}
.trail div:hover {
  opacity: 0.6;
}
@media only screen and (max-width: 650px) {
  .trail div {
    padding: 1rem;
  }
}

.active {
  opacity: 1 !important;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文