增加meditor

master
yutent 2023-09-19 18:50:51 +08:00
parent 902aadd424
commit 98d66014ad
4 changed files with 1160 additions and 0 deletions

141
src/meditor/addon.js Normal file
View File

@ -0,0 +1,141 @@
/**
* 基础拓展
* @author yutent<yutent.io@gmail.com>
* @date 2020/10/14 17:52:44
*/
import { offset } from 'wkit'
var placeholder = '在此输入文本'
function trim(str, sign) {
return str.replace(new RegExp('^' + sign + '|' + sign + '$', 'g'), '')
}
function docScroll(k = 'X') {
return window[`page${k.toUpperCase()}Offset`]
}
// 通用的弹层触发
function showDialog(dialog, elem) {
var { left, top } = offset(elem)
left -= docScroll('X')
top += 29 - docScroll('Y')
left += 'px'
top += 'px'
dialog.moveTo({ top, left })
dialog.show()
return Promise.resolve(dialog)
}
export default {
header(elem) {
showDialog(this.__HEADER_ADDON__, elem)
},
h(level) {
var wrap = this.selection(true) || placeholder
wrap = wrap.replace(/^(#+ )?/, '#'.repeat(level) + ' ')
this.insert(wrap, true)
},
quote(elem) {
var wrap = this.selection(true) || placeholder
wrap = wrap.replace(/^(>+ )?/, '> ')
this.insert(wrap, true)
},
bold(elem) {
var wrap = this.selection() || placeholder
var unwrap = trim(wrap, '\\*\\*')
wrap = wrap === unwrap ? `**${wrap}**` : unwrap
this.insert(wrap, true)
},
italic(elem) {
var wrap = this.selection() || placeholder
var unwrap = trim(wrap, '_')
wrap = wrap === unwrap ? `_${wrap}_` : unwrap
this.insert(wrap, true)
},
through(elem) {
var wrap = this.selection() || placeholder
var unwrap = trim(wrap, '~~')
wrap = wrap === unwrap ? `~~${wrap}~~` : unwrap
this.insert(wrap, true)
},
list(elem) {
var wrap = this.selection(true) || placeholder
wrap = wrap.replace(/^([+\-*] )?/, '+ ')
this.insert(wrap, true)
},
order(elem) {
var wrap = this.selection(true) || placeholder
wrap = wrap.replace(/^(\d+\. )?/, '1. ')
this.insert(wrap, true)
},
line(elem) {
this.insert('\n\n---\n\n', false)
},
code(elem) {
var wrap = this.selection() || placeholder
var unwrap = trim(wrap, '`')
wrap = wrap === unwrap ? `\`${wrap}\`` : unwrap
this.insert(wrap, true)
},
codeblock(elem) {
this.insert('\n```language\n\n```\n')
},
table(elem) {
showDialog(this.__TABLE_ADDON__, elem)
},
link(elem) {
showDialog(this.__LINK_ADDON__, elem).then(dialog => {
var wrap = this.selection() || placeholder
dialog.__txt__.value = wrap
})
},
image(elem) {
var $file = this.__ATTACH_ADDON__.querySelector('input')
this._attach = 'image'
$file.setAttribute('accept', 'image/*')
showDialog(this.__ATTACH_ADDON__, elem)
},
attach(elem) {
var $file = this.__ATTACH_ADDON__.querySelector('input')
this._attach = 'file'
$file.removeAttribute('accept')
showDialog(this.__ATTACH_ADDON__, elem)
},
fullscreen(elem) {
//
this.props.fullscreen = !this.props.fullscreen
if (this.props.fullscreen) {
this.setAttribute('fullscreen', '')
} else {
this.removeAttribute('fullscreen')
}
elem.classList.toggle('active', this.props.fullscreen)
},
preview(elem) {
this.state.preview = !this.state.preview
this.__VIEW__.classList.toggle('active', this.state.preview)
elem.classList.toggle('active', this.state.preview)
}
}

222
src/meditor/helper.js Normal file
View File

@ -0,0 +1,222 @@
/**
* 一些公共的东西
* @author yutent<yutent.io@gmail.com>
* @date 2020/10/12 18:23:23
*/
import ICONS from './svg'
const ELEMS = {
a: function (str, attr, inner) {
let href = attr.match(attrExp('href'))
let title = attr.match(attrExp('title'))
let tar = attr.match(attrExp('target'))
let attrs = ''
href = (href && href[1]) || null
title = (title && title[1]) || null
tar = (tar && tar[1]) || '_self'
if (!href) {
return inner || href
}
href = href.replace('viod(0)', '')
attrs = `target=${tar}`
attrs += title ? `;title=${title}` : ''
return `[${inner || href}](${href} "${attrs}")`
},
em: function (str, attr, inner) {
return (inner && '_' + inner + '_') || ''
},
strong: function (str, attr, inner) {
return (inner && '**' + inner + '**') || ''
},
pre: function (str, attr, inner) {
inner = inner.replace(/<[/]?code>/g, '')
return '\n\n```\n' + inner + '\n```\n'
},
code: function (str, attr, inner) {
return (inner && '`' + inner + '`') || ''
},
blockquote: function (str, attr, inner) {
return '> ' + inner.trim()
},
img: function (str, attr, inner) {
var src = attr.match(attrExp('src')),
alt = attr.match(attrExp('alt'))
src = (src && src[1]) || ''
alt = (alt && alt[1]) || ''
return '![' + alt + '](' + src + ')'
},
p: function (str, attr, inner) {
return inner ? '\n' + inner : ''
},
br: '\n',
'h([1-6])': function (str, level, attr, inner) {
let h = '#'.repeat(level)
return '\n' + h + ' ' + inner + '\n'
},
hr: '\n\n---\n\n'
}
const DEFAULT_TOOLS = [
'header',
'quote',
'bold',
'italic',
'through',
'list',
'order',
'line',
'code',
'codeblock',
'table',
'link',
'image',
'attach',
'fullscreen',
'preview'
]
export const TOOL_TITLE = {
header: '插入标题',
h1: '一级标题',
h2: '二级标题',
h3: '三级标题',
h4: '四级标题',
h5: '五级标题',
h6: '六级标题',
quote: '引用文本',
bold: '粗体',
italic: '斜体',
through: '横线',
list: '无序列表',
order: '有序列表',
line: '分割线',
code: '行内代码',
codeblock: '插入代码块',
table: '插入表格',
link: '插入连接',
image: '上传图片',
attach: '上传附件',
fullscreen: '全屏编辑',
preview: '预览'
}
const LI_EXP = /<(ul|ol)>(?:(?!<ul|<ol)[\s\S])*?<\/\1>/gi
// html标签的属性正则
function attrExp(field, flag = 'i') {
return new RegExp(field + '\\s?=\\s?["\']?([^"\']*)["\']?', flag)
}
// 生成html标签的正则
function tagExp(tag, open) {
var exp = ''
if (['br', 'hr', 'img'].indexOf(tag) > -1) {
exp = '<' + tag + '([^>]*?)\\/?>'
} else {
exp = '<' + tag + '([^>]*?)>([\\s\\S]*?)<\\/' + tag + '>'
}
return new RegExp(exp, 'gi')
}
/**
* 渲染工具栏图标
*/
export function renderToolbar(list, tag = 'span', dict = {}, showText = false) {
return (list || DEFAULT_TOOLS)
.map(it => {
var title = showText ? '' : `title="${dict[it] || ''}"`
var text = showText ? dict[it] || '' : ''
return `<${tag} data-act="${it}" ${title}><svg class="icon" viewBox="0 0 1024 1024"><path d="${ICONS[it]}"/></svg>${text}</${tag}>`
})
.join('')
}
/**
* html转成md
*/
export function html2md(str) {
try {
str = decodeURIComponent(str)
} catch (err) {}
str = str
.replace(/\t/g, ' ')
.replace(/<meta [^>]*>/, '')
.replace(attrExp('class', 'g'), '')
.replace(attrExp('style', 'g'), '')
.replace(/<(?!a |img )(\w+) [^>]*>/g, '<$1>')
.replace(/<svg[^>]*>.*?<\/svg>/g, '{invalid image}')
// log(str)
for (let i in ELEMS) {
let cb = ELEMS[i]
let exp = tagExp(i)
if (i === 'blockquote') {
while (str.match(exp)) {
str = str.replace(exp, cb)
}
} else {
str = str.replace(exp, cb)
}
// 对另外3种同类标签做一次处理
if (i === 'p') {
exp = tagExp('div')
str = str.replace(exp, cb)
}
if (i === 'em') {
exp = tagExp('i')
str = str.replace(exp, cb)
}
if (i === 'strong') {
exp = tagExp('b')
str = str.replace(exp, cb)
}
}
while (str.match(LI_EXP)) {
str = str.replace(LI_EXP, function (match) {
match = match.replace(
/<(ul|ol)>([\s\S]*?)<\/\1>/gi,
function (m, t, inner) {
let li = inner.split('</li>')
li.pop()
for (let i = 0, len = li.length; i < len; i++) {
let pre = t === 'ol' ? i + 1 + '. ' : '* '
li[i] =
pre +
li[i]
.replace(/\s*<li>([\s\S]*)/i, function (m, n) {
n = n.trim().replace(/\n/g, '\n ')
return n
})
.replace(/<[\/]?[\w]*[^>]*>/g, '')
}
return li.join('\n')
}
)
return '\n' + match.trim()
})
}
str = str
.replace(/<[\/]?[\w]*[^>]*>/g, '')
.replace(/```([\w\W]*)```/g, function (str, inner) {
inner = inner
.replace(/&amp;/g, '&')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
return '```' + inner + '```'
})
return str
}

755
src/meditor/index.js Normal file
View File

@ -0,0 +1,755 @@
/**
* {}
* @author yutent<yutent.io@gmail.com>
* @date 2023/09/14 16:49:15
*/
import {
css,
raw,
html,
Component,
bind,
unbind,
nextTick,
styleMap,
classMap,
outsideClick,
clearOutsideClick
} from 'wkit'
import ICONS from './svg.js'
import '../form/input.js'
import '../form/button.js'
const ACTTION = {
bold: 'bold',
italic: 'italic',
under: 'underline',
delete: 'strikeThrough',
left: 'justifyLeft',
center: 'justifyCenter',
right: 'justifyRight',
image: 'insertImage',
font: 'fontSize',
color: 'foreColor',
link: 'createLink',
ordered: 'insertOrderedList',
unordered: 'insertUnorderedList'
}
const DEFAULT_TOOLS = [
'font',
'color',
'bold',
'italic',
'under',
'delete',
'ordered',
'unordered',
'table',
'left',
'center',
'right',
'link',
'image',
'fullscreen'
]
const COLORS = [
'#f3f5fb',
'#dae1e9',
'#62778d',
'#58d68d',
'#3fc2a7',
'#52a3de',
'#ac61ce',
'#ffb618',
'#e67e22',
'#ff5061',
'#ff0000',
'#000000'
]
// 获取一维数组转二维的行
function getY(i) {
return (i / 9) >> 0
}
//获取一维数组转二维的列
function getX(i) {
return i % 9
}
function getIndex(x, y) {
return x + y * 9
}
class MEditor extends Component {
static props = {
toolbar: {
type: String,
default: '',
attribute: false,
observer(v) {
if (v === null) {
this.#toolbar = [...DEFAULT_TOOLS]
} else if (v) {
this.#toolbar = v.split(',').map(it => it.trim())
}
}
},
value: 'str!',
readonly: {
type: Boolean,
observer(v) {
this.#updateStat()
}
},
disabled: {
type: Boolean,
observer(v) {
this.#updateStat()
}
}
}
static styles = [
css`
:host {
display: flex;
min-width: 200px;
max-height: 720px;
border-radius: 3px;
transition: box-shadow 0.15s linear;
background: var(--wc-meditor-background, #fff);
}
.noselect {
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
`,
css`
.meditor {
position: relative;
flex: 1;
display: flex;
flex-direction: column;
width: 100%;
border: 1px solid var(--wc-editor-border-color, var(--color-grey-2));
border-radius: inherit;
font-size: 14px;
background: #fff;
}
.toolbar {
display: none;
width: 100%;
height: 34px;
padding: 5px;
line-height: 24px;
border-bottom: 1px solid var(--color-grey-1);
span {
position: relative;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
width: 24px;
height: 24px;
margin: 0 3px;
border-radius: 3px;
color: var(--color-grey-3);
.icon {
overflow: hidden;
width: 70%;
height: 70%;
fill: currentColor;
color: #62778d;
}
&:hover,
&.active {
background: var(--color-plain-1);
}
&.active {
color: var(--color-teal-1);
}
}
&.active {
display: flex;
}
}
`,
css`
.editor-outbox {
flex: 1;
display: flex;
width: 100%;
min-height: 300px;
border-radius: 3px;
.editor,
.preview {
flex: 1;
flex-shrink: 0;
}
.editor {
height: 100%;
padding: 5px 8px;
line-height: 1.5;
border: 0;
font-size: 14px;
font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;
color: var(--color-dark-1);
background: none;
outline: none;
resize: none;
cursor: inherit;
&::placeholder {
color: var(--color-grey-1);
}
}
.preview {
overflow: hidden;
overflow-y: auto;
display: none;
padding: 6px 12px;
border-left: 1px solid var(--color-plain-2);
&.active {
display: block;
}
}
}
`,
css`
:host([readonly]) {
.editor {
cursor: default;
opacity: 0.8;
}
}
:host([disabled]) {
.editor {
cursor: not-allowed;
opacity: 0.6;
}
}
:host([readonly]),
:host([disabled]) {
.toolbar {
span:hover {
background: none;
}
}
}
:host(:focus-within) {
box-shadow: 0 0 0 2px var(--color-plain-a);
}
:host(.fullscreen) {
position: fixed;
top: 0;
left: 0;
z-index: 9;
width: 100vw;
height: 100vh;
max-height: 100vh;
border-radius: 0;
}
`,
css`
.addon-table {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 222px;
height: 222px;
padding: 2px;
background: #fff;
li {
display: flex;
justify-content: space-between;
height: 20px;
span {
width: 20px;
height: 20px;
background: var(--color-plain-1);
&.active {
background: rgba(77, 182, 172, 0.3);
}
}
}
}
.addon-header {
width: 108px;
height: 190px;
padding: 5px 0;
line-height: 30px;
user-select: none;
background: #fff;
li {
display: flex;
align-items: center;
width: 100%;
height: 30px;
padding: 0 12px;
transition: background 0.1s ease-in-out;
cursor: pointer;
.icon {
width: 14px;
height: 14px;
margin-right: 8px;
}
&:hover {
background: var(--color-plain-1);
}
}
}
.addon-link {
width: 320px;
padding: 8px 5px;
background: #fff;
font-size: 13px;
li {
display: flex;
align-items: center;
padding: 0 12px;
margin-top: 6px;
label {
width: 60px;
margin-right: 8px;
}
wc-input {
flex: 1;
}
wc-button {
width: 80px;
}
}
}
.addon-attach {
width: 320px;
padding: 8px 5px;
background: #fff;
font-size: 13px;
.tabs {
display: flex;
border-bottom: 1px solid var(--color-plain-2);
user-select: none;
span {
height: 28px;
padding: 0 8px;
line-height: 28px;
cursor: pointer;
&.active {
color: var(--color-teal-1);
}
}
}
.remote,
.locale {
display: none;
&.active {
display: block;
}
}
.locale {
height: 120px;
padding: 24px 32px;
.button {
position: relative;
width: 100%;
height: 100%;
padding: 12px 16px;
line-height: 46px;
border: 1px dashed var(--color-plain-3);
border-radius: 4px;
text-align: center;
cursor: pointer;
transition: background 0.1s ease-in-out;
&::after {
content: '点击选择文件,或拖拽文件到此处';
}
&:hover,
&.active {
background: rgba(255, 228, 196, 0.15);
}
}
input {
position: absolute;
left: 0;
top: 0;
z-index: 0;
width: 100%;
height: 100%;
opacity: 0;
}
}
li {
display: flex;
align-items: center;
padding: 0 12px;
margin-top: 6px;
label {
width: 60px;
margin-right: 8px;
}
wc-input {
flex: 1;
}
wc-button {
width: 80px;
}
}
}
`
]
#toolbar = []
#value = ''
#cache = { bar: 0, y: 0 }
#gridx = 0
#gridy = 0
#select = null
__init__() {
//
let { outer, inner, thumb } = this.$refs
let height = outer.offsetHeight
let scrollHeight = inner.scrollHeight + 10
let bar = 50 // 滚动条的高度
bar = (height * (height / scrollHeight)) >> 0
if (bar < 50) {
bar = 50
}
// 100%或主体高度比滚动条还短时不显示
if (bar >= height) {
bar = 0
}
this.#cache.bar = bar
thumb.style.height = bar + 'px'
}
#updateStat() {
if (this.$refs.editor) {
if (this.readOnly || this.disabled) {
this.$refs.editor.removeAttribute('contenteditable')
} else {
this.$refs.editor.setAttribute('contenteditable', '')
}
} else {
nextTick(_ => this.#updateStat())
}
}
#fetchScroll(moveY) {
let { bar } = this.#cache
let { outer, thumb, inner } = this.$refs
let height = outer.offsetHeight
let scrollHeight = inner.scrollHeight + 10
if (moveY < 0) {
moveY = 0
} else if (moveY > height - bar) {
moveY = height - bar
}
inner.scrollTop = (scrollHeight - height) * (moveY / (height - bar))
thumb.style.transform = `translateY(${moveY}px)`
return moveY
}
#hideLayers() {
this.$refs.font.classList.remove('fadein')
this.$refs.color.classList.remove('fadein')
this.$refs.link.classList.remove('fadein')
this.$refs.table.classList.remove('fadein')
}
// 处理图片
#handleImage(ev, file) {
if (ev && ev.type === 'change') {
file = ev.target.files[0]
ev.target.value = ''
}
this.$emit('upload', {
detail: {
file,
send: link => {
this.$refs.editor.focus()
this.restoreSelection()
this.exec(ACTTION.image, link)
this.saveSelection()
// 修正插入的图片,宽度不得超出容器
this.$refs.editor.querySelectorAll('img').forEach(_ => {
_.style.maxWidth = '100%'
})
}
}
})
}
#handlePaste(ev) {
let html = ev.clipboardData.getData('text/html')
let txt = ev.clipboardData.getData('text/plain')
let items = ev.clipboardData.items
// 先文件判断, 避免右键单击复制图片时, 当成html处理
if (items && items.length) {
let blob = null
for (let it of items) {
if (it.type.indexOf('image') > -1) {
blob = it.getAsFile()
}
}
if (blob) {
return this.#handleImage(null, blob)
}
}
if (html) {
html = html
.replace(/\t/g, ' ')
.replace(/<\/?(meta|link|script)[^>]*?>/g, '')
.replace(/<!--[\w\W]*?-->/g, '')
.replace(
/<a[^>]*? href\s?=\s?["']?([^"']*)["']?[^>]*?>/g,
'<a href="$1">'
)
.replace(
/<img[^>]*? src\s?=\s?["']?([^"']*)["']?[^>]*?>/g,
'<img src="$1">'
)
.replace(/<(?!a|img)([\w\-]+)[^>]*>/g, '<$1>')
.replace(/<xml[^>]*?>[\w\W]*?<\/xml>/g, '')
.replace(/<style>[\w\W]*?<\/style>/g, '')
return this.exec('insertHtml', html)
}
if (txt) {
return this.exec('insertText', txt)
}
}
#toolbarClick(ev) {
var target = ev.target
var act
this.restoreSelection()
if (ev.target === ev.currentTarget) {
return
}
if (this.readOnly || this.disabled) {
return
}
while (target.tagName !== 'SPAN') {
target = target.parentNode
}
act = target.dataset.act
this.#hideLayers()
switch (act) {
case 'font':
case 'color':
case 'link':
case 'table':
this.$refs[act].classList.add('fadein')
break
case 'image':
// 这里不作任何处理
break
case 'copy':
navigator.clipboard.writeText(this.value)
break
case 'fullscreen':
this.classList.toggle('fullscreen')
break
default:
this.$refs.editor.focus()
this.restoreSelection()
this.exec(ACTTION[act])
this.saveSelection()
break
}
}
#chnageFontSize(ev) {
if (ev.target === ev.currentTarget) {
return
}
this.$refs.font.classList.remove('fadein')
this.$refs.editor.focus()
this.restoreSelection()
this.exec(ACTTION.font, ev.target.dataset.size)
this.saveSelection()
}
#chnageColor(ev) {
if (ev.target === ev.currentTarget) {
return
}
this.$refs.color.classList.remove('fadein')
this.$refs.editor.focus()
this.restoreSelection()
this.exec(ACTTION.color, ev.target.dataset.value)
this.saveSelection()
}
#insertLink(ev) {
let value = this.$refs.linkinput.value.trim()
if (value) {
this.$refs.link.classList.remove('fadein')
this.$refs.editor.focus()
this.restoreSelection()
this.exec(ACTTION.link, value)
this.saveSelection()
this.$refs.linkinput.value = ''
}
}
#insertTable(ev) {
let th = `<th>&nbsp;</th>`.repeat(this.#gridx + 1)
let td = `<td>&nbsp;</td>`.repeat(this.#gridx + 1)
this.exec(
'insertHtml',
`<br>
<table>
<thead><tr>${th}</tr></thead>
<tbody>${`<tr>${td}</tr>`.repeat(this.#gridy + 1)}</tbody>
</table><br>`
)
this.$refs.table.classList.remove('fadein')
}
#tableSelect(ev) {
let grids = Array.from(this.$refs.table.children)
if (ev.type === 'mousemove') {
if (ev.target === ev.currentTarget) {
return
}
let idx = +ev.target.dataset.idx
let x = getX(idx)
let y = getY(idx)
// 避免每次遍历完所有的节点
let max = Math.max(getIndex(this.#gridx, this.#gridy), idx) + 1
if (x === this.#gridx && y === this.#gridy) {
return
}
this.#gridx = x
this.#gridy = y
for (let i = 0; i < max; i++) {
let _x = getX(i)
let _y = getY(i)
grids[i].classList.toggle('active', _x <= x && _y <= y)
}
} else {
grids.forEach(it => it.classList.remove('active'))
}
}
// 保存选中
saveSelection() {
var gs = this.root.getSelection()
if (gs.getRangeAt && gs.rangeCount) {
this.#select = gs.getRangeAt(0)
}
}
// 清除选中并重置选中
restoreSelection() {
var gs = this.root.getSelection()
if (this.#select) {
try {
gs.removeAllRanges()
} catch (err) {}
gs.addRange(this.#select)
}
}
// 执行命令
exec(cmd, val = '') {
document.execCommand(cmd, false, val)
}
mounted() {}
unmounted() {}
render() {
// toolbar = [
// ...(this.#toolbar.length ? this.#toolbar : DEFAULT_TOOLS),
// 'copy'
// ]
return html`
<div class="meditor">
<section class="toolbar"></section>
<div class="editor-outbox">
<textarea
class="editor"
spellcheck="false"
:value=${this.value}
></textarea>
<wc-markd class="preview"></wc-markd>
</div>
</div>
`
}
}
MEditor.reg('meditor')

42
src/meditor/svg.js Normal file
View File

@ -0,0 +1,42 @@
/**
* icon字典
* @author yutent<yutent.io@gmail.com>
* @date 2019/07/08 17:39:11
*/
export default {
header:
'M128 457.15h329.14v109.71H347.43v329.13H237.71V566.86H128V457.15z m767.98-219.43H680.21v658.27h-117V237.72H347.44V128.01H896l-0.02 109.71z',
h1: 'M567.23 896h-62.15V523.45H222.22V896h-62.93V128h62.93v326.11h282.86V128h62.15v768z m297.48-1.48h-230.2v-59.5h86.99V535.26h-69.38v-47.71l6.3-1.26c32.06-6.4 57.01-15.6 78.51-28.96l1.9-1.18h47.43v378.86h78.45v59.51z',
h2: 'M864.54 896H639.87v-41.55l2.05-2.24C745.85 738.4 792.2 657.17 792.2 588.8c0-67.27-37.32-74.53-53.37-74.53-26.94 0-48.8 24.36-62.39 44.79l-5.89 8.85-34.57-42.49 3.6-4.88C663.09 488.62 693.86 456 743.82 456c63.42 0 104.4 51.46 104.4 131.1 0 40.81-12.01 83.37-36.73 130.12-19.26 36.44-45.83 75.01-83 120.37 12.26-1.15 24.97-2.13 36.18-2.13h99.87V896z m-297.34-0.37h-62.12V523.26H222.36v372.37h-62.91V128h62.91v325.95h282.72V128h62.12v767.63z',
h3: 'M750.38 895.4c-25.28 0-48.37-6.06-68.62-18.01-16.41-9.68-30.85-22.96-44.14-40.59l-3.25-4.31 29.65-47.34 6.88 8.82c23.21 29.74 47.46 43.58 76.3 43.58 36.26 0 59.69-26.54 59.69-67.61 0-50.29-30.34-73.71-95.49-73.71h-7.84v-54.51h7.84c30.05 0 52.33-6.8 66.22-20.2 11.9-11.49 17.94-28.18 17.94-49.63 0-34.99-18.06-56.51-48.32-57.62-27.59 1.28-49.4 21.14-62.85 37.61l-6.6 8.08-31.61-45.8 4.05-4.59c30.51-34.64 62.83-51.48 98.79-51.48 30.23 0 56.07 9.96 74.74 28.81 19.38 19.58 29.63 47.62 29.63 81.1 0 43.53-17.82 77.85-50.55 98.17 15.76 7.15 29.34 18.23 39.81 32.57 14.44 19.79 22.07 44.99 22.07 72.85 0 36.77-11.54 68.12-33.36 90.68-20.67 21.37-49.43 33.13-80.98 33.13z m-183.15 0.6h-62.15V523.45H222.22V896h-62.94V128h62.94v326.11h282.86V128h62.15v768z',
h4: 'M823.31 894.76h-52.82V778.48H634.31v-44.16l133.11-277.17h55.89v263.64h41.41v57.7h-41.41v116.27zM695.34 720.79h75.15V599.11c0-9.81 0.37-22.31 0.86-35.25-3.17 7.66-6.55 15.63-10.16 23.98l-0.17 0.37-65.68 132.58zM567.23 896h-62.15V523.45H222.22V896h-62.94V128h62.94v326.11h282.86V128h62.15v768z',
h5: 'M567.23 896h-62.15V523.45H222.22V896h-62.94V128h62.94v326.11h282.86V128h62.15v768z m181.59-0.16c-58.28 0-91.28-33.08-111.04-57.97l-3.36-4.24 28.84-48.43 7.06 8.89c30.07 37.86 54.74 42.97 74.91 42.97 16.75 0 32.15-8.23 43.37-23.16 12.45-16.58 19.03-39.78 19.03-67.1 0-27.27-5.93-49.76-17.16-65.04-10.5-14.28-25.51-21.83-43.44-21.83-19.59 0-31.69 7.27-49.89 22.55l-4.83 4.06-30.32-23.38 10.97-206.03h176v59.91H723.73l-6.59 97.77c12.81-6.63 25.67-9.67 40.24-9.67 31.08 0 57.49 11.98 76.37 34.65 20.55 24.67 30.97 60.1 30.97 105.32-0.01 98.95-58.31 150.73-115.9 150.73z',
h6: 'M567.22 895.92h-62.14V523.41H222.25v372.51h-62.93V128h62.93v326.08h282.83V128h62.14v767.92z m191.63 0.08c-36.45 0-67.06-18.74-88.53-54.2-22-36.32-33.62-90.02-33.62-155.31 0-75.99 13.35-134.66 39.68-174.4 23.41-35.32 56.12-54 94.61-54 33.88 0 62.8 15.03 85.97 44.68l3.66 4.69-33.35 45.27-6.25-8.98c-12.1-17.38-30.28-27.75-48.64-27.75-22.59 0-40.82 11.25-54.18 33.43-14.23 23.61-22.73 58.91-25.36 105.12 20.59-21.5 45.78-34.22 69.27-34.22 31.54 0 57.57 12.13 75.26 35.06 18.11 23.48 27.3 57.31 27.3 100.55 0 39.09-10.89 74.77-30.67 100.48-19.64 25.52-46.33 39.58-75.15 39.58z m-65.74-175.89c2.63 39.75 9.87 70.41 21.54 91.16 11.06 19.65 25.93 29.62 44.2 29.62 28.99 0 50.02-35.72 50.02-84.94 0-26.16-4.82-47.37-13.95-61.34-9.03-13.82-22.42-20.82-39.81-20.82-21.46-0.01-43.98 16.84-62 46.32z',
codeblock:
'M819.2 864H204.8c-42.35 0-76.8-35.89-76.8-80V240c0-44.11 34.45-80 76.8-80h614.4c42.35 0 76.8 35.89 76.8 80v544c0 44.11-34.45 80-76.8 80zM233.74 221.09c-23.02 0-41.74 19.58-41.74 43.64v494.55c0 24.06 18.72 43.64 41.74 43.64h556.52c23.02 0 41.74-19.57 41.74-43.64V264.73c0-24.06-18.72-43.64-41.74-43.64H233.74z m410.77 417.59l124.33-106.53c4.56-3.9 7.17-9.61 7.16-15.66 0-6.04-2.62-11.75-7.18-15.64L644.44 394.58l-0.08-0.07c-4.15-3.45-9.38-5.07-14.74-4.55-5.37 0.52-10.21 3.12-13.65 7.33-6.96 8.51-5.91 21.33 2.34 28.56l106.15 90.68-106.04 90.86c-5.59 4.64-8.33 12-7.14 19.23 1.2 7.3 6.21 13.39 13.08 15.91 2.23 0.82 4.55 1.21 6.85 1.21a20.11 20.11 0 0 0 13.3-5.06zM414.63 774.64c5.1-1.98 9.11-5.86 11.29-10.93L635.93 276.7c4.44-10.29-0.19-22.37-10.3-26.93-4.92-2.22-10.41-2.37-15.44-0.41-5.1 1.98-9.11 5.86-11.29 10.93L388.88 747.3c-4.44 10.28 0.18 22.36 10.3 26.93 2.63 1.19 5.42 1.78 8.21 1.78 2.45 0 4.89-0.46 7.24-1.37z m-20.52-129.77c8.5 0 16.14-5.45 19.02-13.56 2.84-8.03 0.43-17.11-6.01-22.61L299.6 516.99l107.47-91.67c5.54-4.65 8.23-12.01 7.03-19.19-1.21-7.22-6.17-13.28-12.95-15.81a20.027 20.027 0 0 0-20.06 3.61L255.2 501.31c-4.57 3.9-7.2 9.61-7.2 15.68 0 6.06 2.62 11.77 7.2 15.67l125.88 107.38a20 20 0 0 0 12.99 4.82c0.02 0.01 0.02 0.01 0.04 0.01z',
code: 'M686.87 681.71c-2.86 0-5.73-0.45-8.5-1.38-8.85-2.96-15.33-10.29-16.91-19.12-1.6-8.91 2-17.92 9.4-23.53L829.48 513.1 670.76 388.8c-5.33-4.28-8.57-10.3-9.12-16.94-0.55-6.57 1.61-12.96 6.08-17.97 9.08-10.2 24.78-11.64 35.74-3.29l0.08 0.06 183.01 143.31c6 4.7 9.44 11.66 9.44 19.08 0 7.43-3.43 14.39-9.43 19.09l-182.94 143.7c-4.72 3.84-10.7 5.87-16.75 5.87zM356.91 865.09c-3.4 0-6.86-0.65-10.16-2.01-6.53-2.7-11.49-7.7-13.96-14.08-2.37-6.12-2.13-12.77 0.67-18.72l308.99-656.84c5.75-12.23 20.9-17.85 33.78-12.53 6.53 2.7 11.49 7.7 13.96 14.09 2.37 6.12 2.13 12.77-0.67 18.72L380.54 850.56c-4.28 9.09-13.75 14.53-23.63 14.53zM339 682.25c-5.93 0-11.73-1.98-16.32-5.58L137.47 531.83c-6.02-4.71-9.47-11.67-9.47-19.11 0-7.44 3.45-14.41 9.47-19.11L322.7 348.77c6.94-5.51 16.59-7.13 25.13-4.21 8.73 2.99 15.15 10.27 16.74 19.01 1.61 8.84-1.93 17.84-9.24 23.47L194.59 512.72l160.78 125.72c8.53 6.67 11.7 17.8 7.87 27.69-3.73 9.64-13.46 16.12-24.21 16.12H339z',
quote:
'M328.25 527.53h120.17V896H128V617.21C128 312.66 234.77 149.55 448.42 128v138.19c-80.08 25.76-120.17 99.55-120.17 221.61v39.73z m447.62 0H896V896H575.58V617.21c0-304.55 106.74-467.66 320.32-489.21v138.19c-80.05 25.76-120.13 99.55-120.13 221.61v39.72h0.1z',
bold: 'M573.71 758.85h-192V594.28h192c45.53 0 82.29 36.76 82.29 82.29 0 45.53-36.76 82.28-82.29 82.28m-192-493.71h164.57c45.53 0 82.29 36.75 82.29 82.29s-36.75 82.29-82.29 82.29H381.71m307.21 70.76c53.21-37.3 90.51-98.19 90.51-153.05 0-123.98-96-219.43-219.43-219.43H217.14v768h386.19c115.2 0 203.52-93.26 203.52-207.91 0.01-83.38-47.17-154.7-117.93-187.61z',
image:
'M550.34 397.58h210.87L550.34 186.71v210.87M281.96 129.2h306.72l230.04 230.04v460.08c0 42.17-34.51 76.68-76.68 76.68H281.96c-42.56 0-76.68-34.51-76.68-76.68V205.88a76.406 76.406 0 0 1 22.38-54.3 76.406 76.406 0 0 1 54.3-22.38m0 690.12h460.08V512.6L588.68 665.96 512 589.28 281.96 819.32m76.68-421.74c-42.17 0-76.68 34.51-76.68 76.68s34.51 76.68 76.68 76.68 76.68-34.51 76.68-76.68-34.51-76.68-76.68-76.68z',
attach:
'M821.2 466.43L501.65 785.98c-63.92 63.92-168.48 63.92-232.4 0-63.91-63.91-63.91-168.48 0-232.4l334.07-334.07c40.67-40.67 104.58-40.67 145.25 0s40.67 104.58 0 145.25L414.5 698.83c-15.97 15.97-42.13 15.97-58.1 0-15.97-15.97-15.97-42.13 0-58.1l275.97-275.97-43.57-43.57-275.98 275.96c-40.66 40.67-40.67 104.58 0 145.25s104.58 40.67 145.25 0l334.07-334.07c63.91-63.91 63.92-168.48 0-232.4s-168.49-63.91-232.4 0L225.68 510c-88.6 88.6-88.6 230.95 0 319.55s230.95 88.6 319.55 0L864.78 510l-43.58-43.57z',
link: 'M338.96 895.99c-27.5 0-53.33-10.68-72.73-30.08L158.08 757.76c-19.4-19.4-30.08-45.24-30.08-72.74 0-27.5 10.68-53.33 30.08-72.71l135.97-135.97c12.84-12.84 33.74-12.84 46.58 0 6.22 6.22 9.65 14.5 9.65 23.3s-3.43 17.07-9.65 23.29L204.66 658.88c-14.41 14.41-14.41 37.87 0 52.29l108.15 108.15c14.41 14.42 37.87 14.42 52.31 0l216.29-216.3c6.94-6.94 10.75-16.22 10.75-26.14 0-9.92-3.82-19.21-10.75-26.15l-59.47-59.49c-6.22-6.22-9.65-14.49-9.65-23.29 0-8.8 3.43-17.07 9.65-23.29 12.84-12.84 33.74-12.84 46.58 0L628 504.14c19.38 19.36 30.06 45.19 30.06 72.73 0 27.54-10.67 53.37-30.06 72.73L411.71 865.9c-19.39 19.41-45.23 30.09-72.75 30.09zM478.8 588.96c-8.8 0-17.07-3.43-23.29-9.65l-59.49-59.48c-19.38-19.37-30.06-45.2-30.06-72.73s10.67-53.37 30.06-72.75l216.31-216.3c19.36-19.37 45.19-30.04 72.73-30.04 27.51 0 53.34 10.66 72.73 30.03L865.94 266.2c19.38 19.38 30.06 45.21 30.06 72.74 0 27.53-10.68 53.37-30.06 72.74L729.98 547.64c-6.22 6.22-14.49 9.65-23.29 9.65s-17.07-3.43-23.29-9.65c-6.22-6.22-9.65-14.49-9.65-23.29 0-8.8 3.43-17.07 9.65-23.29l135.96-135.97c6.93-6.95 10.76-16.23 10.76-26.15 0-9.92-3.82-19.21-10.76-26.15L711.2 204.64c-6.59-6.58-16.12-10.36-26.15-10.36h-0.02c-10.03 0-19.55 3.78-26.12 10.36L442.6 420.94c-6.94 6.94-10.76 16.23-10.76 26.15 0 9.92 3.82 19.2 10.76 26.14l59.49 59.49c12.84 12.85 12.84 33.74 0 46.58-6.22 6.23-14.49 9.66-23.29 9.66z',
order:
'M320 215v82h576v-82M320 553h576v-82H320m0 338h576v-82H320m-192 9h85.33v16h-42.67v32h42.67v16H128v32h128V704H128v32z m0-256h76.8L128 547.2V576h128v-32h-76.8l76.8-67.2V448H128m64-128h42V192h-84v32h42',
italic:
'M391.7 128c0.67 38.67 1.33 77.33 2 116h146c-58 169.14-115.99 338.28-173.99 507.42-67.14 0.17-134.28 0.33-201.42 0.5 0.06 47.64 0.11 95.28 0.17 142.92 176.19 0.39 352.39 0.77 528.58 1.16V751.42H510.29C571.1 581.95 631.9 412.47 692.7 243h167V128h-468z',
through:
'M896 514.38v69.72H742.75c34.91 74.61 33.16 278.89-217.48 278.89-290.79 1.74-279.62-226.6-279.62-226.6l138.59 1.74c1.05 117.48 110.31 117.48 131.96 116.09 22.34-1.74 105.77-1.39 112.41-82.97 2.79-38-35.61-66.93-77.5-87.15H128v-69.72h768M770.68 371.1l-138.94-1.04s5.93-96.57-114.5-96.92c-120.44-0.7-109.96 76.69-109.96 86.45 1.4 9.77 11.87 57.88 104.73 80.88H292.42S170.59 205.85 468.01 165.75c304.06-41.82 303.36 206.04 302.67 205.35z',
list: 'M320 215v82h576v-82M320 553h576v-82H320m0 338h576v-82H320m-64-215c0 35.35-28.65 64-64 64s-64-28.65-64-64 28.65-64 64-64 64 28.65 64 64z m0 256c0 35.35-28.65 64-64 64s-64-28.65-64-64 28.65-64 64-64 64 28.65 64 64z m0-512c0 35.35-28.65 64-64 64s-64-28.65-64-64 28.65-64 64-64 64 28.65 64 64z',
line: 'M868.29 539.71H155.71c-15.28 0-27.71-12.43-27.71-27.71s12.43-27.71 27.71-27.71h712.58c15.28 0 27.71 12.43 27.71 27.71s-12.43 27.71-27.71 27.71z',
preview:
'M512 253.14c-174.51 0-322.97 106.97-384 258.86 61.03 151.89 209.49 258.86 384 258.86S834.97 663.89 896 512c-61.03-151.89-209.49-258.86-384-258.86z m0 431.49c-96 0-174.51-77.66-174.51-172.63S416 339.37 512 339.37 686.51 417.03 686.51 512 608 684.63 512 684.63z m0-276.17c-57.6 0-104.74 46.63-104.74 103.54S454.4 615.54 512 615.54 616.74 568.91 616.74 512 569.6 408.46 512 408.46z',
table:
'M860 159H164c-19.88 0-36 16.93-36 37.82v630.36c0 20.89 16.12 37.82 36 37.82h696c19.88 0 36-16.93 36-37.82V196.82c0-20.89-16.12-37.82-36-37.82z m-422 26.74c20.98 0 38 17.01 38 38 0 20.98-17.02 38-38 38-20.99 0-38-17.01-38-38s17.02-38 38-38z m-108 0c20.98 0 38 17.01 38 38 0 20.98-17.02 38-38 38-20.99 0-38-17.01-38-38s17.01-38 38-38z m-108 0c20.98 0 38 17.01 38 38 0 20.98-17.01 38-38 38s-38-17.01-38-38 17.01-38 38-38zM664 808V664h176v144H664z m-64-144v144H424V664h176z m-416 0h176v144H184V664z m480-190h176v144H664V474zM424 618V474h176v144H424z m-64 0H184V474h176v144z m480-338v144H664V280h176z m-240 0v144H424V280h176z m-385.54 0H360v144H184V280h30.46z',
fullscreen:
'M597.33 449.42l40.02 41.25 94.25-93.75 36.4 35V320H654.14l37.44 36.3-94.25 93.12z m-170.66 124.6l-40.41-40.68-93.53 93.93L256 592.76l0.95 111.24 113.96-0.9-37.78-35.78 93.54-93.3z m211.91-40.69l-41.25 40.02 93.75 94.24-35 36.4H768V590.14l-36.3 37.44-93.12-94.25z m-252.86-42.66l40.95-40.23-93.84-93.87L367.56 320l-111.56 0.5 0.48 113.91 36.02-37.62 93.22 93.88zM848 832H176c-26.47 0-48-19.57-48-43.64V235.64c0-24.06 21.53-43.64 48-43.64h672c26.47 0 48 19.58 48 43.64v552.73c0 24.06-21.53 43.63-48 43.63zM206.55 256c-8.02 0-14.55 5.74-14.55 12.8v486.4c0 7.06 6.53 12.8 14.55 12.8h610.91c8.02 0 14.55-5.74 14.55-12.8V268.8c0-7.06-6.53-12.8-14.55-12.8H206.55z'
}