Skip to content
Cards

Cards

ProjectCard

Portfolio grid card with a rounded image that zooms slowly on hover.

npx bezel-add add project-card

packages/ui/src/cards/ProjectCard.tsx · 53 lines

"use client";

type Props = {
  title: string;
  subtitle?: string;
  imageSrc: string;
  imageAlt?: string;
  href?: string;
  large?: boolean;
};

export function ProjectCard({ title, subtitle = "", imageSrc, imageAlt = "", href = "#", large = false }: Props) {
  return (
    <>
      <style>{`
        .yui-proj-card { position: relative; break-inside: avoid; margin-bottom: 3rem; }
        .yui-proj-card a { display: block; text-decoration: none; color: inherit; }
        .yui-proj-card a:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
        .yui-proj-card-img {
          overflow: hidden; border-radius: 1.5rem; isolation: isolate;
          aspect-ratio: 4/3;
        }
        .yui-proj-card-img img {
          width: 100%; height: 100%; object-fit: cover; display: block;
          transition: transform 0.8s cubic-bezier(0.25,1,0.5,1);
        }
        .yui-proj-card:hover .yui-proj-card-img img { transform: scale(1.05); }
        .yui-proj-card-info { margin-top: 1.5rem; }
        .yui-proj-card-info h3 {
          font-size: 2.5rem; font-weight: 600; line-height: 1;
          letter-spacing: -0.05em; text-transform: uppercase; margin: 0 0 0.4rem;
        }
        .yui-proj-card--large .yui-proj-card-info h3 {
          font-size: 4rem; letter-spacing: -0.08em;
        }
        .yui-proj-card-info span {
          font-size: 0.75rem; letter-spacing: 0.08em; text-transform: uppercase; opacity: 0.5;
        }
      `}</style>
      <article className={`yui-proj-card${large ? " yui-proj-card--large" : ""}`}>
        <a href={href}>
          <div className="yui-proj-card-img">
            <img src={imageSrc} alt={imageAlt} />
          </div>
          <div className="yui-proj-card-info">
            <h3>{title}</h3>
            {subtitle && <span>{subtitle}</span>}
          </div>
        </a>
      </article>
    </>
  );
}