mirror of
https://github.com/walkxcode/dashboard-icons.git
synced 2025-06-28 07:20:21 +08:00
feat: implement debounced search query and normalize filtering
This commit is contained in:
parent
f995c84478
commit
b3b88414e7
@ -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<string[]>(initialCategories ?? [])
|
||||
const [sortOption, setSortOption] = useState<SortOption>(initialSort)
|
||||
const timeoutRef = useRef<NodeJS.Timeout | null>(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<string>()
|
||||
@ -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,
|
||||
})
|
||||
|
@ -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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user