142 lines
5.6 KiB
TypeScript
142 lines
5.6 KiB
TypeScript
"use client";
|
|
|
|
import React, { useMemo } from "react";
|
|
import CardStack from "@/components/card/CardStack";
|
|
import TextBox from "@/components/Textbox";
|
|
import type { CardAnimationTypeWith3D } from "@/types/animations";
|
|
import type { GridVariant } from "@/types/grid";
|
|
|
|
export interface FeatureCardOneProps {
|
|
features?: Array<{
|
|
id: string;
|
|
title: string;
|
|
description: string;
|
|
icon?: React.ReactNode;
|
|
mediaItems?: Array<{ type: string; src: string; alt?: string }>;
|
|
}>;
|
|
gridVariant?: GridVariant;
|
|
uniformGridCustomHeightClasses?: string;
|
|
animationType?: CardAnimationTypeWith3D;
|
|
title?: string;
|
|
titleSegments?: Array<{ type: "text"; content: string } | { type: "image"; src: string; alt?: string }>;
|
|
description?: string;
|
|
tag?: string;
|
|
tagAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal";
|
|
buttons?: Array<{ text: string; onClick?: () => void; href?: string }>;
|
|
buttonAnimation?: "none" | "opacity" | "slide-up" | "blur-reveal";
|
|
textboxLayout?: "default" | "split" | "split-actions" | "split-description" | "inline-image";
|
|
useInvertedBackground?: boolean;
|
|
ariaLabel?: string;
|
|
className?: string;
|
|
containerClassName?: string;
|
|
cardClassName?: string;
|
|
mediaClassName?: string;
|
|
textBoxTitleClassName?: string;
|
|
textBoxTitleImageWrapperClassName?: string;
|
|
textBoxTitleImageClassName?: string;
|
|
textBoxDescriptionClassName?: string;
|
|
cardTitleClassName?: string;
|
|
cardDescriptionClassName?: string;
|
|
cardIconClassName?: string;
|
|
cardIconWrapperClassName?: string;
|
|
gridClassName?: string;
|
|
carouselClassName?: string;
|
|
controlsClassName?: string;
|
|
textBoxClassName?: string;
|
|
textBoxTagClassName?: string;
|
|
textBoxButtonContainerClassName?: string;
|
|
textBoxButtonClassName?: string;
|
|
textBoxButtonTextClassName?: string;
|
|
}
|
|
|
|
const FeatureCardOne: React.FC<FeatureCardOneProps> = ({
|
|
features = [],
|
|
gridVariant = "uniform-all-items-equal", uniformGridCustomHeightClasses = "min-h-95 2xl:min-h-105", animationType = "slide-up", title,
|
|
titleSegments,
|
|
description = "", tag,
|
|
tagAnimation,
|
|
buttons,
|
|
buttonAnimation,
|
|
textboxLayout = "default", useInvertedBackground = false,
|
|
ariaLabel = "Feature section", className = "", containerClassName = "", cardClassName = "", mediaClassName = "", textBoxTitleClassName = "", textBoxTitleImageWrapperClassName = "", textBoxTitleImageClassName = "", textBoxDescriptionClassName = "", cardTitleClassName = "", cardDescriptionClassName = "", cardIconClassName = "", cardIconWrapperClassName = "", gridClassName = "", carouselClassName = "", controlsClassName = "", textBoxClassName = "", textBoxTagClassName = "", textBoxButtonContainerClassName = "", textBoxButtonClassName = "", textBoxButtonTextClassName = ""}) => {
|
|
const cardItems = useMemo(
|
|
() =>
|
|
features.map((feature) => (
|
|
<div
|
|
key={feature.id}
|
|
className={`h-full flex flex-col gap-4 p-6 rounded-lg bg-card ${cardClassName}`}
|
|
>
|
|
{feature.icon && (
|
|
<div className={`flex items-center justify-center w-12 h-12 rounded-lg bg-primary-cta/10 ${cardIconWrapperClassName}`}>
|
|
<span className={`text-2xl ${cardIconClassName}`}>{feature.icon}</span>
|
|
</div>
|
|
)}
|
|
<h3 className={`text-xl font-semibold text-foreground ${cardTitleClassName}`}>
|
|
{feature.title}
|
|
</h3>
|
|
<p className={`text-sm text-foreground/70 flex-1 ${cardDescriptionClassName}`}>
|
|
{feature.description}
|
|
</p>
|
|
{feature.mediaItems && (
|
|
<div className={`flex gap-2 mt-auto ${mediaClassName}`}>
|
|
{feature.mediaItems.map((media, idx) => (
|
|
<img
|
|
key={idx}
|
|
src={media.src}
|
|
alt={media.alt || "Feature media"}
|
|
className="w-full h-20 object-cover rounded-lg"
|
|
/>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)),
|
|
[features, cardClassName, cardIconWrapperClassName, cardIconClassName, cardTitleClassName, cardDescriptionClassName, mediaClassName]
|
|
);
|
|
|
|
return (
|
|
<div
|
|
className={`w-full py-20 ${useInvertedBackground ? "bg-background/50" : ""} ${containerClassName}`}
|
|
aria-label={ariaLabel}
|
|
>
|
|
{title && (
|
|
<div className={`max-w-content-width mx-auto px-4 mb-12 ${textBoxClassName}`}>
|
|
<TextBox
|
|
title={title}
|
|
titleSegments={titleSegments}
|
|
description={description}
|
|
tag={tag}
|
|
tagAnimation={tagAnimation}
|
|
buttons={buttons}
|
|
buttonAnimation={buttonAnimation}
|
|
textboxLayout={textboxLayout}
|
|
titleClassName={textBoxTitleClassName}
|
|
descriptionClassName={textBoxDescriptionClassName}
|
|
tagClassName={textBoxTagClassName}
|
|
buttonContainerClassName={textBoxButtonContainerClassName}
|
|
buttonClassName={textBoxButtonClassName}
|
|
buttonTextClassName={textBoxButtonTextClassName}
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
<div className="max-w-content-width mx-auto px-4">
|
|
<CardStack
|
|
gridVariant={gridVariant}
|
|
uniformGridCustomHeightClasses={uniformGridCustomHeightClasses}
|
|
animationType={animationType}
|
|
carouselMode="buttons"
|
|
ariaLabel={ariaLabel}
|
|
className={className}
|
|
gridClassName={gridClassName}
|
|
carouselClassName={carouselClassName}
|
|
controlsClassName={controlsClassName}
|
|
>
|
|
{cardItems.map((item) => item)}
|
|
</CardStack>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default FeatureCardOne; |