diff --git a/src/app/projects/page.jsx b/src/app/projects/page.jsx index 78d2d5aa..b9a421b0 100644 --- a/src/app/projects/page.jsx +++ b/src/app/projects/page.jsx @@ -1,5 +1,6 @@ 'use client' +import { useState, useMemo } from 'react' import Link from 'next/link' import Grid from '@mui/material/Grid' import MuiCard from '@mui/material/Card' @@ -15,7 +16,8 @@ import projects from '@/helper/projects' import { CardProduct } from '@/components/products/CardProduct' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faDiscord, faGithub } from '@fortawesome/free-brands-svg-icons' -import { motion } from 'framer-motion' +import { faSearch } from '@fortawesome/free-solid-svg-icons' +import { motion, AnimatePresence } from 'framer-motion' function LinkIcon(props) { return ( @@ -168,6 +170,8 @@ const styles = { } export default function Projects() { + const [searchQuery, setSearchQuery] = useState('') + const readyToDownload = projects.filter( (p) => p.category === 'Ready to download' ) @@ -176,9 +180,20 @@ export default function Projects() { ) const ongoing = projects.filter((p) => p.category === 'Ongoing') - const sortedProjects = [...projects].sort((a, b) => - (a.name || '').localeCompare(b.name || '', undefined, { sensitivity: 'base' }) - ) + const sortedProjects = useMemo(() => { + return [...projects].sort((a, b) => + (a.name || '').localeCompare(b.name || '', undefined, { sensitivity: 'base' }) + ) + }, []) + + const filteredProjects = useMemo(() => { + const query = searchQuery.toLowerCase().trim() + if (!query) return sortedProjects + + return sortedProjects.filter((project) => + (project.name || '').toLowerCase().includes(query) + ) + }, [searchQuery, sortedProjects]) return ( <> @@ -202,12 +217,56 @@ export default function Projects() { Free, open-source, and built by a global community of developers, designers, researchers, and innovators.

+ + {/* Search Bar */} +
+
+ +
+ +
+ setSearchQuery(e.target.value)} + /> +
+
+

+ {filteredProjects.length === 0 + ? `No projects found matching ${searchQuery.trim()}.` + : `${filteredProjects.length} project${filteredProjects.length === 1 ? '' : 's'} shown.`} +

- {sortedProjects.map((product) => ( - - ))} + + {filteredProjects.map((product) => ( + + + + ))} + + {filteredProjects.length === 0 && ( +
+

+ No projects found matching "{searchQuery}" +

+
+ )}
{/*