Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions apps/web/src/components/chat/ModelPickerContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ export function adjacentModelPickerProvider(input: {
}

const EMPTY_MODEL_JUMP_LABELS = new Map<string, string>();
const MODEL_LIST_ESTIMATED_ITEM_SIZE = 52;

function ModelListSeparator() {
return <div className="h-0.5" />;
Expand Down Expand Up @@ -197,6 +198,7 @@ export const ModelPickerContent = memo(function ModelPickerContent(props: {
const [showBottomScrollFade, setShowBottomScrollFade] = useState(false);
const searchInputRef = useRef<HTMLInputElement>(null);
const modelListRef = useRef<LegendListRef | null>(null);
const pickerContentRef = useRef<HTMLDivElement>(null);
const highlightedModelKeyRef = useRef<string | null>(null);
const favorites = useClientSettings((s) => s.favorites ?? []);
const activeEntry = props.instanceEntries.find(
Expand Down Expand Up @@ -699,6 +701,17 @@ export const ModelPickerContent = memo(function ModelPickerContent(props: {
),
[visibleModels],
);
const [modelListContentSize, setModelListContentSize] = useState(
() => filteredItemKeys.length * MODEL_LIST_ESTIMATED_ITEM_SIZE,
);
const [searchHeight, setSearchHeight] = useState(0);
useLayoutEffect(
() => modelListRef.current?.getState().listen("totalSize", setModelListContentSize),
[],
);
// Fit the list to its rows plus the combobox list `py-1` and LegendList `py-1.5`.
const modelListHeight =
filteredItemKeys.length === 0 ? 0 : `calc(${modelListContentSize}px + var(--spacing) * 5)`;
const updateModelListScrollFades = useCallback(() => {
const scrollElement = modelListRef.current?.getScrollableNode();
if (!(scrollElement instanceof HTMLElement)) {
Expand Down Expand Up @@ -815,7 +828,10 @@ export const ModelPickerContent = memo(function ModelPickerContent(props: {
return (
<TooltipProvider delay={0}>
<div
className="relative flex h-screen max-h-86.5 w-screen max-w-90 flex-row overflow-hidden"
ref={pickerContentRef}
className="relative flex max-h-86.5 w-screen max-w-90 flex-row overflow-hidden"
// Hold the height from when the search started; results scroll instead of resizing.
style={isSearching ? { height: searchHeight } : undefined}
data-model-picker-content="true"
>
{/* Sidebar */}
Expand Down Expand Up @@ -890,7 +906,10 @@ export const ModelPickerContent = memo(function ModelPickerContent(props: {
ref={searchInputRef}
placeholder="Search models..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
onChange={(e) => {
if (!isSearching) setSearchHeight(pickerContentRef.current?.offsetHeight ?? 0);
setSearchQuery(e.target.value);
}}
onKeyDown={(e) => {
if (
showSidebar &&
Expand Down Expand Up @@ -944,7 +963,10 @@ export const ModelPickerContent = memo(function ModelPickerContent(props: {
/>

{/* Model list */}
<div className="relative min-h-0 flex-1 overflow-hidden pr-px">
<div
className="relative min-h-0 overflow-hidden pr-px"
style={{ height: modelListHeight }}
>
<ComboboxListVirtualized>
<LegendList<string>
ref={modelListRef}
Expand Down Expand Up @@ -1013,7 +1035,7 @@ export const ModelPickerContent = memo(function ModelPickerContent(props: {
/>
);
}}
estimatedItemSize={52}
estimatedItemSize={MODEL_LIST_ESTIMATED_ITEM_SIZE}
drawDistance={480}
recycleItems
contentContainerClassName="pl-2 pr-px"
Expand Down
Loading