Skip to content

Commit

Permalink
Merge pull request #17 from dayuy/beta
Browse files Browse the repository at this point in the history
feat: lobeUI ChatItem & EditableMessage
  • Loading branch information
Carrotzpc authored Aug 2, 2024
2 parents ac0ddcd + f8c080a commit 3fdb9ef
Show file tree
Hide file tree
Showing 16 changed files with 1,247 additions and 37 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@
"react-layout-kit": "^1",
"shiki": "^1.10.3",
"swr": "^2.2.5",
"url-join": "^5.0.0"
"url-join": "^5.0.0",
"use-merge-value": "^1.2.0"
},
"devDependencies": {
"@testing-library/react": "^14",
Expand Down
151 changes: 115 additions & 36 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

79 changes: 79 additions & 0 deletions src/ChatItem/components/MessageContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { MarkdownProps } from '@lobehub/ui';
import { useResponsive } from 'antd-style';
import { type ReactNode, memo } from 'react';
import { Flexbox } from 'react-layout-kit';

import EditableMessage from '@/EditableMessage';

import { useStyles } from '../style';
import { ChatItemProps } from '../type';

export interface MessageContentProps {
editing?: ChatItemProps['editing'];
fontSize?: number;
message?: ReactNode;
messageExtra?: ChatItemProps['messageExtra'];
onChange?: ChatItemProps['onChange'];
onDoubleClick?: ChatItemProps['onDoubleClick'];
onEditingChange?: ChatItemProps['onEditingChange'];
placement?: ChatItemProps['placement'];
primary?: ChatItemProps['primary'];
renderMessage?: ChatItemProps['renderMessage'];
text?: ChatItemProps['text'];
type?: ChatItemProps['type'];
markdownProps?: MarkdownProps;
markdownClassname?: string;
}

const MessageContent = memo<MessageContentProps>(
({
editing,
onChange,
onEditingChange,
text,
message,
placement,
messageExtra,
renderMessage,
type,
primary,
onDoubleClick,
fontSize,
markdownProps,
markdownClassname,
}) => {
const { cx, styles } = useStyles({ editing, placement, primary, type });
const { mobile } = useResponsive();

const content = (
<EditableMessage
classNames={{ input: styles.editingInput, markdown: markdownClassname }}
editButtonSize={'small'}
editing={editing}
fontSize={fontSize}
fullFeaturedCodeBlock
markdownProps={markdownProps}
onChange={onChange}
onEditingChange={onEditingChange}
openModal={mobile ? editing : undefined}
text={text}
value={message ? String(message).trim() : ''}
/>
);
const messageContent = renderMessage ? renderMessage(content) : content;

return (
<Flexbox
className={cx(styles.message, editing && styles.editingContainer)}
onDoubleClick={onDoubleClick}
>
{messageContent}
{messageExtra && !editing ? (
<div className={styles.messageExtra}>{messageExtra}</div>
) : null}
</Flexbox>
);
}
);

export default MessageContent;
47 changes: 47 additions & 0 deletions src/ChatItem/demos/Alert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Highlighter, StoryBook, useControls, useCreateStore } from '@lobehub/ui';

import ChatItem, { ChatItemProps } from '..';
import { avatar } from './data';

const demoError = {
details: {
exception:
'Validation filter failedId-f5aab7304f6c754804f70000Id-f5aab7304f6c754804f70000Id-f5aab7304f6c754804f70000Id-f5aab7304f6c754804f70000Id-f5aab7304f6c754804f70000Id-f5aab7304f6c754804f70000',
msgId:
'Id-f5aab7304f6c754804f70000Id-f5aab7304f6c754804f70000Id-f5aab7304f6c754804f70000Id-f5aab7304f6c754804f70000Id-f5aab7304f6c754804f70000',
},
reasons: [
{
language: 'en',
message: 'Validation filter failed',
},
],
};
export default () => {
const store = useCreateStore();
const control: ChatItemProps['error'] | any = useControls(
{
description: '',
message: 'Error',
type: {
options: ['success', 'info', 'warning', 'error'],
value: 'error',
},
},
{ store }
);

return (
<StoryBook levaStore={store}>
<ChatItem
avatar={avatar}
error={control}
errorMessage={
<Highlighter copyButtonSize={'small'} language={'json'} type={'pure'}>
{JSON.stringify(demoError, null, 2)}
</Highlighter>
}
/>
</StoryBook>
);
};
61 changes: 61 additions & 0 deletions src/ChatItem/demos/Tmarkdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { ActionIconGroup, StoryBook, useControls, useCreateStore } from '@lobehub/ui';
import { useState } from 'react';

