
Centered team grid with grayscale avatars, names, and roles, split by vertical column lines.
@efferd
registry/blocks/team/1/team-section.tsx
import { cn } from "@/lib/utils";
import {
Avatar,
AvatarFallback,
AvatarImage,
} from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
type TeamMember = {
name: string;
role: string;
image: string;
link: string;
};
const team: TeamMember[] = [
{
name: "Shaban Haider",
role: "Founder & CEO",
image: "https://github.com/shabanhr.png",
link: "#",
},
{
name: "Jordan Blake",
role: "Head of Product",
image:
"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=800&q=80",
link: "#",
},
{
name: "Priya Nair",
role: "Design Lead",
image:
"https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?auto=format&fit=crop&w=800&q=80",
link: "#",
},
{
name: "Alex Rivera",
role: "Engineering",
image:
"https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&w=800&q=80",
link: "#",
},
{
name: "Sam Okonkwo",
role: "Growth",
image:
"https://images.unsplash.com/photo-1580489944761-15a19d654956?auto=format&fit=crop&w=800&q=80",
link: "#",
},
{
name: "Leo Park",
role: "Developer Experience",
image:
"https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?auto=format&fit=crop&w=800&q=80",
link: "#",
},
{
name: "Elena Ross",
role: "Brand",
image:
"https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=800&q=80",
link: "#",
},
{
name: "Marcus Hale",
role: "Support",
image:
"https://images.unsplash.com/photo-1506794778202-cad84cf45f1d?auto=format&fit=crop&w=800&q=80",
link: "#",
},
];
export function TeamSection() {
return (
<section
aria-labelledby="team-heading"
className="mx-auto flex w-full max-w-5xl flex-col gap-8"
>
<h2
className="font-heading text-balance font-medium text-3xl md:text-4xl"
id="team-heading"
>
Our Incredible Team
</h2>
<div className="relative">
<TeamMemberCardSeparator className="left-0 hidden sm:block" />
<TeamMemberCardSeparator className="left-1/2 lg:hidden" />
<TeamMemberCardSeparator className="left-1/3 hidden lg:block" />
<TeamMemberCardSeparator className="left-2/3 hidden lg:block" />
<TeamMemberCardSeparator className="left-full hidden sm:block" />
<ul className="grid grid-cols-2 lg:grid-cols-3">
{team.map((member) => (
<TeamMemberCard key={member.name} member={member} />
))}
</ul>
</div>
<div className="flex flex-col items-start justify-between gap-4 md:flex-row md:items-center">
<p className="text-pretty text-lg text-muted-foreground">
<span className="font-medium text-foreground">Join us!</span> Let's
shape the future of the web together
</p>
<Button asChild className="w-full md:w-auto">
<a href="#careers">View openings</a>
</Button>
</div>
</section>
);
}
function TeamMemberCard({ member }: { member: TeamMember }) {
const { name, role, image, link } = member;
return (
<li>
<a
className="group flex flex-col items-center gap-4 px-6 py-8 text-center md:py-14"
href={link}
>
<Avatar className="size-10 md:size-12">
<AvatarImage
alt={`${name}'s portrait`}
className="grayscale group-hover:grayscale-0"
src={image}
/>
<AvatarFallback>{getInitials(name)}</AvatarFallback>
</Avatar>
<div className="flex flex-col gap-0.5">
<h3 className="font-heading font-medium text-foreground">{name}</h3>
<p className="text-pretty text-muted-foreground text-xs">{role}</p>
</div>
</a>
</li>
);
}
function TeamMemberCardSeparator({
className,
...props
}: React.ComponentProps<"div">) {
return (
<div
aria-hidden="true"
className={cn(
"pointer-events-none absolute inset-y-0 w-px",
"bg-[linear-gradient(to_bottom,--theme(--color-foreground/.05)_0%,--theme(--color-foreground/.1)_2.5%,--theme(--color-foreground/.1)_97.5%,--theme(--color-foreground/.05)_100%)]",
className
)}
{...props}
/>
);
}
function getInitials(name: string) {
return name
.split(" ")
.map((part) => part[0])
.join("")
.slice(0, 2)
.toUpperCase();
}























