diff --git a/submodules/moragents_dockers/frontend/components/Chat/index.tsx b/submodules/moragents_dockers/frontend/components/Chat/index.tsx index e7dd39b..cac05ee 100644 --- a/submodules/moragents_dockers/frontend/components/Chat/index.tsx +++ b/submodules/moragents_dockers/frontend/components/Chat/index.tsx @@ -2,18 +2,19 @@ import React, { FC, useEffect, useState } from "react"; import { Flex, Box } from "@chakra-ui/react"; import { ChatMessage } from "@/services/types"; import { useTransactionConfirmations } from "wagmi"; -import { MessageList } from "../MessageList"; -import { ChatInput } from "../ChatInput"; -import { LoadingIndicator } from "../LoadingIndicator"; -import { Widgets, shouldOpenWidget } from "../Widgets"; -import { ChatProps } from "./types"; -import { useChat } from "./hooks"; +import { MessageList } from "@/components/MessageList"; +import { ChatInput } from "@/components/ChatInput"; +import { LoadingIndicator } from "@/components/LoadingIndicator"; +import { Widgets, shouldOpenWidget } from "@/components/Widgets"; +import { ChatProps } from "@/components/Chat/types"; +import { useChat } from "@/components/Chat/hooks"; export const Chat: FC = ({ onSubmitMessage, onCancelSwap, messages, onBackendError, + isSidebarOpen = false, }) => { const [messagesData, setMessagesData] = useState(messages); const [activeWidget, setActiveWidget] = useState(null); @@ -86,6 +87,7 @@ export const Chat: FC = ({ showSpinner || messagesData[messagesData.length - 1]?.role === "swap" } + isSidebarOpen={isSidebarOpen} /> void; messages: ChatMessage[]; onBackendError: () => void; + isSidebarOpen?: boolean; }; export type SwapTransaction = { diff --git a/submodules/moragents_dockers/frontend/components/ChatInput/PrefilledOptions.tsx b/submodules/moragents_dockers/frontend/components/ChatInput/PrefilledOptions.tsx index 4db802e..cbdda4b 100644 --- a/submodules/moragents_dockers/frontend/components/ChatInput/PrefilledOptions.tsx +++ b/submodules/moragents_dockers/frontend/components/ChatInput/PrefilledOptions.tsx @@ -26,11 +26,6 @@ type PrefilledOption = { }>; }; -type PrefilledOptionsProps = { - onSelect: (message: string) => void; - isWidgetOpen?: boolean; -}; - const prefilledOptionsMap: Record = { [AGENT_TYPES.DEFAULT]: { title: "Default Agent 🔄", @@ -143,13 +138,22 @@ const prefilledOptionsMap: Record = { }, }; -const PrefilledOptions: React.FC = ({ +const PrefilledOptions = ({ onSelect, isWidgetOpen = false, + isSidebarOpen = true, +}: { + onSelect: (message: string) => void; + isWidgetOpen?: boolean; + isSidebarOpen?: boolean; }) => { const [selectedAgents, setSelectedAgents] = useState([]); const containerStyle = { - paddingLeft: isWidgetOpen ? "5%" : "20%", + paddingLeft: isWidgetOpen + ? "5%" + : isSidebarOpen + ? "calc(260px + 20%)" // Sidebar width first, then percentage + : "20%", paddingRight: isWidgetOpen ? "35%" : "20%", }; diff --git a/submodules/moragents_dockers/frontend/components/ChatInput/index.tsx b/submodules/moragents_dockers/frontend/components/ChatInput/index.tsx index 3b75829..8f95e57 100644 --- a/submodules/moragents_dockers/frontend/components/ChatInput/index.tsx +++ b/submodules/moragents_dockers/frontend/components/ChatInput/index.tsx @@ -24,12 +24,14 @@ type ChatInputProps = { onSubmit: (message: string, file: File | null) => Promise; disabled: boolean; hasMessages?: boolean; + isSidebarOpen?: boolean; }; export const ChatInput: FC = ({ onSubmit, disabled, hasMessages = false, + isSidebarOpen = false, }) => { const [message, setMessage] = useState(""); const [file, setFile] = useState(null); @@ -194,7 +196,12 @@ export const ChatInput: FC = ({ )}
- {!hasMessages && } + {!hasMessages && ( + + )}
{agentSupportsFileUploads && ( diff --git a/submodules/moragents_dockers/frontend/components/HeaderBar/CDPWallets.tsx b/submodules/moragents_dockers/frontend/components/HeaderBar/CDPWallets.tsx index 3273d26..3f5d80e 100644 --- a/submodules/moragents_dockers/frontend/components/HeaderBar/CDPWallets.tsx +++ b/submodules/moragents_dockers/frontend/components/HeaderBar/CDPWallets.tsx @@ -69,6 +69,11 @@ export const CDPWallets: React.FC = () => { const [confirmWalletId, setConfirmWalletId] = useState(""); const cancelRef = React.useRef(null); const toast = useToast(); + const { + isOpen: isMenuOpen, + onClose: closeMenu, + onOpen: openMenu, + } = useDisclosure(); const fetchWallets = useCallback(async () => { try { @@ -327,13 +332,21 @@ export const CDPWallets: React.FC = () => { return ( <> - + }> CDP Wallets - diff --git a/submodules/moragents_dockers/frontend/components/LeftSidebar/index.module.css b/submodules/moragents_dockers/frontend/components/LeftSidebar/index.module.css new file mode 100644 index 0000000..563c47b --- /dev/null +++ b/submodules/moragents_dockers/frontend/components/LeftSidebar/index.module.css @@ -0,0 +1,118 @@ +.sidebar { + background: #0d0d0d; + height: calc(100vh); + position: relative; + transition: all 0.2s ease; + border-right: 1px solid #262626; +} + +.sidebarExpanded { + width: 260px; +} + +.sidebarCollapsed { + width: 0; +} + +.toggleButton { + position: fixed; + left: 10px; + top: 65px; /* Position below header */ + z-index: 100; + background-color: transparent; + color: #808080; + border: none; + width: 32px; + height: 32px; + border-radius: 4px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: background-color 0.2s; +} + +.toggleButton:hover { + background-color: #262626; + color: white; +} + +.container { + height: 100%; + display: flex; + flex-direction: column; + gap: 8px; + padding: 48px 8px 8px 8px; + overflow: hidden; +} + +.newChatButton { + width: 100%; + background-color: transparent; + color: #808080; + border: 1px solid #262626; + padding: 8px 12px; + border-radius: 4px; + cursor: pointer; + transition: all 0.2s; + display: flex; + align-items: center; + gap: 8px; +} + +.newChatButton:hover { + background-color: #262626; + color: white; +} + +.conversationItem { + padding: 8px 12px; + border-radius: 4px; + cursor: pointer; + transition: all 0.2s; + display: flex; + justify-content: space-between; + align-items: center; + color: #808080; + min-height: 40px; +} + +.conversationItem:hover { + background-color: #262626; + color: white; +} + +.conversationActive { + background-color: #262626; + color: white; +} + +.conversationName { + font-size: 14px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.deleteButton { + opacity: 0; + background-color: transparent; + color: #808080; + border: none; + padding: 4px; + border-radius: 4px; + cursor: pointer; + transition: all 0.2s; + display: flex; + align-items: center; + justify-content: center; +} + +.conversationItem:hover .deleteButton { + opacity: 1; +} + +.deleteButton:hover { + background-color: #404040; + color: white; +} diff --git a/submodules/moragents_dockers/frontend/components/LeftSidebar/index.tsx b/submodules/moragents_dockers/frontend/components/LeftSidebar/index.tsx index 61e19be..8fd90e5 100644 --- a/submodules/moragents_dockers/frontend/components/LeftSidebar/index.tsx +++ b/submodules/moragents_dockers/frontend/components/LeftSidebar/index.tsx @@ -1,24 +1,22 @@ import React, { FC, useEffect, useState } from "react"; -import { Box, VStack, Text, Button, useToast } from "@chakra-ui/react"; -import { - IconChevronLeft, - IconChevronRight, - IconPlus, - IconTrash, -} from "@tabler/icons-react"; +import { useToast } from "@chakra-ui/react"; +import { IconMenu2, IconPencilPlus, IconTrash } from "@tabler/icons-react"; import { getHttpClient } from "@/services/constants"; import { createNewConversation } from "@/services/apiHooks"; +import styles from "./index.module.css"; export type LeftSidebarProps = { currentConversationId: string; onConversationSelect: (conversationId: string) => void; onDeleteConversation: (conversationId: string) => void; + setCurrentConversationId: (conversationId: string) => void; }; export const LeftSidebar: FC = ({ currentConversationId, onConversationSelect, onDeleteConversation, + setCurrentConversationId, }) => { const [conversations, setConversations] = useState([]); const [isLoading, setIsLoading] = useState(false); @@ -47,6 +45,7 @@ export const LeftSidebar: FC = ({ const response = await createNewConversation(getHttpClient()); await fetchConversations(); onConversationSelect(response); + setCurrentConversationId(response); toast({ title: "Success", description: "New conversation created", @@ -74,6 +73,7 @@ export const LeftSidebar: FC = ({ await fetchConversations(); if (conversationId === currentConversationId) { onConversationSelect("default"); + setCurrentConversationId("default"); } toast({ title: "Success", @@ -105,82 +105,61 @@ export const LeftSidebar: FC = ({ }; return ( - - + + - - - - {conversations.map((conversationId) => ( - onConversationSelect(conversationId)} - display="flex" - justifyContent="space-between" - alignItems="center" - overflow="hidden" +
+
+ + + {conversations.map((conversationId) => ( +
{ + onConversationSelect(conversationId); + setCurrentConversationId(conversationId); + }} + > + {formatConversationName(conversationId)} - - )} - {conversationId !== "default" && ( - - )} - - ))} - - + + {conversationId !== "default" && ( + + )} +
+ ))} +
+
+ ); }; diff --git a/submodules/moragents_dockers/frontend/components/LoadingIndicator/index.tsx b/submodules/moragents_dockers/frontend/components/LoadingIndicator/index.tsx index 91b5a61..9d9005f 100644 --- a/submodules/moragents_dockers/frontend/components/LoadingIndicator/index.tsx +++ b/submodules/moragents_dockers/frontend/components/LoadingIndicator/index.tsx @@ -2,19 +2,9 @@ import React, { FC } from "react"; import { Grid, GridItem, Text, Box } from "@chakra-ui/react"; import { Avatar } from "../Avatar"; import { Loader } from "../Loader"; -import { availableAgents } from "../../config"; import styles from "./index.module.css"; -type LoadingIndicatorProps = { - selectedAgent: string; -}; - -export const LoadingIndicator: FC = ({ - selectedAgent, -}) => { - const agentName = - availableAgents[selectedAgent]?.name || "Finding the best agent"; - +export const LoadingIndicator: FC = () => { return ( = ({ className={styles.messageGrid} > - + - {agentName} + Finding the best agent diff --git a/submodules/moragents_dockers/frontend/components/Settings/AgentSelection.tsx b/submodules/moragents_dockers/frontend/components/Settings/AgentSelection.tsx index 99b5418..b812c26 100644 --- a/submodules/moragents_dockers/frontend/components/Settings/AgentSelection.tsx +++ b/submodules/moragents_dockers/frontend/components/Settings/AgentSelection.tsx @@ -91,8 +91,14 @@ export const AgentSelection: React.FC = ({ onSave }) => { }; return ( - - + + Agent Configuration @@ -103,45 +109,41 @@ export const AgentSelection: React.FC = ({ onSave }) => { - - {availableAgents.map((agent) => ( - - handleAgentToggle(agent.name)} + + + {availableAgents.map((agent) => ( + = 6 - } > - - - - {agent.human_readable_name} - - - {agent.description} - - - - - - ))} - + handleAgentToggle(agent.name)} + width="100%" + isDisabled={ + !selectedAgents.includes(agent.name) && + selectedAgents.length >= 6 + } + > + + + + {agent.human_readable_name} + + + {agent.description} + + + + + + ))} +
+