Refactor: Extract MessageContainer component from ChatPanel

Created a new MessageContainer.tsx file and moved the MessageContainer component from ChatPanel/index.tsx to the new file.
Imported the MessageContainer component in ChatPanel/index.tsx and removed the previous inline implementation.
MessageContainer component handles the display and management of messages in the chat panel, including message avatars, message contexts, and message blinking.
This commit is contained in:
Rankin Zheng 2023-06-05 19:27:25 +08:00
parent 2ad72ed857
commit 77898b8294
2 changed files with 174 additions and 169 deletions

View File

@ -0,0 +1,171 @@
import { keyframes } from "@emotion/react";
import { Center, Text, Flex, Avatar, Accordion, Box, Stack, Container, Divider } from "@mantine/core";
import React from "react";
import CodeBlock from "./CodeBlock";
// @ts-ignore
import SvgAvatarDevChat from './avatar_devchat.svg';
// @ts-ignore
import SvgAvatarUser from './avatar_spaceman.png';
const MessageContainer = (props: any) => {
const { generating, messages, chatContainerRect, responsed } = props;
const DefaultMessage = (<Center>
<Text size="lg" color="gray" weight={500}>No messages yet</Text>
</Center>);
const MessageAvatar = (props: any) => {
const { type } = props;
return (<Flex
m='10px 0 10px 0'
gap="sm"
justify="flex-start"
align="center"
direction="row"
wrap="wrap">
{
type === 'bot'
? <Avatar
color="indigo"
size={25}
radius="xl"
src={SvgAvatarDevChat} />
: <Avatar
color="cyan"
size={25}
radius="xl"
src={SvgAvatarUser} />
}
<Text weight='bold'>{type === 'bot' ? 'DevChat' : 'User'}</Text>
</Flex>);
};
const MessageContext = (props: any) => {
const { contexts } = props;
return (contexts &&
<Accordion variant="contained" chevronPosition="left"
sx={{
marginTop: 5,
borderRadius: 5,
backgroundColor: 'var(--vscode-menu-background)',
}}
styles={{
item: {
borderColor: 'var(--vscode-menu-border)',
backgroundColor: 'var(--vscode-menu-background)',
'&[data-active]': {
backgroundColor: 'var(--vscode-menu-background)',
}
},
control: {
height: 30,
borderRadius: 3,
backgroundColor: 'var(--vscode-menu-background)',
'&[aria-expanded="true"]': {
borderBottomLeftRadius: 0,
borderBottomRightRadius: 0,
},
'&:hover': {
backgroundColor: 'var(--vscode-menu-background)',
}
},
chevron: {
color: 'var(--vscode-menu-foreground)',
},
icon: {
color: 'var(--vscode-menu-foreground)',
},
label: {
color: 'var(--vscode-menu-foreground)',
},
panel: {
color: 'var(--vscode-menu-foreground)',
backgroundColor: 'var(--vscode-menu-background)',
},
content: {
borderRadius: 3,
backgroundColor: 'var(--vscode-menu-background)',
}
}}
>
{
contexts?.map((item: any, index: number) => {
const { context } = item;
return (
<Accordion.Item value={`item-${index}`} mah='200'>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<Accordion.Control >
{'command' in context ? context.command : context.path}
</Accordion.Control>
</Box>
<Accordion.Panel>
{
context.content
? context.content
: <Center>
<Text c='gray.3'>No content</Text>
</Center>
}
</Accordion.Panel>
</Accordion.Item>
);
})
}
</Accordion>
);
};
const MessageBlink = (props: any) => {
const { generating, messageType, lastMessage } = props;
const blink = keyframes({
'50%': { opacity: 0 },
});
return (generating && messageType === 'bot' && lastMessage
? <Text sx={{
animation: `${blink} 0.5s infinite;`,
width: 5,
marginTop: responsed ? 0 : '1em',
backgroundColor: 'black',
display: 'block'
}}>|</Text>
: <></>);
};
const messageList = messages.map((item: any, index: number) => {
const { message: messageText, type: messageType, contexts } = item;
// setMessage(messageText);
return (<>
<Stack
spacing={0}
key={`message-${index}`}
sx={{
width: chatContainerRect.width,
padding: 0,
margin: 0,
}}>
<MessageAvatar type={messageType} />
<Container sx={{
margin: 0,
padding: 0,
width: chatContainerRect.width,
pre: {
whiteSpace: 'break-spaces'
},
}}>
<MessageContext contexts={contexts} />
<CodeBlock messageText={messageText} />
<MessageBlink generating={generating} messageType={messageType} lastMessage={index === messages.length - 1} />
</Container >
</Stack >
{index !== messages.length - 1 && <Divider my={3} />}
</>);
});
return (messageList.length > 0 ? messageList : DefaultMessage);
};
export default MessageContainer;

View File

