feat(components): extract and reuse ProjectCard for cleaner project showcases

- Created `ProjectCard` component to unify and streamline project card presentation.
- Updated `index.astro`, `projects.astro`, and `zh/projects.astro` to use `ProjectCard` for improved maintainability and consistency.
- Simplified layout and removed duplicate styles across pages.
This commit is contained in:
zguiyang
2026-03-14 11:41:45 +08:00
parent 32954cf69a
commit 2474d51e1b
4 changed files with 132 additions and 161 deletions

View File

@@ -3,6 +3,7 @@ import Layout from "@/layouts/Layout.astro";
import GlassHeader from "@/components/GlassHeader";
import Footer from "@/components/Footer";
import Container from "@/components/ui/Container.astro";
import ProjectCard from "@/components/ProjectCard.astro";
import { useTranslations } from "@/i18n/utils";
import type { Lang } from "@/types/i18n";
import { defaultLang } from "@/i18n/ui";
@@ -206,52 +207,9 @@ const keyFacts = [
<h2 class="text-4xl font-bold tracking-tight sm:text-5xl">{t("home.featured.title")}</h2>
</div>
<div class="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
<div class="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
{featuredProjects.map((project) => (
<article class="group flex flex-col overflow-hidden rounded-3xl border border-border/50 bg-card/50 backdrop-blur-sm transition-all duration-500 hover:-translate-y-2 hover:shadow-2xl hover:shadow-primary/5">
{/* 顶部封面图区域 */}
<div class="relative aspect-video overflow-hidden">
<div class={`absolute inset-0 bg-gradient-to-br ${project.image?.bg || 'from-primary/20 to-purple-500/20'} transition-transform duration-700 group-hover:scale-110`}></div>
<div class="absolute inset-0 flex items-center justify-center">
<span class="text-6xl transition-transform duration-500 group-hover:scale-110 group-hover:rotate-3">{project.icon}</span>
</div>
<div class="absolute top-4 right-4">
<span class="rounded-full bg-background/80 px-3 py-1 text-[10px] font-bold uppercase tracking-wider text-foreground backdrop-blur-md">
{project.type}
</span>
</div>
</div>
{/* 内容区域 */}
<div class="flex flex-1 flex-col p-6 lg:p-8">
<div class="flex-1 space-y-4">
<h3 class="text-2xl font-bold tracking-tight">{project.title}</h3>
<p class="line-clamp-2 text-sm leading-relaxed text-muted-foreground">
{project.impact}
</p>
<div class="flex flex-wrap gap-2">
{project.tech.map((tech) => (
<span class="rounded-md bg-primary/5 px-2 py-1 text-[10px] font-medium text-primary/80">
{tech}
</span>
))}
</div>
</div>
{/* 操作按钮 */}
<div class="mt-8 flex items-center justify-between gap-4">
<a href={`${prefix}/projects`} class="inline-flex h-10 items-center justify-center rounded-full bg-primary px-6 text-xs font-bold text-primary-foreground transition-all hover:bg-primary/90">
{t("home.featured.ctaPrimary")}
</a>
{project.links?.github && (
<a href={project.links.github} target="_blank" rel="noopener noreferrer" class="inline-flex h-10 w-10 items-center justify-center rounded-full border border-border bg-background/50 text-muted-foreground transition-all hover:bg-muted hover:text-foreground">
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 4.125 9.642 9.807 11.53 0.6.111 0.799-0.26 0.799-0.577 0-0.285-0.011-1.04-0.017-2.042-3.338 0.727-4.042-1.61-4.042-1.61-0.546-1.387-1.333-1.756-1.333-1.756-1.089-0.745 0.083-0.729 0.083-0.729 1.205 0.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492 0.997 0.107-0.775 0.418-1.305 0.762-1.604-2.665-0.305-5.467-1.334-5.467-5.931 0-1.311 0.469-2.381 1.236-3.221-0.124-0.303-0.535-1.524 0.117-3.176 0 0 1.008-0.322 3.301 1.23 0.96-0.267 1.98-0.399 3-0.405 1.02 0.006 2.04 0.138 3 0.405 2.28-1.552 3.285-1.23 3.285-1.23 0.654 1.653 0.242 2.874 0.118 3.176 0.77 0.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921 0.43 0.372 0.823 1.102 0.823 2.222 0 1.606-0.014 2.898-0.014 3.293 0 0.319 0.192 0.694 0.801 0.576 5.687-1.889 9.812-6.228 9.812-11.53 0-6.627-5.373-12-12-12z"/></svg>
</a>
)}
</div>
</div>
</article>
<ProjectCard project={project} lang={lang} />
))}
</div>
</Container>