diff --git a/src/components/cardStack/layouts/timelines/TimelineBase.tsx b/src/components/cardStack/layouts/timelines/TimelineBase.tsx index d9405a1..6c3930a 100644 --- a/src/components/cardStack/layouts/timelines/TimelineBase.tsx +++ b/src/components/cardStack/layouts/timelines/TimelineBase.tsx @@ -1,44 +1,149 @@ -import React, { useMemo } from "react"; -import { CardStack, CardStackProps } from "@/components/cardStack"; -import { cn } from "@/lib/utils"; +"use client"; -export interface TimelineItem { - id: string; - reverse?: boolean; - media?: React.ReactNode; - content?: React.ReactNode; +import React, { Children, useCallback } from "react"; +import { cls } from "@/lib/utils"; +import CardStackTextBox from "../../CardStackTextBox"; +import { useCardAnimation } from "../../hooks/useCardAnimation"; +import type { LucideIcon } from "lucide-react"; +import type { ButtonConfig, CardAnimationType, TitleSegment, ButtonAnimationType } from "../../types"; +import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants"; + +type TimelineVariant = "timeline"; + +interface TimelineBaseProps { + children: React.ReactNode; + variant?: TimelineVariant; + uniformGridCustomHeightClasses?: string; + animationType: CardAnimationType; + title?: string; + titleSegments?: TitleSegment[]; + description?: string; + tag?: string; + tagIcon?: LucideIcon; + tagAnimation?: ButtonAnimationType; + buttons?: ButtonConfig[]; + buttonAnimation?: ButtonAnimationType; + textboxLayout?: TextboxLayout; + useInvertedBackground?: InvertedBackground; + className?: string; + containerClassName?: string; + textBoxClassName?: string; + titleClassName?: string; + titleImageWrapperClassName?: string; + titleImageClassName?: string; + descriptionClassName?: string; + tagClassName?: string; + buttonContainerClassName?: string; + buttonClassName?: string; + buttonTextClassName?: string; + ariaLabel?: string; } -export interface TimelineBaseProps extends Omit { - items: TimelineItem[]; - animationType?: "slide-up" | "none" | "opacity" | "blur-reveal"; -} +const TimelineBase = ({ + children, + variant = "timeline", + uniformGridCustomHeightClasses = "min-h-80 2xl:min-h-90", + animationType, + title, + titleSegments, + description, + tag, + tagIcon, + tagAnimation, + buttons, + buttonAnimation, + textboxLayout = "default", + useInvertedBackground, + className = "", + containerClassName = "", + textBoxClassName = "", + titleClassName = "", + titleImageWrapperClassName = "", + titleImageClassName = "", + descriptionClassName = "", + tagClassName = "", + buttonContainerClassName = "", + buttonClassName = "", + buttonTextClassName = "", + ariaLabel = "Timeline section", +}: TimelineBaseProps) => { + const childrenArray = Children.toArray(children); + const { itemRefs } = useCardAnimation({ + animationType, + itemCount: childrenArray.length, + isGrid: false + }); -export const TimelineBase: React.FC = ({ - items, - animationType = "slide-up", className, - containerClassName, - ...props -}) => { - const timelineItems = useMemo( - () => - items.map((item) => ({ - id: item.id, - title: "", description: "", content: item.content, - media: item.media, - reverse: item.reverse - })), - [items] - ); + const getItemClasses = useCallback((index: number) => { + // Timeline variant - scattered/organic pattern + const alignmentClass = + index % 2 === 0 ? "self-start ml-0" : "self-end mr-0"; + + const marginClasses = cls( + index % 4 === 0 && "md:ml-0", + index % 4 === 1 && "md:mr-20", + index % 4 === 2 && "md:ml-15", + index % 4 === 3 && "md:mr-30" + ); + + return cls(alignmentClass, marginClasses); + }, []); return ( - +
+
+ {(title || titleSegments || description) && ( + + )} +
+ {Children.map(childrenArray, (child, index) => ( +
{ itemRefs.current[index] = el; }} + > + {child} +
+ ))} +
+
+
); }; -export default TimelineBase; +TimelineBase.displayName = "TimelineBase"; + +export default React.memo(TimelineBase);