LibreChat/client/src/components/Nav/SearchBar.tsx
Danny Avila 1f0fb497f8
🎉 feat: Optimizations and Anthropic Title Generation (#2184)
* feat: add claude-3-haiku-20240307 to default anthropic list

* refactor: optimize `saveMessage` calls mid-stream via throttling

* chore: remove addMetadata operations and consolidate in BaseClient

* fix(listAssistantsForAzure): attempt to specify correct model mapping as accurately as possible (#2177)

* refactor(client): update last conversation setup with current assistant model, call newConvo again when assistants load to allow fast initial load and ensure assistant model is always the default, not the last selected model

* refactor(cache): explicitly add TTL of 2 minutes when setting titleCache and add default TTL of 10 minutes to abortKeys cache

* feat(AnthropicClient): conversation titling using Anthropic Function Calling

* chore: remove extraneous token usage logging

* fix(convos): unhandled edge case for conversation grouping (undefined conversation)

* style: Improved style of Search Bar after recent UI update

* chore: remove unused code, content part helpers

* feat: always show code option
2024-03-23 20:21:40 -04:00

72 lines
2.4 KiB
TypeScript

import { forwardRef, useState, useCallback, useMemo, Ref } from 'react';
import { Search, X } from 'lucide-react';
import { useSetRecoilState } from 'recoil';
import debounce from 'lodash/debounce';
import { useLocalize } from '~/hooks';
import { cn } from '~/utils';
import store from '~/store';
type SearchBarProps = {
clearSearch: () => void;
};
const SearchBar = forwardRef((props: SearchBarProps, ref: Ref<HTMLDivElement>) => {
const { clearSearch } = props;
const setSearchQuery = useSetRecoilState(store.searchQuery);
const [showClearIcon, setShowClearIcon] = useState(false);
const [text, setText] = useState('');
const localize = useLocalize();
const clearText = useCallback(() => {
setShowClearIcon(false);
setSearchQuery('');
clearSearch();
setText('');
}, [setSearchQuery, clearSearch]);
const handleKeyUp = (e: React.KeyboardEvent<HTMLInputElement>) => {
const { value } = e.target as HTMLInputElement;
if (e.key === 'Backspace' && value === '') {
clearText();
}
};
const sendRequest = useCallback((value: string) => setSearchQuery(value), [setSearchQuery]);
const debouncedSendRequest = useMemo(() => debounce(sendRequest, 350), [sendRequest]);
const onChange = (e: React.FormEvent<HTMLInputElement>) => {
const { value } = e.target as HTMLInputElement;
setShowClearIcon(value.length > 0);
setText(value);
debouncedSendRequest(value);
};
return (
<div
ref={ref}
className="relative mt-1 flex flex h-10 cursor-pointer items-center gap-3 rounded-lg border-white bg-gray-50 px-2 px-3 py-2 text-black transition-colors duration-200 focus-within:bg-gray-200 hover:bg-gray-200 dark:bg-gray-750 dark:text-white dark:focus-within:bg-gray-800 dark:hover:bg-gray-800"
>
{<Search className="absolute left-3 h-4 w-4" />}
<input
type="text"
className="m-0 mr-0 w-full border-none bg-transparent p-0 pl-7 text-sm leading-tight outline-none"
value={text}
onChange={onChange}
onKeyDown={(e) => {
e.code === 'Space' ? e.stopPropagation() : null;
}}
placeholder={localize('com_nav_search_placeholder')}
onKeyUp={handleKeyUp}
/>
<X
className={cn(
'absolute right-[7px] h-5 w-5 cursor-pointer transition-opacity duration-1000',
showClearIcon ? 'opacity-100' : 'opacity-0',
)}
onClick={clearText}
/>
</div>
);
});
export default SearchBar;