Skip to content

Commit

Permalink
Chat bubbles (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
radekkaluzik authored Apr 29, 2024
1 parent a71b967 commit 55e6900
Show file tree
Hide file tree
Showing 11 changed files with 1,810 additions and 112 deletions.
1,728 changes: 1,620 additions & 108 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/module/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@patternfly/react-core": "^5.1.2",
"@patternfly/react-icons": "^5.1.2",
"react-jss": "^10.10.0",
"react-markdown": "^9.0.1",
"clsx": "^2.1.0"
},
"peerDependencies": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import VirtualAssistant from '@patternfly/virtual-assistant/dist/dynamic/VirtualAssistant';
import AssistantMessageEntry from '@patternfly/virtual-assistant/dist/dynamic/AssistantMessageEntry';
import GrinIcon from '@patternfly/react-icons/dist/js/icons/bacon-icon';

export const AssistantMessage: React.FunctionComponent = () => (
<VirtualAssistant>
<AssistantMessageEntry>
How may I help you today? Do you have some question for me?
</AssistantMessageEntry>
<AssistantMessageEntry icon={GrinIcon}>
Assistant message example with custom icon
</AssistantMessageEntry>
</VirtualAssistant>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import VirtualAssistant from '@patternfly/virtual-assistant/dist/dynamic/VirtualAssistant';
import AssistantMessageEntry from '@patternfly/virtual-assistant/dist/dynamic/AssistantMessageEntry';

export const AssistantMessage: React.FunctionComponent = () => (
<VirtualAssistant>
<AssistantMessageEntry
// eslint-disable-next-line no-console
options={[ { title: "Option #1", props: { onClick: () => {console.log('This is an example of onClick event')} } }, { title: "Option #2" }, { title: "Option #3" } ]}
>
How may I help you today? Do you have some question for me?
</AssistantMessageEntry>
</VirtualAssistant>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import VirtualAssistant from '@patternfly/virtual-assistant/dist/dynamic/VirtualAssistant';
import UserMessageEntry from '@patternfly/virtual-assistant/dist/dynamic/UserMessageEntry';
import GrinIcon from '@patternfly/react-icons/dist/js/icons/bacon-icon';

export const UserMessage: React.FunctionComponent = () => (
<VirtualAssistant>
<UserMessageEntry>Hello, can you help me?</UserMessageEntry>
<UserMessageEntry icon={GrinIcon}>User message example with custom icon</UserMessageEntry>
</VirtualAssistant>
);
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ sourceLink: https://github.com/patternfly/virtual-assistant/blob/main/packages/m

import VirtualAssistant from '@patternfly/virtual-assistant/dist/dynamic/VirtualAssistant';
import VirtualAssistantAction from '@patternfly/virtual-assistant/dist/dynamic/VirtualAssistantAction';
import SystemMessageEntry from '@patternfly/virtual-assistant/dist/esm/SystemMessageEntry'
import SystemMessageEntry from '@patternfly/virtual-assistant/dist/dynamic/SystemMessageEntry';
import LoadingMessage from '@patternfly/virtual-assistant/dist/dynamic/LoadingMessage';
import { GrinIcon } from '@patternfly/react-icons';
import { AngleDownIcon } from '@patternfly/react-icons';
import ConversationAlert from '@patternfly/virtual-assistant/dist/esm/ConversationAlert'
import ConversationAlert from '@patternfly/virtual-assistant/dist/dynamic/ConversationAlert';
import AssistantMessageEntry from '@patternfly/virtual-assistant/dist/dynamic/AssistantMessageEntry';
import UserMessageEntry from '@patternfly/virtual-assistant/dist/dynamic/UserMessageEntry';

The **virtual assistant** component renders body of the virtual assistant window.

Expand Down Expand Up @@ -66,8 +68,6 @@ Custom actions can be added to the assistant body using the `actions` property.

```



### Conversation Alert

You can configure a custom title and variant input value using `title` and `variant` props.
Expand All @@ -94,3 +94,26 @@ The `LoadingMessage` component shows a typing indicator for messages still being

```

### Assistant Message

This is an example of a message sent by assistant. Additionally, it allows for the use of a custom icon through the `icon` property.

```js file="./AssistantMessage.tsx"

```

### Assistant Message with follow-up options

This is an example of a message sent by assistant with follow-up options. Follow-up options are defined within `options` property.

```js file="./AssistantMessageWithFollowup.tsx"

```

### User Message

This is an example of a message sent by user. Additionally, it allows for the use of a custom icon through the `icon` property.

```js file="./UserMessage.tsx"

```
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React, { PropsWithChildren } from 'react';
import { Icon, Label, Split, SplitItem, TextContent, LabelProps } from '@patternfly/react-core';
import { createUseStyles } from 'react-jss';
import classnames from "clsx";

import RobotIcon from '@patternfly/react-icons/dist/js/icons/robot-icon';

const useStyles = createUseStyles({
chatbot: {
marginRight: "40px",
},
bubble: {
border: "1px solid var(--pf-v5-global--BackgroundColor--dark-400)",
borderRadius: "14px",
padding: "var(--pf-v5-global--spacer--sm) var(--pf-v5-global--spacer--md) var(--pf-v5-global--spacer--sm) var(--pf-v5-global--spacer--md)",
maxWidth: "100%",
wordWrap: "break-word",
}
})

interface AssistantMessageEntryProps {
options?: {
title: string;
props?: LabelProps
}[],
icon?: React.ComponentClass;
}

export const AssistantMessageEntry = ({ children, options, icon: IconComponent = RobotIcon }: PropsWithChildren<AssistantMessageEntryProps>) => {
const classes = useStyles();
return (
<div className="pf-v5-u-mb-md">
<Split className={classes.chatbot}>
<SplitItem>
<Icon size="lg" className="pf-v5-u-mr-sm pf-v5-u-pt-md">
<IconComponent />
</Icon>
</SplitItem>
<SplitItem className={classnames(classes.bubble," pf-v5-u-background-color-200")}>
<TextContent className="pf-v5-u-font-size-sm">
{children}
</TextContent>
</SplitItem>
</Split>
{options ? (
<Split>
<SplitItem className={classnames(classes.chatbot,"pf-v5-u-ml-xl pf-v5-u-mt-md")}>
{options.map((option, index) => (
<Label key={index} className="pf-v5-u-m-xs" {...option.props}>
{option.title}
</Label>
))}
</SplitItem>
</Split>
) : null
}
</div>
);
};

export default AssistantMessageEntry;
2 changes: 2 additions & 0 deletions packages/module/src/AssistantMessageEntry/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from './AssistantMessageEntry';
export * from './AssistantMessageEntry';
45 changes: 45 additions & 0 deletions packages/module/src/UserMessageEntry/UserMessageEntry.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React, { PropsWithChildren } from 'react';
import { Icon, Split, SplitItem, TextContent } from '@patternfly/react-core';
import OutlinedUserIcon from '@patternfly/react-icons/dist/js/icons/outlined-user-icon';
import { createUseStyles } from 'react-jss';
import classnames from "clsx";

const useStyles = createUseStyles({
user: {
margin: "0 0 12px 40px",
},
bubbleUser: {
border: "1px solid var(--pf-v5-global--BackgroundColor--dark-400)",
borderRadius: "14px",
padding: "var(--pf-v5-global--spacer--sm) var(--pf-v5-global--spacer--md) var(--pf-v5-global--spacer--sm) var(--pf-v5-global--spacer--md)",
maxWidth: "100%",
wordWrap: "break-word",
}
})

interface UserMessageEntryProps {
icon?: React.ComponentClass;
}

const UserMessageEntry = ({ children, icon: IconComponent = OutlinedUserIcon }: PropsWithChildren<UserMessageEntryProps>) => {
const classes = useStyles();

return (
<>
<Split className={classnames(classes.user,"pf-v5-u-mb-md pf-v5-u-align-items-flex-start pf-v5-u-justify-content-flex-end")}>
<SplitItem className={classes.bubbleUser}>
<TextContent className="pf-v5-u-color-300 pf-v5-u-font-size-sm">
{children}
</TextContent>
</SplitItem>
<SplitItem>
<Icon size="lg" className="pf-v5-u-ml-sm pf-v5-u-pt-xs">
<IconComponent />
</Icon>
</SplitItem>
</Split>
</>
);
};

export default UserMessageEntry;
2 changes: 2 additions & 0 deletions packages/module/src/UserMessageEntry/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from './UserMessageEntry';
export * from './UserMessageEntry';
12 changes: 12 additions & 0 deletions packages/module/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
// this file is autogenerated by generate-index.js, modifying it manually will have no effect

export { default as AssistantMessageEntry } from './AssistantMessageEntry';
export * from './AssistantMessageEntry';

export { default as ConversationAlert } from './ConversationAlert';
export * from './ConversationAlert';

export { default as LoadingMessage } from './LoadingMessage';
export * from './LoadingMessage';

export { default as SystemMessageEntry } from './SystemMessageEntry';
export * from './SystemMessageEntry';

export { default as UserMessageEntry } from './UserMessageEntry';
export * from './UserMessageEntry';

export { default as VirtualAssistant } from './VirtualAssistant';
export * from './VirtualAssistant';

Expand Down

0 comments on commit 55e6900

Please sign in to comment.