"use client" import { IconSubmissionContent } from "@/components/icon-submission-form" import { Input } from "@/components/ui/input" import { BASE_URL } from "@/constants" import type { IconSearchProps } from "@/types/icons" import { motion } from "framer-motion" import { Search } from "lucide-react" import Image from "next/image" import Link from "next/link" import { usePathname, useRouter, useSearchParams } from "next/navigation" import { useCallback, useEffect, useRef, useState } from "react" import { useTheme } from "next-themes" import { useInView } from "framer-motion" export function IconSearch({ icons }: IconSearchProps) { const searchParams = useSearchParams() const initialQuery = searchParams.get("q") const router = useRouter() const pathname = usePathname() const [searchQuery, setSearchQuery] = useState(initialQuery ?? "") const timeoutRef = useRef(null) const { resolvedTheme } = useTheme() const [filteredIcons, setFilteredIcons] = useState(() => { if (!initialQuery?.trim()) return icons const q = initialQuery.toLowerCase() return icons.filter(({ name, data }) => { if (name.toLowerCase().includes(q)) return true if (data.aliases.some((alias) => alias.toLowerCase().includes(q))) return true if (data.categories.some((category) => category.toLowerCase().includes(q))) return true return false }) }) const filterIcons = useCallback( (query: string) => { if (!query.trim()) { return icons } const q = query.toLowerCase() return icons.filter(({ name, data }) => { if (name.toLowerCase().includes(q)) return true if (data.aliases.some((alias) => alias.toLowerCase().includes(q))) return true if (data.categories.some((category) => category.toLowerCase().includes(q))) return true return false }) }, [icons], ) const updateResults = useCallback( (query: string) => { setFilteredIcons(filterIcons(query)) const params = new URLSearchParams() if (query) params.set("q", query) const newUrl = query ? `${pathname}?${params.toString()}` : pathname router.push(newUrl, { scroll: false }) }, [filterIcons, pathname, router], ) const handleSearch = useCallback( (query: string) => { setSearchQuery(query) if (timeoutRef.current) { clearTimeout(timeoutRef.current) } timeoutRef.current = setTimeout(() => { updateResults(query) }, 100) }, [updateResults], ) useEffect(() => { return () => { if (timeoutRef.current) { clearTimeout(timeoutRef.current) } } }, []) // Helper function to get the appropriate icon variant based on theme const getIconVariant = (name: string, data: any) => { // Check if the icon has theme variants and use appropriate one if (data.colors) { // If in dark mode and a light variant exists, use the light variant if (resolvedTheme === 'dark' && data.colors.light) { return data.colors.light; } // If in light mode and a dark variant exists, use the dark variant else if (resolvedTheme === 'light' && data.colors.dark) { return data.colors.dark; } } // Fall back to the default name if no appropriate variant return name; } if (!searchParams) return null return ( <> handleSearch(e.target.value)} /> {filteredIcons.length === 0 ? (

We don't have this one...yet!

) : (
{filteredIcons.map(({ name, data }, index) => ( ))}
)} ) } function IconCard({ name, data, getIconVariant }: { name: string; data: any; getIconVariant: (name: string, data: any) => string; }) { const ref = useRef(null); const isInView = useInView(ref, { once: false, amount: 0.2, margin: "100px 0px" }); const variants = { hidden: { opacity: 0, y: 20, scale: 0.95 }, visible: { opacity: 1, y: 0, scale: 1, transition: { duration: 0.4, ease: [0.25, 0.1, 0.25, 1.0] } }, exit: { opacity: 0, y: -10, scale: 0.98, transition: { duration: 0.3, ease: [0.25, 0.1, 0.25, 1.0] } } }; return (
{`${name}
{name.replace(/-/g, " ")} ); }