Skip to content

Commit

Permalink
feat: add date and author to blog card (#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
pReya authored Oct 15, 2024
1 parent 2fcce00 commit 5a76a5b
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 63 deletions.
37 changes: 37 additions & 0 deletions src/components/AuthorsByline.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type { CollectionEntry } from 'astro:content'
import Avatar from './Avatar'

interface AuthorsBylineProps {
authors: CollectionEntry<'authors'>[]
inline?: boolean
}

const AuthorsByline: React.FC<AuthorsBylineProps> = ({ authors, inline }) => {
return (
<p className={`text-lg ${inline ? 'font-normal text-black/50' : 'font-medium pt-4'}`}>
{inline ? 'v' : 'V'}on{' '}
<Avatar
jpgSrc={authors[0]?.data.image.default}
webpSrc={authors[0]?.data.image.webp}
alt={authors[0]?.data.image.alt}
small
/>{' '}
{authors[0].data.firstName + ' ' + authors[0].data.lastName}
{authors.length > 1 && (
<>
{' '}
&
<Avatar
jpgSrc={authors[1]?.data.image.default}
webpSrc={authors[1]?.data.image.webp}
alt={authors[1]?.data.image.alt}
small
/>{' '}
{authors[1].data.firstName + ' ' + authors[1].data.lastName}
</>
)}
</p>
)
}

export default AuthorsByline
81 changes: 57 additions & 24 deletions src/components/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import type { CollectionEntry } from 'astro:content'
import { ConditionalWrapper } from './ConditionalWrapper'
import LinkButton from './LinkButton'
import AuthorsByline from './AuthorsByline'

interface Props {
img?: string
Expand All @@ -8,6 +11,9 @@ interface Props {
href?: string
teaser?: string
className?: string
showButton?: boolean
date?: string
author?: CollectionEntry<'authors'>
}

const Card: React.FC<Props> = ({
Expand All @@ -18,34 +24,61 @@ const Card: React.FC<Props> = ({
teaser,
href,
className,
showButton,
date,
author,
}: Props) => {
return (
<div className={`flex-1 flex flex-col group ${className || ''}`}>
{img && (
<img
className='w-full h-64 object-cover grayscale group-hover:grayscale-0 transition duration-300 ease-in-out'
src={img}
alt={imgAlt}
/>
<ConditionalWrapper
condition={!showButton}
wrapper={(children) => (
<a href={href} className={`flex-1 flex flex-col gap-3 group ${className || ''}`}>
{children}
</a>
)}
{subtitle && (
<h3
className={`font-sans text-lg leading-5 tracking-widest uppercase font-normal text-black opacity-70 ${
img ? 'pt-8' : ''
} line-clamp-1`}
title={subtitle}
>
{subtitle}
</h3>
falseWrapper={(children) => (
<div className={`flex-1 flex flex-col gap-3 group ${className || ''}`}>{children}</div>
)}
{title && (
<h2 className='font-grotesk font-medium text-2xl leading-8 mt-3 line-clamp-2'>{title}</h2>
)}
{teaser && <p className='pt-4'>{teaser}</p>}
{href && (
<LinkButton small caption={'Weiterlesen'} variant='dark' href={href} className='mt-5' />
)}
</div>
>
<>
{img && (
<img
className='w-full h-64 object-cover grayscale group-hover:grayscale-0 transition duration-300 ease-in-out'
src={img}
alt={imgAlt}
/>
)}
{subtitle && (
<h3
className={`font-sans text-lg leading-5 tracking-widest uppercase font-normal text-black opacity-70 ${
img ? 'pt-4' : ''
} line-clamp-1`}
title={subtitle}
>
{subtitle}
</h3>
)}
{title && (
<h2 className='font-grotesk font-medium text-2xl leading-8 line-clamp-2'>{title}</h2>
)}
{teaser && <p className='pt-4 text-lg leading-6 text-black/75'>{teaser}</p>}
{(date || author) && (
<div className='flex gap-2 items-center font-medium'>
{date && <p className='text-lg font-normal text-black/50'>{date}</p>}
{author && (
<>
{'·'}
<AuthorsByline authors={[author]} inline />
</>
)}
</div>
)}

{href && showButton && (
<LinkButton small caption={'Weiterlesen'} variant='dark' href={href} className='mt-2' />
)}
</>
</ConditionalWrapper>
)
}

Expand Down
15 changes: 15 additions & 0 deletions src/components/ConditionalWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { ReactElement, ReactNode } from 'react'

interface ConditionalWrapperProps {
condition: boolean
children: ReactElement | ReactNode
wrapper: (c: ReactElement | ReactNode) => ReactElement | ReactNode | JSX.Element
falseWrapper?: (c: ReactElement | ReactNode) => ReactElement | ReactNode | JSX.Element
}

export const ConditionalWrapper: React.FC<ConditionalWrapperProps> = ({
condition,
wrapper,
falseWrapper,
children,
}) => (condition ? wrapper(children) : falseWrapper ? falseWrapper(children) : children)
29 changes: 2 additions & 27 deletions src/pages/blog/[slug].astro
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
import { SectionGridContainer, Avatar } from '@components'
import AuthorsByline from '@components/AuthorsByline'
import BaseLayout from '@layouts/BaseLayout.astro'
import { getEntry, getCollection } from 'astro:content'
import type { CollectionEntry } from 'astro:content'
Expand Down Expand Up @@ -96,33 +97,7 @@ const schema = {
{teaser}
</p>

{
Boolean(authors.length) && (
<p class='text-lg font-medium pt-4'>
Von
<Avatar
jpgSrc={authors[0]?.data.image.default}
webpSrc={authors[0]?.data.image.webp}
alt={authors[0]?.data.image.alt}
small
/>{' '}
{authors[0].data.firstName + ' ' + authors[0].data.lastName}
{authors.length > 1 && (
<>
{' '}
&
<Avatar
jpgSrc={authors[1]?.data.image.default}
webpSrc={authors[1]?.data.image.webp}
alt={authors[1]?.data.image.alt}
small
/>{' '}
{authors[1].data.firstName + ' ' + authors[1].data.lastName}
</>
)}
</p>
)
}
{Boolean(authors.length) && <AuthorsByline authors={authors} />}
<div class='pb-12'>
{
!!date && (
Expand Down
52 changes: 40 additions & 12 deletions src/pages/blog/index.astro
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
---
import BaseLayout from '@layouts/BaseLayout.astro'
import { Card, SectionGridContainer, SectionMark } from '@components'
import { getCollection } from 'astro:content'
import { getCollection, getEntry, type CollectionEntry } from 'astro:content'
import BbBracket from '@assets/bb_bracket.svg?react'
const contentSortedByDate = (await getCollection('blog')).sort(
(postA, postB) => postB?.data?.date?.getTime() - postA?.data?.date?.getTime(),
)
const [firstPost, ...restPosts] = contentSortedByDate
const firstPostAuthor = await getEntry(
firstPost.data.authors[0].collection,
firstPost.data.authors[0].id,
)
---

<BaseLayout
Expand All @@ -28,17 +33,24 @@ const [firstPost, ...restPosts] = contentSortedByDate
subtitle={firstPost.data.subtitle}
href={'/blog/' + firstPost.slug + '/'}
teaser={firstPost.data.teaser}
date={firstPost.data.date.toLocaleDateString('de-DE', {
year: 'numeric',
month: 'long',
})}
author={firstPostAuthor}
className='order-2 lg:order-1 col-span-1 lg:col-start-2 lg:col-span-4 px-5 lg:px-0'
showButton
/>
<div
<a
class='order-1 lg:order-2 lg:col-start-7 col-span-1 lg:col-span-8 lg:h-[28rem] overflow-hidden lg:-mb-32'
href={'/blog/' + firstPost.slug + '/'}
>
<img
src={firstPost.data.image.url}
alt={firstPost.data.image.alt}
class='w-full h-auto object-cover'
/>
</div>
</a>
</SectionGridContainer>

<SectionGridContainer className='pt-16 lg:pt-48 pb-16' innerClassName='px-5 lg:px-0'>
Expand All @@ -51,15 +63,31 @@ const [firstPost, ...restPosts] = contentSortedByDate
</div>
<div class='col-span-1 lg:col-span-8 grid grid-cols-1 lg:grid-cols-2 gap-x-6 gap-y-16'>
{
restPosts.map((post) => (
<Card
title={post.data.title}
subtitle={post.data.subtitle}
img={post.data.image.url}
imgAlt={post.data.image.alt}
href={'/blog/' + post.slug + '/'}
/>
))
restPosts.map(async (post) => {
let authors = []

for (const author of post.data.authors) {
const authorObj = await getEntry(author.collection, author.id)
if (authorObj) {
authors.push(authorObj)
}
}

return (
<Card
title={post.data.title}
subtitle={post.data.subtitle}
img={post.data.image.url}
imgAlt={post.data.image.alt}
href={'/blog/' + post.slug + '/'}
date={post.data.date.toLocaleDateString('de-DE', {
year: 'numeric',
month: 'long',
})}
author={authors[0]}
/>
)
})
}
</div>
</SectionGridContainer>
Expand Down

0 comments on commit 5a76a5b

Please sign in to comment.