44497619fc
This commit organizes import statements and standardizes code formatting across the Blog, BlogArticle, ProjectDetails, and Projects pages. Improvements include consistent spacing, use of double quotes, and more readable conditional rendering, contributing to better maintainability and readability of the codebase.
241 lines
8.8 KiB
TypeScript
241 lines
8.8 KiB
TypeScript
import PageTransition from "@/components/PageTransition";
|
|
import { Button } from "@/components/ui/button";
|
|
import { useProjects } from "@/hooks/queires/useProjects";
|
|
import { AnimatePresence, motion } from "framer-motion";
|
|
import {
|
|
ArrowLeft,
|
|
Brain,
|
|
Cloud,
|
|
ExternalLink,
|
|
Github,
|
|
Globe,
|
|
Smartphone,
|
|
Workflow,
|
|
} from "lucide-react";
|
|
import { useState } from "react";
|
|
import { Link } from "react-router-dom";
|
|
|
|
const categories = [
|
|
{ id: "all", name: "All Projects", icon: null },
|
|
{ id: "web", name: "Web", icon: Globe },
|
|
{ id: "mobile", name: "Mobile", icon: Smartphone },
|
|
{ id: "ai", name: "AI", icon: Brain },
|
|
{ id: "cloud", name: "Cloud", icon: Cloud },
|
|
{ id: "devops", name: "DEVOPS", icon: Workflow },
|
|
];
|
|
|
|
const containerVariants = {
|
|
hidden: { opacity: 0 },
|
|
visible: {
|
|
opacity: 1,
|
|
transition: {
|
|
staggerChildren: 0.1,
|
|
},
|
|
},
|
|
};
|
|
|
|
const itemVariants = {
|
|
hidden: { opacity: 0, y: 30 },
|
|
visible: {
|
|
opacity: 1,
|
|
y: 0,
|
|
transition: { duration: 0.5, ease: "easeOut" as const },
|
|
},
|
|
};
|
|
|
|
export default function Projects() {
|
|
const { data: projectsData } = useProjects();
|
|
const projects = projectsData?.data.data.result;
|
|
|
|
const [activeCategory, setActiveCategory] = useState("all");
|
|
|
|
const filteredProjects =
|
|
activeCategory === "all"
|
|
? projects
|
|
: projects?.filter((project) => project.category === activeCategory);
|
|
|
|
return (
|
|
<PageTransition>
|
|
<div className="min-h-screen bg-background overflow-x-hidden">
|
|
{/* Hero Section */}
|
|
<section className="pt-32 pb-16 relative overflow-hidden">
|
|
<div className="absolute inset-0">
|
|
<div className="absolute top-1/4 left-1/4 w-96 h-96 bg-primary/20 rounded-full blur-3xl" />
|
|
<div className="absolute bottom-0 right-1/4 w-64 h-64 bg-neon-purple/20 rounded-full blur-3xl" />
|
|
</div>
|
|
|
|
<div className="container mx-auto px-4 relative z-10">
|
|
{/* Back Button */}
|
|
<motion.div
|
|
initial={{ opacity: 0, x: -20 }}
|
|
animate={{ opacity: 1, x: 0 }}
|
|
transition={{ duration: 0.5 }}
|
|
>
|
|
<Link to="/">
|
|
<Button variant="ghost" className="mb-8 group">
|
|
<ArrowLeft className="w-4 h-4 mr-2 transition-transform group-hover:-translate-x-1" />
|
|
Back to Home
|
|
</Button>
|
|
</Link>
|
|
</motion.div>
|
|
|
|
{/* Header */}
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.6 }}
|
|
className="text-center mb-12"
|
|
>
|
|
<h1 className="text-5xl md:text-6xl font-bold mb-6">
|
|
Our{" "}
|
|
<span className="text-primary neon-text-glow">Projects</span>
|
|
</h1>
|
|
<p className="text-muted-foreground max-w-2xl mx-auto text-lg">
|
|
Explore our portfolio of innovative solutions that have
|
|
transformed businesses across industries.
|
|
</p>
|
|
</motion.div>
|
|
|
|
{/* Filter Tabs */}
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.6, delay: 0.2 }}
|
|
className="flex flex-wrap justify-center gap-3 mb-16"
|
|
>
|
|
{categories?.map((category) => {
|
|
const Icon = category.icon;
|
|
return (
|
|
<Button
|
|
key={category.id}
|
|
variant={
|
|
activeCategory === category.id ? "default" : "outline"
|
|
}
|
|
onClick={() => setActiveCategory(category.id)}
|
|
className={`rounded-full px-6 transition-all duration-300 ${
|
|
activeCategory === category.id
|
|
? "neon-glow bg-primary text-primary-foreground"
|
|
: "glass border-primary/30 hover:border-primary"
|
|
}`}
|
|
>
|
|
{Icon && <Icon className="w-4 h-4 mr-2" />}
|
|
{category.name}
|
|
</Button>
|
|
);
|
|
})}
|
|
</motion.div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Projects Grid */}
|
|
<section className="pb-24">
|
|
<div className="container mx-auto px-4">
|
|
<AnimatePresence mode="wait">
|
|
<motion.div
|
|
key={activeCategory}
|
|
variants={containerVariants}
|
|
initial="hidden"
|
|
animate="visible"
|
|
exit="hidden"
|
|
className="grid md:grid-cols-2 gap-8"
|
|
>
|
|
{filteredProjects?.map((project) => (
|
|
<motion.article
|
|
key={project._id}
|
|
variants={itemVariants}
|
|
layout
|
|
className="group glass rounded-3xl overflow-hidden hover:neon-glow transition-all duration-500"
|
|
>
|
|
{/* Image */}
|
|
<div className="relative h-64 overflow-hidden">
|
|
<img
|
|
src={project.image}
|
|
alt={project.title}
|
|
className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110"
|
|
/>
|
|
<div className="absolute inset-0 bg-gradient-to-t from-background via-background/50 to-transparent opacity-60" />
|
|
|
|
{/* Category Badge */}
|
|
<div className="absolute top-4 left-4">
|
|
<span className="px-3 py-1 rounded-full bg-primary/20 text-primary text-sm font-medium backdrop-blur-sm border border-primary/30">
|
|
{
|
|
categories.find((c) => c.id === project.category)
|
|
?.name
|
|
}
|
|
</span>
|
|
</div>
|
|
|
|
{/* Quick Links */}
|
|
<div className="absolute top-4 right-4 flex gap-2 opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
|
<a
|
|
href={project.liveUrl}
|
|
className="p-2 rounded-full glass hover:bg-primary/20 transition-colors"
|
|
aria-label="View live project"
|
|
>
|
|
<ExternalLink className="w-4 h-4" />
|
|
</a>
|
|
<a
|
|
href={project.githubUrl}
|
|
className="p-2 rounded-full glass hover:bg-primary/20 transition-colors"
|
|
aria-label="View on GitHub"
|
|
>
|
|
<Github className="w-4 h-4" />
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Content */}
|
|
<div className="p-8">
|
|
{/* Meta */}
|
|
<div className="flex items-center gap-4 text-sm text-muted-foreground mb-4">
|
|
<span>{project.client}</span>
|
|
<span className="w-1 h-1 rounded-full bg-muted-foreground" />
|
|
<span>{project.year}</span>
|
|
</div>
|
|
|
|
{/* Title */}
|
|
<h3 className="text-2xl font-bold mb-4 group-hover:text-primary transition-colors">
|
|
{project.title}
|
|
</h3>
|
|
|
|
{/* Description */}
|
|
<p className="text-muted-foreground mb-6 leading-relaxed">
|
|
{project.description}
|
|
</p>
|
|
|
|
{/* Technologies */}
|
|
<div className="flex flex-wrap gap-2">
|
|
{project?.technologies.map((tech) => (
|
|
<span
|
|
key={tech}
|
|
className="px-3 py-1 rounded-full bg-muted text-muted-foreground text-xs font-medium"
|
|
>
|
|
{tech}
|
|
</span>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</motion.article>
|
|
))}
|
|
</motion.div>
|
|
</AnimatePresence>
|
|
|
|
{/* Empty State */}
|
|
{filteredProjects?.length === 0 && (
|
|
<motion.div
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
className="text-center py-20"
|
|
>
|
|
<p className="text-muted-foreground text-lg">
|
|
No projects found in this category.
|
|
</p>
|
|
</motion.div>
|
|
)}
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</PageTransition>
|
|
);
|
|
}
|