160 lines
4.5 KiB
TypeScript
160 lines
4.5 KiB
TypeScript
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "@/components/ui/card";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Github, ExternalLink, Star } from "lucide-react";
|
|
|
|
interface Project {
|
|
_id: string;
|
|
title: string;
|
|
description: string;
|
|
technologies: string[];
|
|
githubUrl?: string;
|
|
liveUrl?: string;
|
|
featured: boolean;
|
|
}
|
|
|
|
interface ProjectsSectionProps {
|
|
projects: Project[];
|
|
}
|
|
|
|
export function ProjectsSection({ projects }: ProjectsSectionProps) {
|
|
const featuredProjects = projects.filter((p) => p.featured);
|
|
const otherProjects = projects.filter((p) => !p.featured);
|
|
|
|
return (
|
|
<section id="projects" className="py-20 bg-muted/30">
|
|
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<h2 className="text-4xl font-bold text-center mb-16">Projects</h2>
|
|
|
|
{featuredProjects.length > 0 && (
|
|
<div className="mb-16">
|
|
<h3 className="text-2xl font-semibold mb-8 flex items-center">
|
|
<Star className="mr-2 h-6 w-6 text-yellow-500" />
|
|
Featured Projects
|
|
</h3>
|
|
<div className="grid md:grid-cols-2 gap-8">
|
|
{featuredProjects.map((project) => (
|
|
<Card
|
|
key={project._id}
|
|
className="hover:shadow-lg transition-shadow"
|
|
>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center justify-between">
|
|
{project.title}
|
|
<Badge variant="secondary">Featured</Badge>
|
|
</CardTitle>
|
|
<CardDescription className="leading-relaxed">
|
|
{project.description}
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex flex-wrap gap-2 mb-4">
|
|
{project.technologies.map((tech) => (
|
|
<Badge key={tech} variant="outline">
|
|
{tech}
|
|
</Badge>
|
|
))}
|
|
</div>
|
|
<div className="flex gap-2">
|
|
{project.githubUrl && (
|
|
<Button size="sm" variant="outline" asChild>
|
|
<a
|
|
href={project.githubUrl}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
<Github className="mr-2 h-4 w-4" />
|
|
Code
|
|
</a>
|
|
</Button>
|
|
)}
|
|
{project.liveUrl && (
|
|
<Button size="sm" asChild>
|
|
<a
|
|
href={project.liveUrl}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
<ExternalLink className="mr-2 h-4 w-4" />
|
|
Live Demo
|
|
</a>
|
|
</Button>
|
|
)}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{otherProjects.length > 0 && (
|
|
<div>
|
|
<h3 className="text-2xl font-semibold mb-8">Other Projects</h3>
|
|
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
{otherProjects.map((project) => (
|
|
<Card
|
|
key={project._id}
|
|
className="hover:shadow-lg transition-shadow"
|
|
>
|
|
<CardHeader>
|
|
<CardTitle className="text-lg">{project.title}</CardTitle>
|
|
<CardDescription className="text-sm leading-relaxed">
|
|
{project.description}
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex flex-wrap gap-1 mb-4">
|
|
{project.technologies.slice(0, 3).map((tech) => (
|
|
<Badge key={tech} variant="outline" className="text-xs">
|
|
{tech}
|
|
</Badge>
|
|
))}
|
|
{project.technologies.length > 3 && (
|
|
<Badge variant="outline" className="text-xs">
|
|
+{project.technologies.length - 3}
|
|
</Badge>
|
|
)}
|
|
</div>
|
|
<div className="flex gap-2">
|
|
{project.githubUrl && (
|
|
<Button size="sm" variant="outline" asChild>
|
|
<a
|
|
href={project.githubUrl}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
<Github className="mr-1 h-3 w-3" />
|
|
Code
|
|
</a>
|
|
</Button>
|
|
)}
|
|
{project.liveUrl && (
|
|
<Button size="sm" asChild>
|
|
<a
|
|
href={project.liveUrl}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
<ExternalLink className="mr-1 h-3 w-3" />
|
|
Demo
|
|
</a>
|
|
</Button>
|
|
)}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|