mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-12 04:15:30 +00:00
fix scrolling issue
This commit is contained in:
parent
9cd32362e8
commit
9f66c458c4
3 changed files with 31 additions and 17 deletions
|
|
@ -15,6 +15,7 @@ import { useGetSelectedFromQuery } from "./useGetSelectedFromQuery";
|
|||
interface FilePanelProps {
|
||||
matches: SearchResultFile[];
|
||||
repoInfo: Record<number, RepositoryInfo>;
|
||||
onFilterChange?: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -31,10 +32,12 @@ interface FilePanelProps {
|
|||
*
|
||||
* @param matches - Array of search result files to filter
|
||||
* @param repoInfo - Information about repositories including their display names and icons
|
||||
* @param onFilterChange - Optional callback that is called whenever a filter is applied or removed
|
||||
*/
|
||||
export const FilterPanel = ({
|
||||
matches,
|
||||
repoInfo,
|
||||
onFilterChange,
|
||||
}: FilePanelProps) => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
|
|
@ -148,6 +151,7 @@ export const FilterPanel = ({
|
|||
|
||||
if (newParams.toString() !== searchParams.toString()) {
|
||||
router.replace(`?${newParams.toString()}`, { scroll: false });
|
||||
onFilterChange?.();
|
||||
}
|
||||
}}
|
||||
className="max-h-[50%]"
|
||||
|
|
@ -170,6 +174,7 @@ export const FilterPanel = ({
|
|||
|
||||
if (newParams.toString() !== searchParams.toString()) {
|
||||
router.replace(`?${newParams.toString()}`, { scroll: false });
|
||||
onFilterChange?.();
|
||||
}
|
||||
}}
|
||||
className="overflow-auto"
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import { useStreamedSearch } from "../useStreamedSearch";
|
|||
import { CodePreviewPanel } from "./codePreviewPanel";
|
||||
import { FilterPanel } from "./filterPanel";
|
||||
import { useFilteredMatches } from "./filterPanel/useFilterMatches";
|
||||
import { SearchResultsPanel } from "./searchResultsPanel";
|
||||
import { SearchResultsPanel, SearchResultsPanelHandle } from "./searchResultsPanel";
|
||||
|
||||
interface SearchResultsPageProps {
|
||||
searchQuery: string;
|
||||
|
|
@ -198,6 +198,7 @@ const PanelGroup = ({
|
|||
const [previewedFile, setPreviewedFile] = useState<SearchResultFile | undefined>(undefined);
|
||||
const filteredFileMatches = useFilteredMatches(fileMatches);
|
||||
const filterPanelRef = useRef<ImperativePanelHandle>(null);
|
||||
const searchResultsPanelRef = useRef<SearchResultsPanelHandle>(null);
|
||||
const [selectedMatchIndex, setSelectedMatchIndex] = useState(0);
|
||||
|
||||
const [isFilterPanelCollapsed, setIsFilterPanelCollapsed] = useLocalStorage('isFilterPanelCollapsed', false);
|
||||
|
|
@ -238,6 +239,9 @@ const PanelGroup = ({
|
|||
<FilterPanel
|
||||
matches={fileMatches}
|
||||
repoInfo={repoInfo}
|
||||
onFilterChange={() => {
|
||||
searchResultsPanelRef.current?.resetScroll();
|
||||
}}
|
||||
/>
|
||||
</ResizablePanel>
|
||||
{isFilterPanelCollapsed && (
|
||||
|
|
@ -325,6 +329,7 @@ const PanelGroup = ({
|
|||
</div>
|
||||
{filteredFileMatches.length > 0 ? (
|
||||
<SearchResultsPanel
|
||||
ref={searchResultsPanelRef}
|
||||
fileMatches={filteredFileMatches}
|
||||
onOpenFilePreview={(fileMatch, matchIndex) => {
|
||||
setSelectedMatchIndex(matchIndex ?? 0);
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
import { RepositoryInfo, SearchResultFile } from "@/features/search/types";
|
||||
import { FileMatchContainer, MAX_MATCHES_TO_PREVIEW } from "./fileMatchContainer";
|
||||
import { useVirtualizer, VirtualItem } from "@tanstack/react-virtual";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useDebounce, usePrevious } from "@uidotdev/usehooks";
|
||||
import { useCallback, useEffect, useImperativeHandle, useRef, useState, forwardRef } from "react";
|
||||
import { useDebounce } from "@uidotdev/usehooks";
|
||||
|
||||
interface SearchResultsPanelProps {
|
||||
fileMatches: SearchResultFile[];
|
||||
|
|
@ -15,6 +15,10 @@ interface SearchResultsPanelProps {
|
|||
repoInfo: Record<number, RepositoryInfo>;
|
||||
}
|
||||
|
||||
export interface SearchResultsPanelHandle {
|
||||
resetScroll: () => void;
|
||||
}
|
||||
|
||||
const ESTIMATED_LINE_HEIGHT_PX = 20;
|
||||
const ESTIMATED_NUMBER_OF_LINES_PER_CODE_CELL = 10;
|
||||
const ESTIMATED_MATCH_CONTAINER_HEIGHT_PX = 30;
|
||||
|
|
@ -25,14 +29,14 @@ type ScrollHistoryState = {
|
|||
showAllMatchesStates?: boolean[];
|
||||
}
|
||||
|
||||
export const SearchResultsPanel = ({
|
||||
export const SearchResultsPanel = forwardRef<SearchResultsPanelHandle, SearchResultsPanelProps>(({
|
||||
fileMatches,
|
||||
onOpenFilePreview,
|
||||
isLoadMoreButtonVisible,
|
||||
onLoadMoreButtonClicked,
|
||||
isBranchFilteringEnabled,
|
||||
repoInfo,
|
||||
}: SearchResultsPanelProps) => {
|
||||
}, ref) => {
|
||||
const parentRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Restore the scroll offset, measurements cache, and other state from the history
|
||||
|
|
@ -73,18 +77,16 @@ export const SearchResultsPanel = ({
|
|||
debug: false,
|
||||
});
|
||||
|
||||
// When the number of file matches changes, we need to reset our scroll state.
|
||||
const prevFileMatches = usePrevious(fileMatches);
|
||||
useEffect(() => {
|
||||
if (!prevFileMatches) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (prevFileMatches.length !== fileMatches.length) {
|
||||
const resetScroll = useCallback(() => {
|
||||
setShowAllMatchesStates(Array(fileMatches.length).fill(false));
|
||||
virtualizer.scrollToIndex(0);
|
||||
}
|
||||
}, [fileMatches.length, prevFileMatches, virtualizer]);
|
||||
}, [fileMatches.length, virtualizer]);
|
||||
|
||||
// Expose the resetScroll function to parent components
|
||||
useImperativeHandle(ref, () => ({
|
||||
resetScroll,
|
||||
}), [resetScroll]);
|
||||
|
||||
|
||||
// Save the scroll state to the history stack.
|
||||
const debouncedScrollOffset = useDebounce(virtualizer.scrollOffset, 100);
|
||||
|
|
@ -177,4 +179,6 @@ export const SearchResultsPanel = ({
|
|||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
SearchResultsPanel.displayName = 'SearchResultsPanel';
|
||||
Loading…
Reference in a new issue