Workspace / block / social-proof

Split Testimonial

One substantial customer story given a full editorial treatment: oversized quote marks, a two-column pull quote, and a named, pictured author.

Workspaceblocksocial-proof

paxfx add blocks/block-social-proof-split-12local only

Tier: low. Reduced motion: Fully static layout.

"use client";

import { cn, useInView, useReducedMotion, type BlockCopy } from "@pax-sh/blocks";

export interface SocialProofSplitProps {
  copy?: BlockCopy;
  className?: string;
}

const DEFAULT_COPY: BlockCopy = {
  eyebrow: "Customer story",
  title:
    "We migrated eleven services in a quarter without a single missed page. The tool disappeared into the workflow, which is the highest compliment infrastructure can earn. Six months later the on-call rotation is quieter and nobody can name the last false alarm.",
  description: "Maya Okonkwo",
};

/**
 * One substantial customer story with the full editorial treatment:
 * oversized hanging quote marks, a pull quote that flows into two columns
 * at md and up, and a named author with an initials avatar. Fully static
 * under reduced motion.
 */
export function SocialProofSplit({ copy = DEFAULT_COPY, className }: SocialProofSplitProps) {
  const reduced = useReducedMotion();
  const [ref, inView] = useInView<HTMLDivElement>({ threshold: 0.2 });
  const settled = reduced || inView;
  const author = copy.description ?? "Maya Okonkwo";
  const initials = author
    .split(/\s+/)
    .slice(0, 2)
    .map((part) => part.charAt(0).toUpperCase())
    .join("");

  const enter = (step: number) =>
    reduced
      ? undefined
      : ({
          opacity: settled ? 1 : 0,
          transform: settled ? "translateY(0)" : "translateY(14px)",
          transition: `opacity 0.55s ease ${step * 0.1}s, transform 0.6s cubic-bezier(0.22, 1, 0.36, 1) ${step * 0.1}s`,
        } as const);

  return (
    <section
      className={cn(
        "bg-[var(--pax-paper,#f6f2ea)] px-6 py-20 text-[var(--pax-ink,#12110f)] md:px-10 md:py-28",
        className,
      )}
      data-pax-asset="block-social-proof-split-12"
    >
      <div ref={ref} className="mx-auto max-w-6xl">
        {copy.eyebrow ? (
          <div className="flex items-center gap-4" style={enter(0)}>
            <span className="h-px w-10 bg-current opacity-40" aria-hidden="true" />
            <p className="m-0 text-xs font-medium uppercase tracking-[0.22em] text-[var(--pax-mute,#6b645c)]">
              {copy.eyebrow}
            </p>
          </div>
        ) : null}

        <figure className="m-0 mt-10">
          <div className="relative">
            <span
              className="pointer-events-none absolute -left-2 -top-10 select-none font-serif text-[7rem] leading-none text-[var(--pax-acid,#c8ff00)] md:-left-6 md:text-[9rem]"
              aria-hidden="true"
            >
              &ldquo;
            </span>
            <blockquote
              className="relative m-0 text-xl font-medium leading-snug tracking-tight [text-wrap:pretty] md:columns-2 md:gap-12 md:text-2xl"
              style={enter(1)}
            >
              {copy.title}
            </blockquote>
          </div>

          <figcaption className="mt-10 flex items-center gap-4" style={enter(2)}>
            <span
              className="flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-[var(--pax-ink,#12110f)] text-sm font-bold text-[var(--pax-acid,#c8ff00)]"
              aria-hidden="true"
            >
              {initials}
            </span>
            <div>
              <p className="m-0 text-sm font-semibold">{author}</p>
              <p className="m-0 mt-0.5 text-xs text-[var(--pax-mute,#6b645c)]">
                VP Engineering, Ferrostack
              </p>
            </div>
          </figcaption>
        </figure>
      </div>
    </section>
  );
}