add feature to create new chat in a given folder (#174)

* add feature to create new chat in a given folder

This to not have to drag and drop a chat each time in a folder

* change style

* fix margin

* style: folder gradient

* style

---------

Co-authored-by: Jing Hua <59118459+ztjhz@users.noreply.github.com>
This commit is contained in:
Tindo N. Arsel 2023-04-03 17:33:40 +01:00 committed by GitHub
parent bfe3f1adfa
commit 6d1ae9f526
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 45 additions and 13 deletions

View file

@ -10,6 +10,7 @@ import {
} from '@type/chat'; } from '@type/chat';
import ChatHistory from './ChatHistory'; import ChatHistory from './ChatHistory';
import NewChat from './NewChat';
import EditIcon from '@icon/EditIcon'; import EditIcon from '@icon/EditIcon';
import DeleteIcon from '@icon/DeleteIcon'; import DeleteIcon from '@icon/DeleteIcon';
import CrossIcon from '@icon/CrossIcon'; import CrossIcon from '@icon/CrossIcon';
@ -35,6 +36,7 @@ const ChatFolder = ({
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
const folderRef = useRef<HTMLDivElement>(null); const folderRef = useRef<HTMLDivElement>(null);
const gradientRef = useRef<HTMLDivElement>(null);
const [_folderName, _setFolderName] = useState<string>(folderName); const [_folderName, _setFolderName] = useState<string>(folderName);
const [isEdit, setIsEdit] = useState<boolean>(false); const [isEdit, setIsEdit] = useState<boolean>(false);
@ -153,16 +155,18 @@ const ChatFolder = ({
style={{ background: color || '' }} style={{ background: color || '' }}
className={`${ className={`${
color ? '' : 'hover:bg-gray-850' color ? '' : 'hover:bg-gray-850'
} transition-colors flex py-3 px-3 items-center gap-3 relative rounded-md break-all cursor-pointer`} } transition-colors flex py-3 pl-3 pr-1 items-center gap-3 relative rounded-md break-all cursor-pointer`}
onClick={toggleExpanded} onClick={toggleExpanded}
ref={folderRef} ref={folderRef}
onMouseEnter={() => { onMouseEnter={() => {
if (color && folderRef.current) if (color && folderRef.current)
folderRef.current.style.background = `${color}dd`; folderRef.current.style.background = `${color}dd`;
if (gradientRef.current) gradientRef.current.style.width = '0px';
}} }}
onMouseLeave={() => { onMouseLeave={() => {
if (color && folderRef.current) if (color && folderRef.current)
folderRef.current.style.background = color; folderRef.current.style.background = color;
if (gradientRef.current) gradientRef.current.style.width = '1rem';
}} }}
> >
<FolderIcon className='h-4 w-4' /> <FolderIcon className='h-4 w-4' />
@ -182,6 +186,19 @@ const ChatFolder = ({
) : ( ) : (
_folderName _folderName
)} )}
{isEdit || (
<div
ref={gradientRef}
className='absolute inset-y-0 right-0 w-4 z-10 transition-all'
style={{
background:
color &&
`linear-gradient(to left, ${
color || 'var(--color-900)'
}, rgb(32 33 35 / 0))`,
}}
/>
)}
</div> </div>
<div <div
className='flex text-gray-300' className='flex text-gray-300'
@ -255,7 +272,7 @@ const ChatFolder = ({
)} )}
</div> </div>
</div> </div>
<div className='ml-3 pl-1 border-l-2 border-gray-700 flex flex-col gap-1'> <div className='group/folder ml-3 pl-1 border-l-2 border-gray-700 flex flex-col gap-1'>
{isExpanded && {isExpanded &&
folderChats.map((chat) => ( folderChats.map((chat) => (
<ChatHistory <ChatHistory
@ -264,6 +281,7 @@ const ChatFolder = ({
key={`${chat.title}-${chat.index}`} key={`${chat.title}-${chat.index}`}
/> />
))} ))}
{isExpanded && <NewChat folder={folderId} />}
</div> </div>
</div> </div>
); );

View file

