diff --git a/components/IconGrid.tsx b/components/IconGrid.tsx index b6333a7..494337e 100644 --- a/components/IconGrid.tsx +++ b/components/IconGrid.tsx @@ -1,6 +1,7 @@ import { icons } from "@/lib/client/icons"; import Fuse from "fuse.js"; -import { useMemo } from "react"; +import { forwardRef, useMemo } from "react"; +import { FixedSizeGrid as Grid } from "react-window"; const fuse = new Fuse(icons, { keys: [{ name: "name", weight: 4 }, "tags", "categories"], @@ -17,32 +18,74 @@ type Props = { }; const IconGrid = ({ query, color, weight, iconName, setIconName }: Props) => { - const filteredQueryResultsSelector = useMemo(() => { + // Memoize the filtered results to avoid recalculations on each render + const filteredIcons = useMemo(() => { if (!query) { return icons; } return fuse.search(query).map((result) => result.item); }, [query]); + // Grid configuration + const columnCount = 6; + const rowCount = Math.ceil(filteredIcons.length / columnCount); + const GUTTER_SIZE = 5; + + // Render a single cell (icon) in the grid + const Cell = ({ columnIndex, rowIndex, style }: any) => { + const index = rowIndex * columnCount + columnIndex; + if (index >= filteredIcons.length) return null; // Prevent overflow + + const icon = filteredIcons[index]; + const IconComponent = icon.Icon; + + return ( +
setIconName(icon.pascal_name)} + className={`cursor-pointer p-[6px] rounded-lg bg-base-100 w-full ${ + icon.pascal_name === iconName + ? "outline outline-1 outline-primary" + : "" + }`} + > + +
+ ); + }; + + const innerElementType = forwardRef(({ style, ...rest }: any, ref) => ( +
+ )); + return ( - <> - {filteredQueryResultsSelector.map((icon) => { - const IconComponent = icon.Icon; - return ( -
setIconName(icon.pascal_name)} - className={`cursor-pointer btn p-1 box-border bg-base-100 border-none w-full ${ - icon.pascal_name === iconName - ? "outline outline-1 outline-primary" - : "" - }`} - > - -
- ); - })} - + + {Cell} + ); }; diff --git a/package.json b/package.json index dc19969..b07bbb2 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "react-masonry-css": "^1.0.16", "react-select": "^5.7.4", "react-spinners": "^0.14.1", + "react-window": "^1.8.10", "socks-proxy-agent": "^8.0.2", "stripe": "^12.13.0", "tailwind-merge": "^2.3.0", @@ -89,6 +90,7 @@ "@types/dompurify": "^3.0.4", "@types/jsdom": "^21.1.3", "@types/node-fetch": "^2.6.10", + "@types/react-window": "^1.8.8", "@types/shelljs": "^0.8.15", "autoprefixer": "^10.4.14", "daisyui": "^4.4.2", diff --git a/yarn.lock b/yarn.lock index e06adb4..fdf66a1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2118,6 +2118,13 @@ dependencies: "@types/react" "*" +"@types/react-window@^1.8.8": + version "1.8.8" + resolved "https://registry.yarnpkg.com/@types/react-window/-/react-window-1.8.8.tgz#c20645414d142364fbe735818e1c1e0a145696e3" + integrity sha512-8Ls660bHR1AUA2kuRvVG9D/4XpRC6wjAaPT9dil7Ckc76eP9TKWZwwmgfq8Q1LANX3QNDnoU4Zp48A3w+zK69Q== + dependencies: + "@types/react" "*" + "@types/react@*", "@types/react@18.2.14": version "18.2.14" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.14.tgz#fa7a6fecf1ce35ca94e74874f70c56ce88f7a127" @@ -4516,7 +4523,7 @@ make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== -memoize-one@^5.0.4: +"memoize-one@>=3.1.1 <6", memoize-one@^5.0.4: version "5.2.1" resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== @@ -5421,6 +5428,14 @@ react-transition-group@^4.3.0: loose-envify "^1.4.0" prop-types "^15.6.2" +react-window@^1.8.10: + version "1.8.10" + resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.10.tgz#9e6b08548316814b443f7002b1cf8fd3a1bdde03" + integrity sha512-Y0Cx+dnU6NLa5/EvoHukUD0BklJ8qITCtVEPY1C/nL8wwoZ0b5aEw8Ff1dOVHw7fCzMt55XfJDd8S8W8LCaUCg== + dependencies: + "@babel/runtime" "^7.0.0" + memoize-one ">=3.1.1 <6" + react@18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"