stephane-monnot / react-vertical-timeline

Vertical timeline for React.js

Home Page:https://stephane-monnot.github.io/react-vertical-timeline/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Animation Issue in Timeline when Loading More Items

miguelsmuller opened this issue · comments

Issue Description:

I'm attempting to create a timeline similar to the demonstration provided in oficial documentation (https://stephane-monnot.github.io/react-vertical-timeline/#/demo-load-more), but I've encountered an issue related to the animation.

Currently, when I click on the "Load More Items" button within the timeline, the animation is triggered for all items in the timeline, instead of just the newly loaded items.

Steps to Reproduce:

Navigate to the timeline page.
Scroll down to reveal the "Load More Items" button.
Click the "Load More Items" button.
Expected Behavior:

The animation should only be applied to the newly loaded items in the timeline, leaving the existing items unaffected.

Actual Behavior:

The animation is applied to all items within the timeline, including the existing ones, when the "Load More Items" button is clicked.

Additional Information:

I have attached a video showcasing the observed behavior to this issue. This should provide a clearer understanding of the problem I am facing.

I appreciate any assistance in resolving this animation issue, as it is affecting the overall user experience of the timeline feature.

Thank you.

Screen.Recording.2023-08-15.at.20.26.11.mov

My Code:

import React, { useState } from 'react'

import { VerticalTimeline, VerticalTimelineElement } from 'react-vertical-timeline-component'
import 'react-vertical-timeline-component/style.min.css'
import styled from 'styled-components'

import theme from 'src/styles/theme'

const Timeline = ({ data }: any) => {
  const length = data.length
  const perPage = 2

  const DivElementGroup = styled.div`
    width: 100%;

    .course_group .vertical-timeline-element-content{
      background: ${theme.colors.lightGray} ;
      color: ${theme.colors.darkBlue} ;
      padding: 1em;
    }

    .course_title {
      font-size: 18px;
      margin: 0px;
      padding: 0px;
      font-weight: ${theme.weight.bold};
    }

    .course_local {
      font-size: 14px;
      margin: 0px;
      padding: 0px;
      font-weight: ${theme.weight.semiBold};
    }

    .course_certification{
      font-size: 12px;
      font-weight: ${theme.weight.bold};
      color: ${theme.colors.red};
    }

    .course_icon{
      display:flex;
      justify-content:center;
      align-items:center;
      height: 100%;
      font-size: 22px;
      font-weight: ${theme.weight.extraBold};
    }
  `

  const renderTimelineElement = (item: any, index: number) => {
    return (
      <VerticalTimelineElement
        key={index}
        date={item.completionDate}
        className="course_group vertical-timeline-element--work"
        icon={renderIcon(index)}
        iconStyle={{ background: theme.colors.darkBlue, color: '#fff' }}
      >

        {renderTitle(item)}
        {renderLocal(item)}
        {renderCertificate(item)}

      </VerticalTimelineElement>
    )
  }

  const renderIcon = (icon: any) => {
    return (
      <div className='course_icon'>
        {icon}
      </div>
    )
  }

  const renderTitle = (item: any) => {
    return (
      <p className='course_title'>
        {item.title}
      </p>
    )
  }

  const renderLocal = (item: any) => {
    return (
      <p className='course_local'>
        {item.local}
      </p>
    )
  }

  const renderCertificate = (item: any) => {
    return (
      item.certificateURl && (
        <a
          href={item.certificateURl}
          target="_blank"
          className='course_certification'
          rel="noreferrer"
        >
          Link do Certificado
        </a>
      )
    )
  }

  const loadMoreElements = () => {
    const newElements = [
      data.slice(counter, counter + 2).map((item: any, index: number) => {
        return (renderTimelineElement(item, index + counter))
      })
    ]

    setElements(oldElements => [...oldElements, newElements])
  }

  const [counter, setCounter] = useState(perPage)

  const [elements, setElements] = useState(
    [
      data.slice(0, perPage).map((item: any, index: number) => {
        return (renderTimelineElement(item, index))
      })
    ]
  )

  return (
    <DivElementGroup>
      <VerticalTimeline lineColor={theme.colors.lightGray}>

        {elements}

        {length <= counter
          ? null
          : <VerticalTimelineElement
            className="vertical-timeline-element--click"
            icon={renderIcon('+')}
            iconStyle={{ background: theme.colors.red, color: '#fff' }}
            iconOnClick={() => {
              loadMoreElements()
              setCounter(counter + perPage)
            }}
          >
          </VerticalTimelineElement>
        }
      </VerticalTimeline>
    </DivElementGroup>
  )
}

