schmelczer-dev/src/components/ProjectList.astro

69 lines
2.5 KiB
Text

---
import type { CollectionEntry } from 'astro:content';
import { getEntry } from 'astro:content';
import EntryThumbnail from './EntryThumbnail.astro';
import ProjectLinks from './ProjectLinks.astro';
import { PROJECT_THUMBNAIL, articlePath, entrySlug } from '../lib/site';
interface Props {
projects: CollectionEntry<'projects'>[];
// Opt-in: eagerly load the first thumbnail. Only set when the list is
// reliably above the fold. The home and projects-index lists sit below
// other sections, so leave this off there.
eagerFirstThumbnail?: boolean;
}
const { projects, eagerFirstThumbnail = false } = Astro.props;
// The `essay` field is a `reference('posts')`, so when present it's always a
// `{ collection, id }` shape that `getEntry` resolves to a CollectionEntry.
const essayHrefs = new Map<string, string>();
for (const project of projects) {
const essay = project.data.essay;
if (!essay) continue;
const resolved = await getEntry(essay);
if (resolved) essayHrefs.set(project.id, articlePath(resolved));
}
---
<ol class="project-list">
{
projects.map((project, index) => {
const anchor = entrySlug(project);
const titleId = `${anchor}-title`;
const essayHref = essayHrefs.get(project.id);
const primaryHref = essayHref ?? project.data.links[0]?.url;
return (
<li class="project-card" id={anchor}>
<EntryThumbnail
src={project.data.thumbnail.src}
alt={project.data.thumbnail.alt}
href={primaryHref}
class="project-thumbnail"
widths={PROJECT_THUMBNAIL.widths}
sizes={PROJECT_THUMBNAIL.sizes}
ariaLabel={`Open project: ${project.data.title}`}
loading={eagerFirstThumbnail && index === 0 ? 'eager' : 'lazy'}
fetchpriority={eagerFirstThumbnail && index === 0 ? 'high' : undefined}
/>
<article class="project-card__summary">
<h3 id={titleId}>
{primaryHref ? (
<a href={primaryHref}>{project.data.title}</a>
) : (
project.data.title
)}
{essayHref && <span class="project-essay-badge">Article</span>}
</h3>
<p class="project-description">{project.data.description}</p>
<p class="project-meta">
{project.data.period} · {project.data.technologies.join(', ')}
</p>
{project.data.links.length > 0 && <ProjectLinks links={project.data.links} />}
</article>
</li>
);
})
}
</ol>