Skip to content

Commit b455d54

Browse files
committed
UI
1 parent da3afc6 commit b455d54

File tree

6 files changed

+185
-4
lines changed

6 files changed

+185
-4
lines changed
Lines changed: 6 additions & 0 deletions
Loading
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import {
2+
AIMenu as AIMenuDefault,
3+
//AIMenuSuggestionItem,
4+
//getAIExtension,
5+
getDefaultAIMenuItems,
6+
} from '@blocknote/xl-ai';
7+
//import { RiEmotionHappyFill } from 'react-icons/ri';
8+
9+
import { DocsBlockNoteEditor } from '../../types';
10+
11+
export function AIMenu() {
12+
return (
13+
<AIMenuDefault
14+
items={(editor: DocsBlockNoteEditor, aiResponseStatus) => {
15+
if (aiResponseStatus === 'user-input') {
16+
if (editor.getSelection()) {
17+
// When a selection is active (so when the AI Menu is opened via the Formatting Toolbar),
18+
// we add our `makeInformal` command to the default items.
19+
return [
20+
...getDefaultAIMenuItems(editor, aiResponseStatus),
21+
//aIMenuItemMakeInformal(editor),
22+
];
23+
} else {
24+
return getDefaultAIMenuItems(editor, aiResponseStatus);
25+
}
26+
}
27+
28+
// for other states, return the default items
29+
return getDefaultAIMenuItems(editor, aiResponseStatus);
30+
}}
31+
/>
32+
);
33+
}
34+
35+
// export const aIMenuItemMakeInformal = (
36+
// editor: DocsBlockNoteEditor,
37+
// ): AIMenuSuggestionItem => ({
38+
// key: 'make_informal',
39+
// title: 'Make Informal',
40+
// aliases: ['informal', 'make informal', 'casual'],
41+
// icon: <RiEmotionHappyFill size={18} />,
42+
// onItemClick: () => {
43+
// void getAIExtension(editor).callLLM({
44+
// // The prompt to send to the LLM:
45+
// userPrompt: 'Give the selected text a more informal (casual) tone',
46+
// // Tell the LLM to specifically use the selected content as context (instead of the whole document)
47+
// useSelection: true,
48+
// // We only want the LLM to update selected text, not to add / delete blocks
49+
// defaultStreamTools: {
50+
// add: false,
51+
// delete: false,
52+
// update: true,
53+
// },
54+
// });
55+
// },
56+
// size: 'small',
57+
// });
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { useBlockNoteEditor, useComponentsContext } from '@blocknote/react';
2+
import { getAIExtension } from '@blocknote/xl-ai';
3+
import { useTranslation } from 'react-i18next';
4+
import { css } from 'styled-components';
5+
6+
import { Box, Text } from '@/components';
7+
import { useCunninghamTheme } from '@/cunningham';
8+
9+
import IconAI from '../../assets/IconAI.svg';
10+
import {
11+
DocsBlockSchema,
12+
DocsInlineContentSchema,
13+
DocsStyleSchema,
14+
} from '../../types';
15+
16+
export const AIToolbarButton = () => {
17+
const Components = useComponentsContext();
18+
const { t } = useTranslation();
19+
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
20+
21+
const editor = useBlockNoteEditor<
22+
DocsBlockSchema,
23+
DocsInlineContentSchema,
24+
DocsStyleSchema
25+
>();
26+
27+
const ai = getAIExtension(editor);
28+
29+
const onClick = () => {
30+
editor.formattingToolbar.closeMenu();
31+
const selection = editor.getSelection();
32+
if (!selection) {
33+
throw new Error('No selection');
34+
}
35+
const position = selection.blocks[selection.blocks.length - 1].id;
36+
ai.openAIMenuAtBlock(position);
37+
};
38+
39+
if (!editor.isEditable || !Components) {
40+
return null;
41+
}
42+
43+
return (
44+
<Box
45+
$css={css`
46+
& > button.mantine-Button-root {
47+
padding-inline: ${spacingsTokens['2xs']};
48+
transition: all 0.1s ease-in;
49+
&:hover,
50+
&:hover {
51+
background-color: ${colorsTokens['greyscale-050']};
52+
}
53+
&:hover .--docs--icon-bg {
54+
background-color: #5858e1;
55+
border: 1px solid #8484f5;
56+
color: #ffffff;
57+
}
58+
}
59+
`}
60+
$direction="row"
61+
>
62+
<Components.Generic.Toolbar.Button
63+
className="bn-button"
64+
onClick={onClick}
65+
>
66+
<Box
67+
$direction="row"
68+
$align="center"
69+
$gap={spacingsTokens['xs']}
70+
$padding={{ right: '2xs' }}
71+
>
72+
<Text
73+
className="--docs--icon-bg"
74+
$theme="greyscale"
75+
$variation="600"
76+
$css={css`
77+
border: 1px solid var(--c--theme--colors--greyscale-100);
78+
transition: all 0.1s ease-in;
79+
`}
80+
$radius="100%"
81+
$padding="0.15rem"
82+
>
83+
<IconAI width="16px" />
84+
</Text>
85+
{t('Ask AI')}
86+
</Box>
87+
</Components.Generic.Toolbar.Button>
88+
<Box
89+
$background={colorsTokens['greyscale-100']}
90+
$width="1px"
91+
$height="70%"
92+
$margin={{ left: '2px' }}
93+
$css={css`
94+
align-self: center;
95+
`}
96+
/>
97+
</Box>
98+
);
99+
};

