Merge pull request #115 from pengzhanbo/RC-75

RC 75
This commit is contained in:
pengzhanbo 2024-07-10 07:44:36 +08:00 committed by GitHub
commit f20af9d245
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 188 additions and 103 deletions

View File

@ -1,3 +1,4 @@
import { constants, promises as fsp } from 'node:fs'
import type { App } from 'vuepress/core'
import { getIconContentCSS, getIconData } from '@iconify/utils'
import { fs, logger } from 'vuepress/utils'
@ -15,6 +16,7 @@ export interface IconCacheItem {
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 8)
const iconDataCache = new Map<string, any>()
const URL_CONTENT_RE = /(url\([^]+?\))/
const CSS_PATH = 'internal/md-power/icons.css'
function resolveOption(opt?: boolean | IconsOptions): Required<IconsOptions> {
const options = typeof opt === 'object' ? opt : {}
@ -27,8 +29,16 @@ function resolveOption(opt?: boolean | IconsOptions): Required<IconsOptions> {
export function createIconCSSWriter(app: App, opt?: boolean | IconsOptions) {
const cache = new Map<string, IconCacheItem>()
const isInstalled = isPackageExists('@iconify/json')
const currentPath = app.dir.temp(CSS_PATH)
const write = (content: string) => app.writeTemp('internal/md-power/icons.css', content)
const write = async (content: string) => {
if (!content && app.env.isDev) {
if (existsSync(currentPath) && (await fsp.stat(currentPath)).isFile()) {
return
}
}
await app.writeTemp(CSS_PATH, content)
}
let timer: NodeJS.Timeout | null = null
const options = resolveOption(opt)
@ -42,10 +52,12 @@ export function createIconCSSWriter(app: App, opt?: boolean | IconsOptions) {
timer = setTimeout(async () => {
let css = defaultContent
for (const [, { content, className }] of cache)
css += `.${className} {\n --svg: ${content};\n}\n`
if (cache.size > 0) {
for (const [, { content, className }] of cache)
css += `.${className} {\n --svg: ${content};\n}\n`
await write(css)
await write(css)
}
}, 100)
}
@ -132,3 +144,13 @@ async function genIconContent(iconName: string, cb: (content: string) => void) {
const match = content.match(URL_CONTENT_RE)
return cb(match ? match[1] : '')
}
function existsSync(fp: string) {
try {
fs.accessSync(fp, constants.R_OK)
return true
}
catch {
return false
}
}

View File

@ -106,7 +106,7 @@ const { theme, page } = useData()
@media (min-width: 960px) {
.vp-blog {
min-height: calc(100vh - var(--vp-footer-height, 0px));
min-height: calc(100vh - var(--vp-nav-height) - var(--vp-footer-height, 0px));
}
.blog-container {

View File

@ -173,6 +173,10 @@ watch(
max-width: 784px;
}
.vp-doc-container:not(.has-sidebar.has-aside) .content {
max-width: 884px;
}
.vp-doc-container:not(.has-sidebar) .container {
max-width: 1104px;
}

View File

@ -373,7 +373,7 @@ export function useSidebarControl(item: ComputedRef<ResolvedSidebarItem>): Sideb
}
return item.value.items
? containsActiveLink(page.value.filePathRelative || '', item.value.items)
? containsActiveLink(page.value.path, item.value.items)
: false
})

View File

@ -98,6 +98,10 @@
}
}
.vp-doc > h1:first-of-type {
display: none;
}
.vp-doc img {
display: inline-block;
}

View File

