Merge branch 'optional-icons'
This commit is contained in:
commit
769fc3d414
@ -184,6 +184,10 @@ function onTabNavClick(index: number): void {
|
||||
transition: background var(--vp-t-color);
|
||||
}
|
||||
|
||||
.vp-code-tab-nav:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.vp-code-tab-nav.active {
|
||||
color: var(--vp-code-tab-active-text-color);
|
||||
background: transparent;
|
||||
|
||||
@ -1,9 +1,32 @@
|
||||
import type { PluginSimple } from 'markdown-it'
|
||||
import type { PluginWithOptions } from 'markdown-it'
|
||||
import type { CodeTabsOptions } from '../../shared/index.js'
|
||||
import { tab } from '@mdit/plugin-tab'
|
||||
import { getFileIconName } from '../fileIcons/index.js'
|
||||
import { isPlainObject } from '@vuepress/helper'
|
||||
import { definitions, getFileIconName, getFileIconTypeFromExtension } from '../fileIcons/index.js'
|
||||
import { stringifyProp } from '../utils/stringifyProp.js'
|
||||
|
||||
export const codeTabs: PluginSimple = (md) => {
|
||||
export const codeTabs: PluginWithOptions<CodeTabsOptions> = (md, options: CodeTabsOptions = {}) => {
|
||||
const getIcon = (filename: string): string | undefined => {
|
||||
if (options.icon === false)
|
||||
return undefined
|
||||
const { named, extensions } = isPlainObject(options.icon) ? options.icon : {}
|
||||
if (named === false && definitions.named[filename])
|
||||
return undefined
|
||||
if (extensions === false && getFileIconTypeFromExtension(filename)) {
|
||||
return undefined
|
||||
}
|
||||
const hasNamed = named && named.length
|
||||
const hasExt = extensions && extensions.length
|
||||
if (hasNamed || hasExt) {
|
||||
if (hasNamed && named.includes(filename))
|
||||
return definitions.named[filename]
|
||||
if (hasExt && extensions.some(ext => filename.endsWith(ext)))
|
||||
return getFileIconTypeFromExtension(filename)
|
||||
return undefined
|
||||
}
|
||||
return getFileIconName(filename)
|
||||
}
|
||||
|
||||
tab(md, {
|
||||
name: 'code-tabs',
|
||||
|
||||
@ -17,7 +40,7 @@ export const codeTabs: PluginSimple = (md) => {
|
||||
})
|
||||
|
||||
const titlesContent = titles.map((title, index) => {
|
||||
const icon = getFileIconName(title)
|
||||
const icon = getIcon(title)
|
||||
return `<template #title${index}="{ value, isActive }">${icon ? `<VPIcon name="${icon}"/>` : ''}<span>${title}</span></template>`
|
||||
}).join('')
|
||||
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import type { Markdown } from 'vuepress/markdown'
|
||||
import type { FileTreeIconMode, FileTreeOptions } from '../../shared/index.js'
|
||||
import Token from 'markdown-it/lib/token.mjs'
|
||||
import container from 'markdown-it-container'
|
||||
import { removeEndingSlash, removeLeadingSlash } from 'vuepress/shared'
|
||||
import { getFileIcon } from '../fileIcons/index.js'
|
||||
import { defaultFile, defaultFolder, getFileIcon } from '../fileIcons/index.js'
|
||||
|
||||
interface FileTreeNode {
|
||||
filename: string
|
||||
@ -17,10 +18,22 @@ const closeType = `container_${type}_close`
|
||||
const componentName = 'FileTreeItem'
|
||||
const itemOpen = 'file_tree_item_open'
|
||||
const itemClose = 'file_tree_item_close'
|
||||
const RE_SIMPLE_ICON = /:simple-icon\b/
|
||||
const RE_COLORED_ICON = /:colored-icon\b/
|
||||
|
||||
export function fileTreePlugin(md: Markdown, options: FileTreeOptions = {}) {
|
||||
const getIcon = (filename: string, type: 'folder' | 'file', mode?: FileTreeIconMode): string => {
|
||||
mode ||= options.icon || 'colored'
|
||||
if (mode === 'simple')
|
||||
return type === 'folder' ? defaultFolder : defaultFile
|
||||
return getFileIcon(filename, type)
|
||||
}
|
||||
|
||||
export function fileTreePlugin(md: Markdown) {
|
||||
const validate = (info: string): boolean => info.trim().startsWith(type)
|
||||
|
||||
const render = (tokens: Token[], idx: number): string => {
|
||||
const mode = getFileIconMode(tokens[idx].info)
|
||||
|
||||
if (tokens[idx].nesting === 1) {
|
||||
const hasRes: number[] = [] // level stack
|
||||
for (
|
||||
@ -36,7 +49,7 @@ export function fileTreePlugin(md: Markdown) {
|
||||
hasRes.push(token.level)
|
||||
const [info, inline] = result
|
||||
const { filename, type, expanded, empty } = info
|
||||
const icon = getFileIcon(filename, type)
|
||||
const icon = getIcon(filename, type, mode)
|
||||
|
||||
token.type = itemOpen
|
||||
token.tag = componentName
|
||||
@ -56,9 +69,8 @@ export function fileTreePlugin(md: Markdown) {
|
||||
}
|
||||
}
|
||||
}
|
||||
const info = tokens[idx].info.trim()
|
||||
|
||||
const title = info.slice(type.length).trim()
|
||||
const title = resolveTitle(tokens[idx].info)
|
||||
return `<div class="vp-file-tree">${title ? `<p class="vp-file-tree-title">${title}</p>` : ''}`
|
||||
}
|
||||
else {
|
||||
@ -69,6 +81,20 @@ export function fileTreePlugin(md: Markdown) {
|
||||
md.use(container, type, { validate, render })
|
||||
}
|
||||
|
||||
function getFileIconMode(info: string): FileTreeIconMode | undefined {
|
||||
if (RE_SIMPLE_ICON.test(info))
|
||||
return 'simple'
|
||||
if (RE_COLORED_ICON.test(info))
|
||||
return 'colored'
|
||||
return undefined
|
||||
}
|
||||
|
||||
function resolveTitle(info: string): string {
|
||||
info = info.trim().slice(type.length).trim()
|
||||
info = info.replace(RE_SIMPLE_ICON, '').replace(RE_COLORED_ICON, '')
|
||||
return info.trim()
|
||||
}
|
||||
|
||||
export function resolveTreeNodeInfo(
|
||||
tokens: Token[],
|
||||
current: Token,
|
||||
@ -143,19 +169,21 @@ export function updateInlineToken(inline: Token, info: FileTreeNode, icon: strin
|
||||
if (token.content.includes(' ')) {
|
||||
const [first, ...other] = token.content.split(' ')
|
||||
const text = new Token('text', '', 0)
|
||||
text.content = first
|
||||
text.content = removeEndingSlash(first)
|
||||
tokens.push(text)
|
||||
const comment = new Token('text', '', 0)
|
||||
comment.content = other.join(' ')
|
||||
children.unshift(comment)
|
||||
}
|
||||
else {
|
||||
token.content = removeEndingSlash(token.content)
|
||||
tokens.push(token)
|
||||
}
|
||||
if (!isStrongTag)
|
||||
break
|
||||
}
|
||||
else if (token.tag === 'strong') {
|
||||
token.content = removeEndingSlash(token.content)
|
||||
tokens.push(token)
|
||||
if (token.nesting === 1) {
|
||||
isStrongTag = true
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import type { App } from 'vuepress'
|
||||
import type { Markdown } from 'vuepress/markdown'
|
||||
import type { MarkdownPowerPluginOptions } from '../../shared/index.js'
|
||||
import { isPlainObject } from '@vuepress/helper'
|
||||
import { alignPlugin } from './align.js'
|
||||
import { codeTabs } from './codeTabs.js'
|
||||
import { fileTreePlugin } from './fileTree.js'
|
||||
@ -17,7 +18,7 @@ export async function containerPlugin(
|
||||
// ::: tabs
|
||||
tabs(md)
|
||||
// ::: code-tabs
|
||||
codeTabs(md)
|
||||
codeTabs(md, options.codeTabs)
|
||||
|
||||
if (options.repl)
|
||||
await langReplPlugin(app, md, options.repl)
|
||||
|
||||
@ -30,7 +30,7 @@ export function getFileIconName(fileName: string, type: 'file' | 'folder' = 'fil
|
||||
return icon
|
||||
}
|
||||
|
||||
function getFileIconTypeFromExtension(fileName: string): string | undefined {
|
||||
export function getFileIconTypeFromExtension(fileName: string): string | undefined {
|
||||
const firstDotIndex = fileName.indexOf('.')
|
||||
if (firstDotIndex === -1)
|
||||
return
|
||||
|
||||
@ -6,6 +6,7 @@ import { mark } from '@mdit/plugin-mark'
|
||||
import { sub } from '@mdit/plugin-sub'
|
||||
import { sup } from '@mdit/plugin-sup'
|
||||
import { tasklist } from '@mdit/plugin-tasklist'
|
||||
import { isPlainObject } from '@vuepress/helper'
|
||||
import { iconsPlugin } from './icons.js'
|
||||
import { plotPlugin } from './plot.js'
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user