initial commit
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
/* ============================================================================
|
||||
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" },
|
||||
{ kind: "website", href: "https://example.org", label: "Website" },
|
||||
]}
|
||||
/>
|
||||
</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" | "website";
|
||||
|
||||
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",
|
||||
website: "globe",
|
||||
};
|
||||
|
||||
const SOCIAL_LABEL: Record<CardTeamSocialKind, string> = {
|
||||
linkedin: "LinkedIn",
|
||||
mail: "Email",
|
||||
website: "Website",
|
||||
};
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user