diff options
| author | Armand Philippot <git@armandphilippot.com> | 2023-11-06 18:08:04 +0100 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2023-11-11 18:15:27 +0100 |
| commit | c9c1c90b30e243563bb4f731da15b3fe657556d2 (patch) | |
| tree | 8263c176b4096e2893b9d9319bfa7edb01fce188 /src/components/organisms/post-preview/post-preview.tsx | |
| parent | 2771de88f40a5f4ed7480bd8614532dda72deeda (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.tsx | 132 |
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); |
