Retour au catalogue

Team Bento

Grille bento avec tailles variees pour presenter l'equipe de maniere dynamique.

teammedium Both Responsive a11y
boldeditorialagencyportfoliomasonry
Theme
"use client";

import { motion } from "framer-motion";

interface TeamMember {
  name: string;
  role: string;
  imageUrl: string;
  bio: string;
}

interface TeamBentoProps {
  title?: string;
  subtitle?: string;
  members?: TeamMember[];
}

const EASE = [0.16, 1, 0.3, 1] as const;

export default function TeamBento({
  title = "Notre equipe",
  subtitle = "Equipe",
  members = [],
}: TeamBentoProps) {
  const getSpanClass = (i: number): string => {
    const patterns = [
      "col-span-2 row-span-2",
      "col-span-1 row-span-1",
      "col-span-1 row-span-1",
      "col-span-1 row-span-2",
      "col-span-1 row-span-1",
      "col-span-2 row-span-1",
    ];
    return patterns[i % patterns.length];
  };

  return (
    <section
      style={{
        paddingTop: "var(--section-padding-y)",
        paddingBottom: "var(--section-padding-y)",
        background: "var(--color-background)",
      }}
    >
      <div
        className="mx-auto"
        style={{
          maxWidth: "var(--container-max-width)",
          paddingLeft: "var(--container-padding-x)",
          paddingRight: "var(--container-padding-x)",
        }}
      >
        <motion.div
          initial={{ opacity: 0, y: 16 }}
          whileInView={{ opacity: 1, y: 0 }}
          viewport={{ once: true }}
          transition={{ duration: 0.5, ease: EASE }}
          className="text-center mb-14"
        >
          <p className="text-xs font-semibold uppercase tracking-widest mb-2" style={{ color: "var(--color-accent)" }}>
            {subtitle}
          </p>
          <h2 className="text-2xl md:text-3xl font-bold tracking-tight" style={{ color: "var(--color-foreground)" }}>
            {title}
          </h2>
        </motion.div>

        <div className="grid grid-cols-2 md:grid-cols-3 auto-rows-[180px] gap-4">
          {members.map((member, i) => (
            <motion.div
              key={member.name}
              initial={{ opacity: 0, scale: 0.95 }}
              whileInView={{ opacity: 1, scale: 1 }}
              viewport={{ once: true }}
              transition={{ duration: 0.45, delay: i * 0.06, ease: EASE }}
              className={`${getSpanClass(i)} group relative overflow-hidden rounded-xl`}
              style={{ borderRadius: "var(--radius-lg)" }}
            >
              <img
                src={member.imageUrl}
                alt={member.name}
                className="w-full h-full object-cover transition-transform duration-500 group-hover:scale-105"
              />
              <div
                className="absolute inset-0 flex flex-col justify-end p-4"
                style={{
                  background: "linear-gradient(to top, rgba(0,0,0,0.7) 0%, transparent 60%)",
                }}
              >
                <h3 className="text-sm font-semibold text-white">{member.name}</h3>
                <p className="text-xs text-white/70">{member.role}</p>
              </div>
            </motion.div>
          ))}
        </div>
      </div>
    </section>
  );
}

Avis

Team Bento — React Team Section — Incubator