Add react-remark package and use it to render markdown in ChatPanel

This commit is contained in:
Rankin Zheng 2023-05-06 00:00:25 +08:00
parent f87525da78
commit 9fa3c8fba2
4 changed files with 941 additions and 32 deletions

902
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -139,6 +139,7 @@
"nonce": "^1.0.4", "nonce": "^1.0.4",
"openai": "^3.2.1", "openai": "^3.2.1",
"quote": "^0.4.0", "quote": "^0.4.0",
"react-remark": "^2.1.0",
"shell-escape": "^0.2.0", "shell-escape": "^0.2.0",
"uuid": "^9.0.0" "uuid": "^9.0.0"
} }

View File

@ -1,6 +1,6 @@
import * as React from 'react'; import * as React from 'react';
import { useState } from 'react'; import { useState } from 'react';
import { Avatar, Container, Divider, Flex, Grid, Stack } from '@mantine/core'; import { Avatar, Container, Divider, Flex, Grid, Stack, TypographyStylesProvider } from '@mantine/core';
import { Input, Tooltip } from '@mantine/core'; import { Input, Tooltip } from '@mantine/core';
import { List } from '@mantine/core'; import { List } from '@mantine/core';
import { ScrollArea } from '@mantine/core'; import { ScrollArea } from '@mantine/core';
@ -11,6 +11,7 @@ import { useViewportSize } from '@mantine/hooks';
import { IconEdit, IconRobot, IconSend, IconSquareRoundedPlus, IconUser } from '@tabler/icons-react'; import { IconEdit, IconRobot, IconSend, IconSquareRoundedPlus, IconUser } from '@tabler/icons-react';
import { IconSettings, IconSearch, IconPhoto, IconMessageCircle, IconTrash, IconArrowsLeftRight } from '@tabler/icons-react'; import { IconSettings, IconSearch, IconPhoto, IconMessageCircle, IconTrash, IconArrowsLeftRight } from '@tabler/icons-react';
import { Prism } from '@mantine/prism'; import { Prism } from '@mantine/prism';
import { useRemark } from 'react-remark';
const useStyles = createStyles((theme, _params, classNames) => ({ const useStyles = createStyles((theme, _params, classNames) => ({
panel: { panel: {
@ -35,13 +36,25 @@ const useStyles = createStyles((theme, _params, classNames) => ({
fontSize: '0.8rem', fontSize: '0.8rem',
color: theme.colors.gray[6], color: theme.colors.gray[6],
}, },
responseContent: {
marginTop: 8,
marginLeft: 0,
marginRight: 0,
},
icon: { icon: {
pointerEvents: 'all', pointerEvents: 'all',
}, },
avatar: {
marginTop: 8,
marginLeft: 8,
},
messageBody: {
},
})); }));
const chatPanel = () => { const chatPanel = () => {
const [reactContent, setMarkdownSource] = useRemark();
const [opened, setOpened] = useState(false); const [opened, setOpened] = useState(false);
const [commandOpened, setCommandOpened] = useState(false); const [commandOpened, setCommandOpened] = useState(false);
const { classes } = useStyles(); const { classes } = useStyles();
@ -52,6 +65,10 @@ const chatPanel = () => {
return <Button>Hello</Button> return <Button>Hello</Button>
}`; }`;
setMarkdownSource(`# code block
print '3 backticks or'
print 'indent 4 spaces'`);
const handlePlusBottonClick = (event: React.MouseEvent<HTMLButtonElement>) => { const handlePlusBottonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setOpened(!opened); setOpened(!opened);
event.stopPropagation(); event.stopPropagation();
@ -76,39 +93,39 @@ const chatPanel = () => {
mih={50} mih={50}
gap="md" gap="md"
justify="flex-start" justify="flex-start"
align="center" align="flex-start"
direction="row" direction="row"
wrap="wrap" wrap="wrap"
className={classes.messageBody}
> >
<Avatar src={null} alt="no image here" > <Avatar color="indigo" size='md' radius="xl" className={classes.avatar}>
<IconUser size="1.125rem" /> <IconUser size="1.5rem" />
</Avatar> </Avatar>
<Container className={classes.responseContent}>
<Text> <Text>
Write a hello world, and explain it. Write a hello world, and explain it.
</Text> </Text>
<ActionIcon> </Container>
<IconEdit size="1.125rem" /> {/* <ActionIcon>
</ActionIcon> <IconEdit size="1.5rem" />
</ActionIcon> */}
</Flex> </Flex>
<Divider /> <Divider my="sm" label="Mar 4, 2023" labelPosition="center" />
<Flex <Flex
mih={50} mih={50}
gap="md" gap="md"
justify="flex-start" justify="flex-start"
align="center" align="flex-start"
direction="row" direction="row"
wrap="wrap" wrap="wrap"
className={classes.messageBody}
> >
<Avatar> <Avatar color="blue" size='md' radius="xl" className={classes.avatar}>
<IconRobot size="1.125rem" /> <IconRobot size="1.5rem" />
</Avatar> </Avatar>
{/* <Prism language="tsx">{demoCode}</Prism> */} <Container className={classes.responseContent}>
<Text> {reactContent}
Write a hello world, and explain it. </Container>
</Text>
<ActionIcon>
<IconEdit size="1.125rem" />
</ActionIcon>
</Flex> </Flex>
</ScrollArea> </ScrollArea>
<Menu id='plusMenu' shadow="md" width={200} opened={opened} onChange={setOpened} > <Menu id='plusMenu' shadow="md" width={200} opened={opened} onChange={setOpened} >

View File

@ -1,10 +1,13 @@
import * as React from 'react'; import * as React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import { createRoot } from 'react-dom/client';
import { MantineProvider } from '@mantine/core'; import { MantineProvider } from '@mantine/core';
import App from './App'; import App from './App';
ReactDOM.render( const container = document.getElementById('app')!;
const root = createRoot(container); // createRoot(container!) if you use TypeScript
root.render(
<MantineProvider withGlobalStyles withNormalizeCSS> <MantineProvider withGlobalStyles withNormalizeCSS>
<App /> <App />
</MantineProvider>, </MantineProvider>
document.getElementById('app')); );