diff --git a/src/components/cardStack/layouts/timelines/TimelineProcessFlow.tsx b/src/components/cardStack/layouts/timelines/TimelineProcessFlow.tsx index 51feae7..d400cd2 100644 --- a/src/components/cardStack/layouts/timelines/TimelineProcessFlow.tsx +++ b/src/components/cardStack/layouts/timelines/TimelineProcessFlow.tsx @@ -1,26 +1,202 @@ -import React, { useContext } from 'react'; -import { CardStackContext } from '../../CardStackContext'; +"use client"; -interface TimelineProcessFlowProps { - children: React.ReactNode; - className?: string; +import React, { useEffect, useRef, memo, useState } from "react"; +import { gsap } from "gsap"; +import { ScrollTrigger } from "gsap/ScrollTrigger"; +import CardStackTextBox from "../../CardStackTextBox"; +import { useCardAnimation } from "../../hooks/useCardAnimation"; +import { cls } from "@/lib/utils"; +import type { LucideIcon } from "lucide-react"; +import type { ButtonConfig, ButtonAnimationType, CardAnimationType, TitleSegment } from "../../types"; +import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants"; + +gsap.registerPlugin(ScrollTrigger); + +interface TimelineProcessFlowItem { + id: string; + content: React.ReactNode; + media: React.ReactNode; + reverse: boolean; } -export const TimelineProcessFlow: React.FC = ({ children, className = '' }) => { - const context = useContext(CardStackContext); +interface TimelineProcessFlowProps { + items: TimelineProcessFlowItem[]; + title: string; + titleSegments?: TitleSegment[]; + description: string; + tag?: string; + tagIcon?: LucideIcon; + tagAnimation?: ButtonAnimationType; + buttons?: ButtonConfig[]; + buttonAnimation?: ButtonAnimationType; + textboxLayout: TextboxLayout; + animationType: CardAnimationType; + useInvertedBackground?: InvertedBackground; + ariaLabel?: string; + className?: string; + containerClassName?: string; + textBoxClassName?: string; + textBoxTitleClassName?: string; + textBoxDescriptionClassName?: string; + textBoxTagClassName?: string; + textBoxButtonContainerClassName?: string; + textBoxButtonClassName?: string; + textBoxButtonTextClassName?: string; + itemClassName?: string; + mediaWrapperClassName?: string; + numberClassName?: string; + contentWrapperClassName?: string; + gapClassName?: string; + titleImageWrapperClassName?: string; + titleImageClassName?: string; +} - if (!context) { - return
{children}
; - } +const TimelineProcessFlow = ({ + items, + title, + titleSegments, + description, + tag, + tagIcon, + tagAnimation, + buttons, + buttonAnimation, + textboxLayout, + animationType, + useInvertedBackground, + ariaLabel = "Timeline process flow section", + className = "", + containerClassName = "", + textBoxClassName = "", + textBoxTitleClassName = "", + textBoxDescriptionClassName = "", + textBoxTagClassName = "", + textBoxButtonContainerClassName = "", + textBoxButtonClassName = "", + textBoxButtonTextClassName = "", + itemClassName = "", + mediaWrapperClassName = "", + numberClassName = "", + contentWrapperClassName = "", + gapClassName = "", + titleImageWrapperClassName = "", + titleImageClassName = "", +}: TimelineProcessFlowProps) => { + const processLineRef = useRef(null); + const { itemRefs } = useCardAnimation({ animationType, itemCount: items.length, useIndividualTriggers: true }); + const [isMdScreen, setIsMdScreen] = useState(false); - const { isVisible, getAnimationProps } = context; - const animationProps = getAnimationProps(); + useEffect(() => { + const checkScreenSize = () => { + setIsMdScreen(window.innerWidth >= 768); + }; + + checkScreenSize(); + window.addEventListener('resize', checkScreenSize); + + return () => window.removeEventListener('resize', checkScreenSize); + }, []); + + useEffect(() => { + if (!processLineRef.current) return; + + gsap.fromTo( + processLineRef.current, + { yPercent: -100 }, + { + yPercent: 0, + ease: "none", + scrollTrigger: { + trigger: ".timeline-line", + start: "top center", + end: "bottom center", + scrub: true, + }, + } + ); + + return () => { + ScrollTrigger.getAll().forEach((trigger) => trigger.kill()); + }; + }, []); return ( -
- {children} -
+
+
+
+ +
+
+
+
+
+
+
+
    + {items.map((item, index) => ( +
  1. { + itemRefs.current[index] = el; + }} + className={cls( + "relative z-10 w-full flex flex-col gap-6 md:gap-0 md:flex-row justify-between", + item.reverse && "flex-col md:flex-row-reverse", + itemClassName + )} + > +
    + {item.media} +
    +
    +

    {item.id}

    +
    +
    + {item.content} +
    +
  2. + ))} +
+
+
+
); }; -export default TimelineProcessFlow; \ No newline at end of file +TimelineProcessFlow.displayName = "TimelineProcessFlow"; + +export default memo(TimelineProcessFlow);