From d1310440ec9bb405a966464ad4c94a5467e230ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?El=C3=A9onore=20Voisin?= Date: Fri, 25 Jul 2025 18:41:05 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8(front)=20global=20layout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit modify left panel, header and chat --- .../src/assets/icons/conversation.svg | 31 ++ .../src/assets/icons/left-panel-bold.svg | 3 + .../conversations/src/assets/icons/search.svg | 10 + .../src/assets/logo/assistant.svg | 8 + .../src/assets/logo/logo-assistant.svg | 11 + .../src/components/SideModal.tsx | 2 - .../src/cunningham/cunningham-tokens.ts | 10 +- .../components/ConversationSearchItem.tsx | 61 ++- .../components/ConversationSearchModal.tsx | 13 +- .../src/features/chat/components/Chat.tsx | 419 ++++-------------- .../features/chat/components/InputChat.tsx | 337 ++++++++++++++ .../components/ButtonToggleLeftPanel.tsx | 21 + .../src/features/header/components/Header.tsx | 36 +- .../conversations/src/features/header/conf.ts | 2 +- .../src/features/home/assets/banner.jpg | Bin 417114 -> 0 bytes .../src/features/home/assets/banner.svg | 214 +++++++++ .../features/home/components/HomeBanner.tsx | 39 +- .../features/home/components/HomeBottom.tsx | 6 +- .../features/home/components/HomeContent.tsx | 31 +- .../features/home/components/HomeHeader.tsx | 4 +- .../left-panel/assets/bubble-bold.svg | 6 + .../left-panel/assets/bubble-notif-bold.svg | 7 + .../left-panel/assets/simple-document.svg | 117 ----- .../components/ConversationItemActions.tsx | 23 +- .../left-panel/components/LeftPanel.tsx | 9 +- .../components/LeftPanelConversationItem.tsx | 20 +- .../components/LeftPanelConversations.tsx | 8 +- .../left-panel/components/LeftPanelHeader.tsx | 60 +-- .../components/SimpleConversationItem.tsx | 24 +- .../conversations/src/layouts/MainLayout.tsx | 65 +-- .../src/pages/chat/[id]/index.tsx | 2 +- .../conversations/src/pages/chat/index.tsx | 2 +- .../apps/conversations/src/pages/globals.css | 4 + .../__tests__/app-conversations/home.spec.ts | 7 +- 34 files changed, 984 insertions(+), 628 deletions(-) create mode 100644 src/frontend/apps/conversations/src/assets/icons/conversation.svg create mode 100644 src/frontend/apps/conversations/src/assets/icons/left-panel-bold.svg create mode 100644 src/frontend/apps/conversations/src/assets/icons/search.svg create mode 100644 src/frontend/apps/conversations/src/assets/logo/assistant.svg create mode 100644 src/frontend/apps/conversations/src/assets/logo/logo-assistant.svg create mode 100644 src/frontend/apps/conversations/src/features/chat/components/InputChat.tsx create mode 100644 src/frontend/apps/conversations/src/features/header/components/ButtonToggleLeftPanel.tsx delete mode 100644 src/frontend/apps/conversations/src/features/home/assets/banner.jpg create mode 100644 src/frontend/apps/conversations/src/features/home/assets/banner.svg create mode 100644 src/frontend/apps/conversations/src/features/left-panel/assets/bubble-bold.svg create mode 100644 src/frontend/apps/conversations/src/features/left-panel/assets/bubble-notif-bold.svg delete mode 100644 src/frontend/apps/conversations/src/features/left-panel/assets/simple-document.svg diff --git a/src/frontend/apps/conversations/src/assets/icons/conversation.svg b/src/frontend/apps/conversations/src/assets/icons/conversation.svg new file mode 100644 index 0000000..c011fbd --- /dev/null +++ b/src/frontend/apps/conversations/src/assets/icons/conversation.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/frontend/apps/conversations/src/assets/icons/left-panel-bold.svg b/src/frontend/apps/conversations/src/assets/icons/left-panel-bold.svg new file mode 100644 index 0000000..fab0e9a --- /dev/null +++ b/src/frontend/apps/conversations/src/assets/icons/left-panel-bold.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/frontend/apps/conversations/src/assets/icons/search.svg b/src/frontend/apps/conversations/src/assets/icons/search.svg new file mode 100644 index 0000000..37100c1 --- /dev/null +++ b/src/frontend/apps/conversations/src/assets/icons/search.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/frontend/apps/conversations/src/assets/logo/assistant.svg b/src/frontend/apps/conversations/src/assets/logo/assistant.svg new file mode 100644 index 0000000..d002d01 --- /dev/null +++ b/src/frontend/apps/conversations/src/assets/logo/assistant.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/frontend/apps/conversations/src/assets/logo/logo-assistant.svg b/src/frontend/apps/conversations/src/assets/logo/logo-assistant.svg new file mode 100644 index 0000000..c8d8049 --- /dev/null +++ b/src/frontend/apps/conversations/src/assets/logo/logo-assistant.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/frontend/apps/conversations/src/components/SideModal.tsx b/src/frontend/apps/conversations/src/components/SideModal.tsx index d844304..db6f417 100644 --- a/src/frontend/apps/conversations/src/components/SideModal.tsx +++ b/src/frontend/apps/conversations/src/components/SideModal.tsx @@ -20,8 +20,6 @@ const SideModalStyle = createGlobalStyle` } & .c__modal{ - animation: slidein 0.7s; - width: ${({ width }) => width}; ${({ side }) => side === 'right' && 'left: auto;'}; diff --git a/src/frontend/apps/conversations/src/cunningham/cunningham-tokens.ts b/src/frontend/apps/conversations/src/cunningham/cunningham-tokens.ts index a547d65..d733685 100644 --- a/src/frontend/apps/conversations/src/cunningham/cunningham-tokens.ts +++ b/src/frontend/apps/conversations/src/cunningham/cunningham-tokens.ts @@ -221,7 +221,7 @@ export const tokens = { 'border-radius': '4px', 'small-height': '26px', primary: { - 'background--color': '#000091', + 'background--color': '#3E5DE7', 'background--color-hover': '#1212ff', 'background--color-active': '#2323ff', 'background--color-disabled': '#eee', @@ -232,13 +232,13 @@ export const tokens = { disabled: '#7C7C7C', }, 'primary-text': { - 'background--color': '#000091', + 'background--color': '#3E5DE7', 'background--color-hover': '#eee', 'background--color-active': '#ECECFE', 'background--color-focus-visible': '#fff', 'background--color-disabled': '#fff', - color: '#000091', - 'color-hover': '#000091', + color: '#3E5DE7', + 'color-hover': '#3E5DE7', disabled: '#929292', }, secondary: { @@ -381,7 +381,7 @@ export const tokens = { 'greyscale-200': '#303C4B', 'greyscale-300': '#555F6B', 'greyscale-400': '#79818A', - 'greyscale-500': '#9EA3AA', + 'greyscale-500': '#6D778C', 'greyscale-600': '#C2C6CA', 'greyscale-700': '#E7E8EA', 'greyscale-800': '#F3F4F4', diff --git a/src/frontend/apps/conversations/src/features/chat-search/components/ConversationSearchItem.tsx b/src/frontend/apps/conversations/src/features/chat-search/components/ConversationSearchItem.tsx index a10a8f6..bf9a782 100644 --- a/src/frontend/apps/conversations/src/features/chat-search/components/ConversationSearchItem.tsx +++ b/src/frontend/apps/conversations/src/features/chat-search/components/ConversationSearchItem.tsx @@ -1,7 +1,12 @@ -import { Box, Icon } from '@/components'; +import { DateTime } from 'luxon'; +import { useTranslation } from 'react-i18next'; +import { css } from 'styled-components'; + +import BubbleIcon from '@/assets/icons/conversation.svg'; +import { Box, Icon, Text } from '@/components'; import { QuickSearchItemContent } from '@/components/quick-search/'; +import { useCunninghamTheme } from '@/cunningham'; import { ChatConversation } from '@/features/chat/types'; -import { SimpleConversationItem } from '@/features/left-panel/components/SimpleConversationItem'; import { useResponsiveStore } from '@/stores'; type ConversationSearchItemProps = { @@ -12,6 +17,9 @@ export const ConversationSearchItem = ({ conversation, }: ConversationSearchItemProps) => { const { isDesktop } = useResponsiveStore(); + const { spacingsTokens, colorsTokens } = useCunninghamTheme(); + const { t, i18n } = useTranslation(); + return ( - - + + + + + + + {conversation.title || t('Untitled conversation')} + + + {conversation.updated_at + ? DateTime.fromISO(conversation.updated_at).toRelative({ + locale: i18n.language, + }) + : ''} + + } diff --git a/src/frontend/apps/conversations/src/features/chat-search/components/ConversationSearchModal.tsx b/src/frontend/apps/conversations/src/features/chat-search/components/ConversationSearchModal.tsx index 11b6117..9c7b37c 100644 --- a/src/frontend/apps/conversations/src/features/chat-search/components/ConversationSearchModal.tsx +++ b/src/frontend/apps/conversations/src/features/chat-search/components/ConversationSearchModal.tsx @@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next'; import { InView } from 'react-intersection-observer'; import { useDebouncedCallback } from 'use-debounce'; -import { Box } from '@/components'; +import { Box, Text } from '@/components'; import { QuickSearch, QuickSearchData, @@ -55,7 +55,7 @@ export const ConversationSearchModal = ({ const conversations = data?.pages.flatMap((page) => page.results) || []; return { - groupName: conversations.length > 0 ? t('Select a conversation') : '', + groupName: conversations.length > 0 ? t('Select a chat') : '', elements: search ? conversations : [], emptyString: t('No conversation found'), endActions: hasNextPage @@ -76,8 +76,15 @@ export const ConversationSearchModal = ({ $justify="space-between" className="--docs--doc-search-modal" > + + {t('Search for a chat')} + diff --git a/src/frontend/apps/conversations/src/features/chat/components/Chat.tsx b/src/frontend/apps/conversations/src/features/chat/components/Chat.tsx index 4177945..1c1c6be 100644 --- a/src/frontend/apps/conversations/src/features/chat/components/Chat.tsx +++ b/src/frontend/apps/conversations/src/features/chat/components/Chat.tsx @@ -10,12 +10,11 @@ import rehypeKatex from 'rehype-katex'; import remarkGfm from 'remark-gfm'; import remarkMath from 'remark-math'; -import { Box, BoxButton, Icon, Text } from '@/components'; -import { DropdownMenu } from '@/components/DropdownMenu'; -import { useAuth } from '@/features/auth'; +import { Box, Text } from '@/components'; import { useChat } from '@/features/chat/api/useChat'; import { getConversation } from '@/features/chat/api/useConversation'; import { useCreateChatConversation } from '@/features/chat/api/useCreateConversation'; +import { InputChat } from '@/features/chat/components/InputChat'; import { usePendingChatStore } from '../stores/usePendingChatStore'; @@ -37,10 +36,9 @@ export const Chat = ({ const apiUrl = `chats/${initialConversationId}/conversation/?protocol=${streamProtocol}`; const router = useRouter(); - const { user } = useAuth(); const [files, setFiles] = useState(null); + const fileInputRef = useRef(null); - const [isDragActive, setIsDragActive] = useState(false); const [conversationId, setConversationId] = useState(initialConversationId); const [initialConversationMessages, setInitialConversationMessages] = useState(undefined); @@ -198,87 +196,97 @@ export const Chat = ({ return ( - {messages.map((message) => ( - - - {`${message.role === 'user' ? user?.full_name : message.role}:`} - - - {message.content && ( - ( - - ), - }} + {messages.length > 0 && ( + + {messages.map((message) => ( + + - {message.content} - - )} - - {message.parts - ?.filter((part) => part.type === 'tool-invocation') - .map((part: ToolInvocationUIPart) => ( - , + }} > - {`${part.toolInvocation.toolName}(${JSON.stringify(part.toolInvocation.args, null, 2)})`} - - ))} - {/* Show attachments if present */} - {message.experimental_attachments?.map( - (attachment: Attachment, index: number) => - attachment.contentType?.includes('image/') ? ( - {attachment.name - ) : attachment.contentType?.includes('text/') ? ( -
- {attachment.url} -
- ) : null, - )} + {message.content} + + )} + + {message.parts + ?.filter((part) => part.type === 'tool-invocation') + .map((part: ToolInvocationUIPart) => ( + + {`${part.toolInvocation.toolName}(${JSON.stringify(part.toolInvocation.args, null, 2)})`} + + ))} + {/* Show attachments if present */} + {message.experimental_attachments?.map( + (attachment: Attachment, index: number) => + attachment.contentType?.includes('image/') ? ( + {attachment.name + ) : attachment.contentType?.includes('text/') ? ( +
+ {attachment.url} +
+ ) : null, + )} +
+
-
+ ))}
- ))} + )} {(status === 'streaming' || status === 'submitted') && ( {t('Generating...')} )} +
- - {messages.length === 0 && ( - - - {t('Welcome to your assistant!')} - - - {t('Start a conversation by typing a message below.')} - - - )} - - {/* File preview */} - {files && files.length > 0 && ( - - {Array.from(files).map((file, idx) => { - const { type, name } = file; - const removeFile = () => { - if (!files) { - return; - } - const dt = new DataTransfer(); - Array.from(files).forEach((f, i) => { - if (i !== idx) { - dt.items.add(f); - } - }); - setFiles(dt.files.length > 0 ? dt.files : null); - }; - if (type.startsWith('image/')) { - return ( - - {name} - - {name} - - - - - - ); - } else if (type.startsWith('text/')) { - return ( - - - - {name} - - - - - - ); - } - return null; - })} - - )} - -
{ - e.preventDefault(); - setIsDragActive(true); - }} - onDragLeave={(e) => { - e.preventDefault(); - setIsDragActive(false); - }} - onDrop={(e) => { - e.preventDefault(); - setIsDragActive(false); - if (e.dataTransfer.files && e.dataTransfer.files.length > 0) { - setFiles((prev) => { - if (!prev || prev.length === 0) { - return e.dataTransfer.files; - } - const dt = new DataTransfer(); - Array.from(prev).forEach((f) => dt.items.add(f)); - Array.from(e.dataTransfer.files).forEach((f) => { - if ( - !Array.from(prev).some( - (pf) => - pf.name === f.name && - pf.size === f.size && - pf.lastModified === f.lastModified, - ) - ) { - dt.items.add(f); - } - }); - return dt.files; - }); - } - }} - > - - -