src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import { cssEditor } from '../styles';
3434
import { DocsBlockNoteEditor } from '../types';
3535
import { randomColor } from '../utils';
3636

37+
import { AIMenu } from './AI/AI';
3738
import { BlockNoteSuggestionMenu } from './BlockNoteSuggestionMenu';
3839
import { BlockNoteToolbar } from './BlockNoteToolBar/BlockNoteToolbar';
3940
import { CalloutBlock, DividerBlock } from './custom-blocks';
@@ -201,7 +202,7 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
201202
editable={!readOnly}
202203
theme="light"
203204
>
204-
<AIMenuController />
205+
<AIMenuController aiMenu={AIMenu} />
205206
<BlockNoteSuggestionMenu />
206207
<BlockNoteToolbar />
207208
</BlockNoteView>

src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteToolBar/BlockNoteToolbar.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import {
55
getFormattingToolbarItems,
66
useDictionary,
77
} from '@blocknote/react';
8-
import { AIToolbarButton } from '@blocknote/xl-ai';
98
import React, { JSX, useCallback, useMemo, useState } from 'react';
109
import { useTranslation } from 'react-i18next';
1110

1211
import { useConfig } from '@/core/config/api';
1312

13+
import { AIToolbarButton } from '../AI/AIToolbarButton';
1414
import { getCalloutFormattingToolbarItems } from '../custom-blocks';
1515

1616
import { AIGroupButton } from './AIButton';
@@ -57,10 +57,10 @@ export const BlockNoteToolbar = () => {
5757
const formattingToolbar = useCallback(() => {
5858
return (
5959
<FormattingToolbar>
60-
{toolbarItems}
61-
6260
<AIToolbarButton />
6361

62+
{toolbarItems}
63+
6464
{/* Extra button to do some AI powered actions */}
6565
{conf?.AI_FEATURE_ENABLED && <AIGroupButton key="AIButton" />}
6666

src/frontend/apps/impress/src/features/docs/doc-editor/styles.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { css } from 'styled-components';
22

33
export const cssEditor = (readonly: boolean) => css`
4+
.mantine-Menu-itemLabel,
5+
.mantine-Button-label {
6+
font-family: var(--c--components--button--font-family);
7+
}
8+
49
&,
510
& > .bn-container,
611
& .ProseMirror {
@@ -108,6 +113,19 @@ export const cssEditor = (readonly: boolean) => css`
108113
border-left: 4px solid var(--c--theme--colors--greyscale-300);
109114
font-style: italic;
110115
}
116+
117+
/**
118+
* AI
119+
*/
120+
ins,
121+
[data-type='modification'] {
122+
background: var(--c--theme--colors--primary-100);
123+
border-bottom: 2px solid var(--c--theme--colors--primary-300);
124+
color: var(--c--theme--colors--primary-700);
125+
}
126+
[data-show-selection] {
127+
background-color: var(--c--theme--colors--primary-300);
128+
}
111129
}
112130
113131
& .bn-block-outer:not(:first-child) {

0 commit comments

Comments
 (0)