feat(plugin-md-power): add @[codesandbox](user/id) syntax supported
This commit is contained in:
parent
9124f788a3
commit
3a6ebcf3d4
@ -74,6 +74,7 @@ export const theme: Theme = themePlume({
|
||||
icons: true,
|
||||
codepen: true,
|
||||
replit: true,
|
||||
codeSandbox: true,
|
||||
},
|
||||
comment: {
|
||||
provider: 'Giscus',
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -6,6 +6,7 @@ import PDFViewer from './components/PDFViewer.vue'
|
||||
import Bilibili from './components/Bilibili.vue'
|
||||
import Youtube from './components/Youtube.vue'
|
||||
import Replit from './components/Replit.vue'
|
||||
import CodeSandbox from './components/CodeSandbox.vue'
|
||||
|
||||
import '@internal/md-power/icons.css'
|
||||
|
||||
@ -25,6 +26,9 @@ export default defineClientConfig({
|
||||
if (pluginOptions.replit)
|
||||
app.component('ReplitViewer', Replit)
|
||||
|
||||
if (pluginOptions.codeSandbox)
|
||||
app.component('CodeSandboxViewer', CodeSandbox)
|
||||
|
||||
if (__VUEPRESS_SSR__)
|
||||
return
|
||||
|
||||
|
||||
97
plugins/plugin-md-power/src/node/features/codeSandbox.ts
Normal file
97
plugins/plugin-md-power/src/node/features/codeSandbox.ts
Normal file
@ -0,0 +1,97 @@
|
||||
/**
|
||||
* @[codesandbox](id)
|
||||
* @[codesandbox share](user/id)
|
||||
* @[codesanbox title="xxx" layout="Editor+Preview" height="500px" navbar=false console=false](id#filepath)
|
||||
*/
|
||||
import type { PluginWithOptions } from 'markdown-it'
|
||||
import type { RuleBlock } from 'markdown-it/lib/parser_block.js'
|
||||
import { resolveAttrs } from '../utils/resolveAttrs.js'
|
||||
import { parseRect } from '../utils/parseRect.js'
|
||||
import type { CodeSandboxTokenMeta } from '../../shared/codeSandbox.js'
|
||||
|
||||
// @[codesandbox]()
|
||||
const MIN_LENGTH = 16
|
||||
|
||||
// char codes of `@[codesandbox`
|
||||
const START_CODES = [64, 91, 99, 111, 100, 101, 115, 97, 110, 100, 98, 111, 120]
|
||||
|
||||
// regexp to match the import syntax
|
||||
const SYNTAX_RE = /^@\[codesandbox(?:\s+(embed|share))?(?:\s+([^]*?))?\]\(([^)]*?)\)/
|
||||
|
||||
function createCodeSandboxRuleBlock(): RuleBlock {
|
||||
return (state, startLine, endLine, silent) => {
|
||||
const pos = state.bMarks[startLine] + state.tShift[startLine]
|
||||
const max = state.eMarks[startLine]
|
||||
|
||||
// return false if the length is shorter than min length
|
||||
if (pos + MIN_LENGTH > max)
|
||||
return false
|
||||
|
||||
// check if it's matched the start
|
||||
for (let i = 0; i < START_CODES.length; i += 1) {
|
||||
if (state.src.charCodeAt(pos + i) !== START_CODES[i])
|
||||
return false
|
||||
}
|
||||
|
||||
// check if it's matched the syntax
|
||||
const match = state.src.slice(pos, max).match(SYNTAX_RE)
|
||||
if (!match)
|
||||
return false
|
||||
|
||||
// return true as we have matched the syntax
|
||||
if (silent)
|
||||
return true
|
||||
|
||||
const [, type, info = '', source] = match
|
||||
|
||||
const { attrs } = resolveAttrs(info)
|
||||
const [profile, filepath = ''] = source.split('#')
|
||||
const [user, id] = profile.includes('/') ? profile.split('/') : ['', profile]
|
||||
|
||||
const meta: CodeSandboxTokenMeta = {
|
||||
width: attrs.width ? parseRect(attrs.width) : '100%',
|
||||
height: attrs.height ? parseRect(attrs.height) : '500px',
|
||||
user,
|
||||
id,
|
||||
title: attrs.title ?? '',
|
||||
console: attrs.console ?? false,
|
||||
navbar: attrs.navbar ?? true,
|
||||
layout: attrs.layout ?? '',
|
||||
type: (type || 'embed') as CodeSandboxTokenMeta['type'],
|
||||
filepath,
|
||||
}
|
||||
|
||||
const token = state.push('code_sandbox', '', 0)
|
||||
|
||||
token.meta = meta
|
||||
token.map = [startLine, startLine + 1]
|
||||
token.info = match[0]
|
||||
|
||||
state.line = startLine + 1
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
function resolveCodeSandbox(meta: CodeSandboxTokenMeta) {
|
||||
const { title, height, width, user, id, type, filepath, console, navbar, layout } = meta
|
||||
|
||||
return `<CodeSandboxViewer title="${title}" height="${height}" width="${width}" user="${user}" id="${id}" type="${type}" filepath="${filepath}" :console=${console} :navbar=${navbar} layout="${layout}" />`
|
||||
}
|
||||
|
||||
export const codeSandboxPlugin: PluginWithOptions<never> = (md) => {
|
||||
md.block.ruler.before(
|
||||
'import_code',
|
||||
'code_sandbox',
|
||||
createCodeSandboxRuleBlock(),
|
||||
)
|
||||
|
||||
md.renderer.rules.code_sandbox = (tokens, index) => {
|
||||
const token = tokens[index]
|
||||
|
||||
const content = resolveCodeSandbox(token.meta)
|
||||
token.content = content
|
||||
|
||||
return content
|
||||
}
|
||||
}
|
||||
@ -8,6 +8,7 @@ import { bilibiliPlugin } from './features/video/bilibili.js'
|
||||
import { youtubePlugin } from './features/video/youtube.js'
|
||||
import { codepenPlugin } from './features/codepen.js'
|
||||
import { replitPlugin } from './features/replit.js'
|
||||
import { codeSandboxPlugin } from './features/codeSandbox.js'
|
||||
|
||||
const __dirname = getDirname(import.meta.url)
|
||||
|
||||
@ -64,6 +65,11 @@ export function markdownPowerPlugin(options: MarkdownPowerPluginOptions = {}): P
|
||||
// @[replit](user/repl-name)
|
||||
md.use(replitPlugin)
|
||||
}
|
||||
|
||||
if (options.codeSandbox) {
|
||||
// @[codesandbox](id)
|
||||
md.use(codeSandboxPlugin)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
12
plugins/plugin-md-power/src/shared/codeSandbox.ts
Normal file
12
plugins/plugin-md-power/src/shared/codeSandbox.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import type { SizeOptions } from './size.js'
|
||||
|
||||
export interface CodeSandboxTokenMeta extends SizeOptions {
|
||||
user?: string
|
||||
id?: string
|
||||
layout?: string
|
||||
type?: 'share' | 'embed'
|
||||
title?: string
|
||||
filepath?: string
|
||||
navbar?: boolean
|
||||
console?: boolean
|
||||
}
|
||||
@ -3,4 +3,6 @@ export * from './pdf.js'
|
||||
export * from './icons.js'
|
||||
export * from './video.js'
|
||||
export * from './codepen.js'
|
||||
export * from './codeSandbox.js'
|
||||
export * from './replit.js'
|
||||
export * from './plugin.js'
|
||||
|
||||
@ -15,6 +15,7 @@ export interface MarkdownPowerPluginOptions {
|
||||
// code embed
|
||||
codepen?: boolean
|
||||
replit?: boolean
|
||||
codeSandbox?: boolean
|
||||
|
||||
caniuse?: boolean | CanIUseOptions
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user