diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx index 0b6e0d97..92c22780 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx @@ -1,6 +1,7 @@ import { BlockNoteSchema, Dictionary, + defaultBlockSpecs, locales, withPageBreak, } from '@blocknote/core'; @@ -26,8 +27,16 @@ import { randomColor } from '../utils'; import { BlockNoteSuggestionMenu } from './BlockNoteSuggestionMenu'; import { BlockNoteToolbar } from './BlockNoteToolbar'; +import { QuoteBlock } from './custom-blocks'; -export const blockNoteSchema = withPageBreak(BlockNoteSchema.create()); +export const blockNoteSchema = withPageBreak( + BlockNoteSchema.create({ + blockSpecs: { + ...defaultBlockSpecs, + quote: QuoteBlock, + }, + }), +); interface BlockNoteEditorProps { doc: Doc; @@ -141,8 +150,8 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => { editable={!readOnly} theme="light" > - + ); diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx index 22b11365..961b33be 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx @@ -5,13 +5,19 @@ import { getDefaultReactSlashMenuItems, getPageBreakReactSlashMenuItems, useBlockNoteEditor, + useDictionary, } from '@blocknote/react'; import React, { useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; -import { DocsBlockNoteEditor } from '../types'; +import { DocsBlockSchema } from '../types'; + +import { getQuoteReactSlashMenuItems } from './custom-blocks'; export const BlockNoteSuggestionMenu = () => { - const editor = useBlockNoteEditor() as DocsBlockNoteEditor; + const editor = useBlockNoteEditor(); + const { t } = useTranslation(); + const basicBlocksName = useDictionary().slash_menu.page_break.group; const getSlashMenuItems = useMemo(() => { return async (query: string) => @@ -20,11 +26,12 @@ export const BlockNoteSuggestionMenu = () => { combineByGroup( getDefaultReactSlashMenuItems(editor), getPageBreakReactSlashMenuItems(editor), + getQuoteReactSlashMenuItems(editor, t, basicBlocksName), ), query, ), ); - }, [editor]); + }, [basicBlocksName, editor, t]); return ( { + const dict = useDictionary(); + const { t } = useTranslation(); + const formattingToolbar = useCallback( - ({ blockTypeSelectItems }: FormattingToolbarProps) => ( + () => ( - {getFormattingToolbarItems(blockTypeSelectItems)} + {getFormattingToolbarItems([ + ...blockTypeSelectItems(dict), + getQuoteFormattingToolbarItems(t), + ])} {/* Extra button to do some AI powered actions */} @@ -23,7 +32,7 @@ export const BlockNoteToolbar = () => { ), - [], + [dict, t], ); return ; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-blocks/QuoteBlock.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-blocks/QuoteBlock.tsx new file mode 100644 index 00000000..e5d99802 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-blocks/QuoteBlock.tsx @@ -0,0 +1,77 @@ +import { defaultProps, insertOrUpdateBlock } from '@blocknote/core'; +import { BlockTypeSelectItem, createReactBlockSpec } from '@blocknote/react'; +import { TFunction } from 'i18next'; +import React from 'react'; + +import { Text } from '@/components'; +import { useCunninghamTheme } from '@/cunningham'; + +import { DocsBlockNoteEditor } from '../../types'; + +export const QuoteBlock = createReactBlockSpec( + { + type: 'quote', + propSchema: { + textAlignment: defaultProps.textAlignment, + textColor: defaultProps.textColor, + }, + content: 'inline', + }, + { + render: (props) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const { colorsTokens } = useCunninghamTheme(); + + return ( + + ); + }, + }, +); + +export const getQuoteReactSlashMenuItems = ( + editor: DocsBlockNoteEditor, + t: TFunction<'translation', undefined>, + group: string, +) => [ + { + title: t('Quote'), + onItemClick: () => { + insertOrUpdateBlock(editor, { + type: 'quote', + }); + }, + aliases: ['quote', 'blockquote', 'citation'], + group, + icon: ( + + format_quote + + ), + subtext: t('Add a quote block'), + }, +]; + +export const getQuoteFormattingToolbarItems = ( + t: TFunction<'translation', undefined>, +): BlockTypeSelectItem => ({ + name: t('Quote'), + type: 'quote', + icon: () => ( + + format_quote + + ), + isSelected: (block) => block.type === 'quote', +}); diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-blocks/index.ts b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-blocks/index.ts new file mode 100644 index 00000000..e101ddd8 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-blocks/index.ts @@ -0,0 +1 @@ +export * from './QuoteBlock'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/styles.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/styles.tsx index 4a4a14bc..1eb356f9 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/styles.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/styles.tsx @@ -6,6 +6,10 @@ export const cssEditor = (readonly: boolean) => css` & .ProseMirror { height: 100%; + .bn-side-menu[data-block-type='quote'] { + height: 46px; + } + .collaboration-cursor-custom__base { position: relative; }