83 lines
3.4 KiB
TypeScript
83 lines
3.4 KiB
TypeScript
import React from 'react';
|
|
import { ProjectItem, Language } from '../types';
|
|
import { ExternalLink, Code, Gamepad2, Car, BarChart3 } from 'lucide-react';
|
|
|
|
interface Props {
|
|
project: ProjectItem;
|
|
lang: Language;
|
|
}
|
|
|
|
const ProjectCard: React.FC<Props> = ({ project, lang }) => {
|
|
// Select a placeholder icon fallback
|
|
const getIcon = () => {
|
|
switch (project.imageType) {
|
|
case 'car': return <Car size={32} className="text-white opacity-80" />;
|
|
case 'game': return <Gamepad2 size={32} className="text-white opacity-80" />;
|
|
case 'chart': return <BarChart3 size={32} className="text-white opacity-80" />;
|
|
default: return <Code size={32} className="text-white opacity-80" />;
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="group bg-white rounded-2xl overflow-hidden shadow-md hover:shadow-2xl transition-all duration-300 border border-slate-100 flex flex-col h-full transform hover:-translate-y-1">
|
|
{/* Image Area - Increased height for "Rich" feel */}
|
|
<div className="relative h-64 w-full overflow-hidden bg-slate-900">
|
|
{project.imageUrl ? (
|
|
<img
|
|
src={project.imageUrl}
|
|
alt={project.title[lang]}
|
|
className="w-full h-full object-cover transform group-hover:scale-110 transition-transform duration-700 ease-out"
|
|
loading="lazy"
|
|
/>
|
|
) : (
|
|
<div className="w-full h-full flex items-center justify-center bg-gradient-to-br from-slate-800 to-indigo-900">
|
|
{getIcon()}
|
|
</div>
|
|
)}
|
|
|
|
{/* Dark Gradient Overlay for text readability at bottom */}
|
|
<div className="absolute inset-0 bg-gradient-to-t from-slate-900/80 via-transparent to-transparent opacity-60"></div>
|
|
|
|
{/* Type badge */}
|
|
<div className="absolute top-4 right-4 bg-white/10 backdrop-blur-md px-3 py-1 rounded-full border border-white/20 shadow-sm">
|
|
<span className="text-xs font-bold text-white tracking-wide uppercase">
|
|
{project.imageType || 'Dev'}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Content Area */}
|
|
<div className="p-6 md:p-8 flex-1 flex flex-col">
|
|
<h3 className="text-xl md:text-2xl font-bold text-slate-800 mb-3 group-hover:text-indigo-600 transition-colors">
|
|
{project.title[lang]}
|
|
</h3>
|
|
<p className="text-base text-slate-600 leading-relaxed mb-6 flex-1">
|
|
{project.description[lang]}
|
|
</p>
|
|
|
|
<div className="mt-auto pt-6 border-t border-slate-100 flex items-center justify-between">
|
|
<div className="flex gap-2">
|
|
{/* Decorative dots representing tech stack */}
|
|
<div className="h-2 w-2 rounded-full bg-indigo-500"></div>
|
|
<div className="h-2 w-2 rounded-full bg-blue-400"></div>
|
|
<div className="h-2 w-2 rounded-full bg-purple-400"></div>
|
|
</div>
|
|
|
|
{project.link && (
|
|
<a
|
|
href={project.link}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="inline-flex items-center gap-2 text-sm font-bold text-indigo-600 hover:text-indigo-800 transition-colors bg-indigo-50 px-4 py-2 rounded-lg hover:bg-indigo-100"
|
|
>
|
|
{project.linkText ? project.linkText[lang] : (lang === 'en' ? 'View details' : '查看详情')}
|
|
<ExternalLink size={16} />
|
|
</a>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ProjectCard; |