heroes /
Dating Cards Hero (Member-Card Sticker Wall)
Marketplace/community hero with full nav, eyebrow + headline-with-highlights + body + email-signup pill, 3-stat row, and a couple photo on the right surrounded by floating member cards, payment card, decorative star + moon, pill badges. Built from a
Preview
Source
tsx
import { Heart, Mail, Star } from "lucide-react";
interface MemberCard {
avatarSrc?: string;
avatarFallback?: string;
name: string;
location: string;
}
export interface DatingCardsHeroProps {
brand?: string;
navItems?: { label: string; href: string }[];
loginCta?: { label: string; href: string };
registerCta?: { label: string; href: string };
eyebrow?: string;
headline?: string;
/** Words inside the headline to wrap in the orange highlight (case-insensitive). */
highlightedWords?: string[];
body?: string;
emailPlaceholder?: string;
emailCta?: { label: string; href: string };
stats?: { value: string; label: string }[];
imageSrc?: string;
imageAlt?: string;
pillBadges?: string[];
memberCards?: MemberCard[];
paymentCard?: {
number: string;
holder: string;
expiry: string;
};
/** Default = Datify cream bg #fdf6ee */
bgColor?: string;
/** Default = Datify warm orange #f5762a */
accentColor?: string;
}
function highlightWords(text: string, words: string[], color: string) {
if (!words || words.length === 0) return text;
const escaped = words.map((w) => w.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
const re = new RegExp(`\\b(${escaped.join("|")})\\b`, "gi");
const parts: (string | { match: string })[] = [];
let lastIndex = 0;
let m: RegExpExecArray | null;
while ((m = re.exec(text)) !== null) {
if (m.index > lastIndex) parts.push(text.slice(lastIndex, m.index));
parts.push({ match: m[0] });
lastIndex = re.lastIndex;
}
if (lastIndex < text.length) parts.push(text.slice(lastIndex));
return parts.map((part, i) =>
typeof part === "string" ? (
<span key={i}>{part}</span>
) : (
<span key={i} style={{ color }}>
{part.match}
</span>
)
);
}
export default function DatingCardsHero({
brand = "Datify",
navItems = [
{ label: "Home", href: "#" },
{ label: "Members", href: "#" },
{ label: "Blog", href: "#" },
{ label: "Privacy", href: "#" },
{ label: "Contact", href: "#" },
],
loginCta = { label: "Log in", href: "#" },
registerCta = { label: "Register", href: "#" },
eyebrow = "Because you deserve better!",
headline = "Get noticed for who you are, not what you look like.",
highlightedWords = ["who", "not what"],
body = "You're more than just a photo. You have stories to tell, and passions to share, and things to talk about that are more interesting than the weather. Because you deserve what dating deserves: better.",
emailPlaceholder = "Enter your email",
emailCta = { label: "Get Started", href: "#start" },
stats = [
{ value: "15k+", label: "Dates and matches made everyday" },
{ value: "1,456", label: "New members signup every day" },
{ value: "1M+", label: "Members from around the world" },
],
imageSrc = "/heroes/dating-cards/couple.webp",
imageAlt = "Happy couple",
pillBadges = ["Male", "30-35 Years", "New York"],
memberCards = [
{ avatarSrc: "https://images.unsplash.com/photo-1517841905240-472988babdf9?w=80&h=80&fit=crop&crop=face", name: "Angela Taylor", location: "Cincinnati, OH" },
{ avatarSrc: "https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=80&h=80&fit=crop&crop=face", name: "Mike Johnson", location: "NY City, NY" },
],
paymentCard = { number: "3829 4820 4629 5025", holder: "Anita Rose", expiry: "09/17" },
bgColor = "#fdf6ee",
accentColor = "#f5762a",
}: DatingCardsHeroProps) {
return (
<section
className="relative min-h-[760px] overflow-hidden font-sans"
style={{ background: bgColor, color: "#1a1a1a" }}
>
{/* Subtle background swoop */}
<div
aria-hidden
className="absolute -right-32 -top-32 h-[640px] w-[640px] rounded-full"
style={{ background: "rgba(255,255,255,0.6)" }}
/>
<div className="relative mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
{/* NAV */}
<nav className="flex items-center justify-between py-6">
<a href="/" className="flex items-center gap-2">
<Heart className="h-5 w-5 fill-current" style={{ color: accentColor }} />
<span className="text-xl font-bold text-slate-900">{brand}</span>
</a>
<div className="hidden items-center gap-7 md:flex">
{navItems.map((item, i) => (
<a
key={item.label}
href={item.href}
className={`text-sm font-medium transition-colors ${
i === 0 ? "" : "text-slate-700 hover:text-slate-900"
}`}
style={i === 0 ? { color: accentColor } : undefined}
>
{item.label}
</a>
))}
</div>
<div className="flex items-center gap-4">
<a
href={loginCta.href}
className="text-sm font-medium text-slate-700 transition-colors hover:text-slate-900"
>
{loginCta.label}
</a>
<a
href={registerCta.href}
className="rounded-full px-5 py-2 text-sm font-semibold text-white transition-all hover:-translate-y-0.5"
style={{ background: accentColor, boxShadow: `0 4px 14px ${accentColor}40` }}
>
{registerCta.label}
</a>
</div>
</nav>
{/* Hero grid */}
<div className="grid gap-10 pt-6 pb-16 lg:grid-cols-[1fr_1.1fr] lg:gap-8 lg:pt-10 lg:pb-20">
{/* LEFT */}
<div className="relative z-10 max-w-lg">
<p className="mb-3 text-xs font-medium uppercase tracking-wider" style={{ color: accentColor }}>
{eyebrow}
</p>
<h1 className="text-4xl font-bold leading-[1.15] tracking-tight text-slate-900 sm:text-5xl">
{highlightWords(headline, highlightedWords, accentColor)}
</h1>
<p className="mt-5 max-w-md text-sm leading-relaxed text-slate-600">
{body}
</p>
{/* Email signup pill */}
<div className="mt-7 flex max-w-md items-center gap-1 rounded-full bg-white p-1.5 shadow-md">
<div className="flex flex-1 items-center gap-2 px-3">
<Mail className="h-4 w-4 text-slate-400" />
<input
type="email"
placeholder={emailPlaceholder}
className="flex-1 bg-transparent text-sm outline-none placeholder:text-slate-400"
/>
</div>
<a
href={emailCta.href}
className="rounded-full px-5 py-2.5 text-sm font-semibold text-white transition-all hover:-translate-y-0.5"
style={{ background: accentColor }}
>
{emailCta.label}
</a>
</div>
{/* Stats row */}
<div className="mt-12 grid grid-cols-3 gap-6">
{stats.map((s, i) => (
<div key={s.label}>
<div
className="text-3xl font-bold leading-none"
style={{ color: i === 1 ? accentColor : "#1a1a1a" }}
>
{s.value}
</div>
<p className="mt-2 text-xs leading-snug text-slate-500">
{s.label}
</p>
</div>
))}
</div>
</div>
{/* RIGHT — couple photo + floating cards + decorations */}
<div className="relative min-h-[520px]">
{/* Decorative star */}
<Star
className="absolute right-2 top-[42%] h-6 w-6 fill-current"
style={{ color: "#e84a4a" }}
/>
{/* Decorative moon */}
<div
aria-hidden
className="absolute right-12 bottom-32 h-8 w-8 rounded-full"
style={{ background: "#fbc24d", boxShadow: "inset 6px -3px 0 #f5762a" }}
/>
{/* Couple photo */}
<div className="relative mx-auto h-full w-full max-w-[480px]">
<img
src={imageSrc}
alt={imageAlt}
width={900}
height={1100}
loading="eager"
fetchPriority="high"
decoding="async"
className="block w-full h-auto rounded-3xl object-cover shadow-2xl"
/>
{/* Floating heart icon top-left */}
<div className="absolute -left-2 top-12 flex h-10 w-10 items-center justify-center rounded-full bg-white shadow-md">
<Heart className="h-5 w-5 fill-current" style={{ color: accentColor }} />
</div>
{/* "M" badge */}
<div className="absolute -left-4 top-44 flex h-9 w-9 items-center justify-center rounded-full bg-white text-sm font-bold shadow-md" style={{ color: "#e84a4a" }}>
M
</div>
{/* Heart on right side */}
<div className="absolute -right-3 top-36 flex h-9 w-9 items-center justify-center rounded-full bg-white shadow-md">
<Heart className="h-4 w-4" style={{ color: accentColor }} />
</div>
{/* Pill badges below couple */}
<div className="absolute -bottom-4 left-1/2 flex -translate-x-1/2 items-center gap-2 z-10">
<span className="rounded-full bg-white px-3 py-1.5 text-[10px] font-semibold shadow-md text-slate-700">
♂ {pillBadges[0]}
</span>
<span
className="rounded-full px-3 py-1.5 text-[10px] font-semibold text-white shadow-md"
style={{ background: accentColor }}
>
✦ {pillBadges[1]}
</span>
<span className="rounded-full bg-white px-3 py-1.5 text-[10px] font-semibold shadow-md text-slate-700">
⌖ {pillBadges[2]}
</span>
</div>
</div>
{/* Member cards floating bottom-left */}
<div className="absolute bottom-0 left-0 z-20 flex flex-col gap-3">
{memberCards.map((m) => (
<div
key={m.name}
className="flex items-center gap-3 rounded-xl bg-white p-2 shadow-lg"
>
{m.avatarSrc ? (
<img
src={m.avatarSrc}
alt={m.name}
width={36}
height={36}
className="h-9 w-9 rounded-lg object-cover"
/>
) : (
<div
className="flex h-9 w-9 items-center justify-center rounded-lg text-xs font-bold text-white"
style={{ background: accentColor }}
>
{m.avatarFallback}
</div>
)}
<div className="leading-tight">
<div className="text-xs font-bold text-slate-900">{m.name}</div>
<div className="text-[10px] text-slate-500">{m.location}</div>
</div>
<a
href="#"
className="ml-3 rounded-lg px-3 py-1.5 text-[10px] font-semibold text-white"
style={{ background: accentColor }}
>
Select
</a>
</div>
))}
</div>
{/* Payment card bottom-right */}
<div
className="absolute bottom-2 right-0 z-20 w-[200px] rounded-2xl bg-white p-4 shadow-lg"
>
<div className="mb-3 flex items-center justify-between">
<div className="h-5 w-8 rounded bg-slate-200" />
<div className="h-5 w-5 rounded-full bg-slate-300" />
</div>
<div className="text-[10px] font-semibold uppercase tracking-wider text-slate-400">
Card Number
</div>
<div className="mt-1 font-mono text-[13px] font-bold text-slate-900">
{paymentCard.number}
</div>
<div className="mt-3 flex justify-between">
<div>
<div className="text-[8px] font-semibold uppercase tracking-wider text-slate-400">
Card Holder
</div>
<div className="text-[11px] font-bold text-slate-900">
{paymentCard.holder}
</div>
</div>
<div>
<div className="text-[8px] font-semibold uppercase tracking-wider text-slate-400">
Valid Thru
</div>
<div className="text-[11px] font-bold text-slate-900">
{paymentCard.expiry}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
);
} Claude Code Instructions
CLI Install
npx innovations add dating-cardsWhere to use it
Use this for marketplaces, communities, dating apps, social platforms, member sites — anywhere member previews + signup capture + social proof matter.
In Astro:
---
import DatingCardsHero from '../components/innovations/heroes/dating-cards';
---
<DatingCardsHero />
In Next.js:
import DatingCardsHero from '@/components/innovations/heroes/dating-cards';
No client:* needed — server-renderable. Email input is presentational; wire it up in your project's signup flow.
CUSTOMIZATION:
<DatingCardsHero
brand="YourBrand"
headline="Your headline with words to highlight."
highlightedWords={["highlight"]} /* gets accent color, case-insensitive */
body="Body copy..."
emailCta={{ label: "Sign Up", href: "/signup" }}
stats={[
{ value: "10k+", label: "Active members" },
...
]}
imageSrc="/your-couple.webp"
pillBadges={["Female", "25-30", "Boston"]}
memberCards={[
{ avatarSrc: "/m1.jpg", name: "Name", location: "City, State" },
...
]}
paymentCard={{ number: "1234 ...", holder: "Name", expiry: "12/28" }}
accentColor="#f5762a"
/>
PALETTE: cream + warm orange. Single accentColor prop drives the orange across CTAs, eyebrow, payment-card detail, decorative star.
FLOATING ELEMENTS: each floating card (member, payment, badge, heart, star, moon) is a separate JSX block in the right column. Drop or reposition by editing the className positions (top-X, left-X, etc.). Best to keep the visual rhythm — too many elements gets noisy.
EMAIL INPUT: presentational only. Hook up to your signup endpoint by wrapping the input + button in a <form> in your project.