mirror of
https://github.com/pengzhanbo/vuepress-theme-plume.git
synced 2026-04-23 10:58:13 +08:00
99 lines
2.1 KiB
TypeScript
99 lines
2.1 KiB
TypeScript
/**
|
|
* :[mdi:11]:
|
|
* :[mdi:11 24px]:
|
|
* :[mid:11 /#ccc]:
|
|
* :[fluent-mdl2:toggle-filled 128px/#fff]:
|
|
*/
|
|
import type { PluginWithOptions } from 'markdown-it'
|
|
import type { RuleInline } from 'markdown-it/lib/parser_inline.mjs'
|
|
import { parseRect } from '../../utils/parseRect.js'
|
|
|
|
type AddIcon = (iconName: string) => string | undefined
|
|
|
|
const [openTag, endTag] = [':[', ']:']
|
|
|
|
function createTokenizer(addIcon: AddIcon): RuleInline {
|
|
return (state, silent) => {
|
|
let found = false
|
|
const max = state.posMax
|
|
const start = state.pos
|
|
|
|
if (state.src.slice(start, start + 2) !== openTag)
|
|
return false
|
|
|
|
if (silent)
|
|
return false
|
|
|
|
// :[]:
|
|
if (max - start < 5)
|
|
return false
|
|
|
|
state.pos = start + 2
|
|
|
|
while (state.pos < max) {
|
|
if (state.src.slice(state.pos, state.pos + 2) === endTag) {
|
|
found = true
|
|
break
|
|
}
|
|
|
|
state.md.inline.skipToken(state)
|
|
}
|
|
|
|
if (!found || start + 2 === state.pos) {
|
|
state.pos = start
|
|
|
|
return false
|
|
}
|
|
const content = state.src.slice(start + 2, state.pos)
|
|
|
|
// 不允许前后带有空格
|
|
if (/^\s|\s$/.test(content)) {
|
|
state.pos = start
|
|
return false
|
|
}
|
|
|
|
// found!
|
|
state.posMax = state.pos
|
|
state.pos = start + 2
|
|
|
|
const [iconName, options = ''] = content.split(/\s+/)
|
|
const [size, color] = options.split('/')
|
|
|
|
const open = state.push('iconify_open', 'span', 1)
|
|
open.markup = openTag
|
|
|
|
const className = addIcon(iconName)
|
|
|
|
if (className)
|
|
open.attrSet('class', className)
|
|
|
|
let style = ''
|
|
if (size)
|
|
style += `width:${parseRect(size)};height:${parseRect(size)};`
|
|
|
|
if (color)
|
|
style += `color:${color};`
|
|
|
|
if (style)
|
|
open.attrSet('style', style)
|
|
|
|
const text = state.push('text', '', 0)
|
|
text.content = className ? '' : iconName
|
|
|
|
const close = state.push('iconify_close', 'span', -1)
|
|
close.markup = endTag
|
|
|
|
state.pos = state.posMax + 2
|
|
state.posMax = max
|
|
|
|
return true
|
|
}
|
|
}
|
|
|
|
export const iconsPlugin: PluginWithOptions<AddIcon> = (
|
|
md,
|
|
addIcon = () => '',
|
|
) => {
|
|
md.inline.ruler.before('emphasis', 'iconify', createTokenizer(addIcon))
|
|
}
|