🔥(frontend) remove Quote custom block

Last Blocknote upgrade included a Quote block,
better to use their built-in one.
This commit is contained in:
Anthony LC
2025-04-29 17:14:23 +02:00
parent 4ad917906c
commit 7f2a21cdc9
7 changed files with 16 additions and 97 deletions

View File

@@ -235,7 +235,7 @@ test.describe('Doc Export', () => {
// Trigger slash menu to show menu // Trigger slash menu to show menu
await editor.click(); await editor.click();
await editor.fill('/'); await editor.fill('/');
await page.getByText('Add a quote block').click(); await page.getByText('Quote or excerpt').click();
await expect( await expect(
editor.locator('.bn-block-content[data-content-type="quote"]'), editor.locator('.bn-block-content[data-content-type="quote"]'),

View File

@@ -1,11 +1,10 @@
import { import {
BlockNoteSchema, BlockNoteSchema,
Dictionary,
defaultBlockSpecs, defaultBlockSpecs,
locales,
withPageBreak, withPageBreak,
} from '@blocknote/core'; } from '@blocknote/core';
import '@blocknote/core/fonts/inter.css'; import '@blocknote/core/fonts/inter.css';
import * as locales from '@blocknote/core/locales';
import { BlockNoteView } from '@blocknote/mantine'; import { BlockNoteView } from '@blocknote/mantine';
import '@blocknote/mantine/style.css'; import '@blocknote/mantine/style.css';
import { useCreateBlockNote } from '@blocknote/react'; import { useCreateBlockNote } from '@blocknote/react';
@@ -27,14 +26,13 @@ import { randomColor } from '../utils';
import { BlockNoteSuggestionMenu } from './BlockNoteSuggestionMenu'; import { BlockNoteSuggestionMenu } from './BlockNoteSuggestionMenu';
import { BlockNoteToolbar } from './BlockNoteToolBar/BlockNoteToolbar'; import { BlockNoteToolbar } from './BlockNoteToolBar/BlockNoteToolbar';
import { DividerBlock, QuoteBlock } from './custom-blocks'; import { DividerBlock } from './custom-blocks';
export const blockNoteSchema = withPageBreak( export const blockNoteSchema = withPageBreak(
BlockNoteSchema.create({ BlockNoteSchema.create({
blockSpecs: { blockSpecs: {
...defaultBlockSpecs, ...defaultBlockSpecs,
divider: DividerBlock, divider: DividerBlock,
quote: QuoteBlock,
}, },
}), }),
); );
@@ -112,7 +110,7 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
}, },
showCursorLabels: showCursorLabels as 'always' | 'activity', showCursorLabels: showCursorLabels as 'always' | 'activity',
}, },
dictionary: locales[lang as keyof typeof locales] as Dictionary, dictionary: locales[lang as keyof typeof locales],
uploadFile, uploadFile,
schema: blockNoteSchema, schema: blockNoteSchema,
}, },

View File

