personal-homepage/src/components/ProjectCard.astro

87 lines
2.1 KiB
Plaintext

---
import { site } from '../config';
import type { ProjectDownload } from '../data/loaders';
interface Props {
name: string;
description: string;
coverImage: string;
tags: string[];
repo: string;
repoUrl?: string;
featured?: boolean;
demoVideo?: string;
downloadLink?: string;
downloads?: ProjectDownload[];
}
const {
name,
description,
coverImage,
tags,
repo,
repoUrl,
featured = false,
demoVideo = '',
downloadLink = '',
downloads = [],
} = Astro.props;
const fallbackRepoUrl = repo ? `${site.gitea.url}/${repo}` : '';
const resolvedRepoUrl = repoUrl || fallbackRepoUrl;
const visibleDownloads = downloads.filter((item) => item.name || item.url);
---
<article class="card">
<div class="project-cover">
<img src={coverImage} alt={`${name} 项目封面`} loading="lazy" />
</div>
<div class="project-meta">
<span class="mono">{repo}</span>
{featured ? <span class="tag">featured</span> : null}
</div>
<h3 class="project-title">{name}</h3>
<p class="project-description">{description}</p>
<div class="tag-list" style="margin: 1rem 0 0.95rem;">
{tags.map((tag) => <span class="tag tag--tech">{tag}</span>)}
</div>
<div class="project-links">
{resolvedRepoUrl ? (
<a class="section-link" href={resolvedRepoUrl} target="_blank" rel="noreferrer">
仓库
</a>
) : null}
{demoVideo ? (
<a class="section-link" href={demoVideo} target="_blank" rel="noreferrer">
Demo
</a>
) : null}
{downloadLink && visibleDownloads.length === 0 ? (
<a class="section-link" href={downloadLink} target="_blank" rel="noreferrer">
下载
</a>
) : null}
</div>
{
visibleDownloads.length > 0 ? (
<div class="project-links" style="margin-top: 0.75rem; flex-wrap: wrap; gap: 0.6rem 0.8rem;">
{visibleDownloads.map((item) =>
item.url ? (
<a class="section-link" href={item.url} target="_blank" rel="noreferrer">
{item.name}
</a>
) : (
<span class="tag">{item.name}</span>
),
)}
</div>
) : null
}
</article>