@ -1,180 +1,14 @@
import * as React from 'react';
import { useState, useEffect, useRef } from 'react';
import { Accordion, Avatar, Box, Center, Container, Divider, Flex, Stack, px } from '@mantine/core';
import { Center, Container, Stack, px } from '@mantine/core';
import { ScrollArea } from '@mantine/core';
import { keyframes } from '@mantine/core';
import { Button, Text } from '@mantine/core';
import { Button } from '@mantine/core';
import { useListState, useResizeObserver, useTimeout, useViewportSize } from '@mantine/hooks';
import { IconPlayerStop, IconRotateDot } from '@tabler/icons-react';
import messageUtil from '../../util/MessageUtil';
// @ts-ignore
import SvgAvatarDevChat from './avatar_devchat.svg';
// @ts-ignore
import SvgAvatarUser from './avatar_spaceman.png';
import InputMessage from './InputMessage';
import CodeBlock from './CodeBlock';
const MessageContainer = (props: any) => {
const { generating, messages, chatContainerRect, responsed } = props;
const DefaultMessage = (<Center>
<Text size="lg" color="gray" weight={500}>No messages yet</Text>
</Center>);
const MessageAvatar = (props: any) => {
const { type } = props;
return (<Flex
m='10px 0 10px 0'
gap="sm"
justify="flex-start"
align="center"
direction="row"
wrap="wrap">
{
type === 'bot'
? <Avatar
color="indigo"
size={25}
radius="xl"
src={SvgAvatarDevChat} />
: <Avatar
color="cyan"
size={25}
radius="xl"
src={SvgAvatarUser} />
}
<Text weight='bold'>{type === 'bot' ? 'DevChat' : 'User'}</Text>
</Flex>);
};
const MessageContext = (props: any) => {
const { contexts } = props;
return (contexts &&
<Accordion variant="contained" chevronPosition="left"
sx={{
marginTop: 5,
borderRadius: 5,
backgroundColor: 'var(--vscode-menu-background)',
}}
styles={{
item: {
borderColor: 'var(--vscode-menu-border)',
backgroundColor: 'var(--vscode-menu-background)',
'&[data-active]': {
backgroundColor: 'var(--vscode-menu-background)',
}
},
control: {
height: 30,
borderRadius: 3,
backgroundColor: 'var(--vscode-menu-background)',
'&[aria-expanded="true"]': {
borderBottomLeftRadius: 0,
borderBottomRightRadius: 0,
},
'&:hover': {
backgroundColor: 'var(--vscode-menu-background)',
}
},
chevron: {
color: 'var(--vscode-menu-foreground)',
},
icon: {
color: 'var(--vscode-menu-foreground)',
},
label: {
color: 'var(--vscode-menu-foreground)',
},
panel: {
color: 'var(--vscode-menu-foreground)',
backgroundColor: 'var(--vscode-menu-background)',
},
content: {
borderRadius: 3,
backgroundColor: 'var(--vscode-menu-background)',
}
}}
>
{
contexts?.map((item: any, index: number) => {
const { context } = item;
return (
<Accordion.Item value={`item-${index}`} mah='200'>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<Accordion.Control >
{'command' in context ? context.command : context.path}
</Accordion.Control>
</Box>
<Accordion.Panel>
{
context.content
? context.content
: <Center>
<Text c='gray.3'>No content</Text>
</Center>
}
</Accordion.Panel>
</Accordion.Item>
);
})
}
</Accordion>
);
};
const MessageBlink = (props: any) => {
const { generating, messageType, lastMessage } = props;
const blink = keyframes({
'50%': { opacity: 0 },
});
return (generating && messageType === 'bot' && lastMessage
? <Text sx={{
animation: `${blink} 0.5s infinite;`,
width: 5,
marginTop: responsed ? 0 : '1em',
backgroundColor: 'black',
display: 'block'
}}>|</Text>
: <></>);
};
const messageList = messages.map((item: any, index: number) => {
const { message: messageText, type: messageType, contexts } = item;
// setMessage(messageText);
return (<>
<Stack
spacing={0}
key={`message-${index}`}
sx={{
width: chatContainerRect.width,
padding: 0,
margin: 0,
}}>
<MessageAvatar type={messageType} />
<Container sx={{
margin: 0,
padding: 0,
width: chatContainerRect.width,
pre: {
whiteSpace: 'break-spaces'
},
}}>
<MessageContext contexts={contexts} />
<CodeBlock messageText={messageText} />
<MessageBlink generating={generating} messageType={messageType} lastMessage={index === messages.length - 1} />
</Container >
</Stack >
{index !== messages.length - 1 && <Divider my={3} />}
</>);
});
return (messageList.length > 0 ? messageList : DefaultMessage);
};
import MessageContainer from './MessageContainer';
const chatPanel = () => {
const [chatContainerRef, chatContainerRect] = useResizeObserver();