Files
3120e965-0121-4bc5-9d0e-1c0…/src/components/CardStackTextBox.tsx

163 lines
4.2 KiB
TypeScript

"use client";
import React from "react";
interface TitleSegment {
text: string;
highlight?: boolean;
}
interface Button {
label: string;
href?: string;
onClick?: () => void;
variant?: "primary" | "secondary";
}
interface CardStackTextBoxProps {
title: string;
titleSegments?: TitleSegment[];
description: string;
tag?: string;
tagIcon?: React.ReactNode;
tagAnimation?: string;
buttons?: Button[];
buttonAnimation?: string;
textboxLayout?: "default" | "centered" | "compact";
useInvertedBackground?: boolean;
className?: string;
titleClassName?: string;
titleImageWrapperClassName?: string;
titleImageClassName?: string;
descriptionClassName?: string;
tagClassName?: string;
buttonContainerClassName?: string;
buttonClassName?: string;
buttonTextClassName?: string;
}
export function CardStackTextBox({
title,
titleSegments,
description,
tag,
tagIcon,
tagAnimation,
buttons,
buttonAnimation,
textboxLayout = "default",
useInvertedBackground = false,
className = "",
titleClassName = "",
titleImageWrapperClassName = "",
titleImageClassName = "",
descriptionClassName = "",
tagClassName = "",
buttonContainerClassName = "",
buttonClassName = "",
buttonTextClassName = "",
}: CardStackTextBoxProps) {
const baseClasses = `
w-full h-full p-6 flex flex-col justify-between
${useInvertedBackground ? "bg-slate-900 text-white" : "bg-white text-slate-900"}
rounded-lg transition-all duration-300
`;
const layoutClasses = {
default: "items-start",
centered: "items-center text-center",
compact: "items-start gap-2",
};
const titleDefaultClasses = `
text-2xl font-bold mb-4 leading-tight
${titleClassName}
`;
const descriptionDefaultClasses = `
text-base leading-relaxed mb-4 flex-grow
${useInvertedBackground ? "text-slate-300" : "text-slate-600"}
${descriptionClassName}
`;
const tagDefaultClasses = `
inline-flex items-center gap-2 px-3 py-1 rounded-full text-sm font-medium mb-4
${useInvertedBackground ? "bg-slate-800 text-slate-200" : "bg-slate-100 text-slate-700"}
${tagClassName}
`;
const buttonContainerDefaultClasses = `
flex gap-3 w-full
${textboxLayout === "centered" ? "justify-center" : "justify-start"}
${buttonContainerClassName}
`;
const buttonDefaultClasses = `
px-4 py-2 rounded-lg font-medium transition-all duration-200
${buttonClassName}
`;
const buttonTextDefaultClasses = `
${buttonTextClassName}
`;
const renderTitle = () => {
if (titleSegments && titleSegments.length > 0) {
return (
<h3 className={titleDefaultClasses}>
{titleSegments.map((segment, index) => (
<span
key={index}
className={segment.highlight ? "text-blue-500" : ""}
>
{segment.text}
</span>
))}
</h3>
);
}
return <h3 className={titleDefaultClasses}>{title}</h3>;
};
return (
<div className={`${baseClasses} ${layoutClasses[textboxLayout]} ${className}`}>
<div className="w-full">
{tag && (
<div className={tagDefaultClasses}>
{tagIcon && <span>{tagIcon}</span>}
<span>{tag}</span>
</div>
)}
{renderTitle()}
<p className={descriptionDefaultClasses}>{description}</p>
</div>
{buttons && buttons.length > 0 && (
<div className={buttonContainerDefaultClasses}>
{buttons.map((button, index) => (
<button
key={index}
onClick={button.onClick}
className={`
${buttonDefaultClasses}
${
button.variant === "secondary"
? useInvertedBackground
? "bg-slate-700 hover:bg-slate-600 text-white"
: "bg-slate-200 hover:bg-slate-300 text-slate-900"
: useInvertedBackground
? "bg-blue-600 hover:bg-blue-700 text-white"
: "bg-blue-500 hover:bg-blue-600 text-white"
}
`}
>
<span className={buttonTextDefaultClasses}>{button.label}</span>
</button>
))}
</div>
)}
</div>
);
}