mirror of
https://github.com/NovaOSS/nova-betterchat.git
synced 2024-11-29 10:14:00 +01:00
parent
467160fbb1
commit
55aa22a28b
|
@ -48,6 +48,7 @@
|
||||||
"i18next-browser-languagedetector": "^7.0.1",
|
"i18next-browser-languagedetector": "^7.0.1",
|
||||||
"i18next-http-backend": "^2.1.1",
|
"i18next-http-backend": "^2.1.1",
|
||||||
"jspdf": "^2.5.1",
|
"jspdf": "^2.5.1",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"match-sorter": "^6.3.1",
|
"match-sorter": "^6.3.1",
|
||||||
"papaparse": "^5.4.1",
|
"papaparse": "^5.4.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
@ -64,6 +65,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/typography": "^0.5.9",
|
"@tailwindcss/typography": "^0.5.9",
|
||||||
|
"@types/lodash": "^4.14.192",
|
||||||
"@types/papaparse": "^5.3.7",
|
"@types/papaparse": "^5.3.7",
|
||||||
"@types/react": "^18.0.27",
|
"@types/react": "^18.0.27",
|
||||||
"@types/react-dom": "^18.0.10",
|
"@types/react-dom": "^18.0.10",
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { shallow } from 'zustand/shallow';
|
||||||
import NewFolder from './NewFolder';
|
import NewFolder from './NewFolder';
|
||||||
import ChatFolder from './ChatFolder';
|
import ChatFolder from './ChatFolder';
|
||||||
import ChatHistory from './ChatHistory';
|
import ChatHistory from './ChatHistory';
|
||||||
|
import ChatSearch from './ChatSearch';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ChatHistoryInterface,
|
ChatHistoryInterface,
|
||||||
|
@ -23,10 +24,13 @@ const ChatHistoryList = () => {
|
||||||
const [isHover, setIsHover] = useState<boolean>(false);
|
const [isHover, setIsHover] = useState<boolean>(false);
|
||||||
const [folders, setFolders] = useState<ChatHistoryFolderInterface>({});
|
const [folders, setFolders] = useState<ChatHistoryFolderInterface>({});
|
||||||
const [noFolders, setNoFolders] = useState<ChatHistoryInterface[]>([]);
|
const [noFolders, setNoFolders] = useState<ChatHistoryInterface[]>([]);
|
||||||
|
const [filter, setFilter] = useState<string>('');
|
||||||
|
|
||||||
const chatsRef = useRef<ChatInterface[]>(useStore.getState().chats || []);
|
const chatsRef = useRef<ChatInterface[]>(useStore.getState().chats || []);
|
||||||
const foldersNameRef = useRef<string[]>(useStore.getState().foldersName);
|
const foldersNameRef = useRef<string[]>(useStore.getState().foldersName);
|
||||||
|
const filterRef = useRef<string>(filter);
|
||||||
|
|
||||||
const updateFolders = () => {
|
const updateFolders = useRef(() => {
|
||||||
const _folders: ChatHistoryFolderInterface = {};
|
const _folders: ChatHistoryFolderInterface = {};
|
||||||
const _noFolders: ChatHistoryInterface[] = [];
|
const _noFolders: ChatHistoryInterface[] = [];
|
||||||
const chats = useStore.getState().chats;
|
const chats = useStore.getState().chats;
|
||||||
|
@ -36,6 +40,14 @@ const ChatHistoryList = () => {
|
||||||
|
|
||||||
if (chats) {
|
if (chats) {
|
||||||
chats.forEach((chat, index) => {
|
chats.forEach((chat, index) => {
|
||||||
|
const filterLowerCase = filterRef.current.toLowerCase();
|
||||||
|
if (
|
||||||
|
!chat.title.toLocaleLowerCase().includes(filterLowerCase) &&
|
||||||
|
!chat.folder?.toLowerCase().includes(filterLowerCase) &&
|
||||||
|
index !== currentChatIndex
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!chat.folder) {
|
if (!chat.folder) {
|
||||||
_noFolders.push({ title: chat.title, index: index });
|
_noFolders.push({ title: chat.title, index: index });
|
||||||
} else {
|
} else {
|
||||||
|
@ -47,7 +59,7 @@ const ChatHistoryList = () => {
|
||||||
|
|
||||||
setFolders(_folders);
|
setFolders(_folders);
|
||||||
setNoFolders(_noFolders);
|
setNoFolders(_noFolders);
|
||||||
};
|
}).current;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateFolders();
|
updateFolders();
|
||||||
|
@ -92,6 +104,11 @@ const ChatHistoryList = () => {
|
||||||
}
|
}
|
||||||
}, [currentChatIndex, chatTitles]);
|
}, [currentChatIndex, chatTitles]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
filterRef.current = filter;
|
||||||
|
updateFolders();
|
||||||
|
}, [filter]);
|
||||||
|
|
||||||
const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
|
const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
|
||||||
if (e.dataTransfer) {
|
if (e.dataTransfer) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
@ -130,6 +147,7 @@ const ChatHistoryList = () => {
|
||||||
onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
>
|
>
|
||||||
<NewFolder />
|
<NewFolder />
|
||||||
|
<ChatSearch filter={filter} setFilter={setFilter} />
|
||||||
<div className='flex flex-col gap-2 text-gray-100 text-sm'>
|
<div className='flex flex-col gap-2 text-gray-100 text-sm'>
|
||||||
{Object.keys(folders).map((folderName, folderIndex) => (
|
{Object.keys(folders).map((folderName, folderIndex) => (
|
||||||
<ChatFolder
|
<ChatFolder
|
||||||
|
|
41
src/components/Menu/ChatSearch.tsx
Normal file
41
src/components/Menu/ChatSearch.tsx
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
|
import { debounce } from 'lodash';
|
||||||
|
import useStore from '@store/store';
|
||||||
|
|
||||||
|
import SearchBar from '@components/SearchBar';
|
||||||
|
|
||||||
|
const ChatSearch = ({
|
||||||
|
filter,
|
||||||
|
setFilter,
|
||||||
|
}: {
|
||||||
|
filter: string;
|
||||||
|
setFilter: React.Dispatch<React.SetStateAction<string>>;
|
||||||
|
}) => {
|
||||||
|
const [_filter, _setFilter] = useState<string>(filter);
|
||||||
|
const generating = useStore((state) => state.generating);
|
||||||
|
|
||||||
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
_setFilter(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const debouncedUpdateFilter = useRef(
|
||||||
|
debounce((f) => {
|
||||||
|
setFilter(f);
|
||||||
|
}, 500)
|
||||||
|
).current;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
debouncedUpdateFilter(_filter);
|
||||||
|
}, [_filter]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SearchBar
|
||||||
|
value={_filter}
|
||||||
|
handleChange={handleChange}
|
||||||
|
className='h-8'
|
||||||
|
disabled={generating}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ChatSearch;
|
33
src/components/SearchBar/SearchBar.tsx
Normal file
33
src/components/SearchBar/SearchBar.tsx
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
const SearchBar = ({
|
||||||
|
value,
|
||||||
|
handleChange,
|
||||||
|
className,
|
||||||
|
disabled,
|
||||||
|
}: {
|
||||||
|
value: string;
|
||||||
|
handleChange: React.ChangeEventHandler<HTMLInputElement>;
|
||||||
|
className?: React.HTMLAttributes<HTMLDivElement>['className'];
|
||||||
|
disabled?: boolean;
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
<input
|
||||||
|
disabled={disabled}
|
||||||
|
type='text'
|
||||||
|
className='text-gray-800 dark:text-white p-3 text-sm bg-gray-700 disabled:opacity-40 disabled:cursor-not-allowed transition-opacity m-0 w-full h-full focus:outline-none rounded border-none'
|
||||||
|
placeholder={t('search') as string}
|
||||||
|
value={value}
|
||||||
|
onChange={(e) => {
|
||||||
|
handleChange(e);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SearchBar;
|
1
src/components/SearchBar/index.ts
Normal file
1
src/components/SearchBar/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export { default } from './SearchBar';
|
|
@ -582,6 +582,11 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@types/lodash@^4.14.192":
|
||||||
|
version "4.14.192"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.192.tgz#5790406361a2852d332d41635d927f1600811285"
|
||||||
|
integrity sha512-km+Vyn3BYm5ytMO13k9KTp27O75rbQ0NFw+U//g+PX7VZyjCioXaRFisqSIJRECljcTv73G3i6BpglNGHgUQ5A==
|
||||||
|
|
||||||
"@types/mdast@^3.0.0":
|
"@types/mdast@^3.0.0":
|
||||||
version "3.0.10"
|
version "3.0.10"
|
||||||
resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af"
|
resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af"
|
||||||
|
|
Loading…
Reference in a new issue