(app-impress) button editor convert from markdown

Some people prefer to write in markdown,
or had already written stuff in markdown,
so this commit adds a button to the editor t
hat will convert the markdown to the editor's format.
This commit is contained in:
Anthony LC
2024-04-16 13:10:31 +02:00
committed by Anthony LC
parent 8305cfcf99
commit 45bf99178b
3 changed files with 164 additions and 1 deletions

View File

@@ -77,4 +77,34 @@ test.describe('Pad Editor', () => {
expect(pdfText).toContain('La directrice'); // This is the template text
expect(pdfText).toContain('Hello World'); // This is the pad text
});
test('markdown button converts from markdown to the editor syntax json', async ({
page,
browserName,
}) => {
const randomPad = await createPad(page, 'pad-markdown', browserName, 1);
await expect(page.locator('h2').getByText(randomPad[0])).toBeVisible();
await page.locator('.ProseMirror.bn-editor').click();
await page
.locator('.ProseMirror.bn-editor')
.fill('[test markdown](http://test-markdown.html)');
await expect(page.getByText('[test markdown]')).toBeVisible();
await page.getByText('[test markdown]').dblclick();
await page
.getByRole('button', {
name: 'M',
})
.click();
await expect(page.getByText('[test markdown]')).toBeHidden();
await expect(
page.getByRole('link', {
name: 'test markdown',
}),
).toHaveAttribute('href', 'http://test-markdown.html');
});
});

View File

@@ -10,6 +10,8 @@ import { usePadStore } from '../stores';
import { Pad } from '../types';
import { randomColor } from '../utils';
import { BlockNoteToolbar } from './BlockNoteToolbar';
interface BlockNoteEditorProps {
pad: Pad;
}
@@ -67,7 +69,9 @@ export const BlockNoteContent = ({ pad, provider }: BlockNoteContentProps) => {
};
`}
>
<BlockNoteView editor={editor} />
<BlockNoteView editor={editor} formattingToolbar={false}>
<BlockNoteToolbar />
</BlockNoteView>
</Box>
);
};

View File

@@ -0,0 +1,129 @@
import {
BasicTextStyleButton,
BlockTypeSelect,
ColorStyleButton,
CreateLinkButton,
FormattingToolbar,
FormattingToolbarController,
ImageCaptionButton,
NestBlockButton,
ReplaceImageButton,
TextAlignButton,
ToolbarButton,
UnnestBlockButton,
useBlockNoteEditor,
} from '@blocknote/react';
import '@blocknote/react/style.css';
import { forEach, isArray } from 'lodash';
import React from 'react';
export const BlockNoteToolbar = () => {
return (
<FormattingToolbarController
formattingToolbar={() => (
<FormattingToolbar>
<BlockTypeSelect key="blockTypeSelect" />
{/* Extra button to convert from markdown to json */}
<MarkdownButton key="customButton" />
<ImageCaptionButton key="imageCaptionButton" />
<ReplaceImageButton key="replaceImageButton" />
<BasicTextStyleButton basicTextStyle="bold" key="boldStyleButton" />
<BasicTextStyleButton
basicTextStyle="italic"
key="italicStyleButton"
/>
<BasicTextStyleButton
basicTextStyle="underline"
key="underlineStyleButton"
/>
<BasicTextStyleButton
basicTextStyle="strike"
key="strikeStyleButton"
/>
{/* Extra button to toggle code styles */}
<BasicTextStyleButton key="codeStyleButton" basicTextStyle="code" />
<TextAlignButton textAlignment="left" key="textAlignLeftButton" />
<TextAlignButton textAlignment="center" key="textAlignCenterButton" />
<TextAlignButton textAlignment="right" key="textAlignRightButton" />
<ColorStyleButton key="colorStyleButton" />
<NestBlockButton key="nestBlockButton" />
<UnnestBlockButton key="unnestBlockButton" />
<CreateLinkButton key="createLinkButton" />
</FormattingToolbar>
)}
/>
);
};
type Block = {
type: string;
text: string;
content: Block[];
};
function isBlock(block: Block): block is Block {
return (
block.content &&
isArray(block.content) &&
block.content.length > 0 &&
typeof block.type !== 'undefined'
);
}
const recursiveContent = (content: Block[], base: string = '') => {
let fullContent = base;
for (const innerContent of content) {
if (innerContent.type === 'text') {
fullContent += innerContent.text;
} else if (isBlock(innerContent)) {
fullContent = recursiveContent(innerContent.content, fullContent);
}
}
return fullContent;
};
/**
* Custom Formatting Toolbar Button to convert markdown to json.
*/
export function MarkdownButton() {
const editor = useBlockNoteEditor();
const handleConvertMarkdown = () => {
const blocks = editor.getSelection()?.blocks;
forEach(blocks, async (block) => {
if (!isBlock(block as unknown as Block)) {
return;
}
try {
const fullContent = recursiveContent(
block.content as unknown as Block[],
);
const blockMarkdown =
await editor.tryParseMarkdownToBlocks(fullContent);
editor.replaceBlocks([block.id], blockMarkdown);
} catch (error) {
console.error('Error parsing Markdown:', error);
}
});
};
return (
<ToolbarButton
mainTooltip="Convert Markdown"
onClick={handleConvertMarkdown}
>
M
</ToolbarButton>
);
}