diff --git a/src/components/CardStackTextBox.tsx b/src/components/CardStackTextBox.tsx new file mode 100644 index 0000000..200e9ba --- /dev/null +++ b/src/components/CardStackTextBox.tsx @@ -0,0 +1,163 @@ +"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 ( +

+ {titleSegments.map((segment, index) => ( + + {segment.text} + + ))} +

+ ); + } + return

{title}

; + }; + + return ( +
+
+ {tag && ( +
+ {tagIcon && {tagIcon}} + {tag} +
+ )} + + {renderTitle()} + +

{description}

+
+ + {buttons && buttons.length > 0 && ( +
+ {buttons.map((button, index) => ( + + ))} +
+ )} +
+ ); +} \ No newline at end of file