export default Timeline

Can I work on this issue?

Hello @theavitw ,

Thank you for your willingness to help with this issue.

The question you raised about working on this issue is for me ?

If you're interested in helping me resolve this issue, I would greatly appreciate your assistance. I'm facing some challenges in getting the animation to work as expected, and your expertise would be valuable in addressing this problem.

Once again, thank you for your offer to help.

@miguelsmuller @theavitw

Sorry guys I do not have an idea how to fix that, but I have question. Animation is set default to trigger only once, do you have any idea how to override/increase counter, so animation effect can be executed whenever user has this section in view?

Hello @Neftyr

I would like to request further clarification regarding your previous comment, as I didn't fully comprehend it. Could you provide more details or elaborate further on your question or proposal? This would help clarify how we can proceed in resolving this problem. I appreciate your cooperation in advance.

Hi @miguelsmuller

I'm just asking if there is any way to trigger timeline animation more than once using this framework. Now lets say we have implemented default version of timeline to our component (like below). Once you refresh server on for example http://localhost:3000/ and you scroll down to component, which includes timeline and get timeline in view this timeline will do its animation by appearing while scrolling right? Now when you scroll to the top of your website (you have no longer this component with timeline in view) and get back to timeline again it will not animate, it will just be there as it already animated once. To trigger animation again we need to refresh http://localhost:3000/. I'm asking if there is any way to trigger timeline animation every time you have timeline in view. I did not see such property mentioned by author, so I was wondering if we can change that somehow.

Below you can see my component code:

"use client"

import React from "react"
import expStyle from "@/styles/experience.module.css"
import SectionHeading from "./section-heading"
import "react-vertical-timeline-component/style.min.css"
import { experienceData } from "@/lib/data"
import { VerticalTimeline, VerticalTimelineElement } from "react-vertical-timeline-component"

export default function Experience() {
    return (
        <section className={expStyle.section} id="experience">
            <SectionHeading>My Experience</SectionHeading>
            {/* We are setting lineColor in globals.css to avoid errors in console */}
            <VerticalTimeline lineColor="" animate={true}>
                {experienceData.map((item, index) => (
                    <React.Fragment key={index}>
                        <VerticalTimelineElement
                            contentStyle={{
                                background: "rgba(37, 32, 35, 0.4)",
                                boxShadow: "none",
                                border: "1px solid #805d39",
                                textAlign: "left",
                                padding: "1.3rem 2rem",
                                color: "white",
                            }}
                            contentArrowStyle={{
                                borderRight: "0.4rem solid #805d39",
                            }}
                            date={item.date}
                            icon={item.icon}
                            iconStyle={{
                                background: "rgba(37, 26, 26, 1)",
                                fontSize: "1.5rem",
                                color: "black",
                                boxShadow: "0px 0px 10px #805d39",
                                //boxShadow: "0 0 0 4px #805d39",
                            }}
                        >
                            <h3 className={expStyle.title}>{item.title}</h3>
                            <p className={expStyle.location}>{item.location}</p>
                            <p className={expStyle.desc}>{item.description}</p>
                        </VerticalTimelineElement>
                    </React.Fragment>
                ))}
            </VerticalTimeline>
        </section>
    )
}