🖼️ style: Conversation Menu and Dialogs update (#3601)

* feat: new dropdown

* fix: maintain popover active when open

* fix: update DeleteButton and ShareButton component to use useState for managing dialog state

* BREAKING: style improvement of base Button component

* style: update export button

* a11y: ExportAndShareButton

* add border

* quick style fix

* fix: flick issue on convo

* fix: DropDown opens when renaming

* chore: update radix-ui/react-dropdown-menu to latest

* small fix

* style: bookmarks update

* reorder export modal

* feat: imporved dropdowns

* style: a lot of changes; header, bookmarks, export, nav, convo, convoOptions

* fix: small style issues

* fix: button

* fix: bookmarks header menu

* fix: dropdown close glitch

* feat: Improve accessibility and keyboard navigation in ModelSpec component

* fix: Nav related type issues

* style: ConvoOptions theming and focus ring

---------

Co-authored-by: Danny Avila <danny@librechat.ai>
This commit is contained in:
Marco Beretta 2024-08-16 10:30:14 +02:00 committed by GitHub
parent 7f50d2f7c0
commit 96581d56df
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
62 changed files with 2627 additions and 1821 deletions

View file

@ -123,7 +123,7 @@ export default function useChatFunctions({
conversationId = null;
}
const parentMessage = currentMessages?.find(
const parentMessage = currentMessages.find(
(msg) => msg.messageId === latestMessage?.parentMessageId,
);

View file

@ -2,6 +2,8 @@ import { useEffect, useState, useCallback } from 'react';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { useNavigate, useLocation } from 'react-router-dom';
import { useGetSearchEnabledQuery } from 'librechat-data-provider/react-query';
import type { UseInfiniteQueryResult } from '@tanstack/react-query';
import type { ConversationListResponse } from 'librechat-data-provider';
import { useSearchInfiniteQuery } from '~/data-provider';
import useConversation from './useConversation';
import store from '~/store';
@ -19,7 +21,7 @@ export default function useSearchMessages({ isAuthenticated }: { isAuthenticated
const searchQueryRes = useSearchInfiniteQuery(
{ pageNumber: pageNumber.toString(), searchQuery: searchQuery, isArchived: false },
{ enabled: isAuthenticated && !!searchQuery.length },
);
) as UseInfiniteQueryResult<ConversationListResponse, unknown> | undefined;
useEffect(() => {
if (searchQuery && searchQuery.length > 0) {
@ -36,7 +38,7 @@ export default function useSearchMessages({ isAuthenticated }: { isAuthenticated
}, [navigate, searchQuery]);
useEffect(() => {
if (searchEnabledQuery.data) {
if (searchEnabledQuery.data === true) {
setIsSearchEnabled(searchEnabledQuery.data);
} else if (searchEnabledQuery.isError) {
console.error('Failed to get search enabled', searchEnabledQuery.error);
@ -55,10 +57,10 @@ export default function useSearchMessages({ isAuthenticated }: { isAuthenticated
useEffect(() => {
//we use isInitialLoading here instead of isLoading because query is disabled by default
if (searchQueryRes.data) {
if (searchQueryRes?.data) {
onSearchSuccess();
}
}, [searchQueryRes.data, searchQueryRes.isInitialLoading, onSearchSuccess]);
}, [searchQueryRes?.data, searchQueryRes?.isInitialLoading, onSearchSuccess]);
return {
pageNumber,

View file

@ -31,7 +31,7 @@ export default function useSubmitMessage(helpers?: { clearDraft?: () => void })
}
const rootMessages = getMessages();
const isLatestInRootMessages = rootMessages?.some(
(message) => message?.messageId === latestMessage?.messageId,
(message) => message.messageId === latestMessage?.messageId,
);
if (!isLatestInRootMessages && latestMessage) {
setMessages([...(rootMessages || []), latestMessage]);
@ -86,7 +86,7 @@ export default function useSubmitMessage(helpers?: { clearDraft?: () => void })
}
const currentText = methods.getValues('text');
const newText = currentText?.trim()?.length > 1 ? `\n${parsedText}` : parsedText;
const newText = currentText.trim().length > 1 ? `\n${parsedText}` : parsedText;
setActivePrompt(newText);
},
[autoSendPrompts, submitMessage, setActivePrompt, methods, user],

View file

@ -11,16 +11,18 @@ export default function useNavScrolling<TData>({
hasNextPage?: boolean;
isFetchingNextPage: boolean;
setShowLoading: React.Dispatch<React.SetStateAction<boolean>>;
fetchNextPage: (
options?: FetchNextPageOptions | undefined,
) => Promise<InfiniteQueryObserverResult<TData, unknown>>;
fetchNextPage:
| ((
options?: FetchNextPageOptions | undefined,
) => Promise<InfiniteQueryObserverResult<TData, unknown>>)
| undefined;
}) {
const scrollPositionRef = useRef<number | null>(null);
const containerRef = useRef<HTMLDivElement | null>(null);
// eslint-disable-next-line react-hooks/exhaustive-deps
const fetchNext = useCallback(
throttle(() => fetchNextPage(), 750, { leading: true }),
throttle(() => (fetchNextPage != null ? fetchNextPage() : () => ({})), 750, { leading: true }),
[fetchNextPage],
);
@ -29,7 +31,7 @@ export default function useNavScrolling<TData>({
const { scrollTop, clientHeight, scrollHeight } = containerRef.current;
const nearBottomOfList = scrollTop + clientHeight >= scrollHeight * 0.97;
if (nearBottomOfList && hasNextPage && !isFetchingNextPage) {
if (nearBottomOfList && hasNextPage === true && !isFetchingNextPage) {
setShowLoading(true);
fetchNext();
} else {