Innovations
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-cards

Where 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.