diff --git a/package.json b/package.json index 19dbb3b..e1af5a5 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "dependencies": { "file-saver": "^2.0.2", "framer-motion": "^2.1.0", + "fuse.js": "^6.4.1", "phosphor-react": "^0.2.2", "react": "^17.0.0-rc.0", "react-dom": "^17.0.0-rc.0", diff --git a/src/state/selectors.ts b/src/state/selectors.ts index 81aa453..a666c7b 100644 --- a/src/state/selectors.ts +++ b/src/state/selectors.ts @@ -1,28 +1,25 @@ import { selector, selectorFamily } from "recoil"; import TinyColor from "tinycolor2"; +import Fuse from "fuse.js"; -import { searchQueryAtom, iconStyleAtom, iconColorAtom } from "./atoms"; +import { searchQueryAtom, iconColorAtom } from "./atoms"; import { IconEntry, IconCategory } from "../lib"; import { icons } from "../lib/icons"; -const isQueryMatch = (icon: IconEntry, query: string): boolean => { - return ( - icon.name.includes(query) || - icon.tags.some((tag) => tag.toLowerCase().includes(query)) || - icon.categories.some((category) => category.toLowerCase().includes(query)) - ); -}; +const fuse = new Fuse(icons, { + keys: [{ name: "name", weight: 2 }, "tags", "categories"], + threshold: 0.2, // Tweak this to what feels like the right number of results + // shouldSort: false, // We may want to sort if we find too many results? +}); export const filteredQueryResultsSelector = selector>({ key: "filteredQueryResultsSelector", get: ({ get }) => { const query = get(searchQueryAtom).trim().toLowerCase(); - const style = get(iconStyleAtom); - - if (!query && !style) return icons; + if (!query) return icons; return new Promise((resolve) => - resolve(icons.filter((icon) => isQueryMatch(icon, query))) + resolve(fuse.search(query).map((value) => value.item)) ); }, });