@ -156,7 +156,7 @@ const ChatHistoryList = () => {
return ( return (
<div <div
className={`flex-col flex-1 overflow-y-auto border-b border-white/20 ${ className={`flex-col flex-1 overflow-y-scroll -mr-2 border-b border-white/20 ${
isHover ? 'bg-gray-800/40' : '' isHover ? 'bg-gray-800/40' : ''
}`} }`}
onDrop={handleDrop} onDrop={handleDrop}

View file

@ -6,26 +6,39 @@ import PlusIcon from '@icon/PlusIcon';
import useAddChat from '@hooks/useAddChat'; import useAddChat from '@hooks/useAddChat';
const NewChat = () => { const NewChat = ({ folder }: { folder?: string }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const addChat = useAddChat(); const addChat = useAddChat();
const generating = useStore((state) => state.generating); const generating = useStore((state) => state.generating);
return ( return (
<a <a
className={`max-md:hidden flex py-3 px-3 items-center gap-3 rounded-md hover:bg-gray-500/10 transition-colors duration-200 text-white text-sm md:mb-2 flex-shrink-0 md:border md:border-white/20 transition-opacity ${ className={`flex items-center max-md:hidden rounded-md hover:bg-gray-500/10 transition-all duration-200 text-white text-sm flex-shrink-0 ${
generating generating
? 'cursor-not-allowed opacity-40' ? 'cursor-not-allowed opacity-40'
: 'cursor-pointer opacity-100' : 'cursor-pointer opacity-100'
} ${
folder
? 'justify-start'
: 'py-3 px-3 gap-3 md:mb-2 md:border md:border-white/20'
}`} }`}
onClick={() => { onClick={() => {
if (!generating) addChat(); if (!generating) addChat(folder);
}} }}
title={folder ? String(t('newChat')) : ''}
> >
<PlusIcon />{' '} {folder ? (
<div className='max-h-0 group-hover/folder:max-h-10 group-hover/folder:py-3 px-3 overflow-hidden transition-all duration-200 delay-500 text-sm flex gap-3 items-center text-gray-100'>
<PlusIcon /> {t('newChat')}
</div>
) : (
<>
<PlusIcon />
<span className='hidden md:inline-flex text-white text-sm'> <span className='hidden md:inline-flex text-white text-sm'>
{t('newChat')} {t('newChat')}
</span> </span>
</>
)}
</a> </a>
); );
}; };

View file

@ -57,7 +57,7 @@ export const _defaultChatConfig: ConfigInterface = {
frequency_penalty: 0, frequency_penalty: 0,
}; };
export const generateDefaultChat = (title?: string): ChatInterface => ({ export const generateDefaultChat = (title?: string, folder?: string): ChatInterface => ({
id: uuidv4(), id: uuidv4(),
title: title ? title : 'New Chat', title: title ? title : 'New Chat',
messages: messages:
@ -66,6 +66,7 @@ export const generateDefaultChat = (title?: string): ChatInterface => ({
: [], : [],
config: { ...useStore.getState().defaultChatConfig }, config: { ...useStore.getState().defaultChatConfig },
titleSet: false, titleSet: false,
folder
}); });
export const codeLanguageSubset = [ export const codeLanguageSubset = [

View file

@ -7,7 +7,7 @@ const useAddChat = () => {
const setChats = useStore((state) => state.setChats); const setChats = useStore((state) => state.setChats);
const setCurrentChatIndex = useStore((state) => state.setCurrentChatIndex); const setCurrentChatIndex = useStore((state) => state.setCurrentChatIndex);
const addChat = () => { const addChat = (folder?:string) => {
const chats = useStore.getState().chats; const chats = useStore.getState().chats;
if (chats) { if (chats) {
const updatedChats: ChatInterface[] = JSON.parse(JSON.stringify(chats)); const updatedChats: ChatInterface[] = JSON.parse(JSON.stringify(chats));
@ -19,7 +19,7 @@ const useAddChat = () => {
title = `New Chat ${titleIndex}`; title = `New Chat ${titleIndex}`;
} }
updatedChats.unshift(generateDefaultChat(title)); updatedChats.unshift(generateDefaultChat(title, folder));
setChats(updatedChats); setChats(updatedChats);
setCurrentChatIndex(0); setCurrentChatIndex(0);
} }