diff --git a/package.json b/package.json index a9bcc52c..fc4b4ee0 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,8 @@ "react-hook-form": "^7.53.0", "react-hotkeys-hook": "^4.5.1", "react-resizable-panels": "^2.1.1", + "react-virtualized-auto-sizer": "^1.0.24", + "react-window": "^1.8.10", "sharp": "^0.33.5", "tailwind-merge": "^2.5.2", "tailwindcss-animate": "^1.0.7", @@ -45,6 +47,7 @@ "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "@types/react-window": "^1.8.8", "@typescript-eslint/eslint-plugin": "^8.3.0", "@typescript-eslint/parser": "^8.3.0", "eslint": "^8", diff --git a/src/app/search/searchResults.tsx b/src/app/search/searchResults.tsx index f85b5670..b48e8741 100644 --- a/src/app/search/searchResults.tsx +++ b/src/app/search/searchResults.tsx @@ -1,9 +1,12 @@ 'use client'; -import { ScrollArea } from "@/components/ui/scroll-area"; +import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"; import { Separator } from "@/components/ui/separator"; import { ZoektFileMatch } from "@/lib/types"; import { Scrollbar } from "@radix-ui/react-scroll-area"; +import { useEffect } from "react"; +import { VariableSizeList } from "react-window"; +import AutoSizer from "react-virtualized-auto-sizer"; interface SearchResultsProps { fileMatches: ZoektFileMatch[]; @@ -14,21 +17,47 @@ export const SearchResults = ({ fileMatches, onOpenFileMatch, }: SearchResultsProps) => { - return ( - -
- {fileMatches.map((match, index) => ( - { - onOpenFileMatch(match); - }} - /> - ))} + + const FileMatchShim = ({ index, style }: { index: number, style: React.CSSProperties }) => { + const match = fileMatches[index]; + + return ( +
onOpenFileMatch(match)} + > + onOpenFileMatch(match)} + />
- - + ) + }; + + const calculateItemSize = (index: number) => { + const match = fileMatches[index]; + // Base height for the file name row + let height = 30; + // Add height for each match line + height += match.Matches.length * 50; + // Add some padding + height += 10; + return height; + }; + + return ( + + {({ height, width }) => ( + calculateItemSize(index)} + > + {FileMatchShim} + + )} + ) } @@ -53,7 +82,7 @@ const FileMatch = ({ return (
{ onOpenFile(); }} diff --git a/src/lib/extensions/searchResultHighlightExtension.ts b/src/lib/extensions/searchResultHighlightExtension.ts index f3d00584..58dba858 100644 --- a/src/lib/extensions/searchResultHighlightExtension.ts +++ b/src/lib/extensions/searchResultHighlightExtension.ts @@ -62,7 +62,6 @@ const highlightTheme = EditorView.baseTheme({ }, "&dark .tq-searchMatch-selected": { backgroundColor: "#00ff007a", - } }); diff --git a/yarn.lock b/yarn.lock index 84269e48..b184c684 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,6 +7,13 @@ resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== +"@babel/runtime@^7.0.0": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.6.tgz#9afc3289f7184d8d7f98b099884c26317b9264d2" + integrity sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/runtime@^7.18.6": version "7.25.4" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.4.tgz#6ef37d678428306e7d75f054d5b1bdb8cf8aa8ee" @@ -767,6 +774,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": version "18.3.4" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.4.tgz#dfdd534a1d081307144c00e325c06e00312c93a3" @@ -2506,6 +2520,11 @@ lucide-react@^0.435.0: resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.435.0.tgz#88c5cc6de61b89e42cbef309a38f100deee1bb32" integrity sha512-we5GKfzjMDw9m9SsyZJvWim9qaT+Ya5kaRS+OGFqgLqXUrPM1h+7CiMw5pKdEIoaBqfXz2pyv9TASAdpIAJs0Q== +"memoize-one@>=3.1.1 <6": + 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== + merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" @@ -2932,6 +2951,19 @@ react-style-singleton@^2.2.1: invariant "^2.2.4" tslib "^2.0.0" +react-virtualized-auto-sizer@^1.0.24: + version "1.0.24" + resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.24.tgz#3ebdc92f4b05ad65693b3cc8e7d8dd54924c0227" + integrity sha512-3kCn7N9NEb3FlvJrSHWGQ4iVl+ydQObq2fHMn12i5wbtm74zHOPhz/i64OL3c1S1vi9i2GXtZqNqUJTQ+BnNfg== + +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: version "18.3.1" resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891"