import ChatItem, { ChatItemProps } from '..';
import { content } from '../../EditableMessage/demos/data';
import { avatar, dropdownMenu, items } from './data';

export default () => {
const [edit, setEdit] = useState(false);
const store = useCreateStore();
const control: ChatItemProps | any = useControls(
{
loading: false,
message: {
rows: true,
value: content,
},
placement: {
options: ['left', 'right'],
value: 'left',
},
primary: false,
showTitle: false,
time: 1_686_538_950_084,
type: {
options: ['block', 'pure'],
value: 'block',
},
markdownProps: {
fontSize: 15,
lineHeight: 1.625,
headerMultiple: 0,
},
markdownClassname: 'customMarkdown',
},
{ store }
);

return (
<StoryBook levaStore={store}>
<ChatItem
{...control}
actions={
<ActionIconGroup
dropdownMenu={dropdownMenu}
items={items}
onActionClick={action => {
if (action.key === 'edit') {
setEdit(true);
}
}}
type="ghost"
/>
}
avatar={avatar}
editing={edit}
onEditingChange={setEdit}
/>
</StoryBook>
);
};
37 changes: 37 additions & 0 deletions src/ChatItem/demos/data.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { type ActionIconGroupProps, MetaData } from '@lobehub/ui';
import { Copy, Edit, RotateCw, Trash } from 'lucide-react';

export const avatar: MetaData = {
avatar: '😎',
backgroundColor: '#E8DA5A',
title: 'Advertiser',
};

export const items: ActionIconGroupProps['items'] = [
{
icon: Edit,
key: 'edit',
label: 'Edit',
},
];

export const dropdownMenu: ActionIconGroupProps['dropdownMenu'] = [
{
icon: Copy,
key: 'copy',
label: 'Copy',
},
{
icon: RotateCw,
key: 'regenerate',
label: 'Regenerate',
},
{
type: 'divider',
},
{
icon: Trash,
key: 'delete',
label: 'Delete',
},
];
55 changes: 55 additions & 0 deletions src/ChatItem/demos/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { ActionIconGroup, StoryBook, useControls, useCreateStore } from '@lobehub/ui';
import { useState } from 'react';

import ChatItem, { ChatItemProps } from '..';
import { avatar, dropdownMenu, items } from './data';

export default () => {
const [edit, setEdit] = useState(false);
const store = useCreateStore();
const control: ChatItemProps | any = useControls(
{
loading: false,
message: {
rows: true,
value:
"要使用 dayjs 的 fromNow 函数,需要先安装 dayjs 库并在代码中引入它。然后,可以使用以下语法来获取当前时间与给定时间之间的相对时间:\n\n```javascript\ndayjs().fromNow();\ndayjs('2021-05-01').fromNow();\n```",
},
placement: {
options: ['left', 'right'],
value: 'left',
},
primary: false,
showTitle: false,
time: 1_686_538_950_084,
type: {
options: ['block', 'pure'],
value: 'block',
},
},
{ store }
);

return (
<StoryBook levaStore={store}>
<ChatItem
{...control}
actions={
<ActionIconGroup
dropdownMenu={dropdownMenu}
items={items}
onActionClick={action => {
if (action.key === 'edit') {
setEdit(true);
}
}}
type="ghost"
/>
}
avatar={avatar}
editing={edit}
onEditingChange={setEdit}
/>
</StoryBook>
);
};
22 changes: 22 additions & 0 deletions src/ChatItem/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
nav: Components
group: Chat
title: ChatItem
description: ChatItem is a React component that represents a single item in a chat conversation. It displays the user's avatar, name, and message. It can also display a loading indicator if the message is still being sent.
---

## Default

<code src="./demos/index.tsx" nopadding></code>

## Markdown

<code src="./demos/Tmarkdown.tsx" nopadding></code>

## Alert

<code src="./demos/Alert.tsx" nopadding></code>

## APIs

<API></API>
Loading

0 comments on commit 3fdb9ef

Please sign in to comment.