diff --git a/src/components/sections/metrics/MetricCardEleven.tsx b/src/components/sections/metrics/MetricCardEleven.tsx index 371a979..e2a56f8 100644 --- a/src/components/sections/metrics/MetricCardEleven.tsx +++ b/src/components/sections/metrics/MetricCardEleven.tsx @@ -1,32 +1,274 @@ -import React, { useRef } from 'react'; -import { useCardAnimation, UseCardAnimationOptions } from '@/hooks/useCardAnimation'; +"use client"; -interface MetricCardElevenProps { - metrics: Array<{ id: string; value: string; title: string }>; - containerClassName?: string; -} +import { memo } from "react"; +import CardStackTextBox from "@/components/cardStack/CardStackTextBox"; +import MediaContent from "@/components/shared/MediaContent"; +import { useCardAnimation } from "@/components/cardStack/hooks/useCardAnimation"; +import { cls, shouldUseInvertedText } from "@/lib/utils"; +import { useTheme } from "@/providers/themeProvider/ThemeProvider"; +import type { LucideIcon } from "lucide-react"; +import type { ButtonConfig, CardAnimationType, TitleSegment, ButtonAnimationType } from "@/components/cardStack/types"; +import type { TextboxLayout, InvertedBackground } from "@/providers/themeProvider/config/constants"; -export const MetricCardEleven: React.FC = ({ metrics, containerClassName = '' }) => { - const containerRef = useRef(null); - const itemRefs = useRef<(HTMLDivElement | null)[]>([]); +type MediaProps = + | { + imageSrc: string; + imageAlt?: string; + videoSrc?: never; + videoAriaLabel?: never; + } + | { + videoSrc: string; + videoAriaLabel?: string; + imageSrc?: never; + imageAlt?: never; + }; - const animationOptions: UseCardAnimationOptions = { - containerRef, - itemRefs, - }; - - const { } = useCardAnimation(animationOptions); - - return ( -
- {metrics.map((metric) => ( -
-
{metric.value}
-
{metric.title}
-
- ))} -
- ); +type Metric = MediaProps & { + id: string; + value: string; + title: string; + description: string; }; -export default MetricCardEleven; +interface MetricCardElevenProps { + metrics: Metric[]; + animationType: CardAnimationType; + title: string; + titleSegments?: TitleSegment[]; + description: string; + tag?: string; + tagIcon?: LucideIcon; + tagAnimation?: ButtonAnimationType; + buttons?: ButtonConfig[]; + buttonAnimation?: ButtonAnimationType; + textboxLayout: TextboxLayout; + useInvertedBackground: InvertedBackground; + ariaLabel?: string; + className?: string; + containerClassName?: string; + textBoxClassName?: string; + textBoxTitleClassName?: string; + textBoxTitleImageWrapperClassName?: string; + textBoxTitleImageClassName?: string; + textBoxDescriptionClassName?: string; + textBoxTagClassName?: string; + textBoxButtonContainerClassName?: string; + textBoxButtonClassName?: string; + textBoxButtonTextClassName?: string; + gridClassName?: string; + cardClassName?: string; + valueClassName?: string; + cardTitleClassName?: string; + cardDescriptionClassName?: string; + mediaCardClassName?: string; + mediaClassName?: string; +} + +interface MetricTextCardProps { + metric: Metric; + shouldUseLightText: boolean; + cardClassName?: string; + valueClassName?: string; + cardTitleClassName?: string; + cardDescriptionClassName?: string; +} + +interface MetricMediaCardProps { + metric: Metric; + mediaCardClassName?: string; + mediaClassName?: string; +} + +const MetricTextCard = memo(({ + metric, + shouldUseLightText, + cardClassName = "", + valueClassName = "", + cardTitleClassName = "", + cardDescriptionClassName = "", +}: MetricTextCardProps) => { + return ( +
+

+ {metric.value} +

+ +
+

+ {metric.title} +

+
+

+ {metric.description} +

+
+
+ ); +}); + +MetricTextCard.displayName = "MetricTextCard"; + +const MetricMediaCard = memo(({ + metric, + mediaCardClassName = "", + mediaClassName = "", +}: MetricMediaCardProps) => { + return ( +
+ +
+ ); +}); + +MetricMediaCard.displayName = "MetricMediaCard"; + +const MetricCardEleven = ({ + metrics, + animationType, + title, + titleSegments, + description, + tag, + tagIcon, + tagAnimation, + buttons, + buttonAnimation, + textboxLayout, + useInvertedBackground, + ariaLabel = "Metrics section", + className = "", + containerClassName = "", + textBoxClassName = "", + textBoxTitleClassName = "", + textBoxTitleImageWrapperClassName = "", + textBoxTitleImageClassName = "", + textBoxDescriptionClassName = "", + textBoxTagClassName = "", + textBoxButtonContainerClassName = "", + textBoxButtonClassName = "", + textBoxButtonTextClassName = "", + gridClassName = "", + cardClassName = "", + valueClassName = "", + cardTitleClassName = "", + cardDescriptionClassName = "", + mediaCardClassName = "", + mediaClassName = "", +}: MetricCardElevenProps) => { + const theme = useTheme(); + const shouldUseLightText = shouldUseInvertedText(useInvertedBackground, theme.cardStyle); + + // Inner grid for each metric item (text + media side by side) + const innerGridCols = "grid-cols-2"; + + const { itemRefs } = useCardAnimation({ animationType, itemCount: metrics.length }); + + return ( +
+
+ + +
+ {metrics.map((metric, index) => { + const isLastItem = index === metrics.length - 1; + const isOddTotal = metrics.length % 2 !== 0; + const isSingleItem = metrics.length === 1; + const shouldSpanFull = isSingleItem || (isLastItem && isOddTotal); + // On mobile, even items (2nd, 4th, 6th - index 1, 3, 5) have media first + const isEvenItem = (index + 1) % 2 === 0; + + return ( +
{ itemRefs.current[index] = el; }} + className={cls( + "grid gap-4", + innerGridCols, + shouldSpanFull && "md:col-span-2" + )} + > + + +
+ ); + })} +
+
+
+ ); +}; + +MetricCardEleven.displayName = "MetricCardEleven"; + +export default MetricCardEleven; \ No newline at end of file