import classNames from 'classnames'
import React from 'react'
import CardCta from '../LinkAttachment/components/_shared/CardCta'
import type { LinkAttachmentVariant } from '../LinkAttachment/components/_shared/CardShell'
import type { RichCardActionButton } from './types'
export interface RichCardBodyProps {
/** Surface the action buttons paint against (from `useChinPalette().surface`). */
ctaSurface: LinkAttachmentVariant
/** Ink for the title + subtitle, from `useChinPalette` — fixed per surface. */
chinTextColor: string
title?: string
subtitle?: string
subtitleLines?: number
appIcon?: React.ReactNode
actions?: RichCardActionButton[]
}
// body/small from Figma. Title is medium; subtitle is regular. No
// `text-wrap:balance` — it evened two-line titles by breaking mid-phrase.
const TITLE_CLASS =
'line-clamp-2 text-[14px] font-medium leading-5 tracking-[0.02em]'
const SUBTITLE_CLASS = 'text-[14px] leading-5 tracking-[0.02em]'
/** `
` ignores vertical margin; the spacer is the 6px Figma gap. */
const LineBreak: React.FC = () => (
<>
>
)
const withLineBreaks = (text: string) =>
text.split(/\r?\n/).map((line, index, lines) => (
{line}
{index < lines.length - 1 ? : null}
))
/**
* The action footer. `layout` (chosen by the first action's `variant` in
* {@link RichCardBody}) picks the presentation: `stacked` (`primary`) →
* full-width buttons stacked below the copy; `row` (`secondary`) → content-width
* buttons pinned to the right of the chin row (`shrink-0`, so they never
* compress the title/subtitle). Each button still paints in its own emphasis.
* Returns `null` when there are no actions.
*/
const RichCardFooter: React.FC<{
surface: LinkAttachmentVariant
actions?: RichCardActionButton[]
layout: 'stacked' | 'row'
}> = ({ surface, actions, layout }) => {
if (actions == null || actions.length === 0) return null
const stacked = layout === 'stacked'
return (
{actions.map((action, index) => (
))}
)
}
/**
* The rich card's "chin": title, subtitle (prose, multi-line by default), and
* the action footer. Padding matches `CardBody` (16px x, 12px y) so a rich card
* lines up with the link cards around it.
*/
const RichCardBody: React.FC = ({
ctaSurface,
chinTextColor,
title,
subtitle,
subtitleLines = 3,
appIcon,
actions,
}) => {
const hasTitle = title != null && title.trim() !== ''
const hasSubtitle = subtitle != null && subtitle.trim() !== ''
const hasActions = actions != null && actions.length > 0
if (!hasTitle && !hasSubtitle && !hasActions) return null
const chinTextStyle: React.CSSProperties = { color: chinTextColor }
const subtitleStyle: React.CSSProperties =
subtitleLines > 1
? {
...chinTextStyle,
display: '-webkit-box',
WebkitBoxOrient: 'vertical',
WebkitLineClamp: subtitleLines,
overflow: 'hidden',
}
: chinTextStyle
// A secondary primary-action lays out as a row (copy left, action right);
// primary stacks the button full-width below the copy.
const inline =
hasActions && (actions?.[0]?.variant ?? 'primary') === 'secondary'
const textBlock = (
{hasTitle && (
{appIcon ?
{appIcon} : null}
{title}
)}
{hasSubtitle && (
{subtitleLines > 1 ? withLineBreaks(subtitle ?? '') : subtitle}
)}
)
return (
{inline ? (
{textBlock}
) : (
<>
{textBlock}
>
)}
)
}
export default RichCardBody