Skip to content

Commit 5c600a3

Browse files
committed
Layout: Fix conversation list
1 parent 392b454 commit 5c600a3

18 files changed

+245
-154
lines changed

src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useEffect } from 'react';
2-
import { ChatPage } from './pages/ChatPage';
2+
import { ChatPage } from './components/pages/ChatPage';
33
import MainLayout from './components/layout/MainLayout';
44
import DatabaseInitializer from './components/core/DatabaseInitializer';
55

src/components/chat/ChatHistoryList.tsx

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useState, useRef, useEffect } from 'react';
22
import { Conversation, ConversationFolder } from '../../types/chat';
3-
import { MessageSquare, MoreVertical, Edit, Trash2, ChevronLeft, ChevronRight, AlertTriangle, MessageSquarePlus, FolderPlus, Folder, ChevronDown } from 'lucide-react';
3+
import { MessageSquare, MoreVertical, Edit, Trash2, ChevronLeft, ChevronRight, AlertTriangle, FolderPlus, Folder, ChevronDown, PlusCircle } from 'lucide-react';
44
import ContextMenu, { ContextMenuItem } from '../ui/ContextMenu';
55
import ConfirmDialog from '../ui/ConfirmDialog';
66

@@ -255,7 +255,7 @@ export const ChatHistoryList: React.FC<ChatHistoryListProps> = ({
255255
// Add some ghost image effect
256256
if (e.dataTransfer.setDragImage) {
257257
const elem = document.createElement('div');
258-
elem.classList.add('bg-blue-100', 'p-2', 'rounded', 'shadow', 'text-sm', 'w-fit');
258+
elem.classList.add('conversation-selected-item-bg-color', 'p-2', 'rounded', 'shadow', 'text-sm', 'w-fit');
259259
elem.innerText = conversations.find(c => c.conversationId === item.id)?.title || 'Moving...';
260260
document.body.appendChild(elem);
261261
e.dataTransfer.setDragImage(elem, 10, 10);
@@ -389,7 +389,7 @@ export const ChatHistoryList: React.FC<ChatHistoryListProps> = ({
389389
ref={sidebarRef}
390390
onMouseEnter={handleSidebarMouseEnter}
391391
onMouseLeave={handleSidebarMouseLeave}
392-
className={`flex flex-col h-full border-r border-gray-200 bg-gray-50 transition-all duration-300 ease-in-out ${isCollapsed ? 'w-0' : 'w-64'} relative`}
392+
className={`flex flex-col h-full border-r border-gray-200 major-area-bg-color transition-all duration-300 ease-in-out ${isCollapsed ? 'w-0' : 'w-64'} relative`}
393393
onDragOver={(e) => handleDragOver(e, 'root', 'root')}
394394
onDrop={(e) => handleDrop(e, 'root', 'root')}
395395
>
@@ -413,26 +413,26 @@ export const ChatHistoryList: React.FC<ChatHistoryListProps> = ({
413413
onMouseLeave={handleButtonMouseLeave}
414414
onFocus={() => setIsButtonVisible(true)}
415415
onBlur={() => !isSidebarHovered && setIsButtonVisible(false)}
416-
className={`absolute z-10 flex items-center justify-center w-6 h-20 transform -translate-y-1/2 bg-gray-200 -right-6 top-1/2 hover:bg-gray-300 rounded-r-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50 transition-opacity duration-300 ${isButtonVisible || isButtonHovered ? 'opacity-100' : 'opacity-0'}`}
416+
className={`absolute z-10 flex items-center justify-center w-6 h-20 transform -translate-y-1/2 bg-gray-200 -right-6 top-1/2 hover:bg-gray-300 rounded-r-md transition-opacity duration-300 ${isButtonVisible || isButtonHovered ? 'opacity-100' : 'opacity-0'}`}
417417
aria-label={isCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}
418418
title={isCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}
419419
>
420420
{isCollapsed ? <ChevronRight size={16} /> : <ChevronLeft size={16} />}
421421
</button>
422422

423-
<div className={`p-2 border-b border-gray-200 ${isCollapsed ? 'opacity-0 pointer-events-none' : 'flex justify-between items-center'}`}>
423+
<div className={`p-2 h-12 major-area-bg-color transition-all duration-100 ease-in-out ${isCollapsed ? 'opacity-0 pointer-events-none' : 'flex justify-between items-center gap-2'}`}>
424424
<button
425425
onClick={onCreateNewFolder}
426-
className="flex items-center justify-center p-2 text-sm font-medium text-gray-700 transition-colors bg-white border border-gray-300 rounded-md aspect-square hover:bg-gray-50 checked:outline-none checked:ring-2 checked:ring-blue-500"
426+
className="flex items-center justify-center h-full text-sm font-medium transition-colors aspect-square primary-btn-border primary-btn-bg-color primary-btn-text-color"
427427
>
428428
<FolderPlus size={16}/>
429429
</button>
430430

431431
<button
432432
onClick={onCreateNewChat}
433-
className="flex items-center justify-center gap-1 p-2 text-sm font-medium text-gray-700 transition-colors bg-white border border-gray-300 rounded-md hover:bg-gray-50 checked:outline-none checked:ring-2 checked:ring-blue-500"
433+
className="flex items-center justify-center flex-1 h-full gap-2 pr-2 text-sm font-medium transition-all duration-100 primary-btn-border primary-btn-bg-color primary-btn-text-color"
434434
>
435-
<MessageSquarePlus size={16}/>
435+
<PlusCircle size={16}/>
436436
<span className="text-sm">New Chat</span>
437437
</button>
438438

@@ -447,7 +447,7 @@ export const ChatHistoryList: React.FC<ChatHistoryListProps> = ({
447447
{!isCollapsed && <p className="text-sm">No conversations yet</p>}
448448
</div>
449449
) : (
450-
<ul className="py-2">
450+
<ul className="flex flex-col gap-0.5 py-2">
451451
{rootItems.map(({ type, item }) => (
452452
<li
453453
key={type === 'folder' ? `folder-${item.folderId}` : `conv-${(item as Conversation).conversationId}`}
@@ -479,7 +479,7 @@ export const ChatHistoryList: React.FC<ChatHistoryListProps> = ({
479479
onDrop={(e) => handleDrop(e, (item as ConversationFolder).folderId, 'folder')}
480480
>
481481
{isCollapsed ? (
482-
<Folder size={16} className="mx-auto text-gray-600" />
482+
<Folder fill={(item as ConversationFolder).colorFlag} size={16} className="mx-auto text-gray-600" />
483483
) : (
484484
<>
485485
<div
@@ -492,7 +492,7 @@ export const ChatHistoryList: React.FC<ChatHistoryListProps> = ({
492492
<ChevronRight size={16} className="text-gray-500" />
493493
}
494494
</button>
495-
<Folder size={16} className="flex-shrink-0 mr-1 text-gray-600" />
495+
<Folder fill={(item as ConversationFolder).colorFlag} size={16} className="flex-shrink-0 mr-1 text-gray-600" />
496496
<span className="font-medium truncate select-none">{(item as ConversationFolder).folderName}</span>
497497
</div>
498498
<div onClick={(e) => handleMenuClick(e, (item as ConversationFolder).folderId, 'folder')}>
@@ -508,14 +508,14 @@ export const ChatHistoryList: React.FC<ChatHistoryListProps> = ({
508508
items={getFolderContextMenuItems(item as ConversationFolder)}
509509
isOpen={openMenuId === (item as ConversationFolder).folderId}
510510
onClose={() => setOpenMenuId(null)}
511-
position={{ top: '100%', right: '12px' }}
511+
position={{ top: '2.5rem', right: '12px' }}
512512
width="10rem"
513513
/>
514514
)}
515515

516516
{/* Folder contents */}
517517
{!isCollapsed && expandedFolders[(item as ConversationFolder).folderId] && (
518-
<ul className="pl-6 mt-1">
518+
<ul className="pl-6 mt-1 mr-2">
519519
{conversationsByFolder[(item as ConversationFolder).folderId]?.map((conversation) => (
520520
<li key={conversation.conversationId} className="relative">
521521
{editingId === conversation.conversationId ? (
@@ -538,10 +538,10 @@ export const ChatHistoryList: React.FC<ChatHistoryListProps> = ({
538538
onDragOver={(e) => handleDragOver(e, (item as ConversationFolder).folderId, 'folder')}
539539
onDrop={(e) => handleDrop(e, (item as ConversationFolder).folderId, 'folder')}
540540
onClick={() => onSelectConversation(conversation.conversationId)}
541-
className={`flex items-center justify-between w-full px-2 py-1 text-left rounded-sm ${
541+
className={`flex items-center justify-between w-full px-3 py-2 text-left conversation-item-border ${
542542
activeConversationId === conversation.conversationId
543-
? 'bg-blue-50 text-blue-600'
544-
: 'text-gray-700 hover:bg-gray-100'
543+
? 'conversation-selected-item-bg-color conversation-selected-item-text-color'
544+
: 'conversation-item-bg-color conversation-item-text-color'
545545
}
546546
${draggingItem?.id === conversation.conversationId ? 'opacity-50' : ''}
547547
${
@@ -550,11 +550,11 @@ export const ChatHistoryList: React.FC<ChatHistoryListProps> = ({
550550
}`}
551551
>
552552
<div className="flex items-center truncate">
553-
<MessageSquare size={14} className="flex-shrink-0 mr-1" />
554-
<span className="text-sm truncate">{conversation.title}</span>
553+
<MessageSquare size={16} className="flex-shrink-0 mr-1" />
554+
<span className="truncate">{conversation.title}</span>
555555
</div>
556556
<div onClick={(e) => handleMenuClick(e, conversation.conversationId, 'conversation')}>
557-
<MoreVertical size={14} className="flex-shrink-0 text-gray-400 hover:text-gray-600" />
557+
<MoreVertical size={16} className="flex-shrink-0" />
558558
</div>
559559
</div>
560560
)}
@@ -594,10 +594,10 @@ export const ChatHistoryList: React.FC<ChatHistoryListProps> = ({
594594
onDragStart={(e) => handleDragStart(e, { id: (item as Conversation).conversationId, type: 'conversation' })}
595595
onDragEnd={handleDragEnd}
596596
onClick={() => onSelectConversation((item as Conversation).conversationId)}
597-
className={`flex items-center justify-between w-full ${isCollapsed ? 'px-0 py-3 flex-col' : 'px-4 py-2'} text-left ${
597+
className={`flex flex-1 items-center justify-between mx-2 conversation-item-border px-3 py-2 text-left transition-all duration-100 ${
598598
activeConversationId === (item as Conversation).conversationId
599-
? 'bg-blue-50 text-blue-600'
600-
: 'text-gray-700 hover:bg-gray-100'
599+
? 'conversation-selected-item-bg-color conversation-selected-item-text-color'
600+
: 'conversation-item-bg-color conversation-item-text-color'
601601
} ${draggingItem?.id === (item as Conversation).conversationId ? 'opacity-50' : ''}`}
602602
title={isCollapsed ? (item as Conversation).title : undefined}
603603
>
@@ -610,7 +610,7 @@ export const ChatHistoryList: React.FC<ChatHistoryListProps> = ({
610610
<span className="truncate">{(item as Conversation).title}</span>
611611
</div>
612612
<div onClick={(e) => handleMenuClick(e, (item as Conversation).conversationId, 'conversation')}>
613-
<MoreVertical size={16} className="flex-shrink-0 text-gray-400 hover:text-gray-600" />
613+
<MoreVertical size={16} className="flex-shrink-0" />
614614
</div>
615615
</>
616616
)}

src/components/chat/ChatMessageArea.tsx

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useState, FormEvent, useRef, useEffect } from 'react';
22
import { Conversation, Message } from '../../types/chat';
3-
import { Send, Square, Copy, RotateCcw, Share2, Pencil, Loader2, Globe } from 'lucide-react';
3+
import { Send, Square, Copy, RotateCcw, Pencil, Loader2, Globe } from 'lucide-react';
44
import MarkdownContent from './MarkdownContent';
55
import MessageToolboxMenu, { ToolboxAction } from '../ui/MessageToolboxMenu';
66
import { MessageHelper } from '../../services/message-helper';
@@ -70,7 +70,6 @@ export const ChatMessageArea: React.FC<ChatMessageAreaProps> = ({
7070
}, []);
7171

7272
useEffect(() => {
73-
console.log('Updated provider or model');
7473
const result = ChatService.getInstance().getCurrentProviderModelCapabilities().includes(AIServiceCapability.WebSearch);
7574
setIsWebSearchAllowed(result);
7675
}, [selectedProvider, selectedModel]);
@@ -135,9 +134,9 @@ export const ChatMessageArea: React.FC<ChatMessageAreaProps> = ({
135134
};
136135

137136
// Placeholder error handler for other actions
138-
const handleActionError = (action: string) => {
139-
console.error(`Function not implemented yet: ${action}`);
140-
};
137+
// const handleActionError = (action: string) => {
138+
// console.error(`Function not implemented yet: ${action}`);
139+
// };
141140

142141
const getMessagesList = () => {
143142
return messagesList;
@@ -212,6 +211,16 @@ export const ChatMessageArea: React.FC<ChatMessageAreaProps> = ({
212211
}
213212
};
214213

214+
const getModelName = (modelID: string) => {
215+
const providerSettings = SettingsService.getInstance().getProviderSettings(selectedProvider);
216+
if(!providerSettings.models) return modelID;
217+
218+
const model = providerSettings.models?.find(m => m.modelId === modelID);
219+
if(!model) return modelID;
220+
221+
return model.modelName;
222+
}
223+
215224
// If no active conversation is selected
216225
if (!activeConversation) {
217226
return (
@@ -255,12 +264,12 @@ export const ChatMessageArea: React.FC<ChatMessageAreaProps> = ({
255264
label: 'Copy',
256265
onClick: () => handleCopyMessage(message.content),
257266
},
258-
{
259-
id: 'share',
260-
icon: Share2,
261-
label: 'Share',
262-
onClick: () => handleActionError('share message'),
263-
},
267+
// {
268+
// id: 'share',
269+
// icon: Share2,
270+
// label: 'Share',
271+
// onClick: () => handleActionError('share message'),
272+
// },
264273
{
265274
id: 'regenerate',
266275
icon: RotateCcw,
@@ -303,6 +312,13 @@ export const ChatMessageArea: React.FC<ChatMessageAreaProps> = ({
303312
</div>
304313
) : (
305314
<>
315+
{!isUserMessage &&
316+
<div className="flex items-center flex-1 gap-2 px-2 mb-4 justify-left">
317+
<span className="text-sm text-gray-500">{getModelName(message.model)}</span>
318+
<span className="text-sm text-gray-500 bg-gray-200 rounded-full px-2 py-0.5">{message.provider}</span>
319+
</div>
320+
}
321+
306322
<div
307323
className={`max-w-[80%] rounded-lg p-3 ${
308324
isUserMessage

src/components/layout/MainLayout.tsx

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { ReactNode, useState } from 'react';
22
import Sidebar from './Sidebar';
3-
import SettingsPage from '../../pages/SettingsPage';
3+
import SettingsPage from '../pages/SettingsPage';
44
import TopBar from './TopBar';
55
import { SettingsService } from '../../services/settings-service';
66

@@ -11,18 +11,25 @@ interface MainLayoutProps {
1111
const MainLayout: React.FC<MainLayoutProps> = ({ children }) => {
1212
const [activePage, setActivePage] = useState('chat');
1313
const [showSettings, setShowSettings] = useState(false);
14+
1415
// Handle page changes
1516
const handlePageChange = (page: string) => {
17+
if(activePage === 'settings' && page !== activePage){
18+
// Save settings
19+
}
20+
1621
if (page === 'settings') {
1722
setShowSettings(true);
23+
setActivePage('settings');
1824
} else {
25+
setShowSettings(false);
1926
setActivePage(page);
2027
}
2128
};
2229

2330
// Handle page changes
2431
const handleOpenSettingsDialog = () => {
25-
setShowSettings(true);
32+
handlePageChange('settings');
2633
};
2734

2835
// Handle selecting a model
@@ -45,19 +52,21 @@ const MainLayout: React.FC<MainLayoutProps> = ({ children }) => {
4552
onChangePage={handlePageChange}
4653
/>
4754

48-
<div className="flex flex-col flex-1">
55+
<div className="flex flex-col flex-1 bg-main-background-color">
4956
{/* Main content */}
5057

51-
{showSettings ?
58+
<div className='flex flex-col flex-1 overflow-hidden major-area-border major-area-bg-color'>
5259
<SettingsPage
5360
isOpen={showSettings}
54-
onClose={() => setShowSettings(false)}
5561
/>
56-
:
57-
<div className="flex-1 overflow-auto">
58-
{children}
59-
</div>
60-
}
62+
63+
{!showSettings &&
64+
<div className="flex-1 overflow-auto">
65+
{children}
66+
</div>
67+
}
68+
</div>
69+
6170
{/* <BottomBar loadedModels={loadedModels} /> */}
6271
</div>
6372
</div>

src/components/layout/Sidebar.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ interface SidebarProps {
88

99
export const Sidebar: React.FC<SidebarProps> = ({ activePage, onChangePage }) => {
1010
return (
11-
<div className="w-[68px] h-full bg-[#f8f8f8] border-r border-gray-200 flex flex-col">
11+
<div className="w-[68px] h-full bg-main-background-color flex flex-col">
1212

1313
{/* Navigation buttons */}
1414
<div className="flex flex-col items-center flex-1 pt-2">
1515
<button
16-
className={`w-12 h-12 rounded-lg flex items-center justify-center mb-2 ${
16+
className={`w-12 h-12 rounded-lg flex items-center justify-center ${
1717
activePage === 'chat'
1818
? 'bg-gray-200 text-black'
1919
: 'text-gray-600 hover:bg-gray-100'
@@ -28,9 +28,13 @@ export const Sidebar: React.FC<SidebarProps> = ({ activePage, onChangePage }) =>
2828
</div>
2929

3030
{/* Settings button at bottom */}
31-
<div className="flex justify-center p-4">
31+
<div className="flex justify-center mb-4">
3232
<button
33-
className="flex items-center justify-center w-12 h-12 text-gray-600 rounded-lg hover:bg-gray-100"
33+
className={`flex items-center justify-center w-12 h-12 text-gray-600 rounded-lg ${
34+
activePage === 'settings'
35+
? 'bg-gray-200 text-black'
36+
: 'text-gray-600 hover:bg-gray-100'
37+
}`}
3438
onClick={() => onChangePage('settings')}
3539
aria-label="Settings"
3640
>

0 commit comments

Comments
 (0)