Files
portfolio/src/components/ProjectCard.tsx
lerko96 ea63347cd6 migrate CRA to Next.js 16 + React 19 + TypeScript + Tailwind v4
- replace CRA scaffold with Next.js static export config
- add app router pages: home, homelab, archive
- add components: Nav, Footer, Hero, Skills, ProjectCard, ThemeScript
- add ThemeContext for dark mode with FOUC prevention
- add data layer: projects.ts, services.ts
- update .gitignore for Next.js (ignore .next/, out/, next-env.d.ts)
- add docs: handoff plan, homelab decisions, style reference
2026-04-10 18:46:19 -04:00

70 lines
2.3 KiB
TypeScript

import type { Project } from "@/data/projects";
type Props = {
project: Project;
reversed?: boolean;
};
export default function ProjectCard({ project, reversed = false }: Props) {
return (
<article className={`group flex flex-col ${reversed ? "sm:flex-row-reverse" : "sm:flex-row"} gap-6 mb-16`}>
{/* Gradient image tile */}
<a
href={project.githubUrl}
target="_blank"
rel="noopener noreferrer"
className="shrink-0 sm:w-56 h-36 rounded-lg overflow-hidden"
aria-label={`View ${project.title} on GitHub`}
tabIndex={-1}
>
<div
className={`w-full h-full bg-gradient-to-br ${project.gradient} flex items-center justify-center transition-transform duration-300 group-hover:scale-105`}
>
<span className="font-mono text-xs text-[var(--color-green)] opacity-60 tracking-widest">
{project.slug}
</span>
</div>
</a>
{/* Content */}
<div className={`flex flex-col justify-center gap-3 ${reversed ? "sm:text-right sm:items-end" : ""}`}>
{/* Animated accent bar */}
<div
className={`h-0.5 w-8 bg-[var(--color-grey-1)] rounded-full transition-all duration-300 group-hover:w-16 group-hover:bg-[var(--color-green-darker)] ${reversed ? "self-end" : ""}`}
/>
<div>
<a
href={project.githubUrl}
target="_blank"
rel="noopener noreferrer"
className="font-mono text-base font-semibold text-[var(--color-text-light)] hover:text-[var(--color-green)] transition-colors"
>
{project.title}
</a>
{project.stats && (
<span className="font-mono text-xs text-[var(--color-green)] ml-3 opacity-70">
{project.stats}
</span>
)}
</div>
<p className="text-sm text-[var(--color-grey-3)] leading-relaxed max-w-md">
{project.description}
</p>
<div className={`flex flex-wrap gap-2 ${reversed ? "justify-end" : ""}`}>
{project.tags.map((tag) => (
<span
key={tag}
className="font-mono text-xs px-2 py-0.5 border border-[var(--color-grey-1)] text-[var(--color-grey-2)] rounded"
>
{tag}
</span>
))}
</div>
</div>
</article>
);
}