Merge branch 'optional-icons'

This commit is contained in:
pengzhanbo 2024-09-26 00:20:23 +08:00
commit 769fc3d414
6 changed files with 69 additions and 12 deletions

View File

@ -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;

View File

@ -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('')

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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'