diff options
author | Eugene Sokolov <eug-vs@keemail.me> | 2020-04-09 16:42:12 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-09 16:42:12 +0300 |
commit | ad42e742c04c8302c2bcaf67c07ef215bba04f3b (patch) | |
tree | da29af275ec03232d81938e77c36d894c7093c2f | |
parent | b808381b02097a25eb51b14246f7a239a785b347 (diff) | |
parent | d1bcd3348c67cfbcd83178c9710cc54de9f776e8 (diff) | |
download | react-benzin-ad42e742c04c8302c2bcaf67c07ef215bba04f3b.tar.gz |
Merge pull request #9 from eug-vs/md-improve
Markdown extensive features
-rw-r--r-- | src/lib/Markdown/Content.tsx | 22 | ||||
-rw-r--r-- | src/lib/Markdown/Markdown.tsx | 12 | ||||
-rw-r--r-- | src/lib/Markdown/Section.tsx | 8 | ||||
-rw-r--r-- | src/lib/Markdown/SyntacticSpan.tsx | 7 |
4 files changed, 36 insertions, 13 deletions
diff --git a/src/lib/Markdown/Content.tsx b/src/lib/Markdown/Content.tsx index aaea100..5816214 100644 --- a/src/lib/Markdown/Content.tsx +++ b/src/lib/Markdown/Content.tsx @@ -6,11 +6,10 @@ import { ParserPropTypes } from './types'; const denotesCodeBlock = (line: string): boolean => { - return line.match(/^```.*$/) !== null; -} + return line.match(/^\s*```.*$/) !== null; } const denotesDottedList = (line: string): boolean => { - return line.match(/^ ?- .*$/) !== null; + return line.match(/^ ?[-*] .*$/) !== null; } const denotesOpenHtml= (line: string): string => { @@ -29,6 +28,10 @@ const denotesSelfClosingHtml = (line: string): string[] | null => { return line.match(regex); } +const declaresNoLineBreak = (line: string): boolean => { + return line.match(/\\\|$/) !== null; +} + const Content: React.FC<ParserPropTypes> = ({ rawLines }) => { if (!rawLines.length) return null; @@ -46,14 +49,13 @@ const Content: React.FC<ParserPropTypes> = ({ rawLines }) => { buffer = <ul>{dottedListLines.map(li => <li><Text line={li.slice(2)} /></li>)}</ul>; } else if ((buffer = denotesOpenHtml(line))) { const tag = buffer; - const closeIndex = rawLines.findIndex(line => denotesClosingHtml(line, tag)); - const htmlLines = rawLines.splice(0, closeIndex + 1).slice(0, closeIndex); + const closeIndex = denotesClosingHtml(line, tag) ? -1 : rawLines.findIndex(line => denotesClosingHtml(line, tag)); + const htmlLines = rawLines.splice(0, closeIndex + 1); htmlLines.unshift(line); buffer = <div dangerouslySetInnerHTML={{ __html: htmlLines.join('\n') }}></div>; } else if ((buffer = denotesSelfClosingHtml(line)) !== null) { const match = buffer[0]; const [before, after] = line.split(match); - console.log({ line, match, before, after}); buffer = ( <> <Text line={before} /> @@ -61,6 +63,14 @@ const Content: React.FC<ParserPropTypes> = ({ rawLines }) => { <Text line={after} /> </> ); + } else if (declaresNoLineBreak(line)) { + const closeIndex = rawLines.findIndex(line => !declaresNoLineBreak(line)); + const lineBreakLines = rawLines.splice(0, closeIndex).map(line => line.slice(0, -2)); + lineBreakLines.unshift(line.slice(0, -2)); + lineBreakLines.push(rawLines.splice(0, 1)[0]); + buffer = <p>{lineBreakLines.map(lineBreakLine => <Text line={lineBreakLine} />)}</p>; + } else if (denotesClosingHtml(line, '')) { + buffer = null; } else { buffer = <p><Text line={line} /></p> } diff --git a/src/lib/Markdown/Markdown.tsx b/src/lib/Markdown/Markdown.tsx index 09ad54a..82e889c 100644 --- a/src/lib/Markdown/Markdown.tsx +++ b/src/lib/Markdown/Markdown.tsx @@ -8,15 +8,23 @@ interface PropTypes { url?: string; } +const resolveUrls = (line: string, baseUrl: string): string => { + return line.replace(/src="(?!http)(.*)"[\s>]/, (match, url, offset, string) => `src="${baseUrl}/${url}?sanitize=true"`) + .replace(/\[(.*\]?.*)\]\((?!http)(.+?)\)/, (match, text, url, offset, string) => `[${text}](${baseUrl}/${url})`); +} + const Markdown: React.FC<PropTypes> = ({ data, url }) => { const [markdown, setMarkdown] = useState<string>(data || ''); + if (url) axios.get(url).then(response => setMarkdown(response.data)); + useEffect(() => { if (!url) setMarkdown(data || ''); }, [data, url]); - if (url) axios.get(url).then(response => setMarkdown(response.data)); - return <Section rawLines={markdown.split('\n')} /> + const baseUrl = url?.slice(0, url.lastIndexOf('/')) || ''; + const lines = markdown.split(/\r?\n/).map(line => resolveUrls(line, baseUrl)); + return <Section rawLines={lines} /> }; diff --git a/src/lib/Markdown/Section.tsx b/src/lib/Markdown/Section.tsx index 5ce8954..1fcc46f 100644 --- a/src/lib/Markdown/Section.tsx +++ b/src/lib/Markdown/Section.tsx @@ -1,5 +1,6 @@ import React from 'react'; import ContentSection from '../ContentSection/ContentSection'; +import { Typography } from '@material-ui/core'; import Content from './Content'; import { ParserPropTypes } from './types'; @@ -30,7 +31,12 @@ const Section: React.FC<PropTypes> = ({ rawLines, level = 0 }) => { const deeperLevelIndex = rawLines.findIndex(line => line.match(`^#{${level + 1},} .*$`)); const rawContent = rawLines.splice(0, (deeperLevelIndex < 0) ? rawLines.length : deeperLevelIndex); - if (!level) return <ChildrenSections rawLines={rawLines} level={getHeaderLevel(rawLines[0])}/>; + if (!level) return ( + <> + <Typography> <Content rawLines={rawContent} /> </Typography> + <ChildrenSections rawLines={rawLines} level={getHeaderLevel(rawLines[0])}/> + </> + ) const sectionName = rawContent.splice(0, 1)[0].slice(level).trim(); const deeperLevel = getHeaderLevel(rawLines[0]); diff --git a/src/lib/Markdown/SyntacticSpan.tsx b/src/lib/Markdown/SyntacticSpan.tsx index 299bf87..f3c2125 100644 --- a/src/lib/Markdown/SyntacticSpan.tsx +++ b/src/lib/Markdown/SyntacticSpan.tsx @@ -24,8 +24,8 @@ const enclosureRegex = (e: string): RegexPair => ({ const regex: Record<string, RegexPair> = { conceal: { - global: /(!?\[.+?\]\(.+?\))/g, - local: /!?\[(.+?)\]\((.+?)\)/ + global: /(!?\[.+?\]\(.+?\))(?!])/g, + local: /!?\[(.*\]?.*)\]\((.+?)\)/ }, rawLink: { global: /((?:(?:[A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www\.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)(?:(?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[.!/\\\w]*))?)/, @@ -42,7 +42,6 @@ const splitter = new RegExp(Object.values(regex).map(pair => pair.global.source) const emojiList: Emoji[] = []; Object.keys(emojiLib).forEach(name => emojiList.push({ name, char: emojiLib[name].char })); -console.log({emojiList}) const useStyles = makeStyles(theme => ({ code: { @@ -64,7 +63,7 @@ const SyntacticSpan: React.FC<PropTypes> = ({ span }) => { const matchConceal = regex.conceal.local.exec(span); if (matchConceal) { if (span[0] === '!') return <img src={matchConceal[2]} alt={matchConceal[1]} className={classes.image} />; - return <Link href={matchConceal[2]}>{matchConceal[1]}</Link>; + return <Link href={matchConceal[2]}><SyntacticSpan span={matchConceal[1]} /></Link>; } const matchEmoji = span.match(regex.emoji.local); |