diff options
| author | Armand Philippot <git@armandphilippot.com> | 2023-11-20 11:02:20 +0100 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2023-11-20 19:20:21 +0100 |
| commit | d5ade2359539648845a5854ed353b29367961d74 (patch) | |
| tree | 45a49d90090408887135a971a7fd79c45d9dcd94 /src/components/organisms | |
| parent | 6ab9635a22d69186c8a24181ad5df7736e288577 (diff) | |
refactor(components): extract MetaItem from MetaList
* replace `items` prop on MetaList with `children` prop: it was too
restrictive and the global options was not really useful. It is better
too give control to the consumers.
Diffstat (limited to 'src/components/organisms')
3 files changed, 125 insertions, 161 deletions
diff --git a/src/components/organisms/comment/approved-comment/approved-comment.tsx b/src/components/organisms/comment/approved-comment/approved-comment.tsx index db5345b..233146d 100644 --- a/src/components/organisms/comment/approved-comment/approved-comment.tsx +++ b/src/components/organisms/comment/approved-comment/approved-comment.tsx @@ -12,6 +12,7 @@ import { CardTitle, CardFooter, CardActions, + MetaItem, } from '../../../molecules'; import styles from './approved-comment.module.scss'; @@ -138,20 +139,17 @@ const ApprovedCommentWithRef: ForwardRefRenderFunction< author.name )} </CardTitle> - <CardMeta - hasInlinedItems - items={[ - { - id: 'publication-date', - label: publicationDateLabel, - value: ( - <Link href={commentLink}> - <Time date={publicationDate} showTime /> - </Link> - ), - }, - ]} - /> + <CardMeta> + <MetaItem + isInline + label={publicationDateLabel} + value={ + <Link href={commentLink}> + <Time date={publicationDate} showTime /> + </Link> + } + /> + </CardMeta> </CardHeader> <CardBody className={styles.body} diff --git a/src/components/organisms/post-preview/post-preview-meta/post-preview-meta.tsx b/src/components/organisms/post-preview/post-preview-meta/post-preview-meta.tsx index 5a342da..54e359e 100644 --- a/src/components/organisms/post-preview/post-preview-meta/post-preview-meta.tsx +++ b/src/components/organisms/post-preview/post-preview-meta/post-preview-meta.tsx @@ -1,12 +1,13 @@ -import type { FC, ReactNode } from 'react'; +import type { FC, ReactElement, ReactNode } from 'react'; import { useIntl } from 'react-intl'; import type { PageLink } from '../../../../types'; import { getReadingTimeFrom } from '../../../../utils/helpers'; import { Link, Time, VisuallyHidden } from '../../../atoms'; import { CardMeta, - type MetaItemData, type CardMetaProps, + MetaItem, + type MetaItemProps, } from '../../../molecules'; const a11y = (chunks: ReactNode) => <VisuallyHidden>{chunks}</VisuallyHidden>; @@ -57,20 +58,7 @@ export type PostPreviewMetaData = { wordsCount?: number; }; -const validMetaKeys = [ - 'author', - 'comments', - 'publicationDate', - 'thematics', - 'topics', - 'updateDate', - 'wordsCount', -] satisfies (keyof PostPreviewMetaData)[]; - -const isValidMetaKey = (key: string): key is keyof PostPreviewMetaData => - (validMetaKeys as string[]).includes(key); - -export type PostPreviewMetaProps = Omit<CardMetaProps, 'items'> & { +export type PostPreviewMetaProps = Omit<CardMetaProps, 'children' | 'items'> & { /** * The post meta. */ @@ -83,23 +71,20 @@ export const PostPreviewMeta: FC<PostPreviewMetaProps> = ({ }) => { const intl = useIntl(); - const getAuthor = (): MetaItemData | undefined => { - if (!meta.author) return undefined; - - return { - id: 'author', - label: intl.formatMessage({ + const getAuthor = (author: string): ReactElement<MetaItemProps> => ( + <MetaItem + label={intl.formatMessage({ defaultMessage: 'Written by:', description: 'PostPreviewMeta: author label', id: '2U7ixo', - }), - value: meta.author, - }; - }; - - const getCommentsCount = (): MetaItemData | undefined => { - if (!meta.comments) return undefined; - + })} + value={author} + /> + ); + + const getComments = ( + comments: PostPreviewMetaComment + ): ReactElement<MetaItemProps> => { const commentsLabel = intl.formatMessage<ReactNode>( { defaultMessage: @@ -109,146 +94,121 @@ export const PostPreviewMeta: FC<PostPreviewMetaProps> = ({ }, { a11y, - commentsCount: meta.comments.count, - title: meta.comments.postHeading, + commentsCount: comments.count, + title: comments.postHeading, } ); - return { - id: 'comments', - label: intl.formatMessage({ - defaultMessage: 'Comments:', - description: 'PostPreviewMeta: comments label', - id: 'FCpPCm', - }), - value: meta.comments.url ? ( - <Link href={meta.comments.url}>{commentsLabel}</Link> - ) : ( - <>{commentsLabel}</> - ), - }; + return ( + <MetaItem + label={intl.formatMessage({ + defaultMessage: 'Comments:', + description: 'PostPreviewMeta: comments label', + id: 'FCpPCm', + })} + value={ + comments.url ? ( + <Link href={comments.url}>{commentsLabel}</Link> + ) : ( + <>{commentsLabel}</> + ) + } + /> + ); }; - const getPublicationDate = (): MetaItemData | undefined => { - if (!meta.publicationDate) return undefined; - - return { - id: 'publication-date', - label: intl.formatMessage({ + const getPublicationDate = (date: string): ReactElement<MetaItemProps> => ( + <MetaItem + label={intl.formatMessage({ defaultMessage: 'Published on:', description: 'PostPreviewMeta: publication date label', id: '+6f4p1', - }), - value: <Time date={meta.publicationDate} />, - }; - }; - - const getThematics = (): MetaItemData | undefined => { - if (!meta.thematics?.length) return undefined; - - return { - id: 'thematics', - label: intl.formatMessage( + })} + value={<Time date={date} />} + /> + ); + + const getThematics = (thematics: PageLink[]): ReactElement<MetaItemProps> => ( + <MetaItem + label={intl.formatMessage( { defaultMessage: '{thematicsCount, plural, =0 {Thematics:} one {Thematic:} other {Thematics:}}', description: 'PostPreviewMeta: thematics label', id: '9MTBCG', }, - { thematicsCount: meta.thematics.length } - ), - value: meta.thematics.map((thematic) => { + { thematicsCount: thematics.length } + )} + value={thematics.map((thematic) => { return { id: `thematic-${thematic.id}`, value: <Link href={thematic.url}>{thematic.name}</Link>, }; - }), - }; - }; - - const getTopics = (): MetaItemData | undefined => { - if (!meta.topics?.length) return undefined; + })} + /> + ); - return { - id: 'topics', - label: intl.formatMessage( + const getTopics = (topics: PageLink[]): ReactElement<MetaItemProps> => ( + <MetaItem + label={intl.formatMessage( { defaultMessage: '{topicsCount, plural, =0 {Topics:} one {Topic:} other {Topics:}}', description: 'PostPreviewMeta: topics label', id: 'aBQYbE', }, - { topicsCount: meta.topics.length } - ), - value: meta.topics.map((topic) => { + { topicsCount: topics.length } + )} + value={topics.map((topic) => { return { id: `topic-${topic.id}`, value: <Link href={topic.url}>{topic.name}</Link>, }; - }), - }; - }; + })} + /> + ); - const getUpdateDate = (): MetaItemData | undefined => { - if (!meta.updateDate || meta.updateDate === meta.publicationDate) - return undefined; - - return { - id: 'update-date', - label: intl.formatMessage({ + const getUpdateDate = (date: string): ReactElement<MetaItemProps> => ( + <MetaItem + label={intl.formatMessage({ defaultMessage: 'Updated on:', description: 'PostPreviewMeta: update date label', id: 'ZmRh0V', - }), - value: <Time date={meta.updateDate} />, - }; - }; - - const getReadingTime = (): MetaItemData | undefined => { - if (!meta.wordsCount) return undefined; - - return { - id: 'reading-time', - label: intl.formatMessage({ + })} + value={<Time date={date} />} + /> + ); + + const getReadingTime = (wordsCount: number): ReactElement<MetaItemProps> => ( + <MetaItem + label={intl.formatMessage({ defaultMessage: 'Reading time:', description: 'PostPreviewMeta: reading time label', id: 'B1lS/v', - }), - value: intl.formatMessage( + })} + value={intl.formatMessage( { defaultMessage: '{minutesCount, plural, =0 {Less than one minute} one {# minute} other {# minutes}}', description: 'PostPreviewMeta: rounded minutes count', id: 'y+13Ax', }, - { minutesCount: getReadingTimeFrom(meta.wordsCount).inMinutes() } - ), - }; - }; - - const items: MetaItemData[] = Object.keys(meta) - .filter(isValidMetaKey) - .map((key): MetaItemData | undefined => { - switch (key) { - case 'author': - return getAuthor(); - case 'comments': - return getCommentsCount(); - case 'publicationDate': - return getPublicationDate(); - case 'thematics': - return getThematics(); - case 'topics': - return getTopics(); - case 'updateDate': - return getUpdateDate(); - case 'wordsCount': - return getReadingTime(); - default: - throw new Error('Unsupported meta key.'); - } - }) - .filter((item): item is MetaItemData => item !== undefined); - - return <CardMeta {...props} items={items} />; + { minutesCount: getReadingTimeFrom(wordsCount).inMinutes() } + )} + /> + ); + + return ( + <CardMeta {...props}> + {meta.author ? getAuthor(meta.author) : null} + {meta.publicationDate ? getPublicationDate(meta.publicationDate) : null} + {meta.updateDate && meta.updateDate !== meta.publicationDate + ? getUpdateDate(meta.updateDate) + : null} + {meta.wordsCount ? getReadingTime(meta.wordsCount) : null} + {meta.thematics ? getThematics(meta.thematics) : null} + {meta.topics ? getTopics(meta.topics) : null} + {meta.comments ? getComments(meta.comments) : null} + </CardMeta> + ); }; diff --git a/src/components/organisms/project-overview/project-overview.tsx b/src/components/organisms/project-overview/project-overview.tsx index 2b8be0e..f524120 100644 --- a/src/components/organisms/project-overview/project-overview.tsx +++ b/src/components/organisms/project-overview/project-overview.tsx @@ -6,7 +6,7 @@ import { type ReactElement, } from 'react'; import { useIntl } from 'react-intl'; -import type { Maybe, ValueOf } from '../../../types'; +import type { ValueOf } from '../../../types'; import { Time, type SocialWebsite, @@ -14,7 +14,7 @@ import { SocialLink, Figure, } from '../../atoms'; -import { MetaList, type MetaItemData } from '../../molecules'; +import { MetaItem, type MetaItemProps, MetaList } from '../../molecules'; import styles from './project-overview.module.scss'; export type Repository = { @@ -155,27 +155,31 @@ const ProjectOverviewWithRef: ForwardRefRenderFunction< [intl] ); - const getMetaItems = useCallback((): MetaItemData[] => { + const getMetaItems = useCallback(() => { const keys = Object.keys(meta).filter(isValidMetaKey); return keys - .map((key): Maybe<MetaItemData> => { + .map((key) => { const value = meta[key]; - return value - ? { - id: key, - label: metaLabels[key], - value: getMetaValue(key, value), - hasBorderedValues: key === 'technologies', - hasInlinedValues: - (key === 'technologies' || key === 'repositories') && - Array.isArray(value) && - value.length > 1, + return value ? ( + <MetaItem + hasBorderedValues={key === 'technologies'} + hasInlinedValues={ + (key === 'technologies' || key === 'repositories') && + Array.isArray(value) && + value.length > 1 } - : undefined; + key={key} + label={metaLabels[key]} + value={getMetaValue(key, value)} + /> + ) : undefined; }) - .filter((item): item is MetaItemData => typeof item !== 'undefined'); + .filter( + (item): item is ReactElement<MetaItemProps> => + typeof item !== 'undefined' + ); }, [getMetaValue, meta, metaLabels]); return ( @@ -185,7 +189,9 @@ const ProjectOverviewWithRef: ForwardRefRenderFunction< {cover} </Figure> ) : null} - <MetaList className={styles.meta} isInline items={getMetaItems()} /> + <MetaList className={styles.meta} isInline> + {getMetaItems()} + </MetaList> </div> ); }; |
