aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/organisms/post-preview/post-preview.tsx
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2023-11-06 18:08:04 +0100
committerArmand Philippot <git@armandphilippot.com>2023-11-11 18:15:27 +0100
commitc9c1c90b30e243563bb4f731da15b3fe657556d2 (patch)
tree8263c176b4096e2893b9d9319bfa7edb01fce188 /src/components/organisms/post-preview/post-preview.tsx
parent2771de88f40a5f4ed7480bd8614532dda72deeda (diff)
refactor(components): replace Summary component with PostPreview
* rename component to PostPreview because Summary is an HTML element and it could lead to confusion * replace `title` and `titleLevel` with `heading` and `headingLvl` because `title` is a native attribute * rename `intro` prop to `excerpt` * extract `cover` from `meta` prop * rewrite meta type * extract meta logic into a new component
Diffstat (limited to 'src/components/organisms/post-preview/post-preview.tsx')
-rw-r--r--src/components/organisms/post-preview/post-preview.tsx132
1 files changed, 132 insertions, 0 deletions
diff --git a/src/components/organisms/post-preview/post-preview.tsx b/src/components/organisms/post-preview/post-preview.tsx
new file mode 100644
index 0000000..df459e2
--- /dev/null
+++ b/src/components/organisms/post-preview/post-preview.tsx
@@ -0,0 +1,132 @@
+import {
+ type ForwardRefRenderFunction,
+ type ReactElement,
+ forwardRef,
+ type ReactNode,
+} from 'react';
+import { useIntl } from 'react-intl';
+import {
+ ButtonLink,
+ type HeadingLevel,
+ Icon,
+ Link,
+ VisuallyHidden,
+} from '../../atoms';
+import {
+ Card,
+ CardActions,
+ CardBody,
+ CardFooter,
+ CardHeader,
+ type CardProps,
+ CardTitle,
+ CardCover,
+} from '../../molecules';
+import { PostPreviewMeta, type PostPreviewMetaData } from './post-preview-meta';
+import styles from './post-preview.module.scss';
+
+const a11y = (chunks: ReactNode) => <VisuallyHidden>{chunks}</VisuallyHidden>;
+
+export type PostPreviewProps = Omit<
+ CardProps<undefined>,
+ 'children' | 'cover' | 'linkTo' | 'meta' | 'variant'
+> & {
+ /**
+ * The post cover.
+ */
+ cover?: ReactElement;
+ /**
+ * The post excerpt.
+ */
+ excerpt: string;
+ /**
+ * The post title.
+ */
+ heading: string;
+ /**
+ * The heading level to use on post title.
+ */
+ headingLvl?: HeadingLevel;
+ /**
+ * The post meta.
+ */
+ meta?: PostPreviewMetaData;
+ /**
+ * The post url.
+ */
+ url: string;
+};
+
+const PostPreviewWithRef: ForwardRefRenderFunction<
+ HTMLDivElement,
+ PostPreviewProps
+> = (
+ { className, cover, excerpt, heading, headingLvl, meta, url, ...props },
+ ref
+) => {
+ const wrapperClass = `${styles.wrapper} ${className}`;
+ const intl = useIntl();
+ const coverLabel = intl.formatMessage(
+ {
+ defaultMessage: '{postTitle} cover',
+ description:
+ 'PostPreview: an accessible name for the figure wrapping the cover',
+ id: 'iG5SHf',
+ },
+ { postTitle: heading }
+ );
+ const readMore = intl.formatMessage<ReactNode>(
+ {
+ defaultMessage: 'Read more<a11y> about {postTitle}</a11y>',
+ description: 'PostPreview: read more link',
+ id: 'BYdQze',
+ },
+ {
+ postTitle: heading,
+ a11y,
+ }
+ );
+
+ return (
+ <Card
+ {...props}
+ className={wrapperClass}
+ cover={
+ cover ? (
+ <CardCover aria-label={coverLabel} hasBorders>
+ {cover}
+ </CardCover>
+ ) : undefined
+ }
+ meta={meta ? <PostPreviewMeta meta={meta} /> : undefined}
+ ref={ref}
+ >
+ <CardHeader>
+ <CardTitle className={styles.heading} level={headingLvl}>
+ <Link href={url}>{heading}</Link>
+ </CardTitle>
+ </CardHeader>
+ <CardBody
+ className={styles.excerpt}
+ dangerouslySetInnerHTML={{ __html: excerpt }}
+ />
+ <CardFooter>
+ <CardActions>
+ <ButtonLink to={url}>
+ {readMore}
+ <Icon
+ aria-hidden
+ className={styles.icon}
+ // eslint-disable-next-line react/jsx-no-literals
+ orientation="right"
+ // eslint-disable-next-line react/jsx-no-literals
+ shape="arrow"
+ />
+ </ButtonLink>
+ </CardActions>
+ </CardFooter>
+ </Card>
+ );
+};
+
+export const PostPreview = forwardRef(PostPreviewWithRef);