- Drop the globe icon in the language switcher - Only show RightArrow on nav menuitem hover - Fix EU logo colors in light mode
138 lines
4.3 KiB
TypeScript
138 lines
4.3 KiB
TypeScript
/* ============================================================================
|
|
Card.Team - Figma 25:765 (280 x 295)
|
|
----------------------------------------------------------------------------
|
|
Portrait in an accent frame, name, role, affiliation and up to three social
|
|
links. The social links are real links, so the card itself is only stretched
|
|
over a link when `href` is given - and the links are lifted above the
|
|
overlay so they stay clickable.
|
|
|
|
USAGE
|
|
-----
|
|
<ul className="grid gap-lg sm:grid-cols-2 lg:grid-cols-4">
|
|
<Card.Team
|
|
as="li"
|
|
name="Dr. Helen Vance"
|
|
role="Chief Programme Director"
|
|
affiliation="SHARP-ER Governance Initiative"
|
|
portrait={{ src: "/media/team/helen-vance.jpg", alt: "" }}
|
|
socials={[
|
|
{ kind: "linkedin", href: "https://www.linkedin.com/in/example" },
|
|
{ kind: "mail", href: "mailto:helen.vance@example.org", label: "Email" },
|
|
]}
|
|
/>
|
|
</ul>
|
|
|
|
// Optional bio page - the whole card becomes clickable, socials still work.
|
|
<Card.Team href="/en/about/helen-vance" name="Dr. Helen Vance" … />
|
|
========================================================================= */
|
|
|
|
import { CardLink, CardMedia, CardShell, CardIcon, cx } from "./CardShell";
|
|
import type { CardElement, CardIconName, CardImage, CardTitleElement } from "./types";
|
|
|
|
export type CardTeamSocialKind = "linkedin" | "mail";
|
|
|
|
export interface CardTeamSocial {
|
|
kind: CardTeamSocialKind;
|
|
href: string;
|
|
/**
|
|
* Accessible name of the link. Defaults to the platform name; pass a
|
|
* translated string on Arabic pages ("البريد الإلكتروني").
|
|
*/
|
|
label?: string;
|
|
}
|
|
|
|
export interface CardTeamProps {
|
|
name: string;
|
|
role?: string;
|
|
/** Team, unit or initiative the person belongs to. */
|
|
affiliation?: string;
|
|
portrait?: CardImage;
|
|
socials?: CardTeamSocial[];
|
|
/** Optional bio page. Given, the whole card links to it. */
|
|
href?: string;
|
|
as?: CardElement;
|
|
titleAs?: CardTitleElement;
|
|
className?: string;
|
|
}
|
|
|
|
const SOCIAL_ICON: Record<CardTeamSocialKind, CardIconName> = {
|
|
linkedin: "linkedin",
|
|
mail: "mail",
|
|
};
|
|
|
|
const SOCIAL_LABEL: Record<CardTeamSocialKind, string> = {
|
|
linkedin: "LinkedIn",
|
|
mail: "Email",
|
|
};
|
|
|
|
export function CardTeam({
|
|
name,
|
|
role,
|
|
affiliation,
|
|
portrait,
|
|
socials,
|
|
href,
|
|
as = "article",
|
|
titleAs = "h3",
|
|
className,
|
|
}: CardTeamProps) {
|
|
const Title = titleAs;
|
|
|
|
return (
|
|
<CardShell
|
|
as={as}
|
|
linked={Boolean(href)}
|
|
className={cx("flex-col items-center gap-5 p-xl text-center", className)}
|
|
>
|
|
{/* 96px portrait inside the 4px accent frame, exactly as drawn. */}
|
|
{portrait ? (
|
|
<CardMedia
|
|
image={portrait}
|
|
className="size-24 shrink-0 rounded-surface border-4 border-border-accent"
|
|
/>
|
|
) : null}
|
|
|
|
<div className="flex w-full flex-col gap-xs">
|
|
<Title className="sh-card-title body-md-bold text-text-primary">
|
|
{href ? (
|
|
<CardLink href={href} className="sh-card-link">
|
|
{name}
|
|
</CardLink>
|
|
) : (
|
|
name
|
|
)}
|
|
</Title>
|
|
|
|
{role ? <p className="body-sm text-text-secondary">{role}</p> : null}
|
|
|
|
{affiliation ? (
|
|
<p className="body-sm text-text-accent">{affiliation}</p>
|
|
) : null}
|
|
</div>
|
|
|
|
{socials && socials.length > 0 ? (
|
|
/* sh-card-above keeps these clickable through the stretched-link
|
|
overlay when the card as a whole is a link. */
|
|
<ul className="sh-card-above flex items-start justify-center gap-sm">
|
|
{socials.map((social) => (
|
|
<li key={`${social.kind}-${social.href}`}>
|
|
{/* Figma strokes these icons in text/accent on a background/accent
|
|
chip - green on green, invisible. Painted with the always-white
|
|
on-accent role instead. */}
|
|
<CardLink
|
|
href={social.href}
|
|
className="flex size-8 items-center justify-center rounded-surface bg-surface-accent text-text-on-accent"
|
|
>
|
|
<CardIcon name={SOCIAL_ICON[social.kind]} size={14} />
|
|
<span className="sr-only">
|
|
{`${social.label ?? SOCIAL_LABEL[social.kind]} - ${name}`}
|
|
</span>
|
|
</CardLink>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
) : null}
|
|
</CardShell>
|
|
);
|
|
}
|