mirror of
https://github.com/OpenHands/OpenHands.git
synced 2025-12-26 05:48:36 +08:00
feat(frontend): multiple design changes (#1370)
This commit is contained in:
parent
5515c08624
commit
65558df1f7
@ -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>
|
||||
);
|
||||
|
||||
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@ -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,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]: {
|
||||
|
||||
@ -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"
|
||||
/>
|
||||
}
|
||||
|
||||
@ -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) => (
|
||||
|
||||
@ -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,
|
||||
},
|
||||
|
||||
@ -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",
|
||||
},
|
||||
]}
|
||||
>
|
||||
|
||||
@ -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",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user