Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

General UI/UX improvements #70

Merged
merged 4 commits into from
Apr 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions packages/jupyter-ai/src/components/chat-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import React from 'react';

import {
Box,
IconButton,
Input,
SxProps,
TextField,
Theme,
FormGroup,
FormControlLabel,
Checkbox
Checkbox,
IconButton,
InputAdornment
} from '@mui/material';
import SendIcon from '@mui/icons-material/Send';

Expand All @@ -25,23 +26,33 @@ type ChatInputProps = {
};

export function ChatInput(props: ChatInputProps): JSX.Element {
function handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>) {
if (event.key === 'Enter' && event.shiftKey) {
props.onSend();
event.stopPropagation();
event.preventDefault();
}
}
return (
<Box sx={props.sx}>
<Box sx={{ display: 'flex' }}>
<Input
<TextField
value={props.value}
onChange={e => props.onChange(e.target.value)}
fullWidth
variant="outlined"
multiline
sx={{ flexGrow: 1 }}
onKeyDown={handleKeyDown}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton size="small" color="primary" onClick={props.onSend} disabled={!props.value.trim().length}>
<SendIcon />
</IconButton>
</InputAdornment>
),
}}
/>
<IconButton
size="large"
color="primary"
onClick={props.onSend}
disabled={!props.value.trim().length}
>
<SendIcon />
</IconButton>
</Box>
{props.hasSelection && (
<FormGroup sx={{ display: 'flex', flexDirection: 'row' }}>
Expand Down
15 changes: 9 additions & 6 deletions packages/jupyter-ai/src/components/chat-messages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export function ChatMessageHeader(props: ChatMessageHeaderProps) {
<Typography
sx={{
fontSize: 'var(--jp-ui-font-size1)',
color: 'var(--jp-ui-font-color1)'
color: 'var(--jp-ui-inverse-font-color1)'
}}
>
{props.message.client.initials}
Expand Down Expand Up @@ -85,8 +85,8 @@ export function ChatMessageHeader(props: ChatMessageHeaderProps) {
alignItems: 'center'
}}
>
<Typography sx={{ fontWeight: 700 }}>{name}</Typography>
<Typography sx={{ fontSize: '0.8em', fontWeight: 300 }}>
<Typography sx={{ fontWeight: 700, color: 'var(--jp-ui-font-color1)' }}>{name}</Typography>
<Typography sx={{ fontSize: '0.8em', color: 'var(--jp-ui-font-color2)', fontWeight: 300 }}>
{props.timestamp}
</Typography>
</Box>
Expand Down Expand Up @@ -120,17 +120,20 @@ export function ChatMessages(props: ChatMessagesProps) {

return (
<Box
sx={{ '& > :not(:last-child)': { borderBottom: '1px solid lightgrey' } }}
sx={{ '& > :not(:last-child)': { borderBottom: '1px solid var(--jp-border-color2)' } }}
>
{props.messages.map((message, i) => (
// extra div needed to ensure each bubble is on a new line
<Box key={i} sx={{ padding: 2 }}>
<Box key={i} sx={{ padding: 4 }}>
<ChatMessageHeader
message={message}
timestamp={timestamps[message.id]}
sx={{ marginBottom: '12px' }}
sx={{ marginBottom: 3 }}
/>
<ReactMarkdown
// We are using the jp-RenderedHTMLCommon class here to get the default Jupyter
// markdown styling and then overriding any CSS to make it more compact.
className="jp-RenderedHTMLCommon jp-ai-react-markdown"
components={{
code: ChatCodeView
}}
Expand Down
10 changes: 7 additions & 3 deletions packages/jupyter-ai/src/components/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function ChatBody({ chatHandler }: ChatBodyProps): JSX.Element {

const prompt =
input +
(includeSelection && selection?.text ? '\n--\n' + selection.text : '');
(includeSelection && selection?.text ? '\n\n```\n' + selection.text + '```': '');

// send message to backend
const messageId = await chatHandler.sendMessage({ prompt });
Expand All @@ -90,7 +90,7 @@ function ChatBody({ chatHandler }: ChatBodyProps): JSX.Element {
width: '100%',
height: '100%',
boxSizing: 'border-box',
background: 'white',
background: 'var(--jp-layout-color0)',
display: 'flex',
flexDirection: 'column'
}}
Expand All @@ -114,7 +114,11 @@ function ChatBody({ chatHandler }: ChatBodyProps): JSX.Element {
setReplaceSelection(replaceSelection => !replaceSelection)
}
sx={{
padding: 2
paddingLeft: 4,
paddingRight: 4,
paddingTop: 2,
paddingBottom: 2,
borderTop: '1px solid var(--jp-border-color1)'
}}
/>
</Box>
Expand Down
6 changes: 6 additions & 0 deletions packages/jupyter-ai/src/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@
import { LabIcon } from '@jupyterlab/ui-components';

import psychologySvgStr from '../style/icons/psychology.svg';
import chatSvgStr from '../style/icons/chat.svg';

export const psychologyIcon = new LabIcon({
name: 'jupyter-ai::psychology',
svgstr: psychologySvgStr
});

export const chatIcon = new LabIcon({
name: 'jupyter-ai::chat',
svgstr: chatSvgStr
});
18 changes: 13 additions & 5 deletions packages/jupyter-ai/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
JupyterFrontEnd,
JupyterFrontEndPlugin
JupyterFrontEndPlugin,
ILayoutRestorer
} from '@jupyterlab/application';
import { INotebookTracker } from '@jupyterlab/notebook';
import { IEditorTracker } from '@jupyterlab/fileeditor';
Expand Down Expand Up @@ -50,12 +51,13 @@ const plugin: JupyterFrontEndPlugin<void> = {
id: 'jupyter_ai:plugin',
autoStart: true,
requires: [INotebookTracker, IEditorTracker],
optional: [IGlobalAwareness],
optional: [IGlobalAwareness, ILayoutRestorer],
activate: async (
app: JupyterFrontEnd,
notebookTracker: INotebookTracker,
editorTracker: IEditorTracker,
globalAwareness: Awareness | null
globalAwareness: Awareness | null,
restorer: ILayoutRestorer
) => {
const { commands, shell } = app;

Expand Down Expand Up @@ -92,14 +94,20 @@ const plugin: JupyterFrontEndPlugin<void> = {
const chatHandler = new ChatHandler();
await chatHandler.initialize();

const chatWidget = buildChatSidebar(selectionWatcher, chatHandler, globalAwareness);

/**
* Add Chat widget to right sidebar
*/
shell.add(
buildChatSidebar(selectionWatcher, chatHandler, globalAwareness),
'right'
chatWidget,
'left', { rank: 2000 }
);

if (restorer) {
restorer.add(chatWidget, 'jupyter-ai-chat');
}

/**
* Register inserters
*/
Expand Down
4 changes: 2 additions & 2 deletions packages/jupyter-ai/src/widgets/chat-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ReactWidget } from '@jupyterlab/apputils';
import type { Awareness } from 'y-protocols/awareness';

import { Chat } from '../components/chat';
import { psychologyIcon } from '../icons';
import { chatIcon } from '../icons';
import { SelectionWatcher } from '../selection-watcher';
import { ChatHandler } from '../chat_handler';

Expand All @@ -20,7 +20,7 @@ export function buildChatSidebar(
/>
);
ChatWidget.id = 'jupyter-ai::chat';
ChatWidget.title.icon = psychologyIcon;
ChatWidget.title.icon = chatIcon;
ChatWidget.title.caption = 'Jupyter AI Chat'; // TODO: i18n
return ChatWidget;
}
1 change: 1 addition & 0 deletions packages/jupyter-ai/style/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
*/

@import './expandable-text-field.css';
@import './react-markdown.css';
6 changes: 6 additions & 0 deletions packages/jupyter-ai/style/icons/chat.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions packages/jupyter-ai/style/react-markdown.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.jp-RenderedHTMLCommon.jp-ai-react-markdown > pre {
margin: 0px;
}

.jp-RenderedHTMLCommon.jp-ai-react-markdown {
padding: 0px;
}