diff --git a/src/components/cardStack/layouts/timelines/TimelineHorizontalCardStack.tsx b/src/components/cardStack/layouts/timelines/TimelineHorizontalCardStack.tsx index 73d18db..9088c41 100644 --- a/src/components/cardStack/layouts/timelines/TimelineHorizontalCardStack.tsx +++ b/src/components/cardStack/layouts/timelines/TimelineHorizontalCardStack.tsx @@ -1,25 +1,32 @@ -import React, { useRef } from 'react'; -import { useCardAnimation, UseCardAnimationOptions } from '@/hooks/useCardAnimation'; +"use client"; -export interface TimelineHorizontalCardStackProps { +import React, { Children, useCallback } from "react"; +import { cls } from "@/lib/utils"; +import CardStackTextBox from "../../CardStackTextBox"; +import { useTimelineHorizontal, type MediaItem } from "../../hooks/useTimelineHorizontal"; +import MediaContent from "@/components/shared/MediaContent"; +import type { LucideIcon } from "lucide-react"; +import type { ButtonConfig, ButtonAnimationType, TitleSegment, TextboxLayout, InvertedBackground } from "../../types"; + +interface TimelineHorizontalCardStackProps { children: React.ReactNode; - title?: string; - description?: string; + title: string; + titleSegments?: TitleSegment[]; + description: string; tag?: string; - textboxLayout?: string; - animationType?: string; - containerClassName?: string; - mediaItems?: Array<{ imageSrc?: string; videoSrc?: string; imageAlt?: string; videoAriaLabel?: string }>; - titleSegments?: Array<{ type: 'text'; content: string } | { type: 'image'; src: string; alt?: string }>; - buttons?: Array<{ text: string; onClick?: () => void; href?: string }>; - buttonAnimation?: string; - tagIcon?: any; - tagAnimation?: string; - useInvertedBackground?: boolean; - ariaLabel?: string; + tagIcon?: LucideIcon; + tagAnimation?: ButtonAnimationType; + buttons?: ButtonConfig[]; + buttonAnimation?: ButtonAnimationType; + textboxLayout: TextboxLayout; + useInvertedBackground?: InvertedBackground; + mediaItems?: MediaItem[]; className?: string; + containerClassName?: string; textBoxClassName?: string; titleClassName?: string; + titleImageWrapperClassName?: string; + titleImageClassName?: string; descriptionClassName?: string; tagClassName?: string; buttonContainerClassName?: string; @@ -29,28 +36,140 @@ export interface TimelineHorizontalCardStackProps { progressBarClassName?: string; mediaContainerClassName?: string; mediaClassName?: string; + ariaLabel?: string; } -export const TimelineHorizontalCardStack: React.FC = ({ +const TimelineHorizontalCardStack = ({ children, - containerClassName = '', - ...props -}) => { - const containerRef = useRef(null); - const itemRefs = useRef<(HTMLDivElement | null)[]>([]); + title, + titleSegments, + description, + tag, + tagIcon, + tagAnimation, + buttons, + buttonAnimation, + textboxLayout, + useInvertedBackground, + mediaItems, + className = "", + containerClassName = "", + textBoxClassName = "", + titleClassName = "", + titleImageWrapperClassName = "", + titleImageClassName = "", + descriptionClassName = "", + tagClassName = "", + buttonContainerClassName = "", + buttonClassName = "", + buttonTextClassName = "", + cardClassName = "", + progressBarClassName = "", + mediaContainerClassName = "", + mediaClassName = "", + ariaLabel = "Timeline section", +}: TimelineHorizontalCardStackProps) => { + const childrenArray = Children.toArray(children); + const itemCount = childrenArray.length; - const animationOptions: UseCardAnimationOptions = { - containerRef, - itemRefs, - }; + const { activeIndex, progressRefs, handleItemClick, imageOpacity, currentMediaSrc } = useTimelineHorizontal({ + itemCount, + mediaItems, + }); - const { } = useCardAnimation(animationOptions); + const getGridColumns = useCallback(() => { + if (itemCount === 2) return "md:grid-cols-2"; + if (itemCount === 3) return "md:grid-cols-3"; + return "md:grid-cols-4"; + }, [itemCount]); + + const getItemOpacity = useCallback( + (index: number) => { + return index <= activeIndex ? "opacity-100" : "opacity-50"; + }, + [activeIndex] + ); return ( -
- {children} -
+
+
+ + {mediaItems && mediaItems.length > 0 && ( +
+
+ +
+
+ )} +
+ {Children.map(childrenArray, (child, index) => ( +
handleItemClick(index)} + > + {child} +
+
+
{ + if (el !== null) { + progressRefs.current[index] = el; + } + }} + className={cls("absolute z-10 h-full w-full bg-foreground origin-left", progressBarClassName)} + style={{ transform: "scaleX(0)" }} + /> +
+
+ ))} +
+
+
); }; -export default TimelineHorizontalCardStack; +TimelineHorizontalCardStack.displayName = "TimelineHorizontalCardStack"; + +export default React.memo(TimelineHorizontalCardStack);