Skip to content

Commit 851ce66

Browse files
authored
Merge pull request #7 from animalnots/dev
Merge from dev
2 parents 177a8a8 + 18678c4 commit 851ce66

File tree

19 files changed

+418
-85
lines changed

19 files changed

+418
-85
lines changed

public/locales/en/main.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
{
22
"save": "Save",
33
"generate": "Generate",
4+
"add_image_url": "Add image URL",
5+
"enter_image_url_placeholder": "Enter image URL",
46
"cancel": "Cancel",
57
"confirm": "Confirm",
68
"warning": "Warning",
@@ -33,6 +35,7 @@
3335
"total": "Total",
3436
"resetCost": "Reset Costs",
3537
"countTotalTokens": "Count total tokens",
38+
"displayChatSize": "Display chat size in title",
3639
"morePrompts": "You can find more prompts here: ",
3740
"clearPrompts": "Clear prompts",
3841
"postOnShareGPT": {

src/App.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,12 @@ function App() {
7979
return (
8080
<div className='overflow-hidden w-full h-full relative'>
8181
<Menu />
82-
<Chat />
83-
<ApiPopup />
84-
<Toast />
85-
<ToastContainer />
82+
<div className={`flex h-full flex-1 flex-col`}>
83+
<Chat />
84+
<ApiPopup />
85+
<Toast />
86+
<ToastContainer />
87+
</div>
8688
</div>
8789
);
8890
}

src/components/Chat/Chat.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ import StopGeneratingButton from '@components/StopGeneratingButton/StopGeneratin
77

88
const Chat = () => {
99
const hideSideMenu = useStore((state) => state.hideSideMenu);
10+
const menuWidth = useStore((state) => state.menuWidth);
1011

1112
return (
1213
<div
13-
className={`flex h-full flex-1 flex-col ${
14-
hideSideMenu ? 'md:pl-0' : 'md:pl-[260px]'
15-
}`}
14+
className={`flex h-full flex-1 flex-col`}
15+
style={{ paddingLeft: hideSideMenu ? '0' : `${menuWidth}px` }}
1616
>
1717
<MobileBar />
1818
<main className='relative h-full w-full transition-width flex flex-col overflow-hidden items-stretch flex-1'>

src/components/Chat/ChatContent/ChatTitle.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const ChatTitle = React.memo(() => {
4343
return config ? (
4444
<>
4545
<div
46-
className='flex gap-x-4 gap-y-1 flex-wrap w-full items-center justify-center border-b border-black/10 bg-gray-50 p-3 dark:border-gray-900/50 dark:bg-gray-700 text-gray-600 dark:text-gray-300 cursor-pointer'
46+
className='sticky top-0 z-10 flex gap-x-4 gap-y-1 flex-wrap w-full items-center justify-center border-b border-black/10 bg-gray-50 p-3 dark:border-gray-900/50 dark:bg-gray-700 text-gray-600 dark:text-gray-300 cursor-pointer'
4747
onClick={() => {
4848
setIsModalOpen(true);
4949
}}

src/components/Chat/ChatContent/Message/View/ContentView.tsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ import CrossIcon from '@icon/CrossIcon';
1919

2020
import useSubmit from '@hooks/useSubmit';
2121

22-
import { ChatInterface, ContentInterface, ImageContentInterface, TextContentInterface } from '@type/chat';
22+
import {
23+
ChatInterface,
24+
ContentInterface,
25+
ImageContentInterface,
26+
TextContentInterface,
27+
} from '@type/chat';
2328

2429
import { codeLanguageSubset } from '@constants/chat';
2530

@@ -41,7 +46,7 @@ const ContentView = memo(
4146
messageIndex,
4247
}: {
4348
role: string;
44-
content: ContentInterface[],
49+
content: ContentInterface[];
4550
setIsEdit: React.Dispatch<React.SetStateAction<boolean>>;
4651
messageIndex: number;
4752
}) => {
@@ -132,13 +137,19 @@ const ContentView = memo(
132137
{(content[0] as TextContentInterface).text}
133138
</ReactMarkdown>
134139
) : (
135-
<span className='whitespace-pre-wrap'>{(content[0] as TextContentInterface).text}</span>
140+
<span className='whitespace-pre-wrap'>
141+
{(content[0] as TextContentInterface).text}
142+
</span>
136143
)}
137144
</div>
138-
<div className="flex gap-4">
145+
<div className='flex gap-4'>
139146
{(content.slice(1) as ImageContentInterface[]).map((image, index) => (
140-
<div key={index} className="image-container">
141-
<img src={image.image_url.url} alt={`uploaded-${index}`} className="h-20" />
147+
<div key={index} className='image-container'>
148+
<img
149+
src={image.image_url.url}
150+
alt={`uploaded-${index}`}
151+
className='h-20'
152+
/>
142153
</div>
143154
))}
144155
</div>

src/components/Chat/ChatContent/Message/View/EditView.tsx

Lines changed: 87 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const EditView = ({
3434

3535
const [_content, _setContent] = useState<ContentInterface[]>(content);
3636
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
37+
const [imageUrl, setImageUrl] = useState<string>('');
3738
const textareaRef = React.createRef<HTMLTextAreaElement>();
3839

3940
const { t } = useTranslation();
@@ -104,6 +105,22 @@ const EditView = ({
104105
_setContent(updatedContent);
105106
};
106107

108+
const handleImageUrlChange = () => {
109+
if (imageUrl.trim() === '') return;
110+
111+
const newImage: ImageContentInterface = {
112+
type: 'image_url',
113+
image_url: {
114+
detail: 'auto',
115+
url: imageUrl,
116+
},
117+
};
118+
119+
const updatedContent = [..._content, newImage];
120+
_setContent(updatedContent);
121+
setImageUrl('');
122+
};
123+
107124
const handleImageDetailChange = (index: number, detail: string) => {
108125
const updatedImages = [..._content];
109126
updatedImages[index + 1].image_url.detail = detail;
@@ -229,6 +246,9 @@ const EditView = ({
229246
setIsEdit={setIsEdit}
230247
_setContent={_setContent}
231248
_content={_content}
249+
imageUrl={imageUrl}
250+
setImageUrl={setImageUrl}
251+
handleImageUrlChange={handleImageUrlChange}
232252
/>
233253
{isModalOpen && (
234254
<PopupModal
@@ -254,6 +274,9 @@ const EditViewButtons = memo(
254274
setIsEdit,
255275
_setContent,
256276
_content,
277+
imageUrl,
278+
setImageUrl,
279+
handleImageUrlChange,
257280
}: {
258281
sticky?: boolean;
259282
handleFileChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
@@ -265,6 +288,9 @@ const EditViewButtons = memo(
265288
setIsEdit: React.Dispatch<React.SetStateAction<boolean>>;
266289
_setContent: React.Dispatch<React.SetStateAction<ContentInterface[]>>;
267290
_content: ContentInterface[];
291+
imageUrl: string;
292+
setImageUrl: React.Dispatch<React.SetStateAction<string>>;
293+
handleImageUrlChange: () => void;
268294
}) => {
269295
const { t } = useTranslation();
270296
const generating = useStore.getState().generating;
@@ -286,65 +312,82 @@ const EditViewButtons = memo(
286312
return (
287313
<div>
288314
{modelTypes[model] == 'image' && (
289-
<div className='flex justify-center'>
290-
<div className='flex gap-5'>
291-
{_content.slice(1).map((image, index) => (
292-
<div
293-
key={index}
294-
className='image-container flex flex-col gap-2'
295-
>
296-
<img
297-
src={image.image_url.url}
298-
alt={`uploaded-${index}`}
299-
className='h-10'
300-
/>
301-
<div className='flex flex-row gap-3'>
302-
<select
303-
onChange={(event) =>
304-
handleImageDetailChange(index, event.target.value)
305-
}
306-
title='Select image resolution'
307-
aria-label='Select image resolution'
308-
defaultValue={image.image_url.detail}
309-
style={{ color: 'black' }}
310-
>
311-
<option value='auto'>Auto</option>
312-
<option value='high'>High</option>
313-
<option value='low'>Low</option>
314-
</select>
315-
<button
316-
className='close-button'
317-
onClick={() => handleRemoveImage(index)}
318-
aria-label='Remove Image'
319-
>
320-
&times;
321-
</button>
315+
<>
316+
<div className='flex justify-center'>
317+
<div className='flex gap-5'>
318+
{_content.slice(1).map((image, index) => (
319+
<div
320+
key={index}
321+
className='image-container flex flex-col gap-2'
322+
>
323+
<img
324+
src={image.image_url.url}
325+
alt={`uploaded-${index}`}
326+
className='h-10'
327+
/>
328+
<div className='flex flex-row gap-3'>
329+
<select
330+
onChange={(event) =>
331+
handleImageDetailChange(index, event.target.value)
332+
}
333+
title='Select image resolution'
334+
aria-label='Select image resolution'
335+
defaultValue={image.image_url.detail}
336+
style={{ color: 'black' }}
337+
>
338+
<option value='auto'>Auto</option>
339+
<option value='high'>High</option>
340+
<option value='low'>Low</option>
341+
</select>
342+
<button
343+
className='close-button'
344+
onClick={() => handleRemoveImage(index)}
345+
aria-label='Remove Image'
346+
>
347+
&times;
348+
</button>
349+
</div>
322350
</div>
323-
</div>
324-
))}
351+
))}
325352

353+
<button
354+
className='btn relative btn-neutral h-10'
355+
onClick={handleUploadButtonClick}
356+
aria-label={'Upload Images'}
357+
>
358+
<div className='flex items-center justify-center gap-2'>
359+
<FolderIcon />
360+
</div>
361+
</button>
362+
</div>
363+
</div>
364+
<div className='flex justify-center mt-4'>
365+
<input
366+
type='text'
367+
value={imageUrl}
368+
onChange={(e) => setImageUrl(e.target.value)}
369+
placeholder={t('enter_image_url_placeholder') as string}
370+
className='input input-bordered w-full max-w-xs text-gray-800 dark:text-white p-3 border-none bg-gray-200 dark:bg-gray-600 rounded-md m-0 w-full mr-0 h-10 focus:outline-none'
371+
/>
326372
<button
327-
className='btn relative btn-neutral h-10'
328-
onClick={handleUploadButtonClick}
329-
aria-label={'Upload Images'}
373+
className='btn btn-primary ml-2'
374+
onClick={handleImageUrlChange}
375+
aria-label={t('add_image_url') as string}
330376
>
331-
<div className='flex items-center justify-center gap-2'>
332-
<FolderIcon />
333-
</div>
377+
{t('add_image_url')}
334378
</button>
335379
</div>
336-
337380
{/* Hidden file input */}
338381
<input
339382
type='file'
340383
ref={fileInputRef}
341384
style={{ display: 'none' }}
342385
onChange={handleFileChange}
343-
accept='image/*'
344386
multiple
345387
/>
346-
</div>
388+
</>
347389
)}
390+
348391
<div className='flex'>
349392
<div className='flex-1 text-center mt-2 flex justify-center'>
350393
{sticky && (

src/components/Menu/ChatFolder.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,17 @@ import useHideOnOutsideClick from '@hooks/useHideOnOutsideClick';
2525
const ChatFolder = ({
2626
folderChats,
2727
folderId,
28+
selectedChats,
29+
setSelectedChats,
30+
lastSelectedIndex,
31+
setLastSelectedIndex,
2832
}: {
2933
folderChats: ChatHistoryInterface[];
3034
folderId: string;
35+
selectedChats: number[];
36+
setSelectedChats: (indices: number[]) => void;
37+
lastSelectedIndex: number | null;
38+
setLastSelectedIndex: (index: number) => void;
3139
}) => {
3240
const folderName = useStore((state) => state.folders[folderId]?.name);
3341
const isExpanded = useStore((state) => state.folders[folderId]?.expanded);
@@ -116,12 +124,15 @@ const ChatFolder = ({
116124
setFolders(updatedFolders);
117125

118126
// update chat folderId to new folderId
119-
const chatIndex = Number(e.dataTransfer.getData('chatIndex'));
127+
const chatIndices = JSON.parse(e.dataTransfer.getData('chatIndices'));
120128
const updatedChats: ChatInterface[] = JSON.parse(
121129
JSON.stringify(useStore.getState().chats)
122130
);
123-
updatedChats[chatIndex].folder = folderId;
131+
chatIndices.forEach((chatIndex: number) => {
132+
updatedChats[chatIndex].folder = folderId;
133+
});
124134
setChats(updatedChats);
135+
setSelectedChats([]);
125136
}
126137
};
127138

@@ -304,7 +315,12 @@ const ChatFolder = ({
304315
<ChatHistory
305316
title={chat.title}
306317
chatIndex={chat.index}
318+
chatSize={chat.chatSize}
307319
key={`${chat.title}-${chat.index}`}
320+
selectedChats={selectedChats}
321+
setSelectedChats={setSelectedChats}
322+
lastSelectedIndex={lastSelectedIndex}
323+
setLastSelectedIndex={setLastSelectedIndex}
308324
/>
309325
))}
310326
</div>

0 commit comments

Comments
 (0)