Add InfoCard component to display customizable card layouts
Introduced a reusable InfoCard component with support for a variety of props including images, colors, text, and buttons. This component enhances flexibility and consistency in displaying card-based UI elements across the application.
This commit is contained in:
142
frontend/src/components/info-card.tsx
Normal file
142
frontend/src/components/info-card.tsx
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
import React from "react";
|
||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { Card } from "@/components/ui/card";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
interface CardButton {
|
||||||
|
text: string;
|
||||||
|
href: string;
|
||||||
|
backgroundColor?: string;
|
||||||
|
textColor?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface InfoCardProps {
|
||||||
|
imageSrc?: string | null;
|
||||||
|
imageAlt?: string;
|
||||||
|
imagePosition?: "left" | "right";
|
||||||
|
borderColor?: string;
|
||||||
|
backgroundColor?: string;
|
||||||
|
boxShadow?: string;
|
||||||
|
headingText: string;
|
||||||
|
headingStyle?: React.CSSProperties;
|
||||||
|
bodyText?: string;
|
||||||
|
bodyTextColor?: string;
|
||||||
|
buttonProps?: CardButtonProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CardButtonProps {
|
||||||
|
text: string;
|
||||||
|
href: string;
|
||||||
|
backgroundColor?: string;
|
||||||
|
textColor?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const InfoCard: React.FC<InfoCardProps> = ({
|
||||||
|
imageSrc,
|
||||||
|
imageAlt = "Image",
|
||||||
|
imagePosition = "left",
|
||||||
|
borderColor = "#ccc",
|
||||||
|
backgroundColor = "rgba(240,233,214,0.7)",
|
||||||
|
boxShadow = "0 2px 4px rgba(0, 0, 0, 0.05)",
|
||||||
|
headingText,
|
||||||
|
headingStyle = {},
|
||||||
|
bodyText,
|
||||||
|
bodyTextColor = "#555",
|
||||||
|
buttonProps,
|
||||||
|
}) => {
|
||||||
|
const imageElement = (
|
||||||
|
<div className="mb-4 hidden md:mb-0 md:block">
|
||||||
|
<div
|
||||||
|
className="flex h-28 w-28 items-center justify-center rounded-full border-2 md:h-32 md:w-32"
|
||||||
|
style={{ borderColor }}
|
||||||
|
>
|
||||||
|
{imageSrc ? (
|
||||||
|
<div className="relative h-24 w-24 md:h-28 md:w-28">
|
||||||
|
<Image
|
||||||
|
src={imageSrc}
|
||||||
|
alt={imageAlt ?? "Image"}
|
||||||
|
fill
|
||||||
|
className="object-contain"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<p className="text-center text-sm">{imageAlt ?? "Image"}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"mb-10 flex flex-col items-center md:items-start md:space-x-6",
|
||||||
|
imagePosition === "right"
|
||||||
|
? "md:flex-row-reverse md:space-x-reverse"
|
||||||
|
: "md:flex-row",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{imageElement}
|
||||||
|
|
||||||
|
<Card
|
||||||
|
className="flex-1 relative overflow-hidden p-6"
|
||||||
|
style={{ backgroundColor, borderColor, boxShadow }}
|
||||||
|
>
|
||||||
|
{imageSrc && (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"absolute bottom-0 h-32 w-32 opacity-20 md:hidden",
|
||||||
|
imagePosition === "right" ? "left-0" : "right-0",
|
||||||
|
)}
|
||||||
|
style={{
|
||||||
|
backgroundImage: `url(${imageSrc})`,
|
||||||
|
backgroundSize: "contain",
|
||||||
|
backgroundRepeat: "no-repeat",
|
||||||
|
backgroundPosition:
|
||||||
|
imagePosition === "right" ? "bottom left" : "bottom right",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<h3
|
||||||
|
className="mb-2 text-center text-2xl font-bold md:text-left"
|
||||||
|
style={headingStyle}
|
||||||
|
>
|
||||||
|
{headingText}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
{bodyText && (
|
||||||
|
<p
|
||||||
|
className="text-center md:text-left"
|
||||||
|
style={{ color: bodyTextColor }}
|
||||||
|
>
|
||||||
|
{bodyText}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{buttonProps && (
|
||||||
|
<div className="mt-4 text-center md:text-left">
|
||||||
|
<Link
|
||||||
|
href={buttonProps.href}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
className="rounded-full"
|
||||||
|
style={{
|
||||||
|
backgroundColor: buttonProps.backgroundColor,
|
||||||
|
color: buttonProps.textColor ?? "white",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{buttonProps.text}
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default InfoCard;
|
||||||
Reference in New Issue
Block a user