fix: blockquote newline (#894)
This commit is contained in:
parent
d1cf12ec84
commit
69d11e831e
@ -1,7 +1,10 @@
|
|||||||
import { isNotNullish, isNullish } from './null.util';
|
import { isNotNullish, isNullish } from './null.util';
|
||||||
|
|
||||||
export function isEmpty(value: string | null | undefined): value is null | undefined {
|
export function isEmpty(
|
||||||
return isNullish(value) || value === '';
|
value: string | null | undefined,
|
||||||
|
ignoreWhitespace?: boolean,
|
||||||
|
): value is null | undefined {
|
||||||
|
return isNullish(value) || (ignoreWhitespace ? value.trim() === '' : value === '');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNotEmpty(value: string | null | undefined): value is string {
|
export function isNotEmpty(value: string | null | undefined): value is string {
|
||||||
|
@ -2,5 +2,6 @@
|
|||||||
@apply border-l-2
|
@apply border-l-2
|
||||||
border-gray-400
|
border-gray-400
|
||||||
ml-2
|
ml-2
|
||||||
pl-2;
|
pl-2
|
||||||
|
my-2;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import type { MdPlatePlugin } from '@staticcms/markdown';
|
|||||||
const softBreakPlugin: Partial<MdPlatePlugin<SoftBreakPlugin>> = {
|
const softBreakPlugin: Partial<MdPlatePlugin<SoftBreakPlugin>> = {
|
||||||
options: {
|
options: {
|
||||||
rules: [
|
rules: [
|
||||||
{ hotkey: 'shift+enter' },
|
|
||||||
{
|
{
|
||||||
hotkey: 'enter',
|
hotkey: 'enter',
|
||||||
query: {
|
query: {
|
||||||
|
@ -108,7 +108,9 @@ function serializeMarkdownNode(
|
|||||||
childrenHasLink = chunk.children.some(f => !isLeafNode(f) && f.type === NodeTypes.link);
|
childrenHasLink = chunk.children.some(f => !isLeafNode(f) && f.type === NodeTypes.link);
|
||||||
}
|
}
|
||||||
|
|
||||||
return serializeMarkdownNode(
|
return {
|
||||||
|
type: 'type' in c ? c.type : undefined,
|
||||||
|
response: serializeMarkdownNode(
|
||||||
{ ...c, parentType: type },
|
{ ...c, parentType: type },
|
||||||
{
|
{
|
||||||
// WOAH.
|
// WOAH.
|
||||||
@ -132,9 +134,34 @@ function serializeMarkdownNode(
|
|||||||
index: childIndex,
|
index: childIndex,
|
||||||
shortcodeConfigs,
|
shortcodeConfigs,
|
||||||
},
|
},
|
||||||
);
|
),
|
||||||
|
};
|
||||||
})
|
})
|
||||||
.join(separator);
|
.map(({ response, type }) => {
|
||||||
|
if (selfIsBlockquote) {
|
||||||
|
let serializedChild = response;
|
||||||
|
|
||||||
|
if (listDepth === 0) {
|
||||||
|
serializedChild = serializedChild.replace(
|
||||||
|
/(?<!(?:[ ]*(?:-|1.) [^\n]*)|[\n])[\n]{1}([^\n])/g,
|
||||||
|
' \n$1',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { response: serializedChild, type };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { response, type };
|
||||||
|
})
|
||||||
|
.reduce((acc, { response, type }, index) => {
|
||||||
|
if (selfIsBlockquote) {
|
||||||
|
if (type === NodeTypes.block_quote) {
|
||||||
|
return index === 0 ? response : `${acc}${separator}\n${response}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return index === 0 ? response : `${acc}${separator}${response}`;
|
||||||
|
}, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is pretty fragile code, check the long comment where we iterate over children
|
// This is pretty fragile code, check the long comment where we iterate over children
|
||||||
@ -152,7 +179,7 @@ function serializeMarkdownNode(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (children === '' && !VOID_ELEMENTS.find(k => NodeTypes[k] === type)) {
|
if (children === '' && !VOID_ELEMENTS.find(k => NodeTypes[k] === type)) {
|
||||||
return;
|
return '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Never allow decorating break tags with rich text formatting,
|
// Never allow decorating break tags with rich text formatting,
|
||||||
@ -237,10 +264,11 @@ function serializeMarkdownNode(
|
|||||||
return `###### ${handleInBlockNewline(children)}\n`;
|
return `###### ${handleInBlockNewline(children)}\n`;
|
||||||
|
|
||||||
case NodeTypes.block_quote:
|
case NodeTypes.block_quote:
|
||||||
return `${selfIsBlockquote && blockquoteDepth > 0 ? '\n' : ''}> ${children
|
return `> ${children
|
||||||
.replace(/^[\n]*|[\n]*$/gm, '')
|
.replace(/[\n]+$/g, '')
|
||||||
.split('\n')
|
.split('\n')
|
||||||
.join('\n> ')}\n`;
|
.join('\n> ')
|
||||||
|
.replace(/\n>[ \t]*\n/g, '\n>\n')}${selfIsBlockquote && blockquoteDepth === 0 ? '\n' : ''}`;
|
||||||
|
|
||||||
case NodeTypes.code_block:
|
case NodeTypes.code_block:
|
||||||
const codeBlock = chunk as MdCodeBlockElement;
|
const codeBlock = chunk as MdCodeBlockElement;
|
||||||
@ -319,7 +347,9 @@ ${bodyRows.join('\n')}`;
|
|||||||
|
|
||||||
case NodeTypes.tableHeaderCell:
|
case NodeTypes.tableHeaderCell:
|
||||||
case NodeTypes.tableCell:
|
case NodeTypes.tableCell:
|
||||||
return isEmpty(children) ? ' ' : children.replace(/\|/g, '\\|').replace(/\n/g, BREAK_TAG);
|
return isEmpty(children, true)
|
||||||
|
? ' '
|
||||||
|
: children.replace(/\|/g, '\\|').replace(/\n/g, BREAK_TAG);
|
||||||
|
|
||||||
case NodeTypes.shortcode:
|
case NodeTypes.shortcode:
|
||||||
const shortcodeNode = chunk as MdShortcodeElement;
|
const shortcodeNode = chunk as MdShortcodeElement;
|
||||||
|
@ -92,6 +92,8 @@ export interface Options {
|
|||||||
isInTable?: boolean;
|
isInTable?: boolean;
|
||||||
isInLink?: boolean;
|
isInLink?: boolean;
|
||||||
isInTableHeaderRow?: boolean;
|
isInTableHeaderRow?: boolean;
|
||||||
|
isInBlockquote?: boolean;
|
||||||
|
isInList?: boolean;
|
||||||
tableAlign?: (string | null)[];
|
tableAlign?: (string | null)[];
|
||||||
useMdx: boolean;
|
useMdx: boolean;
|
||||||
shortcodeConfigs: Record<string, ShortcodeConfig>;
|
shortcodeConfigs: Record<string, ShortcodeConfig>;
|
||||||
@ -105,6 +107,8 @@ export default function deserializeMarkdown(node: MdastNode, options: Options) {
|
|||||||
isInTable = false,
|
isInTable = false,
|
||||||
isInLink = false,
|
isInLink = false,
|
||||||
isInTableHeaderRow = false,
|
isInTableHeaderRow = false,
|
||||||
|
isInBlockquote = false,
|
||||||
|
isInList = false,
|
||||||
tableAlign,
|
tableAlign,
|
||||||
useMdx,
|
useMdx,
|
||||||
shortcodeConfigs,
|
shortcodeConfigs,
|
||||||
@ -114,6 +118,8 @@ export default function deserializeMarkdown(node: MdastNode, options: Options) {
|
|||||||
const selfIsTable = node.type === 'table';
|
const selfIsTable = node.type === 'table';
|
||||||
const selfIsLink = node.type === 'link';
|
const selfIsLink = node.type === 'link';
|
||||||
const selfIsTableHeaderRow = node.type === 'tableRow' && index === 0;
|
const selfIsTableHeaderRow = node.type === 'tableRow' && index === 0;
|
||||||
|
const selfIsBlockquote = node.type === 'blockquote';
|
||||||
|
const selfIsList = node.type === 'list';
|
||||||
|
|
||||||
const nodeChildren = node.children;
|
const nodeChildren = node.children;
|
||||||
if (nodeChildren && Array.isArray(nodeChildren) && nodeChildren.length > 0) {
|
if (nodeChildren && Array.isArray(nodeChildren) && nodeChildren.length > 0) {
|
||||||
@ -128,6 +134,8 @@ export default function deserializeMarkdown(node: MdastNode, options: Options) {
|
|||||||
isInTable: selfIsTable || isInTable,
|
isInTable: selfIsTable || isInTable,
|
||||||
isInLink: selfIsLink || isInLink,
|
isInLink: selfIsLink || isInLink,
|
||||||
isInTableHeaderRow: selfIsTableHeaderRow || isInTableHeaderRow,
|
isInTableHeaderRow: selfIsTableHeaderRow || isInTableHeaderRow,
|
||||||
|
isInBlockquote: selfIsBlockquote || isInBlockquote,
|
||||||
|
isInList: selfIsList || isInList,
|
||||||
useMdx,
|
useMdx,
|
||||||
shortcodeConfigs,
|
shortcodeConfigs,
|
||||||
index: childIndex,
|
index: childIndex,
|
||||||
@ -181,7 +189,25 @@ export default function deserializeMarkdown(node: MdastNode, options: Options) {
|
|||||||
} as ListItemNode;
|
} as ListItemNode;
|
||||||
|
|
||||||
case 'paragraph':
|
case 'paragraph':
|
||||||
if ('ordered' in node) {
|
if (isInBlockquote || isInList) {
|
||||||
|
if (isInBlockquote && index > 0) {
|
||||||
|
if (children.length > 0) {
|
||||||
|
let firstChild = children[0];
|
||||||
|
if ('text' in firstChild) {
|
||||||
|
firstChild = { text: `\n\n${firstChild.text}` };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (children.length > 1) {
|
||||||
|
const [_, ...rest] = children;
|
||||||
|
return [firstChild, ...rest];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [firstChild];
|
||||||
|
}
|
||||||
|
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +238,20 @@ export default function deserializeMarkdown(node: MdastNode, options: Options) {
|
|||||||
} as ImageNode;
|
} as ImageNode;
|
||||||
|
|
||||||
case 'blockquote':
|
case 'blockquote':
|
||||||
return { type: NodeTypes.block_quote, children } as BlockQuoteNode;
|
const blockquoteChildren = children.reduce((acc, n) => {
|
||||||
|
const lastNode = acc.length > 0 ? acc[acc.length - 1] : null;
|
||||||
|
if (lastNode && 'text' in lastNode && lastNode.text && 'text' in n && n.text) {
|
||||||
|
acc[acc.length - 1] = {
|
||||||
|
text: `${lastNode.text}${n.text}`,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
acc.push(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, [] as DeserializedNode[]);
|
||||||
|
|
||||||
|
return { type: NodeTypes.block_quote, children: blockquoteChildren } as BlockQuoteNode;
|
||||||
|
|
||||||
case 'code':
|
case 'code':
|
||||||
return {
|
return {
|
||||||
@ -230,7 +269,7 @@ export default function deserializeMarkdown(node: MdastNode, options: Options) {
|
|||||||
children: [{ text: node.value?.replace(/<br>/g, '') || '' }],
|
children: [{ text: node.value?.replace(/<br>/g, '') || '' }],
|
||||||
} as ParagraphNode;
|
} as ParagraphNode;
|
||||||
}
|
}
|
||||||
return { type: 'p', children: [{ text: node.value || '' }] };
|
return { type: 'p', children: [{ text: node.value ?? '' }] };
|
||||||
|
|
||||||
case 'emphasis':
|
case 'emphasis':
|
||||||
return {
|
return {
|
||||||
@ -285,7 +324,7 @@ export default function deserializeMarkdown(node: MdastNode, options: Options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { text: node.value || '' };
|
return { text: node.value ?? '' };
|
||||||
|
|
||||||
case 'mdxJsxTextElement':
|
case 'mdxJsxTextElement':
|
||||||
if ('name' in node && node.type === 'mdxJsxTextElement') {
|
if ('name' in node && node.type === 'mdxJsxTextElement') {
|
||||||
@ -344,26 +383,37 @@ export default function deserializeMarkdown(node: MdastNode, options: Options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { text: node.value || '' };
|
return { text: node.value ?? '' };
|
||||||
|
|
||||||
|
case 'break':
|
||||||
|
return { text: '\n' };
|
||||||
|
|
||||||
case 'text':
|
case 'text':
|
||||||
if (useMdx) {
|
if (useMdx) {
|
||||||
return { text: node.value || '' };
|
return { text: (node.value ?? '').replace(/(?<![\n]|[ ]{2})[\n]{1}([^\n])/g, ' $1') };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!node.value) {
|
if (!node.value) {
|
||||||
return { text: '' };
|
return { text: '' };
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodes = autoLinkToSlate(
|
let nodes = autoLinkToSlate(
|
||||||
processShortcodeConfigsToSlate(shortcodeConfigs, [node]),
|
processShortcodeConfigsToSlate(shortcodeConfigs, [node]),
|
||||||
isInLink,
|
isInLink,
|
||||||
);
|
);
|
||||||
|
|
||||||
return nodes.map(node => (node.type === 'text' ? { text: node.value ?? '' } : node));
|
nodes = nodes.map(n => {
|
||||||
|
if (n.type !== 'text') {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { text: (n.value ?? '').replace(/(?<![\n]|[ ]{2})[\n]{1}([^\n])/g, ' $1') };
|
||||||
|
});
|
||||||
|
|
||||||
|
return nodes;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
console.warn('[StaticCMS] Unrecognized mdast node, proceeding as text', node);
|
console.warn('[StaticCMS] Unrecognized mdast node, proceeding as text', node);
|
||||||
return { text: node.value || '' };
|
return { text: node.value ?? '' };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,14 +75,13 @@ const serializationTestData: SerializationTests = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
'paragraph with line break': {
|
'paragraph with line break': {
|
||||||
markdown: `A line of text
|
markdown: `A line of text with another in the same paragraph`,
|
||||||
With another in the same paragraph`,
|
|
||||||
slate: [
|
slate: [
|
||||||
{
|
{
|
||||||
type: ELEMENT_PARAGRAPH,
|
type: ELEMENT_PARAGRAPH,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
text: 'A line of text\nWith another in the same paragraph',
|
text: 'A line of text with another in the same paragraph',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -234,20 +233,6 @@ And a completely new paragraph`,
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
'multiline blockquote': {
|
|
||||||
markdown: '> I am a block quote\n> And another line',
|
|
||||||
slate: [
|
|
||||||
{
|
|
||||||
type: ELEMENT_BLOCKQUOTE,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
text: 'I am a block quote\nAnd another line',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
'nested blockquote': {
|
'nested blockquote': {
|
||||||
markdown: '> I am a block quote\n> > And another line',
|
markdown: '> I am a block quote\n> > And another line',
|
||||||
slate: [
|
slate: [
|
||||||
@ -269,6 +254,116 @@ And a completely new paragraph`,
|
|||||||
},
|
},
|
||||||
] as MdValue,
|
] as MdValue,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'multiline blockquote (double space and carrot each line)': {
|
||||||
|
markdown: '> One line \n> Another line',
|
||||||
|
slate: [
|
||||||
|
{
|
||||||
|
type: ELEMENT_BLOCKQUOTE,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: 'One line\nAnother line',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
] as MdValue,
|
||||||
|
},
|
||||||
|
|
||||||
|
'multiline blockquote (empty line carrot)': {
|
||||||
|
markdown: '> One line\n>\n> Another line',
|
||||||
|
slate: [
|
||||||
|
{
|
||||||
|
type: ELEMENT_BLOCKQUOTE,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: 'One line\n\nAnother line',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
] as MdValue,
|
||||||
|
},
|
||||||
|
|
||||||
|
'sequential blockquote': {
|
||||||
|
markdown: `> I am a block quote
|
||||||
|
|
||||||
|
> And another block quote`,
|
||||||
|
slate: [
|
||||||
|
{
|
||||||
|
type: ELEMENT_BLOCKQUOTE,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: 'I am a block quote',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: ELEMENT_BLOCKQUOTE,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: 'And another block quote',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
] as MdValue,
|
||||||
|
},
|
||||||
|
|
||||||
|
'blockquote with link': {
|
||||||
|
// First line has double space
|
||||||
|
markdown: `> I am a [block quote](https://example.com/). Another line
|
||||||
|
>
|
||||||
|
> Final Line`,
|
||||||
|
slate: [
|
||||||
|
{
|
||||||
|
type: ELEMENT_BLOCKQUOTE,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: 'I am a ',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: ELEMENT_LINK,
|
||||||
|
url: 'https://example.com/',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: 'block quote',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '. Another line\n\nFinal Line',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
'blockquote with link (no punctuation)': {
|
||||||
|
// First line has double space
|
||||||
|
markdown: `> I am a [block quote](https://example.com/) and another line
|
||||||
|
>
|
||||||
|
> Final Line`,
|
||||||
|
slate: [
|
||||||
|
{
|
||||||
|
type: ELEMENT_BLOCKQUOTE,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: 'I am a ',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: ELEMENT_LINK,
|
||||||
|
url: 'https://example.com/',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: 'block quote',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: ' and another line\n\nFinal Line',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1543,8 +1638,7 @@ label: 'Blog post content',
|
|||||||
widget: 'markdown',
|
widget: 'markdown',
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
> See the table below for default options
|
> See the table below for default options \n> More API information can be found in the document
|
||||||
> More API information can be found in the document
|
|
||||||
|
|
||||||
|Name|Type|Default|Description|
|
|Name|Type|Default|Description|
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
@ -2683,8 +2777,86 @@ Text ahead [youtube|p6h-rYSVX90] and behind and another {{< twitter 917359331535
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const deserializationOnlyTestData: SerializationTests = {
|
export const deserializationOnlyTestData: SerializationTests = {
|
||||||
|
blcokquote: {
|
||||||
|
both: {
|
||||||
|
'blockquote with link': {
|
||||||
|
// First line has double space
|
||||||
|
markdown: `> I am a [block quote](https://example.com/).
|
||||||
|
> Another line
|
||||||
|
>
|
||||||
|
> Final Line`,
|
||||||
|
slate: [
|
||||||
|
{
|
||||||
|
type: ELEMENT_BLOCKQUOTE,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: 'I am a ',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: ELEMENT_LINK,
|
||||||
|
url: 'https://example.com/',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: 'block quote',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '. Another line\n\nFinal Line',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
'multiline blockquote (carrot each line)': {
|
||||||
|
markdown: `> One line
|
||||||
|
> Another line`,
|
||||||
|
slate: [
|
||||||
|
{
|
||||||
|
type: ELEMENT_BLOCKQUOTE,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: 'One line Another line',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
] as MdValue,
|
||||||
|
},
|
||||||
|
|
||||||
|
'multiline blockquote (double space)': {
|
||||||
|
markdown: '> One line \nAnother line',
|
||||||
|
slate: [
|
||||||
|
{
|
||||||
|
type: ELEMENT_BLOCKQUOTE,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: 'One line\nAnother line',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
] as MdValue,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
paragraph: {
|
paragraph: {
|
||||||
markdown: {
|
markdown: {
|
||||||
|
'paragraph with line break': {
|
||||||
|
markdown: `A line of text
|
||||||
|
With another in the same paragraph`,
|
||||||
|
slate: [
|
||||||
|
{
|
||||||
|
type: ELEMENT_PARAGRAPH,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: 'A line of text With another in the same paragraph',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
'paragraph with link': {
|
'paragraph with link': {
|
||||||
markdown:
|
markdown:
|
||||||
'A line of text with a link https://www.youtube.com/watch?v=p6h-rYSVX90 and some more text',
|
'A line of text with a link https://www.youtube.com/watch?v=p6h-rYSVX90 and some more text',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user