diff --git a/docs/.vuepress/notes.ts b/docs/.vuepress/notes.ts index e5bc3398..98c9bd90 100644 --- a/docs/.vuepress/notes.ts +++ b/docs/.vuepress/notes.ts @@ -116,7 +116,7 @@ export const zhNotes = definePlumeNotesConfig({ { text: 'plugin-netlify-functions', dir: 'netlify-functions', - link: '/plugins/plugin-netlify-functions/', + link: 'plugin-netlify-functions/', items: [ '介绍', '使用', diff --git a/theme/src/client/composables/sidebar.ts b/theme/src/client/composables/sidebar.ts index 9ae094fa..08d505cd 100644 --- a/theme/src/client/composables/sidebar.ts +++ b/theme/src/client/composables/sidebar.ts @@ -23,6 +23,7 @@ import { isActive, normalizeLink, normalizePrefix, resolveNavLink } from '../uti import type { Sidebar, SidebarItem } from '../../shared/index.js' import type { ResolvedSidebarItem } from '../../shared/resolved/sidebar.js' import { useData } from './data.js' +import { useEncrypt } from './encrypt.js' export type SidebarData = Record @@ -229,6 +230,7 @@ export function useSidebar(): UseSidebarReturn { const { theme, frontmatter, page } = useData() const routeLocal = useRouteLocale() const is960 = useMediaQuery('(min-width: 960px)') + const { isPageDecrypted } = useEncrypt() const isOpen = ref(false) @@ -257,6 +259,13 @@ export function useSidebar(): UseSidebarReturn { const hasAside = computed(() => { if (frontmatter.value.pageLayout === 'home' || frontmatter.value.home) return false + + if (frontmatter.value.pageLayout === 'friends' || frontmatter.value.friends) + return false + + if (!isPageDecrypted.value) + return false + if (frontmatter.value.aside != null) return !!frontmatter.value.aside return theme.value.aside !== false diff --git a/theme/src/node/autoFrontmatter/resolveOptions.ts b/theme/src/node/autoFrontmatter/resolveOptions.ts index 46b66ee7..c0e83d6c 100644 --- a/theme/src/node/autoFrontmatter/resolveOptions.ts +++ b/theme/src/node/autoFrontmatter/resolveOptions.ts @@ -101,7 +101,7 @@ export function resolveOptions( const note = findNote(relativePath) if (note?.text) return note.text - return getCurrentDirname(note?.dir, relativePath) || '' + return getCurrentDirname('', relativePath) || '' }, ...baseFrontmatter, permalink(permalink: string, { relativePath }, data: any) { diff --git a/theme/src/node/prepare/prepareSidebar.ts b/theme/src/node/prepare/prepareSidebar.ts index c341f605..51e0e99a 100644 --- a/theme/src/node/prepare/prepareSidebar.ts +++ b/theme/src/node/prepare/prepareSidebar.ts @@ -1,6 +1,17 @@ import type { App, Page } from 'vuepress' -import { entries, isArray, isPlainObject, removeLeadingSlash } from '@vuepress/helper' -import type { PlumeThemeLocaleOptions, PlumeThemePageData, Sidebar, SidebarItem, ThemeIcon } from '../../shared/index.js' +import { + entries, + isArray, + isPlainObject, + removeLeadingSlash, +} from '@vuepress/helper' +import type { + PlumeThemeLocaleOptions, + PlumeThemePageData, + Sidebar, + SidebarItem, + ThemeIcon, +} from '../../shared/index.js' import { normalizeLink, resolveContent, writeTemp } from '../utils/index.js' import type { ResolvedSidebarItem } from '../../shared/resolved/sidebar.js' @@ -53,6 +64,14 @@ function getSidebarData( return resolved } +const MD_RE = /\.md$/ +const NUMBER_RE = /^\d+\./ +function resolveTitle(dirname: string) { + return dirname + .replace(MD_RE, '') + .replace(NUMBER_RE, '') +} + function getAutoDirSidebar( app: App, localePath: string, @@ -80,6 +99,7 @@ function getAutoDirSidebar( } const RE_INDEX = ['index.md', 'README.md', 'readme.md'] + const result: ResolvedSidebarItem[] = [] for (const page of pages) { const { data, title, path, frontmatter } = page @@ -90,25 +110,37 @@ function getAutoDirSidebar( let index = 0 let dir: string let items = result + let parent: ResolvedSidebarItem | undefined // eslint-disable-next-line no-cond-assign while ((dir = paths[index])) { - const text = dir.replace(/\.md$/, '').replace(/^\d+\./, '') + const text = resolveTitle(dir) + const isHome = RE_INDEX.includes(dir) let current = items.find(item => item.text === text) if (!current) { current = { text, link: undefined, items: [] } as ResolvedSidebarItem - !RE_INDEX.includes(dir) ? items.push(current) : items.unshift(current) + if (!isHome) { + items.push(current) + } + else { + !parent && items.unshift(current) + } } if (dir.endsWith('.md')) { - current.link = path - current.text = title + if (isHome && parent) { + parent.link = path + } + else { + current.link = path + current.text = title + } } - if (frontmatter.icon) + if (frontmatter.icon) { current.icon = frontmatter.icon as ThemeIcon - - if (index > 0) { - current.collapsed = false } - + if (parent?.items?.length) { + parent.collapsed = true + } + parent = current items = current.items as ResolvedSidebarItem[] index++ } diff --git a/theme/src/node/setupPages.ts b/theme/src/node/setupPages.ts index f4427d7f..37c4f3c0 100644 --- a/theme/src/node/setupPages.ts +++ b/theme/src/node/setupPages.ts @@ -2,17 +2,19 @@ import { ensureLeadingSlash, getRootLang, getRootLangPath, + removeLeadingSlash, } from '@vuepress/helper' import type { App, Page } from 'vuepress/core' import { createPage } from 'vuepress/core' +import { createFilter } from 'create-filter' import type { PageCategoryData, PlumeThemeLocaleOptions, PlumeThemePageData, } from '../shared/index.js' -import { withBase } from './utils/index.js' +import { normalizePath, withBase } from './utils/index.js' import { PRESET_LOCALES } from './locales/index.js' -import { resolveNotesLinkList } from './config/index.js' +import { resolveNotesLinkList, resolveNotesOptions } from './config/index.js' export async function setupPage( app: App, @@ -56,6 +58,35 @@ export async function setupPage( app.pages.push(...await Promise.all(pageList)) } +const weakFilter = new WeakMap boolean>() + +function createBlogFilter(localeOptions: PlumeThemeLocaleOptions) { + if (weakFilter.has(localeOptions)) + return weakFilter.get(localeOptions)! + + const blog = localeOptions.blog || {} + const notesList = resolveNotesOptions(localeOptions) + const notesDirList = notesList + .map(notes => removeLeadingSlash(normalizePath(`${notes.dir}/**`))) + .filter(Boolean) + + const filter = createFilter( + blog.include ?? ['**/*.md'], + [ + '**/{README,readme,index}.md', + '.vuepress/', + 'node_modules/', + ...(blog.exclude ?? []), + ...notesDirList, + ].filter(Boolean), + { resolve: false }, + ) + + weakFilter.set(localeOptions, filter) + + return filter +} + export function extendsPageData( page: Page, localeOptions: PlumeThemeLocaleOptions, @@ -63,6 +94,10 @@ export function extendsPageData( page.data.filePathRelative = page.filePathRelative page.routeMeta.title = page.frontmatter.title || page.title + if (createBlogFilter(localeOptions)(page.filePathRelative || '')) { + page.data.isBlogPost = true + } + if (page.frontmatter.icon) { page.routeMeta.icon = page.frontmatter.icon }