@@ -11,10 +11,7 @@ import { useTranslation } from 'react-i18next';
import { DocsBlockSchema } from '../types'; import { DocsBlockSchema } from '../types';
import { import { getDividerReactSlashMenuItems } from './custom-blocks';
getDividerReactSlashMenuItems,
getQuoteReactSlashMenuItems,
} from './custom-blocks';
export const BlockNoteSuggestionMenu = () => { export const BlockNoteSuggestionMenu = () => {
const editor = useBlockNoteEditor<DocsBlockSchema>(); const editor = useBlockNoteEditor<DocsBlockSchema>();
@@ -28,7 +25,6 @@ export const BlockNoteSuggestionMenu = () => {
combineByGroup( combineByGroup(
getDefaultReactSlashMenuItems(editor), getDefaultReactSlashMenuItems(editor),
getPageBreakReactSlashMenuItems(editor), getPageBreakReactSlashMenuItems(editor),
getQuoteReactSlashMenuItems(editor, t, basicBlocksName),
getDividerReactSlashMenuItems(editor, t, basicBlocksName), getDividerReactSlashMenuItems(editor, t, basicBlocksName),
), ),
query, query,

View File

@@ -6,12 +6,9 @@ import {
useDictionary, useDictionary,
} from '@blocknote/react'; } from '@blocknote/react';
import React, { JSX, useCallback, useMemo, useState } from 'react'; import React, { JSX, useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useConfig } from '@/core/config/api'; import { useConfig } from '@/core/config/api';
import { getQuoteFormattingToolbarItems } from '../custom-blocks';
import { AIGroupButton } from './AIButton'; import { AIGroupButton } from './AIButton';
import { FileDownloadButton } from './FileDownloadButton'; import { FileDownloadButton } from './FileDownloadButton';
import { MarkdownButton } from './MarkdownButton'; import { MarkdownButton } from './MarkdownButton';
@@ -21,13 +18,11 @@ export const BlockNoteToolbar = () => {
const dict = useDictionary(); const dict = useDictionary();
const [confirmOpen, setIsConfirmOpen] = useState(false); const [confirmOpen, setIsConfirmOpen] = useState(false);
const [onConfirm, setOnConfirm] = useState<() => void | Promise<void>>(); const [onConfirm, setOnConfirm] = useState<() => void | Promise<void>>();
const { t } = useTranslation();
const { data: conf } = useConfig(); const { data: conf } = useConfig();
const toolbarItems = useMemo(() => { const toolbarItems = useMemo(() => {
const toolbarItems = getFormattingToolbarItems([ const toolbarItems = getFormattingToolbarItems([
...blockTypeSelectItems(dict), ...blockTypeSelectItems(dict),
getQuoteFormattingToolbarItems(t),
]); ]);
const fileDownloadButtonIndex = toolbarItems.findIndex( const fileDownloadButtonIndex = toolbarItems.findIndex(
(item) => (item) =>
@@ -51,7 +46,7 @@ export const BlockNoteToolbar = () => {
} }
return toolbarItems as JSX.Element[]; return toolbarItems as JSX.Element[];
}, [dict, t]); }, [dict]);
const formattingToolbar = useCallback(() => { const formattingToolbar = useCallback(() => {
return ( return (

View File

@@ -1,68 +0,0 @@
import { defaultProps, insertOrUpdateBlock } from '@blocknote/core';
import { BlockTypeSelectItem, createReactBlockSpec } from '@blocknote/react';
import { TFunction } from 'i18next';
import { Box, Icon } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { DocsBlockNoteEditor } from '../../types';
export const QuoteBlock = createReactBlockSpec(
{
type: 'quote',
propSchema: {
textAlignment: defaultProps.textAlignment,
},
content: 'inline',
},
{
render: (props) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const { colorsTokens } = useCunninghamTheme();
return (
<Box
as="blockquote"
className="inline-content"
$margin="0 0 1rem 0"
$padding="0.5rem 1rem"
style={{
borderLeft: `4px solid ${colorsTokens['greyscale-300']}`,
fontStyle: 'italic',
flexGrow: 1,
}}
$color="var(--c--theme--colors--greyscale-500)"
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: <Icon iconName="format_quote" $size="18px" />,
subtext: t('Add a quote block'),
},
];
export const getQuoteFormattingToolbarItems = (
t: TFunction<'translation', undefined>,
): BlockTypeSelectItem => ({
name: t('Quote'),
type: 'quote',
icon: () => <Icon iconName="format_quote" $size="16px" />,
isSelected: (block) => block.type === 'quote',
});

View File

@@ -1,2 +1 @@
export * from './DividerBlock'; export * from './DividerBlock';
export * from './QuoteBlock';

View File

@@ -57,9 +57,6 @@ export const cssEditor = (readonly: boolean) => css`
.bn-side-menu[data-block-type='heading'][data-level='3'] { .bn-side-menu[data-block-type='heading'][data-level='3'] {
height: 35px; height: 35px;
} }
.bn-side-menu[data-block-type='quote'] {
height: 46px;
}
.bn-side-menu[data-block-type='divider'] { .bn-side-menu[data-block-type='divider'] {
height: 38px; height: 38px;
} }
@@ -84,11 +81,19 @@ export const cssEditor = (readonly: boolean) => css`
} }
} }
.bn-editor { & .bn-editor {
color: var(--c--theme--colors--greyscale-700); color: var(--c--theme--colors--greyscale-700);
/**
* Quotes
*/
blockquote {
border-left: 4px solid var(--c--theme--colors--greyscale-300);
font-style: italic;
}
} }
.bn-block-outer:not(:first-child) { & .bn-block-outer:not(:first-child) {
&:has(h1) { &:has(h1) {
margin-top: 32px; margin-top: 32px;
} }
@@ -105,12 +110,6 @@ export const cssEditor = (readonly: boolean) => css`
padding: 2px; padding: 2px;
border-radius: 4px; border-radius: 4px;
} }
& .bn-inline-content {
width: 100%;
}
.bn-block-content[data-content-type='checkListItem'] > div {
width: 100%;
}
@media screen and (width <= 768px) { @media screen and (width <= 768px) {
& .bn-editor { & .bn-editor {