mirror of
https://github.com/walkxcode/dashboard-icons.git
synced 2025-06-28 15:30:22 +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 router = useRouter()
|
||||||
const pathname = usePathname()
|
const pathname = usePathname()
|
||||||
const [searchQuery, setSearchQuery] = useState(initialQuery ?? "")
|
const [searchQuery, setSearchQuery] = useState(initialQuery ?? "")
|
||||||
|
const [debouncedQuery, setDebouncedQuery] = useState(initialQuery ?? "")
|
||||||
const [selectedCategories, setSelectedCategories] = useState<string[]>(initialCategories ?? [])
|
const [selectedCategories, setSelectedCategories] = useState<string[]>(initialCategories ?? [])
|
||||||
const [sortOption, setSortOption] = useState<SortOption>(initialSort)
|
const [sortOption, setSortOption] = useState<SortOption>(initialSort)
|
||||||
const timeoutRef = useRef<NodeJS.Timeout | null>(null)
|
const timeoutRef = useRef<NodeJS.Timeout | null>(null)
|
||||||
const { resolvedTheme } = useTheme()
|
const { resolvedTheme } = useTheme()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
setDebouncedQuery(searchQuery)
|
||||||
|
}, 200)
|
||||||
|
|
||||||
|
return () => clearTimeout(timer)
|
||||||
|
}, [searchQuery])
|
||||||
|
|
||||||
// Extract all unique categories
|
// Extract all unique categories
|
||||||
const allCategories = useMemo(() => {
|
const allCategories = useMemo(() => {
|
||||||
const categories = new Set<string>()
|
const categories = new Set<string>()
|
||||||
@ -66,11 +75,17 @@ export function IconSearch({ icons }: IconSearchProps) {
|
|||||||
|
|
||||||
// Then filter by search query
|
// Then filter by search query
|
||||||
if (query.trim()) {
|
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 }) => {
|
filtered = filtered.filter(({ name, data }) => {
|
||||||
if (name.toLowerCase().includes(q)) return true
|
// Check normalized name
|
||||||
if (data.aliases.some((alias) => alias.toLowerCase().includes(q))) return true
|
if (normalizeString(name).includes(normalizedQuery)) return true
|
||||||
if (data.categories.some((category) => category.toLowerCase().includes(q))) 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
|
return false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -89,6 +104,7 @@ export function IconSearch({ icons }: IconSearchProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Default sort (relevance or fallback to alphabetical)
|
// Default sort (relevance or fallback to alphabetical)
|
||||||
|
// TODO: Implement actual relevance sorting
|
||||||
return filtered.sort((a, b) => a.name.localeCompare(b.name))
|
return filtered.sort((a, b) => a.name.localeCompare(b.name))
|
||||||
},
|
},
|
||||||
[icons],
|
[icons],
|
||||||
@ -114,10 +130,10 @@ export function IconSearch({ icons }: IconSearchProps) {
|
|||||||
return matches
|
return matches
|
||||||
}, [icons, searchQuery])
|
}, [icons, searchQuery])
|
||||||
|
|
||||||
// Use useMemo for filtered icons
|
// Use useMemo for filtered icons with debounced query
|
||||||
const filteredIcons = useMemo(() => {
|
const filteredIcons = useMemo(() => {
|
||||||
return filterIcons(searchQuery, selectedCategories, sortOption)
|
return filterIcons(debouncedQuery, selectedCategories, sortOption)
|
||||||
}, [filterIcons, searchQuery, selectedCategories, sortOption])
|
}, [filterIcons, debouncedQuery, selectedCategories, sortOption])
|
||||||
|
|
||||||
const updateResults = useCallback(
|
const updateResults = useCallback(
|
||||||
(query: string, categories: string[], sort: SortOption) => {
|
(query: string, categories: string[], sort: SortOption) => {
|
||||||
@ -140,8 +156,6 @@ export function IconSearch({ icons }: IconSearchProps) {
|
|||||||
[pathname, router, initialSort],
|
[pathname, router, initialSort],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const handleSearch = useCallback(
|
const handleSearch = useCallback(
|
||||||
(query: string) => {
|
(query: string) => {
|
||||||
setSearchQuery(query)
|
setSearchQuery(query)
|
||||||
@ -197,7 +211,10 @@ export function IconSearch({ icons }: IconSearchProps) {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
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", {
|
posthog.capture("no icons found", {
|
||||||
query: searchQuery,
|
query: searchQuery,
|
||||||
})
|
})
|
||||||
|
@ -7,7 +7,7 @@ import { Suspense, useEffect } from "react"
|
|||||||
|
|
||||||
export function PostHogProvider({ children }: { children: React.ReactNode }) {
|
export function PostHogProvider({ children }: { children: React.ReactNode }) {
|
||||||
useEffect(() => {
|
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.
|
// 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!, {
|
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
|
||||||
ui_host: "https://eu.posthog.com",
|
ui_host: "https://eu.posthog.com",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user