@ -93,7 +93,6 @@ export async function watchAutoFrontmatter(app: App, watchers: any[], enable?: (
async function generator(file: AutoFrontmatterMarkdownFile): Promise<void> {
if (!generate)
return
const { filepath, relativePath } = file
const current = generate.rules.find(({ filter }) => filter(relativePath))
@ -115,7 +114,7 @@ async function generator(file: AutoFrontmatterMarkdownFile): Promise<void> {
.replace(/\s+\n/g, '\n')
const newContent = yaml ? `${yaml}---\n${content}` : content
fs.writeFileSync(filepath, newContent, 'utf-8')
await fs.promises.writeFile(filepath, newContent, 'utf-8')
}
catch (e) {
console.error(e)

View File

@ -22,7 +22,7 @@ import { resolveNotesOptions } from '../config/index.js'
export function resolveOptions(
localeOptions: PlumeThemeLocaleOptions,
frontmatter: AutoFrontmatter,
options: AutoFrontmatter,
): AutoFrontmatter {
const pkg = getPackage()
const { locales = {}, article: articlePrefix = '/article/' } = localeOptions
@ -46,23 +46,28 @@ export function resolveOptions(
})
.filter(Boolean)
const baseFrontmatter: AutoFrontmatterObject = {
author(author: string, { relativePath }, data: any) {
const baseFrontmatter: AutoFrontmatterObject = {}
if (options.author !== false) {
baseFrontmatter.author = (author: string, { relativePath }, data) => {
if (author)
return author
if (data.friends)
if (data.friends || data.pageLayout === 'friends')
return
const profile = resolveOptions(relativePath).profile ?? resolveOptions(relativePath).avatar
return profile?.name || pkg.author || ''
},
createTime(formatTime: string, { createTime }, data: any) {
}
}
if (options.createTime !== false) {
baseFrontmatter.createTime = (formatTime: string, { createTime }, data) => {
if (formatTime)
return formatTime
if (data.friends)
if (data.friends || data.pageLayout === 'friends')
return
return format(new Date(createTime), 'yyyy/MM/dd HH:mm:ss')
},
}
}
const notesByLocale = (locale: string) => {
@ -86,8 +91,8 @@ export function resolveOptions(
}
return {
include: frontmatter?.include ?? ['**/*.md'],
exclude: uniq(['.vuepress/**/*', 'node_modules', ...(frontmatter?.exclude ?? [])]),
include: options?.include ?? ['**/*.md'],
exclude: uniq(['.vuepress/**/*', 'node_modules', ...(options?.exclude ?? [])]),
frontmatter: [
localesNotesDirs.length
@ -95,31 +100,39 @@ export function resolveOptions(
// note 首页链接
include: localesNotesDirs.map(dir => pathJoin(dir, '/{readme,README,index}.md')),
frontmatter: {
title(title: string, { relativePath }) {
if (title)
return title
const note = findNote(relativePath)
if (note?.text)
return note.text
return getCurrentDirname('', relativePath) || ''
},
...options.title !== false
? {
title(title: string, { relativePath }) {
if (title)
return title
const note = findNote(relativePath)
if (note?.text)
return note.text
return getCurrentDirname('', relativePath) || ''
},
} as AutoFrontmatterObject
: undefined,
...baseFrontmatter,
permalink(permalink: string, { relativePath }, data: any) {
if (permalink)
return permalink
if (data.friends)
return
const locale = resolveLocale(relativePath)
...options.permalink !== false
? {
permalink(permalink: string, { relativePath }, data: any) {
if (permalink)
return permalink
if (data.friends)
return
const locale = resolveLocale(relativePath)
const prefix = notesByLocale(locale)?.link || ''
const note = findNote(relativePath)
return pathJoin(
locale,
prefix,
note?.link || getCurrentDirname(note?.dir, relativePath),
'/',
)
},
const prefix = notesByLocale(locale)?.link || ''
const note = findNote(relativePath)
return pathJoin(
locale,
prefix,
note?.link || getCurrentDirname(note?.dir, relativePath),
'/',
)
},
} as AutoFrontmatterObject
: undefined,
},
}
: '',
@ -127,45 +140,53 @@ export function resolveOptions(
? {
include: localesNotesDirs.map(dir => `${dir}**/**.md`),
frontmatter: {
title(title: string, { relativePath }) {
if (title)
return title
...options.title !== false
? {
title(title: string, { relativePath }) {
if (title)
return title
const note = findNote(relativePath)
let basename = path.basename(relativePath, '.md')
if (note?.sidebar === 'auto')
basename = basename.replace(/^\d+\./, '')
const note = findNote(relativePath)
let basename = path.basename(relativePath, '.md')
if (note?.sidebar === 'auto')
basename = basename.replace(/^\d+\./, '')
return basename
},
return basename
},
} as AutoFrontmatterObject
: undefined,
...baseFrontmatter,
permalink(permalink: string, { relativePath }, data: any) {
if (permalink)
return permalink
if (data.friends)
return
const locale = resolveLocale(relativePath)
const notes = notesByLocale(locale)
const note = findNote(relativePath)
const prefix = notes?.link || ''
const args: string[] = [
locale,
prefix,
note?.link || '',
]
const sidebar = note?.sidebar
...options.permalink !== false
? {
permalink(permalink: string, { relativePath }, data: any) {
if (permalink)
return permalink
if (data.friends)
return
const locale = resolveLocale(relativePath)
const notes = notesByLocale(locale)
const note = findNote(relativePath)
const prefix = notes?.link || ''
const args: string[] = [
locale,
prefix,
note?.link || '',
]
const sidebar = note?.sidebar
if (note && sidebar && sidebar !== 'auto') {
const res = resolveLinkBySidebar(sidebar, pathJoin(notes?.dir || '', note.dir || ''))
const file = ensureLeadingSlash(relativePath)
if (res[file])
args.push(res[file])
else
res[path.dirname(file)] && args.push(res[path.dirname(file)])
}
if (note && sidebar && sidebar !== 'auto') {
const res = resolveLinkBySidebar(sidebar, pathJoin(notes?.dir || '', note.dir || ''))
const file = ensureLeadingSlash(relativePath)
if (res[file])
args.push(res[file])
else
res[path.dirname(file)] && args.push(res[path.dirname(file)])
}
return pathJoin(...args, nanoid(), '/')
},
return pathJoin(...args, nanoid(), '/')
},
} as AutoFrontmatterObject
: undefined,
},
}
: '',
@ -176,21 +197,29 @@ export function resolveOptions(
{
include: '*',
frontmatter: {
title(title: string, { relativePath }) {
if (title)
return title
const basename = path.basename(relativePath || '', '.md')
return basename
},
...options.title !== false
? {
title(title: string, { relativePath }) {
if (title)
return title
const basename = path.basename(relativePath || '', '.md')
return basename
},
} as AutoFrontmatterObject
: undefined,
...baseFrontmatter,
permalink(permalink: string, { relativePath }) {
if (permalink)
return permalink
const locale = resolveLocale(relativePath)
const prefix = withBase(articlePrefix, locale)
...options.permalink !== false
? {
permalink(permalink: string, { relativePath }) {
if (permalink)
return permalink
const locale = resolveLocale(relativePath)
const prefix = withBase(articlePrefix, locale)
return normalizePath(`${prefix}/${nanoid()}/`)
},
return normalizePath(`${prefix}/${nanoid()}/`)
},
} as AutoFrontmatterObject
: undefined,
},
},
].filter(Boolean) as AutoFrontmatterArray,

View File

@ -27,7 +27,6 @@ export interface Loader {
dependencies: string[]
load: () => Promise<{ config: ThemeConfig, dependencies: string[] }>
loaded: boolean
watcher: FSWatcher | null
changeEvents: ChangeEvent[]
whenLoaded: ChangeEvent[]
defaultConfig: ThemeConfig
@ -47,7 +46,6 @@ export async function initConfigLoader(
dependencies: [],
load: () => compiler(loader!.configFile),
loaded: false,
watcher: null,
changeEvents: [],
whenLoaded: [],
defaultConfig,
@ -64,7 +62,7 @@ export async function initConfigLoader(
const { config, dependencies = [] } = await loader.load()
loader.loaded = true
addDependencies(dependencies)
loader.dependencies = [...dependencies]
updateResolvedConfig(app, config)
runChangeEvents()
@ -81,14 +79,14 @@ export function watchConfigFile(app: App, watchers: any[]) {
cwd: path.join(path.dirname(loader.configFile), '../'),
})
addDependencies()
addDependencies(watcher)
watcher.on('change', async () => {
if (loader) {
loader.loaded = false
const { config, dependencies = [] } = await loader.load()
loader.loaded = true
addDependencies(dependencies)
addDependencies(watcher, dependencies)
updateResolvedConfig(app, config)
runChangeEvents()
}
@ -99,8 +97,6 @@ export function watchConfigFile(app: App, watchers: any[]) {
runChangeEvents()
})
loader.watcher = watcher
watchers.push(watcher)
}
@ -147,7 +143,7 @@ function runChangeEvents() {
}
}
function addDependencies(dependencies?: string[]) {
function addDependencies(watcher: FSWatcher, dependencies?: string[]) {
if (!loader)
return
@ -155,9 +151,9 @@ function addDependencies(dependencies?: string[]) {
const deps = dependencies
.filter(dep => !loader!.dependencies.includes(dep) && dep[0] === '.')
loader.dependencies.push(...deps)
deps.length && loader.watcher?.add(deps)
watcher.add(deps)
}
else {
loader.watcher?.add(loader.dependencies)
watcher.add(loader.dependencies)
}
}

View File

@ -138,7 +138,7 @@ function getAutoDirSidebar(
current.icon = frontmatter.icon as ThemeIcon
}
if (parent?.items?.length) {
parent.collapsed = true
parent.collapsed = false
}
parent = current
items = current.items as ResolvedSidebarItem[]

View File

@ -1,4 +1,5 @@
import type { Stats } from 'node:fs'
import type { PlumeThemePageFrontmatter } from './frontmatter/page.js'
export interface AutoFrontmatterMarkdownFile {
filepath: string
@ -8,13 +9,13 @@ export interface AutoFrontmatterMarkdownFile {
stats: Stats
}
export type FrontmatterFn<T = any, K = object> = (
export type FrontmatterFn<T = any> = (
value: T,
file: AutoFrontmatterMarkdownFile,
data: K
data: PlumeThemePageFrontmatter
) => T | PromiseLike<T>
export type AutoFrontmatterObject<K = object, T = any> = Record<string, FrontmatterFn<T, K>>
export type AutoFrontmatterObject<T = any> = Record<string, FrontmatterFn<T>>
export type AutoFrontmatterArray = {
include: string | string[]
@ -23,12 +24,42 @@ export type AutoFrontmatterArray = {
export interface AutoFrontmatter {
/**
* FilterPattern
* glob frontmatter
*
* @default ['**\/*.md']
*/
include?: string | string[]
/**
* glob frontmatter
*/
exclude?: string | string[]
/**
* permalink
*
* @default true
*/
permalink?: boolean
/**
* createTime
*
* `createTitme` vuepress `date`
*/
createTime?: boolean
/**
* author
*
* `profile.name` `package.json` `author`
*/
author?: boolean
/**
* title
*
*
*/
title?: boolean
/**
* {
* key(value, file, data) {