feat: allow html blocks inside code groups (#2719)

pull/2721/head
Divyansh Singh 1 year ago committed by GitHub
parent 0f38eb4404
commit 7f0c18e013
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,6 +1,17 @@
import { inBrowser } from 'vitepress' import { inBrowser, onContentUpdated } from 'vitepress'
export function useCodeGroups() { export function useCodeGroups() {
if (import.meta.env.DEV) {
onContentUpdated(() => {
document.querySelectorAll('.vp-code-group > .blocks').forEach((el) => {
Array.from(el.children).forEach((child) => {
child.classList.remove('active')
})
el.children[0].classList.add('active')
})
})
}
if (inBrowser) { if (inBrowser) {
window.addEventListener('click', (e) => { window.addEventListener('click', (e) => {
const el = e.target as HTMLInputElement const el = e.target as HTMLInputElement
@ -8,18 +19,25 @@ export function useCodeGroups() {
if (el.matches('.vp-code-group input')) { if (el.matches('.vp-code-group input')) {
// input <- .tabs <- .vp-code-group // input <- .tabs <- .vp-code-group
const group = el.parentElement?.parentElement const group = el.parentElement?.parentElement
const i = Array.from(group?.querySelectorAll('input') || []).indexOf(el) if (!group) return
const current = group?.querySelector('div[class*="language-"].active') const i = Array.from(group.querySelectorAll('input')).indexOf(el)
const next = group?.querySelectorAll( if (i < 0) return
'div[class*="language-"]:not(.language-id)'
)?.[i] const blocks = group.querySelector('.blocks')
if (!blocks) return
const current = Array.from(blocks.children).find((child) =>
child.classList.contains('active')
)
if (!current) return
const next = blocks.children[i]
if (!next || current === next) return
if (current && next && current !== next) {
current.classList.remove('active') current.classList.remove('active')
next.classList.add('active') next.classList.add('active')
} }
}
}) })
} }
} }

@ -59,7 +59,7 @@ const VitePressApp = defineComponent({
useCodeGroups() useCodeGroups()
if (Theme.setup) Theme.setup() if (Theme.setup) Theme.setup()
return () => h(Theme.Layout) return () => h(Theme.Layout!)
} }
}) })

@ -9,7 +9,7 @@ export interface EnhanceAppContext {
} }
export interface Theme { export interface Theme {
Layout: Component Layout?: Component
enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void> enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>
extends?: Theme extends?: Theme

@ -66,13 +66,19 @@
background-color: var(--vp-code-tab-active-bar-color); background-color: var(--vp-code-tab-active-bar-color);
} }
.vp-code-group div[class*='language-'] { .vp-code-group div[class*='language-'],
.vp-block {
display: none; display: none;
margin-top: 0 !important; margin-top: 0 !important;
border-top-left-radius: 0 !important; border-top-left-radius: 0 !important;
border-top-right-radius: 0 !important; border-top-right-radius: 0 !important;
} }
.vp-code-group div[class*='language-'].active { .vp-code-group div[class*='language-'].active,
.vp-block.active {
display: block; display: block;
} }
.vp-block {
padding: 20px 24px;
}

@ -278,7 +278,8 @@
color: var(--vp-c-brand-dark); color: var(--vp-c-brand-dark);
} }
.vp-doc div[class*='language-'] { .vp-doc div[class*='language-'],
.vp-block {
position: relative; position: relative;
margin: 16px -24px; margin: 16px -24px;
background-color: var(--vp-code-block-bg); background-color: var(--vp-code-block-bg);
@ -287,7 +288,8 @@
} }
@media (min-width: 640px) { @media (min-width: 640px) {
.vp-doc div[class*='language-'] { .vp-doc div[class*='language-'],
.vp-block {
border-radius: 8px; border-radius: 8px;
margin: 16px 0; margin: 16px 0;
} }

@ -74,13 +74,22 @@ function createCodeGroup(options: Options): ContainerArgs {
); );
++i ++i
) { ) {
if (tokens[i].type === 'fence' && tokens[i].tag === 'code') { const isHtml = tokens[i].type === 'html_block'
const title = extractTitle(tokens[i].info)
if (
(tokens[i].type === 'fence' && tokens[i].tag === 'code') ||
isHtml
) {
const title = extractTitle(
isHtml ? tokens[i].content : tokens[i].info,
isHtml
)
if (title) {
const id = nanoid(7) const id = nanoid(7)
tabs += `<input type="radio" name="group-${name}" id="tab-${id}" ${checked}><label for="tab-${id}">${title}</label>` tabs += `<input type="radio" name="group-${name}" id="tab-${id}" ${checked}><label for="tab-${id}">${title}</label>`
if (checked) { if (checked && !isHtml) tokens[i].info += ' active'
tokens[i].info += ' active'
checked = '' checked = ''
} }
} }

@ -9,14 +9,18 @@ export function preWrapperPlugin(md: MarkdownIt, options: Options) {
md.renderer.rules.fence = (...args) => { md.renderer.rules.fence = (...args) => {
const [tokens, idx] = args const [tokens, idx] = args
const token = tokens[idx] const token = tokens[idx]
// remove title from info // remove title from info
token.info = token.info.replace(/\[.*\]/, '') token.info = token.info.replace(/\[.*\]/, '')
const active = / active( |$)/.test(token.info) ? ' active' : ''
token.info = token.info.replace(/ active$/, '').replace(/ active /, ' ')
const lang = extractLang(token.info) const lang = extractLang(token.info)
const rawCode = fence(...args) const rawCode = fence(...args)
return `<div class="language-${lang}${getAdaptiveThemeMarker(options)}${ return `<div class="language-${lang}${getAdaptiveThemeMarker(
/ active( |$)/.test(token.info) ? ' active' : '' options
}"><button title="Copy Code" class="copy"></button><span class="lang">${lang}</span>${rawCode}</div>` )}${active}"><button title="Copy Code" class="copy"></button><span class="lang">${lang}</span>${rawCode}</div>`
} }
} }
@ -24,7 +28,12 @@ export function getAdaptiveThemeMarker(options: Options) {
return options.hasSingleTheme ? '' : ' vp-adaptive-theme' return options.hasSingleTheme ? '' : ' vp-adaptive-theme'
} }
export function extractTitle(info: string) { export function extractTitle(info: string, html = false) {
if (html) {
return (
info.replace(/<!--[^]*?-->/g, '').match(/data-title="(.*?)"/)?.[1] || ''
)
}
return info.match(/\[(.*)\]/)?.[1] || extractLang(info) || 'txt' return info.match(/\[(.*)\]/)?.[1] || extractLang(info) || 'txt'
} }

Loading…
Cancel
Save