feat: add title render support for code block (#522)
This commit is contained in:
parent
79d3ee6565
commit
3d9361e2f1
@ -5,11 +5,17 @@ import { isPlainObject } from '@vuepress/helper'
|
||||
import { definitions, getFileIconName, getFileIconTypeFromExtension } from '../fileIcons/index.js'
|
||||
import { stringifyProp } from '../utils/stringifyProp.js'
|
||||
|
||||
export const codeTabs: PluginWithOptions<CodeTabsOptions> = (md, options: CodeTabsOptions = {}) => {
|
||||
const getIcon = (filename: string): string | void => {
|
||||
if (options.icon === false)
|
||||
return undefined
|
||||
const { named, extensions } = isPlainObject(options.icon) ? options.icon : {}
|
||||
export function createCodeTabIconGetter(
|
||||
options: CodeTabsOptions = {},
|
||||
): (filename: string) => string | void {
|
||||
const noop = () => undefined
|
||||
|
||||
if (options.icon === false)
|
||||
return noop
|
||||
|
||||
const { named, extensions } = isPlainObject(options.icon) ? options.icon : {}
|
||||
|
||||
return function getIcon(filename: string): string | void {
|
||||
if (named === false && definitions.named[filename])
|
||||
return undefined
|
||||
if (extensions === false && getFileIconTypeFromExtension(filename)) {
|
||||
@ -26,6 +32,10 @@ export const codeTabs: PluginWithOptions<CodeTabsOptions> = (md, options: CodeTa
|
||||
}
|
||||
return getFileIconName(filename)
|
||||
}
|
||||
}
|
||||
|
||||
export const codeTabs: PluginWithOptions<CodeTabsOptions> = (md, options: CodeTabsOptions = {}) => {
|
||||
const getIcon = createCodeTabIconGetter(options)
|
||||
|
||||
tab(md, {
|
||||
name: 'code-tabs',
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
export * from '../shared/index.js'
|
||||
export { createCodeTabIconGetter } from './container/codeTabs.js'
|
||||
export { resolveImageSize } from './enhance/imageSize.js'
|
||||
export * from './plugin.js'
|
||||
|
||||
@ -42,7 +42,7 @@ html:not([data-theme="dark"]) .vp-code span {
|
||||
z-index: 3;
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-code-line-number-color);
|
||||
content: attr(data-title);
|
||||
content: attr(data-ext);
|
||||
transition: color var(--vp-t-color);
|
||||
}
|
||||
|
||||
@ -236,8 +236,9 @@ html:not([data-theme="dark"]) .vp-code span {
|
||||
content: "+";
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy Code Button
|
||||
/*
|
||||
Copy Code Button
|
||||
--------------------------------------------------------------------------
|
||||
*/
|
||||
.vp-copy-code-button {
|
||||
--copy-code-c-text: var(--vp-code-block-color);
|
||||
@ -280,3 +281,33 @@ html:not([data-theme="dark"]) .vp-code span {
|
||||
.vp-doc div[class*="language-"].has-collapsed-lines:not(.collapsed) .collapsed-lines:hover {
|
||||
--vp-collapsed-lines-bg: transparent;
|
||||
}
|
||||
|
||||
/*
|
||||
Code Block Title
|
||||
---------------------------------------------------------------
|
||||
*/
|
||||
:root {
|
||||
--code-title-c-bg: var(--vp-code-block-bg);
|
||||
--code-title-divider: var(--vp-c-divider);
|
||||
--code-title-c-text: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
/* stylelint-disable-next-line no-descending-specificity */
|
||||
.vp-doc .code-block-title div[class*="language-"] {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
.code-block-title .code-block-title-bar {
|
||||
margin-bottom: -16px;
|
||||
}
|
||||
|
||||
.code-block-title .code-block-title-bar .title {
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.code-block-title .code-block-title-bar .title .vp-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ import { shikiPlugin } from '@vuepress/plugin-shiki'
|
||||
import { sitemapPlugin } from '@vuepress/plugin-sitemap'
|
||||
import { watermarkPlugin } from '@vuepress/plugin-watermark'
|
||||
import { mdEnhancePlugin } from 'vuepress-plugin-md-enhance'
|
||||
import { markdownPowerPlugin } from 'vuepress-plugin-md-power'
|
||||
import { createCodeTabIconGetter, markdownPowerPlugin } from 'vuepress-plugin-md-power'
|
||||
import { getThemeConfig } from '../loadConfig/index.js'
|
||||
|
||||
export interface SetupPluginOptions {
|
||||
@ -118,10 +118,16 @@ export function getPlugins({
|
||||
const shikiTheme = shikiOptions && 'theme' in shikiOptions ? shikiOptions.theme : shikiOptions && 'themes' in shikiOptions ? shikiOptions.themes : { light: 'vitesse-light', dark: 'vitesse-dark' }
|
||||
|
||||
if (shikiOptions !== false) {
|
||||
const { twoslash, ...restShikiOptions } = isPlainObject(shikiOptions) ? shikiOptions : {}
|
||||
const { twoslash, codeBlockTitle: _, langs = [], ...restShikiOptions } = isPlainObject(shikiOptions) ? shikiOptions : {}
|
||||
const twoslashOptions = twoslash === true ? {} : twoslash
|
||||
const markdownPower = isPlainObject(pluginOptions.markdownPower) ? pluginOptions.markdownPower : {}
|
||||
const getIcon = createCodeTabIconGetter(markdownPower.codeTabs)
|
||||
plugins.push(shikiPlugin({
|
||||
// enable some default features
|
||||
langs: [
|
||||
...twoslash ? ['js', 'ts', 'vue'] : [],
|
||||
...langs,
|
||||
],
|
||||
notationDiff: true,
|
||||
notationErrorLevel: true,
|
||||
notationFocus: true,
|
||||
@ -129,6 +135,15 @@ export function getPlugins({
|
||||
notationWordHighlight: true,
|
||||
highlightLines: true,
|
||||
collapsedLines: false,
|
||||
codeBlockTitle: (title, code) => {
|
||||
const icon = getIcon(title)
|
||||
return `<div class="code-block-title">
|
||||
<div class="code-block-title-bar">
|
||||
<span class="title">${icon ? `<VPIcon name="${icon}"/>` : ''}${title}</span>
|
||||
</div>
|
||||
${code}
|
||||
</div>`
|
||||
},
|
||||
twoslash: isPlainObject(twoslashOptions)
|
||||
? {
|
||||
...twoslashOptions,
|
||||
@ -171,7 +186,6 @@ export function getPlugins({
|
||||
|
||||
if (pluginOptions.watermark) {
|
||||
plugins.push(watermarkPlugin({
|
||||
delay: 300,
|
||||
enabled: true,
|
||||
...isPlainObject(pluginOptions.watermark) ? pluginOptions.watermark : {},
|
||||
}))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user