Components
Loading preview...
Here is Blog Card Component
@prebuiltui
npx shadcn@latest add https://21st.dev/r/prebuiltui/cards"use client";
import React from "react";
type CardT = {
image: string;
name: string;
handle: string;
date?: string;
};
const DEFAULT_DATA: CardT[] = [
{
image:
"https://images.unsplash.com/photo-1633332755192-727a05c4013d?q=80&w=200",
name: "Briar Martin",
handle: "@neilstellar",
},
{
image:
"https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?q=80&w=200",
name: "Avery Johnson",
handle: "@averywrites",
},
{
image:
"https://images.unsplash.com/photo-1527980965255-d3b416303d12?w=200&auto=format&fit=crop&q=60",
name: "Jordan Lee",
handle: "@jordantalks",
},
{
image:
"https://images.unsplash.com/photo-1522075469751-3a6694fb2f61?w=200&auto=format&fit=crop&q=60",
name: "Avery Johnson",
handle: "@averywrites",
},
];
const VerifyIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
viewBox="0 0 48 48"
className="inline-block"
>
<polygon
fill="#42a5f5"
points="29.62,3 33.053,8.308 39.367,8.624 39.686,14.937 44.997,18.367 42.116,23.995 45,29.62 39.692,33.053 39.376,39.367 33.063,39.686 29.633,44.997 24.005,42.116 18.38,45 14.947,39.692 8.633,39.376 8.314,33.063 3.003,29.633 5.884,24.005 3,18.38 8.308,14.947 8.624,8.633 14.937,8.314 18.367,3.003 23.995,5.884"
></polygon>
<polygon
fill="#fff"
points="21.396,31.255 14.899,24.76 17.021,22.639 21.428,27.046 30.996,17.772 33.084,19.926"
></polygon>
</svg>
);
const Card = ({ card }: { card: CardT }) => (
<div className="p-4 rounded-lg mx-4 shadow hover:shadow-lg transition-all duration-200 w-72 shrink-0 bg-white">
<div className="flex gap-2">
<img className="size-11 rounded-full" src={card.image} alt={card.name} />
<div className="flex flex-col">
<div className="flex items-center gap-1">
<p className="font-medium">{card.name}</p>
<VerifyIcon />
</div>
<span className="text-xs text-slate-500">{card.handle}</span>
</div>
</div>
<p className="text-sm pt-4 text-gray-800">
Radiant made undercutting all of our competitors an absolute breeze.
</p>
</div>
);
function MarqueeRow({
data,
reverse = false,
speed = 25,
}: {
data: CardT[];
reverse?: boolean;
speed?: number;
}) {
const doubled = React.useMemo(() => [...data, ...data], [data]);
return (
<div className="relative w-full mx-auto max-w-5xl overflow-hidden isolation-isolate">
<div className="pointer-events-none absolute left-0 top-0 h-full w-24 md:w-32 z-10 bg-gradient-to-r from-white to-transparent blur-md" />
<div
className={`flex transform-gpu min-w-[200%] ${
reverse ? "pt-5 pb-10" : "pt-10 pb-5"
}`}
style={{
animation: `marqueeScroll ${speed}s linear infinite`,
animationDirection: reverse ? "reverse" : "normal",
}}
>
{doubled.map((c, i) => (
<Card key={i} card={c} />
))}
</div>
<div className="pointer-events-none absolute right-0 top-0 h-full w-24 md:w-32 z-10 bg-gradient-to-l from-white to-transparent blur-md" />
</div>
);
}
export default function Marquee({
row1 = DEFAULT_DATA,
row2 = DEFAULT_DATA,
}: {
row1?: CardT[];
row2?: CardT[];
}) {
return (
<>
<style>{`
@keyframes marqueeScroll {
0% { transform: translateX(0%); }
100% { transform: translateX(-50%); }
}
`}</style>
<div className="flex flex-col gap-6">
<MarqueeRow data={row1} reverse={false} speed={25} />
<MarqueeRow data={row2} reverse={true} speed={25} />
</div>
</>
);
}