Files
xrpl-dev-portal/shared/components/StandardCard/index.tsx
gabriel-ortiz deb5ad7144 Add FeaturedVideoHero pattern component with showcase and styles
- Introduced the FeaturedVideoHero component featuring a responsive layout with a headline, optional subtitle, call-to-action buttons, and a video element.
- Added associated SCSS styles for the component to ensure proper spacing and theming.
- Created a showcase page to demonstrate the usage of the FeaturedVideoHero pattern.
- Updated types to include design constraints for buttons and video elements.
- Implemented validation for required props to enhance development experience.
2026-06-08 16:54:41 -07:00

105 lines
2.6 KiB
TypeScript

import React, { forwardRef } from "react";
import clsx from "clsx";
import Button from "../Button/Button";
import {
DesignConstrainedButtonProps,
isEnvironment,
isEmpty,
} from "../../utils";
import { DesignConstrainedCallToActionsProps } from "shared/utils/types";
/**
* Available background color variants for StandardCard:
* - 'neutral': Default neutral background
* - 'green': XRPL brand green background
* - 'yellow': Yellow background
* - 'blue': Blue background
*/
export type StandardCardVariant = "neutral" | "green" | "yellow" | "blue";
export interface StandardCardProps
extends
React.ComponentPropsWithoutRef<"article">,
DesignConstrainedCallToActionsProps {
headline: React.ReactNode;
/** Background color variant */
variant: StandardCardVariant;
children?: React.ReactNode;
}
/**
* StandardCard props without the variant prop.
* Used by StandardCardGroupSection to ensure uniform variant across all cards.
*/
export type StandardCardPropsWithoutVariant = Omit<
StandardCardProps,
"variant"
>;
const StandardCard = forwardRef<HTMLElement, StandardCardProps>(
(props, ref) => {
const {
headline,
variant = "neutral",
callsToAction,
className,
children,
...rest
} = props;
const [primaryButton, secondaryButton] = callsToAction;
const hasButtons = callsToAction.some((button) => !isEmpty(button));
if (!headline) {
if (isEnvironment("development")) {
console.warn("Headline is required for StandardCard");
}
return null;
}
return (
<article
ref={ref}
className={clsx(
"bds-standard-card",
`bds-standard-card--${variant}`,
className,
)}
{...rest}
>
<div className="bds-standard-card__content">
<h2 className="bds-standard-card__headline sh-md-r">{headline}</h2>
{!isEmpty(children) && (
<div className="bds-standard-card__description body-l">
{children}
</div>
)}
</div>
{hasButtons && (
<div className="bds-standard-card__buttons">
{primaryButton && (
<Button
{...primaryButton}
variant="primary"
color="black"
forceColor={true}
/>
)}
{secondaryButton && (
<Button
{...secondaryButton}
variant="tertiary"
color="black"
forceColor={true}
/>
)}
</div>
)}
</article>
);
},
);
export default StandardCard;