Просмотр исходного кода

feat(frontend): multiple design changes (#1370)

Alex Bäuerle 1 год назад
Родитель
Сommit
65558df1f7

+ 10 - 8
frontend/src/components/ChatInput.tsx

@@ -1,8 +1,8 @@
 import { Textarea } from "@nextui-org/react";
 import React from "react";
 import { useTranslation } from "react-i18next";
+import { VscArrowUp } from "react-icons/vsc";
 import { twMerge } from "tailwind-merge";
-import { VscSend } from "react-icons/vsc";
 import { I18nKey } from "#/i18n/declaration";
 
 interface ChatInputProps {
@@ -32,7 +32,7 @@ function ChatInput({ disabled, onSendMessage }: ChatInputProps) {
   };
 
   return (
-    <div className="w-full relative text-base">
+    <div className="w-full relative text-base flex">
       <Textarea
         value={message}
         onChange={(e) => setMessage(e.target.value)}
@@ -41,10 +41,10 @@ function ChatInput({ disabled, onSendMessage }: ChatInputProps) {
         onCompositionStart={() => setIsComposing(true)}
         onCompositionEnd={() => setIsComposing(false)}
         placeholder={t(I18nKey.CHAT_INTERFACE$INPUT_PLACEHOLDER)}
-        className="pt-2 pb-4 px-4"
+        className="pt-2 pb-3 px-3"
         classNames={{
-          inputWrapper: "bg-neutral-700",
-          input: "pr-16 py-2",
+          inputWrapper: "bg-neutral-700 border border-neutral-600 rounded-lg",
+          input: "pr-16 text-neutral-400",
         }}
         maxRows={10}
         minRows={1}
@@ -55,12 +55,14 @@ function ChatInput({ disabled, onSendMessage }: ChatInputProps) {
         type="button"
         onClick={handleSendChatMessage}
         className={twMerge(
-          "bg-transparent border-none rounded py-2.5 px-5 hover:opacity-80 cursor-pointer select-none absolute right-5 bottom-6",
-          disabled && "cursor-not-allowed opacity-80",
+          "bg-transparent border rounded-lg p-1 border-white hover:opacity-80 cursor-pointer select-none absolute right-5 bottom-[19px] transition active:bg-white active:text-black",
+          disabled
+            ? "cursor-not-allowed border-neutral-400 text-neutral-400"
+            : "hover:bg-neutral-500 ",
         )}
         aria-label="Send message"
       >
-        <VscSend />
+        <VscArrowUp />
       </button>
     </div>
   );

+ 22 - 23
frontend/src/components/ChatInterface.tsx

@@ -1,4 +1,3 @@
-import { Card, CardBody } from "@nextui-org/react";
 import React, { useEffect, useRef } from "react";
 import { IoMdChatbubbles } from "react-icons/io";
 import { useSelector } from "react-redux";
@@ -38,25 +37,29 @@ function TypingChat() {
   });
 
   return (
-    <Card className="bg-neutral-500">
-      <CardBody>{messageContent}</CardBody>
-    </Card>
+    <div className="flex max-w-[90%]">
+      <div className="flex mb-0 min-w-0">
+        <div className="bg-neutral-500 rounded-lg">
+          <div className="p-3">{messageContent}</div>
+        </div>
+      </div>
+    </div>
   );
 }
 
 function ChatBubble({ msg }: IChatBubbleProps): JSX.Element {
   return (
     <div
-      className={`flex mb-2.5 pr-5 pl-5 max-w-[90%] ${msg?.sender === "user" ? "self-end" : ""}`}
+      className={`flex max-w-[90%] ${msg?.sender === "user" ? "self-end" : ""}`}
     >
       <div
-        className={`flex mt-2.5 mb-0 min-w-0 ${msg?.sender === "user" && "flex-row-reverse ml-auto"}`}
+        className={`flex mb-0 min-w-0 ${msg?.sender === "user" && "flex-row-reverse ml-auto"}`}
       >
-        <Card
-          className={`${msg?.sender === "user" ? "bg-neutral-700" : "bg-neutral-500"}`}
+        <div
+          className={`${msg?.sender === "user" ? "bg-neutral-700" : "bg-neutral-500"} rounded-lg`}
         >
-          <CardBody>{msg?.content}</CardBody>
-        </Card>
+          <div className="p-3">{msg?.content}</div>
+        </div>
       </div>
     </div>
   );
@@ -95,19 +98,15 @@ function MessageList(): JSX.Element {
   }, [typeThis]);
 
   return (
-    <div className="flex-1 overflow-y-auto flex flex-col">
-      {newChatSequence.map((msg, index) => (
-        <ChatBubble key={index} msg={msg} />
-      ))}
-
-      {typingActive && (
-        <div className="flex mb-2.5 pr-5 pl-5 max-w-[90%]">
-          <div className="flex mt-2.5 mb-0 min-w-0 ">
-            <TypingChat />
-          </div>
-        </div>
-      )}
-      <div ref={messagesEndRef} />
+    <div className="flex-1 flex flex-col gap-3 pt-3 px-3 relative min-h-0">
+      <div className="overflow-y-auto flex flex-col h-full gap-3">
+        {newChatSequence.map((msg, index) => (
+          <ChatBubble key={index} msg={msg} />
+        ))}
+        {typingActive && <TypingChat />}
+        <div ref={messagesEndRef} />
+      </div>
+      <div className="absolute bottom-0 left-0 right-0 h-4 bg-gradient-to-b from-transparent to-neutral-800" />
     </div>
   );
 }

+ 2 - 2
frontend/src/components/CodeEditor.tsx

@@ -50,12 +50,12 @@ function CodeEditor(): JSX.Element {
         <Tabs
           disableCursorAnimation
           classNames={{
-            base: "border-b border-divider",
+            base: "border-b border-divider border-neutral-600 mb-4",
             tabList:
               "w-full relative rounded-none bg-neutral-900 p-0 border-divider",
             cursor: "w-full bg-neutral-600 rounded-none",
             tab: "max-w-fit px-4 h-[36px]",
-            tabContent: "group-data-[selected=true]:text-white ",
+            tabContent: "group-data-[selected=true]:text-white",
           }}
           aria-label="Options"
         >

+ 2 - 3
frontend/src/components/Workspace.tsx

@@ -2,9 +2,8 @@ import { Tab, Tabs } from "@nextui-org/react";
 import React, { useEffect, useMemo, useState } from "react";
 import { useTranslation } from "react-i18next";
 import { IoIosGlobe } from "react-icons/io";
-import { VscCode } from "react-icons/vsc";
+import { VscCode, VscListOrdered } from "react-icons/vsc";
 import { useSelector } from "react-redux";
-import Calendar from "#/assets/calendar";
 import { I18nKey } from "#/i18n/declaration";
 import { initialState as initialBrowserState } from "#/state/browserSlice";
 import { initialState as initialCodeState } from "#/state/codeSlice";
@@ -33,7 +32,7 @@ function Workspace() {
     () => ({
       [TabOption.PLANNER]: {
         name: t(I18nKey.WORKSPACE$PLANNER_TAB_LABEL),
-        icon: <Calendar />,
+        icon: <VscListOrdered size={18} />,
         component: <Planner key="planner" />,
       },
       [TabOption.CODE]: {

+ 3 - 3
frontend/src/components/file-explorer/FileExplorer.tsx

@@ -1,3 +1,4 @@
+import { WorkspaceFile, getWorkspace } from "#/services/fileService";
 import React from "react";
 import {
   IoIosArrowBack,
@@ -5,10 +6,9 @@ import {
   IoIosRefresh,
 } from "react-icons/io";
 import { twMerge } from "tailwind-merge";
-import { WorkspaceFile, getWorkspace } from "#/services/fileService";
+import IconButton from "../IconButton";
 import ExplorerTree from "./ExplorerTree";
 import { removeEmptyNodes } from "./utils";
-import IconButton from "../IconButton";
 
 interface ExplorerActionsProps {
   onRefresh: () => void;
@@ -32,7 +32,7 @@ function ExplorerActions({
         <IconButton
           icon={
             <IoIosRefresh
-              size={20}
+              size={16}
               className="text-neutral-400 hover:text-neutral-100 transition"
             />
           }

+ 2 - 2
frontend/src/components/modals/base-modal/BaseModal.tsx

@@ -1,4 +1,3 @@
-import React from "react";
 import {
   Modal,
   ModalBody,
@@ -6,6 +5,7 @@ import {
   ModalFooter,
   ModalHeader,
 } from "@nextui-org/react";
+import React from "react";
 import { Action, FooterContent } from "./FooterContent";
 import { HeaderContent } from "./HeaderContent";
 
@@ -37,7 +37,7 @@ function BaseModal({
       backdrop="blur"
       hideCloseButton
       size="sm"
-      className="bg-neutral-900 rounded-large"
+      className="bg-neutral-900 rounded-lg"
     >
       <ModalContent className="max-w-[24rem] p-[40px]">
         {(closeModal) => (

+ 7 - 7
frontend/src/components/modals/load-previous-session/LoadPreviousSessionModal.tsx

@@ -1,11 +1,11 @@
 import React from "react";
 import { useTranslation } from "react-i18next";
+import { I18nKey } from "#/i18n/declaration";
+import { handleAssistantMessage } from "#/services/actions";
+import { sendChatMessageFromEvent } from "#/services/chatService";
+import { clearMsgs, fetchMsgs } from "#/services/session";
+import toast from "#/utils/toast";
 import BaseModal from "../base-modal/BaseModal";
-import { clearMsgs, fetchMsgs } from "../../../services/session";
-import { sendChatMessageFromEvent } from "../../../services/chatService";
-import { handleAssistantMessage } from "../../../services/actions";
-import toast from "../../../utils/toast";
-import { I18nKey } from "../../../i18n/declaration";
 
 interface LoadPreviousSessionModalProps {
   isOpen: boolean;
@@ -49,13 +49,13 @@ function LoadPreviousSessionModal({
       actions={[
         {
           label: t(I18nKey.LOAD_SESSION$RESUME_SESSION_MODAL_ACTION_LABEL),
-          className: "bg-primary rounded-small",
+          className: "bg-primary rounded-lg",
           action: onResumeSession,
           closeAfterAction: true,
         },
         {
           label: t(I18nKey.LOAD_SESSION$START_NEW_SESSION_MODAL_ACTION_LABEL),
-          className: "bg-neutral-500 rounded-small",
+          className: "bg-neutral-500 rounded-lg",
           action: onStartNewSession,
           closeAfterAction: true,
         },

+ 9 - 9
frontend/src/components/modals/settings/SettingsModal.tsx

@@ -1,16 +1,16 @@
-import React from "react";
-import { useTranslation } from "react-i18next";
-import { Spinner } from "@nextui-org/react";
-import BaseModal from "../base-modal/BaseModal";
-import SettingsForm from "./SettingsForm";
+import { AvailableLanguages } from "#/i18n";
+import { I18nKey } from "#/i18n/declaration";
 import {
   fetchAgents,
   fetchModels,
   getCurrentSettings,
   saveSettings,
 } from "#/services/settingsService";
-import { I18nKey } from "#/i18n/declaration";
-import { AvailableLanguages } from "#/i18n";
+import { Spinner } from "@nextui-org/react";
+import React from "react";
+import { useTranslation } from "react-i18next";
+import BaseModal from "../base-modal/BaseModal";
+import SettingsForm from "./SettingsForm";
 
 interface SettingsProps {
   isOpen: boolean;
@@ -70,7 +70,7 @@ function SettingsModal({ isOpen, onOpenChange }: SettingsProps) {
             saveSettings(settings);
           },
           closeAfterAction: true,
-          className: "bg-primary rounded-small",
+          className: "bg-primary rounded-lg",
         },
         {
           label: t(I18nKey.CONFIGURATION$MODAL_CLOSE_BUTTON_LABEL),
@@ -78,7 +78,7 @@ function SettingsModal({ isOpen, onOpenChange }: SettingsProps) {
             setSettings(currentSettings); // reset settings from any changes
           },
           closeAfterAction: true,
-          className: "bg-neutral-500 rounded-small",
+          className: "bg-neutral-500 rounded-lg",
         },
       ]}
     >

+ 12 - 12
frontend/src/i18n/translation.json

@@ -256,18 +256,18 @@
     "tr": "Ajan başlatılıyor (bu işlem 10 saniye kadar sürebilir)..."
   },
   "CHAT_INTERFACE$INPUT_PLACEHOLDER": {
-    "en": "Send a message (won't interrupt the Assistant)",
-    "zh-CN": "发送消息(不会打断助理)",
-    "de": "Sende eine Nachricht (unterbricht den Assistenten nicht)",
-    "ko-KR": "메시지 전송(어시스턴트를 방해하지 않음)",
-    "no": "Send en melding (det vil ikke avbryte assistenten)",
-    "zh-TW": "發送訊息(不會打擾到助理)",
-    "it": "Invia un messaggio (non interromperà l'Assistente)",
-    "pt": "Envie uma mensagem (não interromperá o Assistente)",
-    "es": "Enviar un mensaje (no interrumpirá al Asistente)",
-    "ar": "إرسال رسالة (لن يقاطع المساعد)",
-    "fr": "Envoyer un message (ne pas interrompre l'Assistant)",
-    "tr": "Bir mesaj gönderin (Asistan Kesilmeyecek)"
+    "en": "Message assistant...",
+    "zh-CN": "畀助手發消息",
+    "de": "Sende eine Nachricht an den Assistenten...",
+    "ko-KR": "어시스턴트에게 메시지 보내기",
+    "no": "Send melding til assistenten...",
+    "zh-TW": "给助理留言",
+    "it": "Invia un messaggio all'assistente...",
+    "pt": "Envie uma mensagem para o assistente...",
+    "es": "Mensaje al asistente...",
+    "ar": "مراسلة المساعد",
+    "fr": "Envoyez un message à l'assistant...",
+    "tr": "Asistana mesaj gönder..."
   },
   "CHAT_INTERFACE$INPUT_SEND_MESSAGE_BUTTON_CONTENT": {
     "en": "Send",