c95db3a044
- the plate carries project colour on the lead image, in the cards and in every row, not only when an entry lacks an image - entries no longer fade in one after another, the page is readable at once - detail pages lead on: previous, next and more from the project - the month band shows from the first month, the nav item hides without one - side cards and row teasers get room instead of ellipsis - admin opens on drafts, scheduled and published plus what was edited last, and its tables use the full width
84 lines
2.7 KiB
TypeScript
84 lines
2.7 KiB
TypeScript
import Link from 'next/link'
|
|
import { useTranslations } from 'next-intl'
|
|
import { Badge } from '~/components/ui/Badge'
|
|
import { Cover, type CoverMedia } from '~/components/ui/Cover'
|
|
import { EntryDate } from '~/components/ui/EntryDate'
|
|
import { Plate, projectStyle } from '~/components/ui/Plate'
|
|
import { SectionLabel } from '~/components/ui/SectionLabel'
|
|
import { postPath } from '~/lib/routes'
|
|
import type { PostListItem } from '~/data/repositories/posts'
|
|
|
|
export type SideEntriesProps = {
|
|
items: PostListItem[]
|
|
covers?: Map<string, CoverMedia>
|
|
label?: string
|
|
layout?: 'column' | 'grid'
|
|
className?: string
|
|
}
|
|
|
|
const coverSizes = '(min-width: 64rem) 22rem, 40vw'
|
|
|
|
export function SideEntries({ items, covers, label, layout = 'column', className }: SideEntriesProps) {
|
|
const t = useTranslations('entry')
|
|
|
|
if (items.length === 0) {
|
|
return null
|
|
}
|
|
|
|
return (
|
|
<aside className={`flex flex-col gap-3 ${className ?? ''}`}>
|
|
<SectionLabel as="h3">{label ?? t('next')}</SectionLabel>
|
|
<ul className={`m-0 grid list-none gap-3 p-0 ${layout === 'grid' ? 'md:grid-cols-3' : 'md:grid-cols-2 lg:grid-cols-1'}`}>
|
|
{items.map(item => {
|
|
const source = { code: item.projectCode, slug: item.projectSlug }
|
|
|
|
return (
|
|
<li key={item.id}>
|
|
<Link
|
|
href={postPath(item.projectSlug, item.slug)}
|
|
style={projectStyle(item.projectColor)}
|
|
className="group flex flex-col gap-2 border border-rule bg-surface p-3 no-underline transition-colors duration-120 hover:border-ink-3 motion-reduce:transition-none"
|
|
>
|
|
<Cover
|
|
media={covers?.get(item.id)}
|
|
sizes={coverSizes}
|
|
className="aspect-shot w-full"
|
|
fallback={
|
|
<Plate
|
|
project={source}
|
|
color={item.projectColor}
|
|
number={item.number}
|
|
size="card"
|
|
className="w-full"
|
|
/>
|
|
}
|
|
/>
|
|
<span className="flex min-w-0 flex-col gap-1.5">
|
|
<span className="flex flex-wrap items-center gap-x-3 gap-y-1">
|
|
<Plate
|
|
project={source}
|
|
color={item.projectColor}
|
|
number={item.number}
|
|
size="row"
|
|
/>
|
|
<Badge type={item.type} />
|
|
</span>
|
|
<span className="font-display text-base font-semibold leading-snug text-balance text-ink">
|
|
{item.title}
|
|
</span>
|
|
{item.teaser ? (
|
|
<span className="line-clamp-2 text-small leading-snug text-ink-2">{item.teaser}</span>
|
|
) : null}
|
|
{item.publishAt ? (
|
|
<EntryDate date={item.publishAt} className="font-mono text-micro text-ink-3" />
|
|
) : null}
|
|
</span>
|
|
</Link>
|
|
</li>
|
|
)
|
|
})}
|
|
</ul>
|
|
</aside>
|
|
)
|
|
}
|