Files
com.gregkilmer.www/src/components/professional/ProjectCard.astro
T
2026-07-04 07:42:24 -04:00

80 lines
2.5 KiB
Plaintext

---
/**
* ProjectCard.astro
* ---------------------------------------------------------------------------
* Card for a single project entry from the `projects` collection. Renders title,
* role, tech pills, summary, and links (repo/demo/case study). Placeholder
* entries (frontmatter `placeholder: true`) get a subtle badge so they read as
* "to be filled" rather than real work, per the chosen content approach.
*/
import { type CollectionEntry } from 'astro:content';
import Icon from '@components/Icon.astro';
interface Props {
project: CollectionEntry<'projects'>;
}
const { project } = Astro.props;
const d = project.data;
const links = [
d.repo && { href: d.repo, label: 'GitHub', icon: 'github' },
d.demo && { href: d.demo, label: 'Live demo', icon: 'open-in-new' },
d.caseStudy && { href: d.caseStudy, label: 'Case study', icon: 'file-document-outline' },
].filter(Boolean) as { href: string; label: string; icon: string }[];
---
<article
class:list={[
'card card-interactive flex h-full flex-col gap-4',
d.placeholder && 'border-dashed',
]}
style={d.placeholder ? 'border-color: color-mix(in srgb, var(--color-accent) 45%, transparent);' : ''}
>
<div class="flex items-start justify-between gap-3">
<div class="flex flex-col gap-1">
<h3 style="color: var(--color-text);">{d.title}</h3>
<p class="font-mono text-xs uppercase tracking-[0.18em]" style="color: var(--color-text-subtle);">
{d.role}
</p>
</div>
{d.placeholder && (
<span
class="pill"
style="background: color-mix(in srgb, var(--color-accent) 18%, transparent); color: var(--color-accent);"
>
<Icon name="pencil" class="h-3.5 w-3.5" />
Placeholder
</span>
)}
</div>
{d.tech.length > 0 && (
<ul class="flex flex-wrap gap-2">
{d.tech.map((t) => <li class="pill">{t}</li>)}
</ul>
)}
<p class="grow text-sm leading-relaxed" style="color: var(--color-text-muted);">
{d.summary}
</p>
{links.length > 0 && (
<ul class="mt-1 flex flex-wrap gap-4">
{links.map((l) => (
<li>
<a
href={l.href}
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center gap-1.5 font-sans text-sm font-semibold transition-colors"
style="color: var(--color-accent);"
>
<Icon name={l.icon} class="h-4 w-4" />
{l.label}
</a>
</li>
))}
</ul>
)}
</article>