69 lines
2.5 KiB
Text
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>
|