nnuer
강희태@gmlxo9917

체크가 튀어나오며 그려지는 결제 완료 화면

기타 블록

파란 원이 통통 튀며 나타나고 흰 체크가 그려진 뒤, 결제 정보와 두 버튼이 차례로 올라오는 토스 느낌의 완료 화면입니다.

블록 신고

운영자가 확인한 뒤 필요하면 블록을 숨깁니다.

사유
Claude Code · claude-opus-5-5 · React (TSX)
결과 코드펼치기
import { useEffect, useRef, useState } from "react";

const EASE_POP = "cubic-bezier(0.2, 0.9, 0.3, 1.3)";

export default function PaymentComplete() {
  const circle = useRef<SVGSVGElement>(null);
  const ring = useRef<HTMLSpanElement>(null);
  const check = useRef<SVGPathElement>(null);
  const texts = useRef<HTMLDivElement>(null);
  const [round, setRound] = useState(0);

  useEffect(() => {
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
    const anims = [
      circle.current?.animate(
        [
          { opacity: 0, transform: "scale(0.4)" },
          { opacity: 1, transform: "scale(1.1)", offset: 0.55 },
          { transform: "scale(0.96)", offset: 0.75 },
          { transform: "scale(1)" },
        ],
        { duration: 560, easing: EASE_POP, fill: "both" },
      ),
      ring.current?.animate(
        [
          { opacity: 0.6, transform: "scale(1)" },
          { opacity: 0, transform: "scale(1.9)" },
        ],
        { duration: 900, delay: 450, easing: "ease-out", fill: "both" },
      ),
      check.current?.animate([{ strokeDashoffset: 60 }, { strokeDashoffset: 0 }], {
        duration: 380,
        delay: 420,
        easing: "ease-out",
        fill: "both",
      }),
      ...Array.from(texts.current?.children ?? []).map((el, i) =>
        el.animate(
          [
            { opacity: 0, transform: "translateY(10px)" },
            { opacity: 1, transform: "none" },
          ],
          { duration: 420, delay: 520 + i * 90, easing: "ease-out", fill: "both" },
        ),
      ),
    ];
    return () => anims.forEach((a) => a?.cancel());
  }, [round]);

  return (
    <section className="w-full bg-white px-5 py-20 text-zinc-900 sm:px-8">
      <div role="status" className="mx-auto flex max-w-md flex-col items-center text-center">
        <div className="relative h-24 w-24">
          <span ref={ring} aria-hidden className="absolute inset-0 rounded-full bg-[#3182f6]/40 opacity-0" />
          <svg ref={circle} aria-hidden viewBox="0 0 96 96" className="relative h-24 w-24">
            <circle cx="48" cy="48" r="44" fill="#3182f6" />
            <path
              ref={check}
              d="M30 49.5 42 61.5 66 35"
              fill="none"
              stroke="white"
              strokeWidth="7"
              strokeLinecap="round"
              strokeLinejoin="round"
              strokeDasharray="60"
            />
          </svg>
        </div>
        <div ref={texts} className="w-full">
          <h2 className="mt-7 text-2xl font-bold tracking-tight">결제를 마쳤어요</h2>
          <p className="mt-2 text-[15px] text-zinc-500">주문하신 상품은 내일 도착 예정이에요.</p>
          <dl className="mt-6 divide-y divide-zinc-100 rounded-2xl bg-zinc-50 px-5 text-left text-sm">
            <div className="flex justify-between py-3">
              <dt className="text-zinc-500">결제 금액</dt>
              <dd className="font-semibold">38,900원</dd>
            </div>
            <div className="flex justify-between py-3">
              <dt className="text-zinc-500">결제 수단</dt>
              <dd>체크카드 (1234)</dd>
            </div>
          </dl>
          <div className="mt-8 flex flex-col gap-2 sm:flex-row">
            <a
              href="#"
              className="flex h-12 flex-1 items-center justify-center rounded-xl bg-[#3182f6] text-[15px] font-semibold text-white transition hover:bg-[#1b64da] active:scale-[0.98]"
            >
              주문 내역 보기
            </a>
            <a
              href="#"
              className="flex h-12 flex-1 items-center justify-center rounded-xl bg-zinc-100 text-[15px] font-semibold text-zinc-700 transition hover:bg-zinc-200 active:scale-[0.98]"
            >
              쇼핑 계속하기
            </a>
          </div>
          <button
            type="button"
            onClick={() => setRound((r) => r + 1)}
            className="mt-5 text-xs text-zinc-400 underline-offset-4 hover:text-zinc-600 hover:underline"
          >
            애니메이션 다시 보기
          </button>
        </div>
      </div>
    </section>
  );
}

적용 사이트 0

이 블록이 실제로 쓰인 사이트입니다.

로그인하고 내 사이트 추가

아직 등록된 사이트가 없습니다. 이 블록을 쓴 사이트가 있다면 알려 주세요.

로그인하고 재현 결과 올리기

재현 후기

v1 · 0개

아직 이 버전의 프롬프트로 직접 만들어 본 사람이 없습니다. 첫 번째로 재현해 보세요.