"use client"; import { useEffect, useMemo, useState } from "react"; import { motion } from "framer-motion"; import { ExternalLink, Github, Calendar, ArrowLeft, Search } from "lucide-react"; import Link from "next/link"; export type ProjectListItem = { id: number; slug: string; title: string; description: string; content: string; tags: string[]; featured: boolean; category: string; date: string; github?: string | null; live?: string | null; imageUrl?: string | null; }; export default function ProjectsPageClient({ projects, locale, }: { projects: ProjectListItem[]; locale: string; }) { const [selectedCategory, setSelectedCategory] = useState("All"); const [searchQuery, setSearchQuery] = useState(""); const [mounted, setMounted] = useState(false); useEffect(() => { setMounted(true); }, []); const categories = useMemo(() => { const unique = Array.from(new Set(projects.map((p) => p.category))).filter(Boolean); return ["All", ...unique]; }, [projects]); const filteredProjects = useMemo(() => { let result = projects; if (selectedCategory !== "All") { result = result.filter((project) => project.category === selectedCategory); } if (searchQuery) { const query = searchQuery.toLowerCase(); result = result.filter( (project) => project.title.toLowerCase().includes(query) || project.description.toLowerCase().includes(query) || project.tags.some((tag) => tag.toLowerCase().includes(query)), ); } return result; }, [projects, selectedCategory, searchQuery]); if (!mounted) return null; return (
{/* Header */} Back to Home

My Projects

Explore my portfolio of projects, from web applications to mobile apps. Each project showcases different skills and technologies.

{/* Filters & Search */} {/* Categories */}
{categories.map((category) => ( ))}
{/* Search */}
setSearchQuery(e.target.value)} className="w-full pl-10 pr-4 py-2 bg-white border border-stone-200 rounded-full text-stone-800 placeholder:text-stone-400 focus:outline-none focus:ring-2 focus:ring-stone-200 focus:border-stone-400 transition-all" />
{/* Projects Grid */}
{filteredProjects.map((project, index) => ( {/* Image / Fallback / Cover Area */}
{project.imageUrl ? ( <> {/* eslint-disable-next-line @next/next/no-img-element */} {project.title}
) : (
{project.title.charAt(0)}
)} {/* Texture/Grain Overlay */}
{/* Animated Shine Effect */}
{project.featured && (
Featured
)} {/* Overlay Links */}
{project.github && ( e.stopPropagation()} > )} {project.live && !project.title.toLowerCase().includes("kernel panic") && ( e.stopPropagation()} > )}
{/* Stretched Link covering the whole card (including image area) */}

{project.title}

{new Date(project.date).getFullYear()}

{project.description}

{project.tags.slice(0, 4).map((tag) => ( {tag} ))} {project.tags.length > 4 && ( + {project.tags.length - 4} )}
{project.github && ( e.stopPropagation()} > )} {project.live && !project.title.toLowerCase().includes("kernel panic") && ( e.stopPropagation()} > )}
))}
{filteredProjects.length === 0 && (

No projects found matching your criteria.

)}
); }