Basic markdown renderer (#197)

* Add basic markdown it rendering
* Add markdown preview
* Add embedings for vimeo, youtube, gist
* Add support for legacy shortcodes and link detection
* Set "both" as editor default
* Add markdown-it-task-lists
* Add twemoji
* Changed SlideShare short-code behaviour from embedding to generating a link
* Extract markdown it parser debugger into separate component
* Deactivate markdown it linkify for now
* Add link safety attributes
* Add one-click-embedding component and use it
* Added embedding changes and deprecations to CHANGELOG.md

Signed-off-by: Tilman Vatteroth <tilman.vatteroth@tu-dortmund.de>
Co-authored-by: Philip Molares <philip@mauricedoepke.de>
Co-authored-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
mrdrogdrog 2020-06-20 00:44:18 +02:00 committed by GitHub
parent 8ba2be7c70
commit 7189a63618
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 637 additions and 16 deletions

View file

@ -1,9 +1,81 @@
import React from 'react'
import MarkdownIt from 'markdown-it'
import emoji from 'markdown-it-emoji'
import markdownItRegex from 'markdown-it-regex'
import taskList from 'markdown-it-task-lists'
import React, { ReactElement, useMemo } from 'react'
import ReactHtmlParser, { convertNodeToElement, Transform } from 'react-html-parser'
import { MarkdownItParserDebugger } from './markdown-it-plugins/parser-debugger'
import './markdown-preview.scss'
import { replaceGistLink } from './regex-plugins/replace-gist-link'
import { replaceLegacyGistShortCode } from './regex-plugins/replace-legacy-gist-short-code'
import { replaceLegacySlideshareShortCode } from './regex-plugins/replace-legacy-slideshare-short-code'
import { replaceLegacySpeakerdeckShortCode } from './regex-plugins/replace-legacy-speakerdeck-short-code'
import { replaceLegacyVimeoShortCode } from './regex-plugins/replace-legacy-vimeo-short-code'
import { replaceLegacyYoutubeShortCode } from './regex-plugins/replace-legacy-youtube-short-code'
import { replaceVimeoLink } from './regex-plugins/replace-vimeo-link'
import { replaceYouTubeLink } from './regex-plugins/replace-youtube-link'
import { getGistReplacement } from './replace-components/gist/gist-frame'
import { getVimeoReplacement } from './replace-components/vimeo/vimeo-frame'
import { getYouTubeReplacement } from './replace-components/youtube/youtube-frame'
export interface MarkdownPreviewProps {
content: string
}
const MarkdownPreview: React.FC<MarkdownPreviewProps> = ({ content }) => {
const markdownIt = useMemo(() => {
const md = new MarkdownIt('default', {
html: true,
breaks: true,
langPrefix: '',
linkify: false,
typographer: true
})
md.use(taskList)
md.use(emoji)
md.use(markdownItRegex, replaceLegacyYoutubeShortCode)
md.use(markdownItRegex, replaceLegacyVimeoShortCode)
md.use(markdownItRegex, replaceLegacyGistShortCode)
md.use(markdownItRegex, replaceLegacySlideshareShortCode)
md.use(markdownItRegex, replaceLegacySpeakerdeckShortCode)
md.use(markdownItRegex, replaceYouTubeLink)
md.use(markdownItRegex, replaceVimeoLink)
md.use(markdownItRegex, replaceGistLink)
md.use(MarkdownItParserDebugger)
return md
}, [])
const result: ReactElement[] = useMemo(() => {
const youtubeIdCounterMap = new Map<string, number>()
const vimeoIdCounterMap = new Map<string, number>()
const gistIdCounterMap = new Map<string, number>()
const html: string = markdownIt.render(content)
const transform: Transform = (node, index) => {
const resultYT = getYouTubeReplacement(node, youtubeIdCounterMap)
if (resultYT) {
return resultYT
}
const resultVimeo = getVimeoReplacement(node, vimeoIdCounterMap)
if (resultVimeo) {
return resultVimeo
}
const resultGist = getGistReplacement(node, gistIdCounterMap)
if (resultGist) {
return resultGist
}
return convertNodeToElement(node, index, transform)
}
const ret: ReactElement[] = ReactHtmlParser(html, { transform: transform })
return ret
}, [content, markdownIt])
const MarkdownPreview: React.FC = () => {
return (
<div className='h-100 px-2 py-1 bg-white'>
Hello, MarkdownPreview!
<div className={'bg-light container-fluid flex-fill h-100 overflow-y-scroll pb-5'}>
<div className={'markdown-body container-fluid'}>{result}</div>
</div>
)
}