summaryrefslogtreecommitdiffstats
path: root/src/components/molecules/layout/card.tsx
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2022-04-13 19:28:16 +0200
committerArmand Philippot <git@armandphilippot.com>2022-04-13 19:28:16 +0200
commit47e35fcd7c2c346f4799630bf6521d6a4bf49e85 (patch)
tree99228c523b6ced1d9c1e83a03a4dd9fc2468e4b0 /src/components/molecules/layout/card.tsx
parent017d01680a933897df6ddd11d2e081730756250b (diff)
chore: add a Card component
Diffstat (limited to 'src/components/molecules/layout/card.tsx')
-rw-r--r--src/components/molecules/layout/card.tsx114
1 files changed, 114 insertions, 0 deletions
diff --git a/src/components/molecules/layout/card.tsx b/src/components/molecules/layout/card.tsx
new file mode 100644
index 0000000..23a0e54
--- /dev/null
+++ b/src/components/molecules/layout/card.tsx
@@ -0,0 +1,114 @@
+import ButtonLink from '@components/atoms/buttons/button-link';
+import Heading, { type HeadingLevel } from '@components/atoms/headings/heading';
+import DescriptionList, {
+ DescriptionListItem,
+} from '@components/atoms/lists/description-list';
+import { VFC } from 'react';
+import ResponsiveImage, {
+ ResponsiveImageProps,
+} from '../images/responsive-image';
+import styles from './card.module.scss';
+
+export type Cover = {
+ /**
+ * The cover alternative text.
+ */
+ alt: string;
+ /**
+ * The cover height.
+ */
+ height: number;
+ /**
+ * The cover source.
+ */
+ src: string;
+ /**
+ * The cover width.
+ */
+ width: number;
+};
+
+export type CardProps = {
+ /**
+ * Set additional classnames to the card wrapper.
+ */
+ className?: string;
+ /**
+ * The card cover.
+ */
+ cover?: Cover;
+ /**
+ * The cover fit. Default: cover.
+ */
+ coverFit?: ResponsiveImageProps['objectFit'];
+ /**
+ * The card meta.
+ */
+ meta?: DescriptionListItem[];
+ /**
+ * The card tagline.
+ */
+ tagline?: string;
+ /**
+ * The card title.
+ */
+ title: string;
+ /**
+ * The title level (hn).
+ */
+ titleLevel: HeadingLevel;
+ /**
+ * The card target.
+ */
+ url: string;
+};
+
+/**
+ * Card component
+ *
+ * Render a link with minimal information about its content.
+ */
+const Card: VFC<CardProps> = ({
+ className = '',
+ cover,
+ coverFit = 'cover',
+ meta,
+ tagline,
+ title,
+ titleLevel,
+ url,
+}) => {
+ return (
+ <ButtonLink target={url} className={`${styles.wrapper} ${className}`}>
+ <article className={styles.article}>
+ <header className={styles.header}>
+ {cover && (
+ <ResponsiveImage
+ {...cover}
+ objectFit={coverFit}
+ className={styles.cover}
+ />
+ )}
+ <Heading level={titleLevel} className={styles.title}>
+ {title}
+ </Heading>
+ </header>
+ <div className={styles.tagline}>{tagline}</div>
+ {meta && (
+ <footer className={styles.footer}>
+ <DescriptionList
+ items={meta}
+ layout="inline"
+ className={styles.list}
+ groupClassName={styles.items}
+ termClassName={styles.term}
+ descriptionClassName={styles.description}
+ />
+ </footer>
+ )}
+ </article>
+ </ButtonLink>
+ );
+};
+
+export default Card;