initial commit
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
/* ============================================================================
|
||||
Card.Content - Figma 25:752 (360 x 372)
|
||||
----------------------------------------------------------------------------
|
||||
The news / blog / programme card: image, category badge, eyebrow, title,
|
||||
excerpt and a "Read more" affordance. The whole card is one link.
|
||||
|
||||
USAGE
|
||||
-----
|
||||
<ul className="grid gap-lg sm:grid-cols-2 lg:grid-cols-3">
|
||||
<Card.Content
|
||||
as="li"
|
||||
href="/en/news/civic-dialogue"
|
||||
eyebrow="Programme"
|
||||
badge="Rule of Law"
|
||||
title="Strengthening Civic Dialogue"
|
||||
excerpt="Supporting coordinated efforts among institutions, civil society,
|
||||
and local actors to foster community resilience."
|
||||
actionLabel="Read more"
|
||||
image={{ src: "/media/dialogue.jpg", alt: "" }}
|
||||
/>
|
||||
</ul>
|
||||
|
||||
// Arabic - the copy is the only thing that changes, RTL mirrors itself.
|
||||
<Card.Content
|
||||
href="/ar/news/civic-dialogue"
|
||||
title="تعزيز الحوار المدني"
|
||||
actionLabel="اقرأ المزيد"
|
||||
image={{ src: "/media/dialogue.jpg", alt: "" }}
|
||||
/>
|
||||
|
||||
// Above the fold - skip lazy loading for the lead card only.
|
||||
<Card.Content … image={{ src: "/media/lead.jpg", alt: "", priority: true }} />
|
||||
========================================================================= */
|
||||
|
||||
import {
|
||||
CardActionHint,
|
||||
CardEyebrow,
|
||||
CardLink,
|
||||
CardMedia,
|
||||
CardShell,
|
||||
cx,
|
||||
} from "./CardShell";
|
||||
import type { CardElement, CardImage, CardTitleElement } from "./types";
|
||||
|
||||
export interface CardContentProps {
|
||||
/** Where the whole card goes. */
|
||||
href: string;
|
||||
title: string;
|
||||
/**
|
||||
* Label of the "Read more" affordance. Required rather than defaulted so an
|
||||
* Arabic page cannot silently ship the English string.
|
||||
*/
|
||||
actionLabel: string;
|
||||
/** Accent kicker above the title, rendered uppercase. */
|
||||
eyebrow?: string;
|
||||
excerpt?: string;
|
||||
/** Chip over the top-inline-start corner of the image ("Rule of Law"). */
|
||||
badge?: string;
|
||||
image?: CardImage;
|
||||
as?: CardElement;
|
||||
/** Heading level - match the surrounding page outline. */
|
||||
titleAs?: CardTitleElement;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function CardContent({
|
||||
href,
|
||||
title,
|
||||
actionLabel,
|
||||
eyebrow,
|
||||
excerpt,
|
||||
badge,
|
||||
image,
|
||||
as = "article",
|
||||
titleAs = "h3",
|
||||
className,
|
||||
}: CardContentProps) {
|
||||
const Title = titleAs;
|
||||
|
||||
return (
|
||||
<CardShell as={as} linked className={cx("flex-col overflow-hidden", className)}>
|
||||
{image ? (
|
||||
<CardMedia image={image} className="aspect-[9/5] w-full">
|
||||
{/* The chip sits on a scrim over the photo, so its label has to stay
|
||||
light on both surfaces - text-on-accent is the only always-white
|
||||
role, text-primary would go dark on the light surface. */}
|
||||
{badge ? (
|
||||
<span className="absolute start-md top-md rounded-control-lg bg-overlay-scrim px-xs py-2xs label-md text-text-on-accent backdrop-blur-[4px]">
|
||||
{badge}
|
||||
</span>
|
||||
) : null}
|
||||
</CardMedia>
|
||||
) : null}
|
||||
|
||||
<div className="flex flex-col gap-md p-lg">
|
||||
<div className="flex flex-col gap-xs">
|
||||
{eyebrow ? <CardEyebrow>{eyebrow}</CardEyebrow> : null}
|
||||
|
||||
<Title className="sh-card-title body-lg-bold text-text-primary">
|
||||
<CardLink href={href} className="sh-card-link">
|
||||
{title}
|
||||
</CardLink>
|
||||
</Title>
|
||||
|
||||
{excerpt ? (
|
||||
<p className="body-sm text-text-secondary line-clamp-3">{excerpt}</p>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<CardActionHint label={actionLabel} />
|
||||
</div>
|
||||
</CardShell>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user