diff --git a/web/src/app/icons/components/icon-search.tsx b/web/src/app/icons/components/icon-search.tsx index b89901a9..b9a515bc 100644 --- a/web/src/app/icons/components/icon-search.tsx +++ b/web/src/app/icons/components/icon-search.tsx @@ -37,11 +37,20 @@ export function IconSearch({ icons }: IconSearchProps) { const router = useRouter() const pathname = usePathname() const [searchQuery, setSearchQuery] = useState(initialQuery ?? "") + const [debouncedQuery, setDebouncedQuery] = useState(initialQuery ?? "") const [selectedCategories, setSelectedCategories] = useState(initialCategories ?? []) const [sortOption, setSortOption] = useState(initialSort) const timeoutRef = useRef(null) const { resolvedTheme } = useTheme() + useEffect(() => { + const timer = setTimeout(() => { + setDebouncedQuery(searchQuery) + }, 200) + + return () => clearTimeout(timer) + }, [searchQuery]) + // Extract all unique categories const allCategories = useMemo(() => { const categories = new Set() @@ -66,11 +75,17 @@ export function IconSearch({ icons }: IconSearchProps) { // Then filter by search query if (query.trim()) { - const q = query.toLowerCase() + // Normalization function: lowercase, remove spaces and hyphens + const normalizeString = (str: string) => str.toLowerCase().replace(/[-\s]/g, '') + const normalizedQuery = normalizeString(query) + filtered = filtered.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 + // Check normalized name + if (normalizeString(name).includes(normalizedQuery)) return true + // Check normalized aliases + if (data.aliases.some((alias) => normalizeString(alias).includes(normalizedQuery))) return true + // Check normalized categories + if (data.categories.some((category) => normalizeString(category).includes(normalizedQuery))) return true return false }) } @@ -89,6 +104,7 @@ export function IconSearch({ icons }: IconSearchProps) { } // Default sort (relevance or fallback to alphabetical) + // TODO: Implement actual relevance sorting return filtered.sort((a, b) => a.name.localeCompare(b.name)) }, [icons], @@ -114,10 +130,10 @@ export function IconSearch({ icons }: IconSearchProps) { return matches }, [icons, searchQuery]) - // Use useMemo for filtered icons + // Use useMemo for filtered icons with debounced query const filteredIcons = useMemo(() => { - return filterIcons(searchQuery, selectedCategories, sortOption) - }, [filterIcons, searchQuery, selectedCategories, sortOption]) + return filterIcons(debouncedQuery, selectedCategories, sortOption) + }, [filterIcons, debouncedQuery, selectedCategories, sortOption]) const updateResults = useCallback( (query: string, categories: string[], sort: SortOption) => { @@ -140,8 +156,6 @@ export function IconSearch({ icons }: IconSearchProps) { [pathname, router, initialSort], ) - - const handleSearch = useCallback( (query: string) => { setSearchQuery(query) @@ -197,7 +211,10 @@ export function IconSearch({ icons }: IconSearchProps) { }, []) useEffect(() => { - if (filteredIcons.length === 0) { + if (filteredIcons.length === 0 && searchQuery && searchQuery.length > 3) { + console.log("no icons found", { + query: searchQuery, + }) posthog.capture("no icons found", { query: searchQuery, }) diff --git a/web/src/components/PostHogProvider.tsx b/web/src/components/PostHogProvider.tsx index 203ed29c..cf8d2383 100644 --- a/web/src/components/PostHogProvider.tsx +++ b/web/src/components/PostHogProvider.tsx @@ -7,7 +7,7 @@ import { Suspense, useEffect } from "react" export function PostHogProvider({ children }: { children: React.ReactNode }) { useEffect(() => { - if (process.env.NODE_ENV === "development" || process.env.DISABLE_POSTHOG === "true") return + if (process.env.DISABLE_POSTHOG === "true") return // biome-ignore lint/style/noNonNullAssertion: The NEXT_PUBLIC_POSTHOG_KEY environment variable is guaranteed to be set in production. posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, { ui_host: "https://eu.posthog.com",