Refactor FormattedDate and PostPreview components to include cover image support; enhance blog post display with year markers in pagination

This commit is contained in:
KazooTTT
2025-01-19 22:50:29 +08:00
parent 8c1fbba215
commit 802a051bc4
4 changed files with 40 additions and 16 deletions

View File

@ -1,18 +1,31 @@
--- ---
import type { HTMLAttributes } from 'astro/types' import type { HTMLAttributes } from 'astro/types'
import { getFormattedDate } from '@/utils' interface Props extends HTMLAttributes<'time'> {
type Props = HTMLAttributes<'time'> & {
date: Date date: Date
dateTimeOptions?: Intl.DateTimeFormatOptions coverImage: string
} }
const { date, dateTimeOptions, ...attrs } = Astro.props const { date, coverImage: coverImage, ...attrs } = Astro.props
console.log('coverImage', coverImage)
const postDate = getFormattedDate(date, dateTimeOptions) const formattedDate = date.toISOString().slice(0, 10).replace(/-/g, '')
--- ---
<time datetime={date.toISOString()} {...attrs}> {
{postDate} coverImage ? (
</time> <div class='relative'>
<time datetime={date.toISOString()} {...attrs}>
{formattedDate}
</time>
<img
src={coverImage}
class='absolute left-0 top-0 -z-10 h-full w-full object-cover opacity-10'
/>
</div>
) : (
<time datetime={date.toISOString()} {...attrs}>
{formattedDate}
</time>
)
}

View File

@ -8,14 +8,18 @@ type Props<Tag extends HTMLTag> = Polymorphic<{ as: Tag }> & {
post: CollectionEntry<'post'> post: CollectionEntry<'post'>
prefix?: string prefix?: string
withDesc?: boolean withDesc?: boolean
showYear?: boolean
} }
const { as: Tag = 'div', post, prefix = '/blog/', withDesc = false } = Astro.props const { as: Tag = 'div', post, prefix = '/blog/', withDesc = false, showYear = false } = Astro.props
const postDate = post.data.date const postDate = post.data.date
const year = postDate.getFullYear()
const coverImage = post.data.coverImage
--- ---
{showYear && <h2 class='my-2 text-xl font-semibold'>{year}</h2>}
<li class='flex flex-col gap-2 sm:flex-row sm:gap-x-4 [&_q]:basis-full'> <li class='flex flex-col gap-2 sm:flex-row sm:gap-x-4 [&_q]:basis-full'>
<FormattedDate class='min-w-[120px]' date={postDate} /> <FormattedDate class='min-w-[80px]' date={postDate} coverImage={coverImage} />
<Tag> <Tag>
{post.data.draft && <span class='text-red-500'>(Draft) </span>} {post.data.draft && <span class='text-red-500'>(Draft) </span>}

View File

@ -15,11 +15,10 @@ interface Props {
const { post, simple = false, backHref = '/blog' } = Astro.props const { post, simple = false, backHref = '/blog' } = Astro.props
const { const {
data: { description, ogImage, title, date }, data: { description, ogImage, title, date }
slug
} = post } = post
const socialImage = ogImage ?? `/og-image/${slug}.png` const socialImage = ogImage
const articleDate = date?.toISOString() const articleDate = date?.toISOString()
const { headings } = await post.render() const { headings } = await post.render()
--- ---

View File

@ -53,6 +53,14 @@ const paginationProps = {
} }
}) })
} }
// Group posts by year and mark first post of each year
const postsWithYearMarkers = page.data.map((post, index) => {
const currentYear = post.data.date.getFullYear()
const prevYear = index > 0 ? page.data[index - 1].data.date.getFullYear() : null
const showYear = currentYear !== prevYear
return { post, showYear }
})
--- ---
<PageLayout meta={meta}> <PageLayout meta={meta}>
@ -81,8 +89,8 @@ const paginationProps = {
<div class='grid gap-y-16 sm:grid-cols-[3fr_1fr] sm:gap-x-8'> <div class='grid gap-y-16 sm:grid-cols-[3fr_1fr] sm:gap-x-8'>
<section aria-label='Blog posts list'> <section aria-label='Blog posts list'>
<ul class='flex flex-col gap-y-4 text-start'> <ul class='flex flex-col gap-y-4 text-start'>
{page.data.map((p) => ( {postsWithYearMarkers.map(({ post, showYear }) => (
<PostPreview post={p} /> <PostPreview post={post} showYear={showYear} withDesc={true} />
))} ))}
</ul> </ul>
<Pagination {...paginationProps} /> <Pagination {...paginationProps} />