import { Space, Text, useMantineTheme } from '@mantine/core'
import parse from 'html-react-parser'
import React from 'react'
interface SlackMarkdownToHtmlProps {
markdown: string
keyword?: string
}
const listTypesRegex = {
ordered: /^\s*([a-z]|\d+)\.\s+(.*)/,
unordered: /^\s*(•|◦|▪︎)\s+(.*)/,
}
function getIndentLevel(line: any) {
const leadingWhitespace = line.match(/^(\s*)/)[0]
return leadingWhitespace.length / 4
}
function parseList(inputString: string) {
const lines = inputString.split('\n')
let previousIndent = 0
let listTypeStack = []
let previousListType = ''
let parsedHTML = ''
for (let line of lines) {
const indent = getIndentLevel(line)
const orderedListMatch = line.match(listTypesRegex.ordered)
const unorderedListMatch = line.match(listTypesRegex.unordered)
let itemContent, listType
while (indent < previousIndent) {
parsedHTML += `</li></${listTypeStack.pop()}>`
previousIndent--
}
if (orderedListMatch) {
listType = 'ol'
itemContent = orderedListMatch[2]
} else if (unorderedListMatch) {
listType = 'ul'
itemContent = unorderedListMatch[2]
} else {
while (listTypeStack.length) {
parsedHTML += `</li></${listTypeStack.pop()}>`
previousIndent--
}
parsedHTML += parsedHTML ? `\n${line}` : `${line}`
continue
}
if (previousListType === listType && indent === previousIndent) {
parsedHTML += `<li>${itemContent}`
previousListType = listType
continue
}
else if (previousListType != listType && indent === previousIndent) {
while (listTypeStack.length) {
parsedHTML += `</li></${listTypeStack.pop()}>`
previousIndent--
}
}
parsedHTML += `<${listType}>`
listTypeStack.push(listType)
previousIndent = indent
parsedHTML += `<li>${itemContent}`
previousListType = listType
}
return parsedHTML
}
export const SlackMarkdownToHtml: React.FC<SlackMarkdownToHtmlProps> = ({ markdown, keyword = '' }) => {
const { colors } = useMantineTheme()
let html = markdown.replace(/\n?<@(.*?)>/g, '@[ユーザ名]')
const channelIdNameList = html.match(/<#.+?\|.*?>/g)
if (channelIdNameList !== null && channelIdNameList.length > 0) {
for (const channelIdName of channelIdNameList) {
const channelName = channelIdName.match(/<#.+\|(.*)>/)
if (channelName == null) continue
if (channelName[1] === '') {
html = html.replace(channelIdName, '#[チャンネル名]')
} else {
html = html.replace(channelIdName, `#${channelName[1]}`)
}
}
}
html = html.replace(/\n?:(.*?):/g, '<em-emoji id="$1" set="twitter" size="1em"></em-emoji>')
html = html.replace(/<(.+?)%7C(.+?)>/g, '<a href="$1" style="color:#3575ad; word-wrap: break-word;">$2</a>')
html = html.replace(
/(?<!<a href=")<?(http[s]?:\/\/[^<>\s]+)(?!">)>?/g,
'<a href="$1" style="color:#3575ad; word-wrap: break-word;">$1</a>',
)
html = html.replace(/\*(.+?)\*/g, '<b>$1</b>')
html = html.replace(/\_(.+?)\_/g, '<i>$1</i>')
html = html.replace(/\~(.+?)\~/g, '<s>$1</s>')
html = parseList(html)
html = html.replace(
/\n?> (.+)\n?/gm,
'<blockquote style="padding: 0 1em; border-left: 4px solid #d6dde3;color: #333333; overflow: scroll;">$1</blockquote>',
)
html = html.replace(
/\n?```(.*?)```\n?/gs,
'<pre style="background-color:#eee;border-radius: 3px; overflow: scroll; "><code style="display: inline-block;font-family: courier, monospace;padding: 0 3px; font-size:12px;">$1</code></pre>',
)
html = html.replace(
/\n?\`(.*?)\`\n?/g,
'<code style="background-color:#eee;border-radius: 3px;font-family: courier, monospace;padding: 0 3px; color: #E84D7E; font-size:12px; overflow: scroll;">$1</code>',
)
html = html.replace(/\n/g, '<br />')
return (
<Text fz='sm'>
{parse(html)}
<Space h={10} />
</Text>
)
}