mirror of
https://github.com/Patiun/com.gregkilmer.www.git
synced 2026-11-08 04:08:24 +00:00
80 lines
2.5 KiB
Plaintext
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>
|