From 47e35fcd7c2c346f4799630bf6521d6a4bf49e85 Mon Sep 17 00:00:00 2001
From: Armand Philippot <git@armandphilippot.com>
Date: Wed, 13 Apr 2022 19:28:16 +0200
Subject: chore: add a Card component

---
 src/components/molecules/layout/card.tsx | 114 +++++++++++++++++++++++++++++++
 1 file changed, 114 insertions(+)
 create mode 100644 src/components/molecules/layout/card.tsx

(limited to 'src/components/molecules/layout/card.tsx')

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;
-- 
cgit v1.2.3

