✨(frontend) add quote blocks to the editor
Add a custom block to quote in the editor.
This commit is contained in:
@@ -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"
|
||||
>
|
||||
<BlockNoteToolbar />
|
||||
<BlockNoteSuggestionMenu />
|
||||
<BlockNoteToolbar />
|
||||
</BlockNoteView>
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -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<DocsBlockSchema>();
|
||||
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 (
|
||||
<SuggestionMenuController
|
||||
|
||||
@@ -2,19 +2,28 @@ import '@blocknote/mantine/style.css';
|
||||
import {
|
||||
FormattingToolbar,
|
||||
FormattingToolbarController,
|
||||
FormattingToolbarProps,
|
||||
blockTypeSelectItems,
|
||||
getFormattingToolbarItems,
|
||||
useDictionary,
|
||||
} from '@blocknote/react';
|
||||
import React, { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { AIGroupButton } from './AIButton';
|
||||
import { MarkdownButton } from './MarkdownButton';
|
||||
import { getQuoteFormattingToolbarItems } from './custom-blocks';
|
||||
|
||||
export const BlockNoteToolbar = () => {
|
||||
const dict = useDictionary();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formattingToolbar = useCallback(
|
||||
({ blockTypeSelectItems }: FormattingToolbarProps) => (
|
||||
() => (
|
||||
<FormattingToolbar>
|
||||
{getFormattingToolbarItems(blockTypeSelectItems)}
|
||||
{getFormattingToolbarItems([
|
||||
...blockTypeSelectItems(dict),
|
||||
getQuoteFormattingToolbarItems(t),
|
||||
])}
|
||||
|
||||
{/* Extra button to do some AI powered actions */}
|
||||
<AIGroupButton key="AIButton" />
|
||||
@@ -23,7 +32,7 @@ export const BlockNoteToolbar = () => {
|
||||
<MarkdownButton key="customButton" />
|
||||
</FormattingToolbar>
|
||||
),
|
||||
[],
|
||||
[dict, t],
|
||||
);
|
||||
|
||||
return <FormattingToolbarController formattingToolbar={formattingToolbar} />;
|
||||
|
||||
@@ -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 (
|
||||
<Text
|
||||
className="inline-content"
|
||||
$margin="0 0 1rem 0"
|
||||
$padding="0.5rem 1rem"
|
||||
$variation="600"
|
||||
style={{
|
||||
borderLeft: `4px solid ${colorsTokens()['greyscale-300']}`,
|
||||
fontStyle: 'italic',
|
||||
flexGrow: 1,
|
||||
}}
|
||||
ref={props.contentRef}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
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: (
|
||||
<Text $isMaterialIcon $size="18px">
|
||||
format_quote
|
||||
</Text>
|
||||
),
|
||||
subtext: t('Add a quote block'),
|
||||
},
|
||||
];
|
||||
|
||||
export const getQuoteFormattingToolbarItems = (
|
||||
t: TFunction<'translation', undefined>,
|
||||
): BlockTypeSelectItem => ({
|
||||
name: t('Quote'),
|
||||
type: 'quote',
|
||||
icon: () => (
|
||||
<Text $isMaterialIcon $size="16px">
|
||||
format_quote
|
||||
</Text>
|
||||
),
|
||||
isSelected: (block) => block.type === 'quote',
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
export * from './QuoteBlock';
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user