The Node.js® Website
at main 1.7 kB view raw
1import { useTranslations } from 'next-intl'; 2import type { FC } from 'react'; 3 4import AvatarGroup from '@/components/Common/AvatarGroup'; 5import FormattedTime from '@/components/Common/FormattedTime'; 6import Preview from '@/components/Common/Preview'; 7import Link from '@/components/Link'; 8import { mapBlogCategoryToPreviewType } from '@/util/blogUtils'; 9 10import styles from './index.module.css'; 11 12// @todo: this should probably be a global type? 13type Author = { fullName: string; src: string }; 14 15type BlogPostCardProps = { 16 title: string; 17 category: string; 18 description?: string; 19 authors?: Array<Author>; 20 date?: Date; 21 slug?: string; 22}; 23 24const BlogPostCard: FC<BlogPostCardProps> = ({ 25 title, 26 slug, 27 category, 28 description, 29 authors = [], 30 date, 31}) => { 32 const t = useTranslations(); 33 34 const avatars = authors.map(({ fullName, src }) => ({ alt: fullName, src })); 35 36 const type = mapBlogCategoryToPreviewType(category); 37 38 return ( 39 <article className={styles.container}> 40 <Link href={slug} aria-label={title}> 41 <Preview title={title} type={type} /> 42 </Link> 43 44 <Link href={`/blog/${category}`} className={styles.subtitle}> 45 {t(`layouts.blog.categories.${category}`)} 46 </Link> 47 48 <Link href={slug} className={styles.title}> 49 {title} 50 </Link> 51 52 {description && <p className={styles.description}>{description}</p>} 53 54 <footer className={styles.footer}> 55 <AvatarGroup avatars={avatars ?? []} /> 56 57 <div className={styles.author}> 58 {avatars && <p>{avatars.map(({ alt }) => alt).join(', ')}</p>} 59 60 {date && <FormattedTime date={date} />} 61 </div> 62 </footer> 63 </article> 64 ); 65}; 66 67export default BlogPostCard;