Skip to content

Commit

Permalink
feat(ChatbotModal): Add style-able modal for general use
Browse files Browse the repository at this point in the history
  • Loading branch information
rebeccaalpert committed Nov 15, 2024
1 parent 0019c2e commit 7cece91
Show file tree
Hide file tree
Showing 9 changed files with 231 additions and 124 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';
import { Button, ModalBody, ModalFooter, ModalHeader } from '@patternfly/react-core';
import { ChatbotModal } from '@patternfly/virtual-assistant/dist/dynamic/ChatbotModal';
import { ChatbotDisplayMode } from '@patternfly/virtual-assistant/dist/dynamic/Chatbot';

export const ChatbotModalExample: React.FunctionComponent = () => {
const [isModalOpen, setIsModalOpen] = React.useState(false);

const handleModalToggle = (_event: React.MouseEvent | MouseEvent | KeyboardEvent) => {
setIsModalOpen(!isModalOpen);
};

return (
<>
<Button onClick={handleModalToggle}>Launch modal</Button>
<ChatbotModal
isOpen={isModalOpen}
displayMode={ChatbotDisplayMode.default}
onClose={handleModalToggle}
ouiaId="ChatbotModal"
aria-labelledby="basic-modal-title"
aria-describedby="modal-box-body-basic"
>
<ModalHeader title="Basic modal" labelId="basic-modal-title" />
<ModalBody id="modal-box-body-basic">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
est laborum.
</ModalBody>
<ModalFooter>
<Button key="confirm" variant="primary" onClick={handleModalToggle}>
Confirm
</Button>
<Button key="cancel" variant="link" onClick={handleModalToggle}>
Cancel
</Button>
</ModalFooter>
</ChatbotModal>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,33 @@ id: UI
source: react
# If you use typescript, the name of the interface to display props for
# These are found through the sourceProps function provided in patternfly-docs.source.js
propComponents: [
'Chatbot',
'ChatbotContent',
'MessageBox',
'ChatbotWelcomePrompt',
'WelcomePrompt',
'ChatbotToggle',
'ChatbotHeader',
'ChatbotHeaderMain',
'ChatbotHeaderMenu',
'ChatbotHeaderActions',
'ChatbotHeaderTitle',
'ChatbotHeaderOptionsDropdown',
'ChatbotHeaderSelectorDropdown',
'ChatbotFooter',
'MessageBar',
'ChatbotFootnote',
'ChatbotFootnotePopover',
'ChatbotFootnotePopoverCTA',
'ChatbotFootnotePopoverBannerImage',
'ChatbotFootnotePopoverLink',
'MessageBarWithAttachMenuProps',
'SourceDetailsMenuItem',
'ChatbotConversationHistoryNav',
'Conversation'
]
propComponents:
[
'Chatbot',
'ChatbotContent',
'MessageBox',
'ChatbotWelcomePrompt',
'WelcomePrompt',
'ChatbotToggle',
'ChatbotHeader',
'ChatbotHeaderMain',
'ChatbotHeaderMenu',
'ChatbotHeaderActions',
'ChatbotHeaderTitle',
'ChatbotHeaderOptionsDropdown',
'ChatbotHeaderSelectorDropdown',
'ChatbotFooter',
'MessageBar',
'ChatbotFootnote',
'ChatbotFootnotePopover',
'ChatbotFootnotePopoverCTA',
'ChatbotFootnotePopoverBannerImage',
'ChatbotFootnotePopoverLink',
'MessageBarWithAttachMenuProps',
'SourceDetailsMenuItem',
'ChatbotConversationHistoryNav',
'Conversation'
]
sortValue: 2
---

Expand Down Expand Up @@ -63,6 +64,7 @@ ChatbotHeaderSelectorDropdown
import { ChatbotFooter, ChatbotFootnote } from '@patternfly/virtual-assistant/dist/dynamic/ChatbotFooter';
import { MessageBar } from '@patternfly/virtual-assistant/dist/dynamic/MessageBar';
import SourceDetailsMenuItem from '@patternfly/virtual-assistant/dist/dynamic/SourceDetailsMenuItem';
import { ChatbotModal } from '@patternfly/virtual-assistant/dist/dynamic/ChatbotModal';
import { BellIcon, CalendarAltIcon, ClipboardIcon, CodeIcon, UploadIcon } from '@patternfly/react-icons';
import { useDropzone } from 'react-dropzone';

Expand Down Expand Up @@ -265,6 +267,7 @@ To enable the stop button, set `hasStopButton` to `true` and pass in a `handleSt
## Navigation

### Side nav in a drawer

The chatbot conversation history is contained in an interactive drawer, where users can interact with previous conversations or start a new conversation.

The `<ChatbotConversationHistoryNav>` component is a wrapper placed within `<Chatbot>`, which contains all other chatbot components in `drawerContent`. There is a focus trap so users can only tab within the drawer while it is open.
Expand Down Expand Up @@ -313,3 +316,11 @@ Actions can be added to conversations with `menuItems`. Optionally, you can also
```js file="./ChatbotHeaderDrawerWithActions.tsx"

```

### Modal

Based on the [PatternFly modal](/components/modal), this modal adapts to the chatbot display mode and accepts components typically used in a modal. It is primarily used and tested in the context of the [attachment modals](/patternfly-ai/chatbot/messages#attachment-preview), but you can customize this modal to adapt it to other use cases as needed.

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

```
93 changes: 93 additions & 0 deletions packages/module/src/ChatbotModal/ChatbotModal.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
.pf-chatbot__chatbot-modal-backdrop {
position: static;
}

.pf-chatbot__chatbot-modal {
--pf-v6-c-modal-box--BorderRadius: var(--pf-t--global--border--radius--medium);
position: fixed;
inset-block-end: var(--pf-t--global--spacer--800); // no associated semantic token
inset-inline-end: var(--pf-t--global--spacer--lg);
width: 30rem;
height: 70vh;
background-color: var(--pf-t--global--background--color--secondary--default);

.pf-v6-c-modal-box__title {
--pf-v6-c-modal-box__title--FontSize: var(--pf-t--global--font--size--heading--h3);
}
.pf-v6-c-button.pf-m-primary.pf-m-block,
.pf-v6-c-button.pf-m-link.pf-m-block {
--pf-v6-c-button--FontWeight: 500;
}
.pf-v6-c-modal-box__footer {
padding-block-start: var(--pf-t--global--spacer--xl);
padding-block-end: var(--pf-t--global--spacer--xl);
}
.pf-v6-c-modal-box__header {
padding-block-end: var(--pf-t--global--spacer--lg);
}
}

// ============================================================================
// Chatbot Display Mode - Fullscreen and Embedded
// ============================================================================
@media screen and (max-width: 600px) {
.pf-chatbot__chatbot-modal--embedded,
.pf-chatbot__chatbot-modal--fullscreen {
inset-block-end: 0;
inset-inline-end: 0;
width: 100%;
height: 100%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
@media screen and (min-width: 601px) {
.pf-chatbot__chatbot-modal--embedded,
.pf-chatbot__chatbot-modal--fullscreen {
inset-block-end: 0;
inset-inline-end: 0;
width: 50%;
height: fit-content;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}

// ============================================================================
// Chatbot Display Mode - Default
// ============================================================================
.pf-chatbot__chatbot-modal--default {
box-shadow: unset;
}

// ============================================================================
// Chatbot Display Mode - Docked
// ============================================================================
.pf-chatbot__chatbot-modal--docked {
height: 100vh;
inset-block-end: 0;
inset-inline-end: 0;
border-radius: 0;
--pf-v6-c-modal-box--MaxHeight: 100vh;
box-shadow: unset;
}

// ============================================================================
// Dark theme
// ============================================================================
.pf-v6-theme-dark {
.pf-v6-c-modal-box.pf-chatbot__chatbot-modal {
.pf-v6-c-modal-box__title {
color: #fff;
}
}
}

// ============================================================================
// Backdrop
// ============================================================================
.pf-v6-c-backdrop.pf-chatbot__backdrop {
position: absolute;
}
43 changes: 43 additions & 0 deletions packages/module/src/ChatbotModal/ChatbotModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// ============================================================================
// Code Modal - Chatbot Modal with Code Editor
// ============================================================================
import React from 'react';

// Import PatternFly components
import { Modal, ModalProps } from '@patternfly/react-core';
import { ChatbotDisplayMode } from '../Chatbot';

export interface ChatbotModalProps extends Omit<ModalProps, 'ref'> {
/** Display mode for the Chatbot parent; this influences the styles applied */
displayMode?: ChatbotDisplayMode;
className?: string;
}

export const ChatbotModal: React.FunctionComponent<ChatbotModalProps> = ({
children,
displayMode = ChatbotDisplayMode.default,
className,
isOpen,
...props
}: ChatbotModalProps) => {
const modal = (
<Modal
isOpen={isOpen}
ouiaId="ChatbotModal"
aria-labelledby="chatbot-modal-title"
aria-describedby="chatbot-modal"
className={`pf-chatbot__chatbot-modal pf-chatbot__chatbot-modal--${displayMode} ${className}`}
backdropClassName="pf-chatbot__chatbot-modal-backdrop"
{...props}
>
{children}
</Modal>
);

if ((displayMode === ChatbotDisplayMode.fullscreen || displayMode === ChatbotDisplayMode.embedded) && isOpen) {
return <div className="pf-v6-c-backdrop pf-chatbot__backdrop">{modal}</div>;
}
return modal;
};

export default ChatbotModal;
3 changes: 3 additions & 0 deletions packages/module/src/ChatbotModal/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { default } from './ChatbotModal';

export * from './ChatbotModal';
94 changes: 3 additions & 91 deletions packages/module/src/CodeModal/CodeModal.scss
Original file line number Diff line number Diff line change
@@ -1,19 +1,4 @@
.pf-chatbot__code-modal-backdrop {
position: static;
}

.pf-chatbot__code-modal {
--pf-v6-c-modal-box--BorderRadius: var(--pf-t--global--border--radius--medium);
position: fixed;
inset-block-end: var(--pf-t--global--spacer--800); // no associated semantic token
inset-inline-end: var(--pf-t--global--spacer--lg);
width: 30rem;
height: 70vh;
background-color: var(--pf-t--global--background--color--secondary--default);

.pf-v6-c-modal-box__title {
--pf-v6-c-modal-box__title--FontSize: var(--pf-t--global--font--size--heading--h3);
}
.pf-v6-c-code-editor {
--pf-v6-c-code-editor__main--BackgroundColor: #1f1f1f;
--pf-v6-c-code-editor__main--BorderEndStartRadius: 0;
Expand All @@ -26,6 +11,9 @@
border-start-start-radius: var(--pf-t--global--border--radius--small);
border-start-end-radius: var(--pf-t--global--border--radius--small);
}
.pf-chatbot__code-modal-body {
gap: var(--pf-t--global--spacer--lg);
}
.pf-chatbot__code-modal--controls > .pf-v6-c-code-editor__header {
flex-direction: row-reverse;
border-radius: var(--pf-t--global--border--radius--small);
Expand Down Expand Up @@ -70,75 +58,11 @@
.pf-v6-c-code-editor__header-main {
display: none;
}
.pf-v6-c-button.pf-m-primary.pf-m-block,
.pf-v6-c-button.pf-m-link.pf-m-block {
--pf-v6-c-button--FontWeight: 500;
}
.pf-v6-c-modal-box__close {
--pf-v6-c-modal-box__close--InsetBlockStart: 1.125rem;
}
.pf-chatbot__code-modal-body {
gap: var(--pf-t--global--spacer--lg);
}
.pf-v6-c-modal-box__footer {
padding-block-start: var(--pf-t--global--spacer--xl);
padding-block-end: var(--pf-t--global--spacer--xl);
}
.pf-v6-c-modal-box__header {
padding-block-end: var(--pf-t--global--spacer--lg);
}
.pf-chatbot__code-modal-file-details {
padding-inline-start: var(--pf-t--global--spacer--md);
}
}

// ============================================================================
// Chatbot Display Mode - Fullscreen and Embedded
// ============================================================================
@media screen and (max-width: 600px) {
.pf-chatbot__code-modal--embedded,
.pf-chatbot__code-modal--fullscreen {
inset-block-end: 0;
inset-inline-end: 0;
width: 100%;
height: 100%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
@media screen and (min-width: 601px) {
.pf-chatbot__code-modal--embedded,
.pf-chatbot__code-modal--fullscreen {
inset-block-end: 0;
inset-inline-end: 0;
width: 50%;
height: fit-content;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}

// ============================================================================
// Chatbot Display Mode - Default
// ============================================================================
.pf-chatbot__code-modal--default {
box-shadow: unset;
}

// ============================================================================
// Chatbot Display Mode - Docked
// ============================================================================
.pf-chatbot__code-modal--docked {
height: 100vh;
inset-block-end: 0;
inset-inline-end: 0;
border-radius: 0;
--pf-v6-c-modal-box--MaxHeight: 100vh;
box-shadow: unset;
}

// ============================================================================
// Dark theme
// ============================================================================
Expand All @@ -149,16 +73,4 @@
--pf-v6-c-button--hover__icon--Color: #c7c7c7;
}
}
.pf-v6-c-modal-box.pf-chatbot__code-modal {
.pf-v6-c-modal-box__title {
color: #fff;
}
}
}

// ============================================================================
// Backdrop
// ============================================================================
.pf-v6-c-backdrop.pf-chatbot__backdrop {
position: absolute;
}
Loading

0 comments on commit 7cece91

Please sign in to comment.