feat(theme)!: add collections support (#704)

* feat(theme)!: add collection support
This commit is contained in:
pengzhanbo 2025-10-07 23:13:09 +08:00 committed by GitHub
parent fae5825618
commit 4d2361a704
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
397 changed files with 8101 additions and 6008 deletions

View File

@ -40,8 +40,8 @@
}, },
"plume-deps": { "plume-deps": {
"vuepress": "2.0.0-rc.24", "vuepress": "2.0.0-rc.24",
"vue": "^3.5.21", "vue": "^3.5.22",
"http-server": "^14.1.1", "http-server": "^14.1.1",
"typescript": "^5.9.2" "typescript": "^5.9.3"
} }
} }

View File

@ -0,0 +1,124 @@
/**
* @see https://theme-plume.vuejs.press/guide/collection/ 查看文档了解配置详情。
*
* Collections 配置文件,它在 `.vuepress/plume.config.{{#if useTs}}ts{{else}}js{{/if}}` 中被导入。
*
* 请注意,你应该先在这里配置好 Collections然后再启动 vuepress主题会在启动 vuepress 时,
* 读取这里配置的 Collections然后在与 Collection 相关的 Markdown 文件中,自动生成 permalink。
*
* collection 的 type 为 `post` 时,表示为 文档列表类型(即没有侧边导航栏,有文档列表页)
* 可用于实现如 博客、专栏 等以文章列表聚合形式的文档集合 (内容相对碎片化的)
*
* collection 的 type 为 `doc` 时,表示为文档类型(即有侧边导航栏)
* 可用于实现如 笔记、知识库、文档等以侧边导航栏形式的文档集合 (内容强关联、成体系的)
* 如果发现 侧边栏没有显示,那么请检查你的配置是否正确,以及 Markdown 文件中的 permalink
* 是否是以对应的 Collection 配置的 link 的前缀开头。 是否展示侧边栏是根据 页面链接 的前缀 与 `collection.link`
* 的前缀是否匹配来决定。
*/
/**
* 在受支持的 IDE 中会智能提示配置项。
*
* - `defineCollections` 是用于定义 collection 集合的帮助函数
* - `defineCollection` 是用于定义单个 collection 配置的帮助函数
*
* 通过 `defineCollection` 定义的 collection 配置,应该填入 `defineCollections` 中
*/
import { defineCollection, defineCollections } from 'vuepress-theme-plume'
{{#if multiLanguage}}
{{#each locales}}
/* =================== locale: {{ lang }} ======================= */
const {{ prefix }}Blog = defineCollection({
// post 类型,这里用于实现 博客功能
type: 'post',
// 文档集合所在目录,相对于 `docs{{ path }}`
dir: 'blog',
// 文档标题,它将用于在页面的面包屑导航中显示
title: 'Blog',
// 文章列表页的链接,如果 `linkPrefix` 未定义,它也将作为 相关的文章的 permalink 的前缀
link: '/blog/',
// linkPrefix: '/article/', // 相关文章的链接前缀
// postList: true, // 是否启用文章列表页
// tags: true, // 是否启用标签页
// archives: true, // 是否启用归档页
// categories: true, // 是否启用分类页
// postCover: 'right', // 文章封面位置
// pagination: 15, // 每页显示文章数量
})
const {{ prefix }}DemoDoc = defineCollection({
// doc 类型,该类型带有侧边栏
type: 'doc',
// 文档集合所在目录,相对于 `docs{{ path }}`
dir: 'demo',
// `dir` 所指向的目录中的所有 markdown 文件,其 permalink 需要以 `linkPrefix` 配置作为前缀
// 如果 前缀不一致,则无法生成侧边栏。
// 所以请确保 markdown 文件的 permalink 都以 `{{ path }}` + `linkPrefix` 开头
linkPrefix: '/demo',
// 文档标题,它将用于在页面的面包屑导航中显示
title: 'Demo',
// 手动配置侧边栏结构
sidebar: ['', 'foo', 'bar'],
// 根据文件结构自动生成侧边栏
// sidebar: 'auto',
})
/**
* 导出所有的 collections
* ({{ prefix }}Blog 为博客示例,如果不需要博客功能,请删除)
* ({{ prefix }}DemoDoc 为参考示例,如果不需要它,请删除)
*/
export const {{ prefix }}Collections = defineCollections([
{{ prefix }}Blog,
{{ prefix }}DemoDoc,
])
{{/each}}
{{else}}
const blog = defineCollection({
// post 类型,这里用于实现 博客功能
type: 'post',
// 文档集合所在目录,相对于 `docs{{ path }}`
dir: 'blog',
// 文档标题,它将用于在页面的面包屑导航中显示
title: 'Blog',
// 文章列表页的链接,如果 `linkPrefix` 未定义,它也将作为 相关的文章的 permalink 的前缀
link: '/blog/',
// linkPrefix: '/article/', // 相关文章的链接前缀
// postList: true, // 是否启用文章列表页
// tags: true, // 是否启用标签页
// archives: true, // 是否启用归档页
// categories: true, // 是否启用分类页
// postCover: 'right', // 文章封面位置
// pagination: 15, // 每页显示文章数量
})
const demoDoc = defineCollection({
// doc 类型,该类型带有侧边栏
type: 'doc',
// 文档集合所在目录,相对于 `docs{{ path }}`
dir: 'demo',
// `dir` 所指向的目录中的所有 markdown 文件,其 permalink 需要以 `linkPrefix` 配置作为前缀
// 如果 前缀不一致,则无法生成侧边栏。
// 所以请确保 markdown 文件的 permalink 都以 `linkPrefix` 开头
linkPrefix: '/demo',
// 文档标题,它将用于在页面的面包屑导航中显示
title: 'Demo',
// 手动配置侧边栏结构
sidebar: ['', 'foo', 'bar'],
// 根据文件结构自动生成侧边栏
// sidebar: 'auto',
})
/**
* 导出所有的 collections
* (blog 为博客示例,如果不需要博客功能,请删除)
* (demoDoc 为参考示例,如果不需要它,请删除)
*/
export default defineCollection([
blog,
demoDoc,
])
{{/if}}

View File

@ -54,23 +54,6 @@ export default defineUserConfig({
// contributors: true, // contributors: true,
// changelog: false, // changelog: false,
/**
* 博客
* @see https://theme-plume.vuejs.press/config/basic/#blog
*/
// blog: false, // 禁用博客
// blog: {
// postList: true, // 是否启用文章列表页
// tags: true, // 是否启用标签页
// archives: true, // 是否启用归档页
// categories: true, // 是否启用分类页
// postCover: 'right', // 文章封面位置
// pagination: 15, // 每页显示文章数量
// },
/* 博客文章页面链接前缀 */
article: '/article/',
/** /**
* 编译缓存,加快编译速度 * 编译缓存,加快编译速度
* @see https://theme-plume.vuejs.press/config/basic/#cache * @see https://theme-plume.vuejs.press/config/basic/#cache
@ -116,9 +99,9 @@ export default defineUserConfig({
// readingTime: true, // readingTime: true,
/** /**
* markdown * markdown
* @see https://theme-plume.vuejs.press/config/markdown/ * @see https://theme-plume.vuejs.press/config/markdown/
*/ */
// markdown: { // markdown: {
// abbr: true, // 启用 abbr 语法 *[label]: content // abbr: true, // 启用 abbr 语法 *[label]: content
// annotation: true, // 启用 annotation 语法 [+label]: content // annotation: true, // 启用 annotation 语法 [+label]: content

View File

@ -15,7 +15,7 @@ export const {{prefix}}Navbar = defineNavbarConfig([
{ text: '{{#if isEn}}Archives{{else}}归档{{/if}}', link: '{{ path }}blog/archives/' }, { text: '{{#if isEn}}Archives{{else}}归档{{/if}}', link: '{{ path }}blog/archives/' },
{ {
text: '{{#if isEn}}Notes{{else}}笔记{{/if}}', text: '{{#if isEn}}Notes{{else}}笔记{{/if}}',
items: [{ text: '{{#if isEn}}Demo{{else}}示例{{/if}}', link: '{{ path }}notes/demo/README.md' }] items: [{ text: '{{#if isEn}}Demo{{else}}示例{{/if}}', link: '{{ path }}demo/README.md' }]
}, },
]) ])
@ -28,7 +28,7 @@ export default defineNavbarConfig([
{ text: '{{#if isEn}}Archives{{else}}归档{{/if}}', link: '/blog/archives/' }, { text: '{{#if isEn}}Archives{{else}}归档{{/if}}', link: '/blog/archives/' },
{ {
text: '{{#if isEn}}Notes{{else}}笔记{{/if}}', text: '{{#if isEn}}Notes{{else}}笔记{{/if}}',
items: [{ text: '{{#if isEn}}Demo{{else}}示例{{/if}}', link: '/notes/demo/README.md' }] items: [{ text: '{{#if isEn}}Demo{{else}}示例{{/if}}', link: '/demo/README.md' }]
}, },
]) ])
{{/if}} {{/if}}

View File

@ -1,75 +0,0 @@
/**
* @see https://theme-plume.vuejs.press/guide/document/ 查看文档了解配置详情。
*
* Notes 配置文件,它在 `.vuepress/plume.config.{{#if useTs}}ts{{else}}js{{/if}}` 中被导入。
*
* 请注意,你应该先在这里配置好 Notes然后再启动 vuepress主题会在启动 vuepress 时,
* 读取这里配置的 Notes然后在与 Note 相关的 Markdown 文件中,自动生成 permalink。
*
* 如果你发现 侧边栏没有显示,那么请检查你的配置是否正确,以及 Markdown 文件中的 permalink
* 是否是以对应的 note 配置的 link 的前缀开头。 是否展示侧边栏是根据 页面链接 的前缀 与 `note.link`
* 的前缀是否匹配来决定。
*/
/**
* 在受支持的 IDE 中会智能提示配置项。
*
* - `defineNoteConfig` 是用于定义单个 note 配置的帮助函数
* - `defineNotesConfig` 是用于定义 notes 集合的帮助函数
*
* 通过 `defineNoteConfig` 定义的 note 配置,应该填入 `defineNotesConfig` 的 notes 数组中
*/
import { defineNoteConfig, defineNotesConfig } from 'vuepress-theme-plume'
{{#if multiLanguage}}
{{#each locales}}
/* =================== locale: {{ lang }} ======================= */
const {{ prefix }}DemoNote = defineNoteConfig({
dir: 'demo',
// `dir` 所指向的目录中的所有 markdown 文件,其 permalink 需要以 `link` 配置作为前缀
// 如果 前缀不一致,则无法生成侧边栏。
// 所以请确保 markdown 文件的 permalink 都以 `link` 开头
link: '/demo',
// 手动配置侧边栏结构
sidebar: ['', 'foo', 'bar'],
// 根据文件结构自动生成侧边栏
// sidebar: 'auto',
})
/**
* 导出所有的 note
* 每一个 note 都应该填入到 `notes.notes` 数组中
* {{ prefix }}DemoNote 为参考示例,如果不需要它,请删除)
*/
export const {{ prefix }}Notes = defineNotesConfig({
dir: '{{ removeLeadingSlash path }}notes',
link: '{{ path }}',
notes: [{{ prefix }}DemoNote],
})
{{/each}}
{{else}}
const demoNote = defineNoteConfig({
dir: 'demo',
// `dir` 所指向的目录中的所有 markdown 文件,其 permalink 需要以 `link` 配置作为前缀
// 如果 前缀不一致,则无法生成侧边栏。
// 所以请确保 markdown 文件的 permalink 都以 `link` 开头
link: '/demo',
// 手动配置侧边栏结构
sidebar: ['', 'foo', 'bar'],
// 根据文件结构自动生成侧边栏
// sidebar: 'auto',
})
/**
* 导出所有的 note
* 每一个 note 都应该填入到 `notes.notes` 数组中
* DemoNote 为参考示例,如果不需要它,请删除)
*/
export default defineNotesConfig({
dir: 'notes',
link: '/',
notes: [demoNote],
})
{{/if}}

View File

@ -12,11 +12,11 @@
import { defineThemeConfig } from 'vuepress-theme-plume' import { defineThemeConfig } from 'vuepress-theme-plume'
{{#if multiLanguage}} {{#if multiLanguage}}
import { enCollections, zhCollections } from './collections'
import { enNavbar, zhNavbar } from './navbar' import { enNavbar, zhNavbar } from './navbar'
import { enNotes, zhNotes } from './notes'
{{else}} {{else}}
import navbar from './navbar' import navbar from './navbar'
import notes from './notes' import collections from './collections'
{{/if}} {{/if}}
/** /**
@ -64,7 +64,7 @@ export default defineThemeConfig({
}, },
navbar, navbar,
notes, collections,
/** /**
* 公告板 * 公告板
@ -102,7 +102,7 @@ export default defineThemeConfig({
}, },
navbar: {{ prefix }}Navbar, navbar: {{ prefix }}Navbar,
notes: {{ prefix }}Notes, collections: {{ prefix }}Collections,
/** /**
* 公告板 * 公告板

View File

@ -2,6 +2,7 @@ import type { ClientConfig } from 'vuepress/client'
import { defineMermaidConfig } from '@vuepress/plugin-markdown-chart/client' import { defineMermaidConfig } from '@vuepress/plugin-markdown-chart/client'
import { h } from 'vue' import { h } from 'vue'
import { Layout } from 'vuepress-theme-plume/client' import { Layout } from 'vuepress-theme-plume/client'
import VPPostItem from 'vuepress-theme-plume/components/Posts/VPPostItem.vue'
import { defineClientConfig } from 'vuepress/client' import { defineClientConfig } from 'vuepress/client'
import AsideNav from '~/components/AsideNav.vue' import AsideNav from '~/components/AsideNav.vue'
import { setupThemeColors } from '~/composables/theme-colors.js' import { setupThemeColors } from '~/composables/theme-colors.js'
@ -14,6 +15,9 @@ defineMermaidConfig({
}) })
export default defineClientConfig({ export default defineClientConfig({
enhance({ app }) {
app.component('VPPostItem', VPPostItem)
},
setup() { setup() {
setupThemeColors() setupThemeColors()
}, },

View File

@ -0,0 +1,8 @@
import { defineCollections, type ThemeCollections } from 'vuepress-theme-plume'
import { themeConfig } from './theme-config.js'
import { themeGuide } from './theme-guide.js'
export const enCollections: ThemeCollections = defineCollections([
themeGuide,
themeConfig,
])

View File

@ -1,9 +1,11 @@
import type { ThemeNote } from 'vuepress-theme-plume' import type { ThemeCollectionItem } from 'vuepress-theme-plume'
import { defineNoteConfig } from 'vuepress-theme-plume' import { defineCollection } from 'vuepress-theme-plume'
export const themeConfig: ThemeNote = defineNoteConfig({ export const themeConfig: ThemeCollectionItem = defineCollection({
dir: 'theme/config', type: 'doc',
link: '/config/', dir: 'config',
title: 'Config',
linkPrefix: '/config/',
sidebar: [ sidebar: [
{ {
text: 'Config', text: 'Config',

View File

@ -1,9 +1,11 @@
import type { ThemeNote } from 'vuepress-theme-plume' import type { ThemeCollectionItem } from 'vuepress-theme-plume'
import { defineNoteConfig } from 'vuepress-theme-plume' import { defineCollection } from 'vuepress-theme-plume'
export const themeGuide: ThemeNote = defineNoteConfig({ export const themeGuide: ThemeCollectionItem = defineCollection({
dir: 'theme/guide', type: 'doc',
link: '/guide/', dir: 'guide',
title: 'Guide',
linkPrefix: '/guide/',
sidebar: [ sidebar: [
{ {
text: 'Quick Start', text: 'Quick Start',

View File

@ -0,0 +1,10 @@
import { defineCollections, type ThemeCollections } from 'vuepress-theme-plume'
import { themeConfig } from './theme-config.js'
import { themeGuide } from './theme-guide.js'
import { tools } from './tools.js'
export const zhCollections: ThemeCollections = defineCollections([
themeGuide,
themeConfig,
tools,
])

View File

@ -1,9 +1,11 @@
import type { ThemeNote } from 'vuepress-theme-plume' import type { ThemeCollectionItem } from 'vuepress-theme-plume'
import { defineNoteConfig } from 'vuepress-theme-plume' import { defineCollection } from 'vuepress-theme-plume'
export const themeConfig: ThemeNote = defineNoteConfig({ export const themeConfig: ThemeCollectionItem = defineCollection({
dir: 'theme/config', type: 'doc',
link: '/config/', title: '配置',
dir: 'config',
linkPrefix: '/config/',
sidebar: [ sidebar: [
{ {
text: '配置', text: '配置',
@ -13,8 +15,8 @@ export const themeConfig: ThemeNote = defineNoteConfig({
'theme', 'theme',
'locales', 'locales',
'navbar', 'navbar',
'notes',
'sidebar', 'sidebar',
'collections',
'markdown', 'markdown',
], ],
}, },

View File

@ -1,9 +1,11 @@
import type { ThemeNote } from 'vuepress-theme-plume' import type { ThemeCollectionItem } from 'vuepress-theme-plume'
import { defineNoteConfig } from 'vuepress-theme-plume' import { defineCollection } from 'vuepress-theme-plume'
export const themeGuide: ThemeNote = defineNoteConfig({ export const themeGuide: ThemeCollectionItem = defineCollection({
dir: 'theme/guide', type: 'doc',
link: '/guide/', dir: 'guide',
title: '指南',
linkPrefix: '/guide/',
sidebar: [ sidebar: [
{ {
text: '从这里开始', text: '从这里开始',
@ -14,9 +16,13 @@ export const themeGuide: ThemeNote = defineNoteConfig({
'intro', 'intro',
'usage', 'usage',
'project-structure', 'project-structure',
{
text: '集合',
link: 'collection',
items: ['collection-post', 'collection-doc'],
},
'sidebar',
'write', 'write',
'blog',
'document',
'locales', 'locales',
'deployment', 'deployment',
'optimize-build', 'optimize-build',

View File

@ -0,0 +1,20 @@
import type { ThemeCollectionItem } from 'vuepress-theme-plume'
import { defineCollection } from 'vuepress-theme-plume'
export const tools: ThemeCollectionItem = defineCollection({
type: 'doc',
dir: 'tools',
title: '工具',
linkPrefix: '/tools/',
sidebar: [
{
text: '工具',
icon: 'tabler:tools',
items: [
'custom-theme',
'home-hero-tint-plate',
'caniuse',
],
},
],
})

View File

@ -28,7 +28,7 @@ export default defineUserConfig({
['meta', { name: 'google-site-verification', content: 'AaTP7bapCAcoO9ZGE67ilpy99GL6tYqtD30tRHjO9Ps' }], ['meta', { name: 'google-site-verification', content: 'AaTP7bapCAcoO9ZGE67ilpy99GL6tYqtD30tRHjO9Ps' }],
], ],
pagePatterns: ['**/*.md', '!**/*.snippet.md', '!.vuepress', '!node_modules', '!docs/notes/theme/guide/代码演示/demo/*'], pagePatterns: ['**/*.md', '!**/*.snippet.md', '!.vuepress', '!node_modules', '!docs/guide/repl/demo/*'],
extendsBundlerOptions(bundlerOptions, app) { extendsBundlerOptions(bundlerOptions, app) {
addViteOptimizeDepsInclude(bundlerOptions, app, '@simonwep/pickr') addViteOptimizeDepsInclude(bundlerOptions, app, '@simonwep/pickr')

View File

@ -2,13 +2,7 @@ import type { LLMPage, LLMState } from '@vuepress/plugin-llms'
import type { ThemeSidebarItem } from 'vuepress-theme-plume' import type { ThemeSidebarItem } from 'vuepress-theme-plume'
import { generateTOCLink as rawGenerateTOCLink } from '@vuepress/plugin-llms' import { generateTOCLink as rawGenerateTOCLink } from '@vuepress/plugin-llms'
import { ensureEndingSlash, ensureLeadingSlash } from 'vuepress/shared' import { ensureEndingSlash, ensureLeadingSlash } from 'vuepress/shared'
import { zhNotes } from './notes/zh/index.js' import { zhCollections } from './collections/zh/index.js'
const noteNames = {
'/guide/': '指南',
'/config/': '配置',
'/tools/': '工具',
}
function normalizePath(prefix: string, path = ''): string { function normalizePath(prefix: string, path = ''): string {
if (path.startsWith('/')) if (path.startsWith('/'))
@ -79,9 +73,9 @@ export function tocGetter(llmPages: LLMPage[], llmState: LLMState): string {
} }
// Notes // Notes
zhNotes.notes.forEach(({ dir, link, sidebar = [] }) => { zhCollections.filter(note => note.type === 'doc').forEach(({ dir, title, sidebar = [] }) => {
tableOfContent += `### ${noteNames[link]}\n\n` tableOfContent += `### ${title}\n\n`
const prefix = normalizePath('/notes/', dir) const prefix = normalizePath(dir)
if (sidebar === 'auto') { if (sidebar === 'auto') {
tableOfContent += `${processAutoSidebar(prefix).join('')}\n` tableOfContent += `${processAutoSidebar(prefix).join('')}\n`
} }

View File

@ -6,13 +6,13 @@ export const zhNavbar: ThemeNavItem[] = defineNavbarConfig([
{ {
text: '指南', text: '指南',
icon: 'icon-park-outline:guide-board', icon: 'icon-park-outline:guide-board',
link: '/notes/theme/guide/quick-start/intro.md', link: '/guide/quick-start/intro.md',
activeMatch: '^/guide/', activeMatch: '^/guide/',
}, },
{ {
text: '配置', text: '配置',
icon: 'icon-park-outline:setting-two', icon: 'icon-park-outline:setting-two',
link: '/notes/theme/config/intro.md', link: '/config/intro.md',
activeMatch: '^/config/', activeMatch: '^/config/',
}, },
{ {

View File

@ -1,13 +0,0 @@
import type { ThemeNoteListOptions } from 'vuepress-theme-plume'
import { defineNotesConfig } from 'vuepress-theme-plume'
import { themeConfig } from './theme-config'
import { themeGuide } from './theme-guide'
export const enNotes: ThemeNoteListOptions = defineNotesConfig({
dir: 'en/notes',
link: '/',
notes: [
themeGuide,
themeConfig,
],
})

View File

@ -1,17 +0,0 @@
import type { ThemeNoteListOptions } from 'vuepress-theme-plume'
import { defineNotesConfig } from 'vuepress-theme-plume'
// import { plugins } from './plugins'
import { themeConfig } from './theme-config'
import { themeGuide } from './theme-guide'
import { tools } from './tools'
export const zhNotes: ThemeNoteListOptions = defineNotesConfig({
dir: 'notes',
link: '/',
notes: [
themeGuide,
themeConfig,
// plugins,
tools,
],
})

View File

@ -1,33 +0,0 @@
import type { ThemeNote } from 'vuepress-theme-plume'
import { defineNoteConfig } from 'vuepress-theme-plume'
export const plugins: ThemeNote = defineNoteConfig({
dir: 'plugins',
link: '/plugins/',
sidebar: [
{
text: '插件',
link: '/plugins/',
items: [
// 'caniuse',
// 'iconify',
'shiki',
'md-power',
'content-updated',
{
text: 'plugin-netlify-functions',
dir: 'netlify-functions',
link: '/plugins/plugin-netlify-functions/',
collapsed: true,
items: [
'介绍',
'使用',
'功能',
'api',
'functions',
],
},
],
},
],
})

View File

@ -1,18 +0,0 @@
import type { ThemeNote } from 'vuepress-theme-plume'
import { defineNoteConfig } from 'vuepress-theme-plume'
export const tools: ThemeNote = defineNoteConfig({
dir: 'tools',
link: '/tools/',
sidebar: [
{
text: '工具',
icon: 'tabler:tools',
items: [
'custom-theme',
'home-hero-tint-plate',
'caniuse',
],
},
],
})

View File

@ -1,8 +1,8 @@
import type { ThemeConfig } from 'vuepress-theme-plume' import type { ThemeConfig } from 'vuepress-theme-plume'
import path from 'node:path' import path from 'node:path'
import { defineThemeConfig } from 'vuepress-theme-plume' import { defineThemeConfig } from 'vuepress-theme-plume'
import { enCollections, zhCollections } from './collections/index.js'
import { enNavbar, zhNavbar } from './navbar.js' import { enNavbar, zhNavbar } from './navbar.js'
import { enNotes, zhNotes } from './notes/index.js'
export default defineThemeConfig({ export default defineThemeConfig({
logo: '/plume.png', logo: '/plume.png',
@ -27,12 +27,24 @@ export default defineThemeConfig({
locales: { locales: {
'/': { '/': {
notes: zhNotes, // notes: zhNotes,
navbar: zhNavbar, navbar: zhNavbar,
collections: [
// 博客
{ type: 'post', dir: '/blog/', link: '/blog/', title: '博客' },
// 文档
...zhCollections,
],
}, },
'/en/': { '/en/': {
notes: enNotes, // notes: enNotes,
navbar: enNavbar, navbar: enNavbar,
collections: [
// 博客
{ type: 'post', dir: '/blog/', link: '/blog/', title: 'Blog' },
// 文档
...enCollections,
],
}, },
}, },
@ -41,7 +53,6 @@ export default defineThemeConfig({
'/article/enx7c9s/': '123456', '/article/enx7c9s/': '123456',
}, },
}, },
autoFrontmatter: { exclude: ['**/*.snippet.*'] },
bulletin: { bulletin: {
layout: 'top-right', layout: 'top-right',

View File

@ -174,6 +174,7 @@ npm run docs:dev
'Hammuu1112', 'Hammuu1112',
'SherkeyXD', 'SherkeyXD',
{ github: 'Kinneyzhang', name: 'Geekinney' }, { github: 'Kinneyzhang', name: 'Geekinney' },
'huyunan',
]" ]"
/> />

View File

@ -590,7 +590,7 @@ export default config
**输出:** **输出:**
@[code](../notes/theme/snippet/snippet-1.js) @[code](../../snippet/snippet-1.js)
如果你只想导入这个文件的一部分: 如果你只想导入这个文件的一部分:

View File

@ -2,7 +2,6 @@
title: 1.0.0-rc.154 更新说明 title: 1.0.0-rc.154 更新说明
createTime: 2025/06/19 18:10:18 createTime: 2025/06/19 18:10:18
permalink: /article/yw0dmwcm/ permalink: /article/yw0dmwcm/
sticky: true
tags: tags:
- 破坏性更新 - 破坏性更新
--- ---

View File

@ -0,0 +1,188 @@
---
title: ⚠️ 1.0.0-rc.165 破坏性更新说明:博客与笔记功能迁移至“集合”
sticky: true
createTime: 2025/09/28 22:18:52
permalink: /blog/dk58a4t2/
tags:
- 破坏性更新
- 重要更新
---
:::important ‼️ 本次更新为破坏性更新!博客与笔记功能已整体迁移至全新的“集合”架构。‼️
:::
<!-- more -->
## 设计动机:为什么引入“集合”?
[跳转至迁移指南 👇👇👇](#迁移指南){.read-more}
### 背景与问题分析
主题最初仅支持**博客**功能,将 `docs` 源目录下的所有 Markdown 文件识别为博客文章。随着版本迭代,我们新增了**笔记/知识库**功能,默认将 `notes` 目录作为笔记根目录,并将其内容从博客列表中排除。
这种分阶段实现导致了**架构上的不平衡**:博客成为“一等公民”,而笔记功能则显得边缘化。这给用户带来了以下困扰:
- **路径冗余**:笔记文件必须存放在 `notes/` 目录下,增加了不必要的目录层级
- **链接复杂**:未开启 `autoFrontmatter`URL 会强制包含 `/notes/` 前缀
- **概念混淆**:用户常困惑于“笔记”与“文档”的功能区别
- **配置繁琐**:需要额外调整 `notes.dir` 配置才能实现标准文档站结构
这些设计缺陷源于历史迭代的遗留问题,我们对此深表歉意。
### 解决方案:统一的内容抽象
经过对主流静态站点生成器(如 Hugo、VitePress和全栈框架如 Nuxt的调研我们从 `@nuxt/content``collection` 概念中获得灵感。
我们决定引入**集合**作为统一的内容组织单元。无论是博客、笔记、文档还是知识库,本质上都是 Markdown 文件的特定集合,只是在呈现方式上有所差异。
:::important 核心洞察:通过“集合”抽象,统一各类内容的组织形式,同时保留各自的展示特性。
:::
基于内容特征,我们定义了两种集合类型:
- **`post` 类型**:适用于碎片化、关联性弱的内容(如博客、专栏),提供文章列表作为导航入口
- **`doc` 类型**:适用于结构化、关联性强的内容(如文档、手册),提供侧边栏进行快速导航
这一设计既解决了历史架构问题,又为未来扩展更多内容类型奠定了基础。
## 迁移指南
### 核心概念
- **集合**:通过 `collection.dir` 指定目录,该目录下所有 Markdown 文件均归属该集合
- **集合类型**
- `post`:碎片化内容,支持文章列表导航
- `doc`:结构化内容,支持侧边栏导航
### 配置迁移
替换原有的 `blog``notes` 配置:
```ts twoslash
// @noErrors
import { defineUserConfig } from 'vuepress'
import { plumeTheme } from 'vuepress-theme-plume'
export default defineUserConfig({
theme: plumeTheme({
// [!code --:9]
// 移除旧的 blog 和 notes 配置
blog: { /* 博客配置 */ },
notes: {
link: '/',
dir: '/notes/',
notes: [
{ dir: 'typescript', link: '/typescript/', sidebar: 'auto' }
]
},
// [!code ++:16]
// 使用 collections 配置
collections: [
{
type: 'post', // 替代原博客功能
dir: 'blog', // 指向 docs/blog 目录
title: '博客' // 集合显示名称
// 原博客配置继续保留
// ...
},
{
type: 'doc', // 替代原笔记功能
dir: 'typescript', // 指向 docs/typescript 目录
title: 'TypeScript笔记',
sidebar: 'auto', // 自动生成侧边栏
},
]
})
})
```
### 目录结构调整
按照以下步骤迁移文件:
**操作步骤:**
1. 将 `notes` 目录下的子目录直接移至 `docs` 根目录
2. 创建 `blog` 目录,将原博客文章移入其中
3. 移除空的 `notes` 目录
:::: flex
<div style="flex:1">
::: file-tree title="迁移前结构"
- docs
- -- notes
- typescript
- basic.md
- advanced.md
- blog-cate-1
- post-1.md
- blog-cate-2
- post-2.md
- blog-post.md
- README.md
:::
</div>
<div style="align-self: center"><Icon name="mingcute:arrow-right-fill" /></div>
<div style="flex:1">
:::file-tree title="迁移后结构"
- docs
- typescript
- basic.md
- advanced.md
- ++ blog
- blog-cate-1
- post-1.md
- blog-cate-2
- post-2.md
- blog-post.md
- README.md
:::
</div>
::::
### 帮助函数
- `defineCollection`:用于定义单个 collection 配置的帮助函数
- `defineCollections`:用于定义多个 collection 配置的帮助函数
```ts twoslash
import { defineCollection, defineCollections } from 'vuepress-theme-plume'
export const blog = defineCollection({
type: 'post',
dir: 'blog',
title: '博客'
})
export const typescript = defineCollection({
type: 'doc',
dir: 'typescript',
title: 'TypeScript笔记',
sidebar: 'auto'
})
export const collections = defineCollections([
blog,
typescript
])
```
## 详细文档
[集合文档](../../guide/quick-start/collection.md){.read-more}
[post 集合](../../guide/quick-start/collection-post.md){.read-more}
[doc 集合](../../guide/quick-start/collection-doc.md){.read-more}

528
docs/config/collections.md Normal file
View File

@ -0,0 +1,528 @@
---
title: 集合配置
createTime: 2025/09/28 14:00:06
permalink: /config/collections/
---
## 概述
**Collections集合** 是主题中用于组织和管理文档的核心概念。每个集合指向源目录下的特定文件夹,将其中的所有 Markdown 文件作为一个逻辑单元进行管理。
通过灵活的集合配置,您可以轻松构建多种内容体系:
- **博客** - 个人随笔与技术分享
- **专栏** - 专题系列文章
- **使用手册** - 产品使用文档
- **笔记** - 学习笔记与知识整理
- **产品文档** - 完整的项目文档
- **知识库** - 团队知识管理体系
集合主要分为两种类型,适应不同的内容组织需求:
- **`post` 类型**:适用于碎片化内容,文章间关联较弱,如博客、专栏等
- **`doc` 类型**:适用于结构化文档,内容关联紧密,如使用手册、产品文档、知识库等
::: tip 配置位置
集合配置支持在 `.vuepress/config.ts` 或独立的 `plume.config.ts` 文件中进行配置。
:::
## 基础配置
假设您的项目采用以下目录结构:
::: file-tree title="项目结构"
- docs
- **blog**
- post-1.md
- post-2.md
- **typescript**
- basic
- intro.md
- variable.md
- types.md
:::
对应的集合配置示例如下:
::: code-tabs#configs
@tab .vuepress/config.ts
```ts twoslash
import { defineUserConfig } from 'vuepress'
import { plumeTheme } from 'vuepress-theme-plume'
export default defineUserConfig({
theme: plumeTheme({
// 集合配置 // [!code focus:7]
collections: [
// 注册 post 类型集合,实现博客功能
{ type: 'post', dir: 'blog', title: '博客' },
// 注册 doc 类型集合,实现 TypeScript 文档功能
{ type: 'doc', dir: 'typescript', title: 'TypeScript笔记', sidebar: 'auto' }
],
})
})
```
@tab .vuepress/plume.config.ts
```ts twoslash
import { defineThemeConfig } from 'vuepress-theme-plume'
export default defineThemeConfig({
// 独立配置文件中的集合配置 // [!code focus:7]
collections: [
{ type: 'post', dir: 'blog', title: '博客' },
{ type: 'doc', dir: 'typescript', title: 'TypeScript笔记', sidebar: 'auto' }
],
})
```
:::
## 多语言配置
对于多语言项目,您可以在 `locales` 字段中为每种语言单独配置集合:
::: file-tree title="多语言项目结构"
- docs
- **blog/**
- post-1.md
- post-2.md
- **typescript/**
- basic
- intro.md
- variable.md
- types.md
- en
- **blog/**
- post-1.md
- post-2.md
- **typescript/**
- basic
- intro.md
- variable.md
- types.md
:::
::: code-tabs#configs
@tab .vuepress/config.ts
```ts
import { defineUserConfig } from 'vuepress'
import { plumeTheme } from 'vuepress-theme-plume'
export default defineUserConfig({
theme: plumeTheme({
locales: {
'/': {
// 中文集合配置 // [!code focus:4]
collections: [
{ type: 'post', dir: 'blog', title: '博客' },
{ type: 'doc', dir: 'typescript', title: 'TypeScript笔记', sidebar: 'auto' }
],
},
'/en/': {
// 英文集合配置 // [!code focus:4]
collections: [
{ type: 'post', dir: 'blog', title: 'Blog' },
{ type: 'doc', dir: 'typescript', title: 'TypeScript Note', sidebar: 'auto' }
],
}
}
})
})
```
@tab .vuepress/plume.config.ts
```ts
import { defineThemeConfig } from 'vuepress-theme-plume'
export default defineThemeConfig({
locales: {
'/': {
// 中文集合配置 // [!code focus:4]
collections: [
{ type: 'post', dir: 'blog', title: '博客' },
{ type: 'doc', dir: 'typescript', title: 'TypeScript笔记', sidebar: 'auto' }
],
},
'/en/': {
// 英文集合配置 // [!code focus:4]
collections: [
{ type: 'post', dir: 'blog', title: 'Blog' },
{ type: 'doc', dir: 'typescript', title: 'TypeScript Note', sidebar: 'auto' }
],
}
}
})
```
:::
## Post 集合详解
Post 集合专为博客、专栏等碎片化内容设计,提供完整的文章管理体系:
### 核心功能
- **文章列表页** - 支持文章置顶、封面图、摘要显示、个人信息等
- **文章分类页** - 基于目录结构自动生成分类
- **文章标签页** - 灵活的标签管理
- **文章归档页** - 按时间维度组织内容
### 配置示例
```ts twoslash
import { defineThemeConfig } from 'vuepress-theme-plume'
export default defineThemeConfig({
collections: [
// 博客集合配置
{
type: 'post',
dir: 'blog',
title: '博客',
link: '/blog/', // 列表页链接
linkPrefix: '/article/', // 文章链接前缀
postCover: 'top', // 封面图位置
autoFrontmatter: { permalink: true }, // 自动 frontmatter
},
// 面试专栏配置
{
type: 'post',
dir: 'interview',
title: '面试专栏',
link: '/interview/', // 列表页链接
}
]
})
```
## Doc 集合详解
Doc 集合适用于结构化文档,强调内容间的逻辑关系:
### 核心功能
- **侧边导航栏** - 提供清晰的文档结构导航
- **自动生成目录** - 基于文件结构智能生成侧边栏
- **多级嵌套支持** - 支持复杂的文档层次结构
### 配置示例
```ts twoslash
import { defineThemeConfig } from 'vuepress-theme-plume'
export default defineThemeConfig({
collections: [
// TypeScript 笔记 - 自动生成侧边栏
{
type: 'doc',
dir: 'typescript',
title: 'TypeScript笔记',
sidebar: 'auto'
},
// Python 笔记 - 手动配置侧边栏
{
type: 'doc',
dir: 'python',
title: 'Python 笔记',
sidebar: [
{ text: '基础语法', link: 'basic' },
{
text: 'API 文档',
items: [
{ text: 'asyncio', link: 'asyncio' }
]
},
'advanced' // 简写形式
]
}
]
})
```
## 配置类型声明
### 基础集合配置
```ts
/* 集合配置数组 */
type ThemeCollections = ThemeCollectionItem[]
/* 单个集合项 */
type ThemeCollectionItem = ThemePostCollection | ThemeDocCollection
/* 集合公共配置 */
interface ThemeBaseCollection {
/**
* 集合类型
* - `post`: 文章列表(博客、专栏)
* - `doc`: 结构化文档(笔记、知识库)
*/
type: 'post' | 'doc'
/**
* 文档目录(相对于源目录)
*/
dir: string
/**
* 文章链接前缀
*/
linkPrefix?: string
/**
* 集合标题(用于面包屑导航)
*/
title: string
/**
* 标签颜色主题
* @default 'colored'
*/
tagsTheme?: 'colored' | 'gray' | 'brand'
/**
* 自动生成 frontmatter
*/
autoFrontmatter?: AutoFrontmatterOptions | false
}
```
### Post 集合专用配置
```ts title="Post 集合配置"
interface ThemePostCollection extends ThemeBaseCollection {
type: 'post'
/**
* 包含文件规则glob 模式)
* @default ['**\/*.md']
*/
include?: string[]
/**
* 排除文件规则glob 模式)
* @default []
*/
exclude?: string[]
/**
* 分页配置
*/
pagination?: false | number | {
/**
* 每页文章数量
* @default 15
*/
perPage?: number
}
/**
* 文章列表页链接
* @default '/{dir}/'
*/
link?: string
/**
* 是否启用文章列表页
* @default true
*/
postList?: boolean
/**
* 是否启用标签页
* @default true
*/
tags?: boolean
/**
* 标签页链接
* @default '/{link}/tags/'
*/
tagsLink?: string
/**
* 标签页文本
*/
tagsText?: string
/**
* 是否启用归档页
* @default true
*/
archives?: boolean
/**
* 归档页链接
* @default '/{link}/archives/'
*/
archivesLink?: string
/**
* 归档页文本
*/
archivesText?: string
/**
* 是否启用分类功能
* @default true
*/
categories?: boolean
/**
* 分类页链接
* @default '/{link}/categories/'
*/
categoriesLink?: string
/**
* 分类页文本
*/
categoriesText?: string
/**
* 分类展开深度
* @default 'deep'
*/
categoriesExpand?: number | 'deep'
/**
* 分类列表转换函数
*/
categoriesTransform?: (categories: PostsCategoryItem[]) => PostsCategoryItem[]
/**
* 文章封面图配置
* @default 'right'
*/
postCover?: PostsCoverLayout | PostsCoverStyle
/**
* 个人信息配置
*/
profile?: ProfileOptions | false
/**
* 社交账号配置
*/
social?: SocialLink[] | false
}
/* 文章分类项 */
interface PostsCategoryItem {
id: string
sort: number
name: string
}
/* 封面图布局 */
type PostsCoverLayout = 'left' | 'right' | 'odd-left' | 'odd-right' | 'top'
/* 封面图样式 */
interface PostsCoverStyle {
layout?: PostsCoverLayout
ratio?: number | `${number}:${number}` | `${number}/${number}`
width?: number
compact?: boolean
}
/* 社交链接图标 */
type SocialLinkIcon = SocialLinkIconUnion | { svg: string, name?: string }
/* 社交链接 */
interface SocialLink {
icon: SocialLinkIcon
link: string
ariaLabel?: string
}
/**
* 个人资料
*/
export interface ProfileOptions {
/**
* 头像链接地址
*/
avatar?: string
/**
* 名称
*/
name?: string
/**
* 描述 / 简介 / 座右铭 / 签名
*/
description?: string
/**
* 是否显示为圆形头像
*/
circle?: boolean
/**
* 地理位置
*/
location?: string
/**
* 组织,公司
*/
organization?: string
/**
* 布局位置,左侧或者右侧
* @default 'right'
*/
layout?: 'left' | 'right'
}
```
### Doc 集合专用配置
```ts title="Doc 集合配置"
interface ThemeDocCollection extends ThemeBaseCollection {
type: 'doc'
/**
* 侧边栏配置
*/
sidebar?: 'auto' | (string | ThemeSidebarItem)[]
/**
* 是否显示侧边栏滚动条
* @default true
*/
sidebarScrollbar?: boolean
/**
* 侧边栏默认折叠状态
* @default false
*/
sidebarCollapsed?: boolean
}
/* 侧边栏项配置 */
interface ThemeSidebarItem {
text?: string
link?: string
icon?: ThemeIcon
badge?: string | ThemeBadge
items?: 'auto' | (string | ThemeSidebarItem)[]
collapsed?: boolean
prefix?: string
rel?: string
target?: string
}
/* 图标类型 */
type ThemeIcon = string | { svg: string }
/* 徽章配置 */
export interface ThemeBadge {
text?: string
type?: string
color?: string
bgColor?: string
borderColor?: string
}
```
### 自动侧边栏生成
将 Doc 集合的 `sidebar` 设置为 `'auto'` 时,系统会根据目录结构自动生成侧边栏导航。排序规则遵循[文件夹命名约定](../guide/quick-start/write.md#文件夹命名约定)。
### 侧边栏图标配置
主题支持两种方式配置侧边栏图标:
- **在侧边栏配置中直接定义**
```ts
sidebar: [
{ text: '介绍', link: 'intro', icon: 'mdi:tooltip-text-outline' }
]
```
- **在文档 frontmatter 中定义**
```md
---
title: 主题介绍
icon: mdi:tooltip-text-outline
---
```
两种方式具有相同的效果,您可以根据具体场景选择使用。
如需了解侧边栏的完整配置选项和使用技巧,请参阅[侧边栏配置指南](../guide/quick-start/sidebar.md)。

173
docs/config/intro.md Normal file
View File

@ -0,0 +1,173 @@
---
title: 配置说明
createTime: 2024/03/02 10:48:14
permalink: /config/intro/
---
## 概述
==vuepress-theme-plume== 是基于 [VuePress](https://v2.vuepress.vuejs.org/) 开发的主题,其配置完全遵循 VuePress 的配置规范。
**VuePress 提供三种配置类型:**
- **站点配置**:在配置文件(如 `.vuepress/config.ts`)中直接导出的对象
- **主题配置**:传递给 `plumeTheme()` 函数的参数对象
- **页面配置**:基于 YAML 语法在页面 Frontmatter 中定义
## VuePress 配置文件
VuePress 的基础配置文件通常是 `.vuepress/config.js`,同时也支持 TypeScript 配置文件。使用 `.vuepress/config.ts` 可以获得更完善的类型提示。
VuePress 按以下优先顺序解析配置文件:
**当前工作目录 (cwd) 下:**
- `vuepress.config.ts`
- `vuepress.config.js`
- `vuepress.config.mjs`
**源文件目录 (sourceDir) 下:**
- `.vuepress/config.ts` <Badge type="tip" text="推荐使用" />
- `.vuepress/config.js`
- `.vuepress/config.mjs`
**基础配置示例:**
```ts title=".vuepress/config.ts" twoslash
import { viteBundler } from '@vuepress/bundler-vite'
import { defineUserConfig } from 'vuepress'
import { plumeTheme } from 'vuepress-theme-plume'
export default defineUserConfig({
// [!code hl:5]
// VuePress 基础配置
lang: 'zh-CN',
title: '你好, VuePress ',
description: '这是我的第一个 VuePress 站点',
// ...
// 使用 Vite 作为构建工具
bundler: viteBundler(),
// 启用 Plume 主题
theme: plumeTheme({ // [!code ++:4]
// 主题配置项
// ...
}),
})
```
## 主题配置文件
通常我们在 `.vuepress/config.ts` 中配置主题:
```ts title=".vuepress/config.ts" twoslash
import { defineUserConfig } from 'vuepress'
import { plumeTheme } from 'vuepress-theme-plume'
export default defineUserConfig({
theme: plumeTheme({
// 主题配置
}),
// ...
})
```
然而,修改此文件会导致 VuePress 服务重启并全量刷新。对于小型站点,这个过程很快;但对于内容较多的站点,每次重启都需要较长时间。
频繁修改配置文件还容易导致 VuePress ==服务崩溃=={.caution} ::twemoji:angry-face::,需要手动重启服务,严重影响内容编写效率。
**解决方案:主题热更新配置**
主题提供了 `plume.config.ts` 配置文件,==对该文件的修改支持热更新,无需重启服务=={.tip} ::twemoji:confetti-ball::。
你可以在其中配置支持热更新的字段,如 `navbar``profile` 等。
::: tip
这些字段仍可在 VuePress 配置文件的 `theme` 中配置,但主题配置文件的设置最终会合并到主配置中。
为避免数据重复,请勿在两地同时配置同一字段。
:::
::: details 什么是热更新?
**热更新** 是一种开发技术,在 VuePress 中体现为:
- 配置修改实时生效,无需重启服务,浏览器不刷新页面
- 页面修改实时生效,浏览器无刷新更新内容
:::
### 配置方法
在 VuePress 配置文件同级目录下创建 `plume.config.ts` 文件:
::: file-tree
- docs
- .vuepress
- config.ts
- **plume.config.ts**
:::
```ts title="plume.config.ts" twoslash
// @filename: ./navbar.ts
export default []
// ---cut---
import { defineThemeConfig } from 'vuepress-theme-plume'
import navbar from './navbar'
export default defineThemeConfig({
// 主题配置
profile: {
name: 'Your name',
},
navbar,
})
```
`defineThemeConfig(config)` 函数提供完整的类型提示。除 `plugins` 外,大多数配置都可在此文件中定义。
::: warning 注意事项
- 主题配置文件仅支持部分热更新字段
- 避免在 VuePress 配置文件中重复配置已在主题配置文件中设置的字段
:::
### 自定义配置文件路径
如需使用非默认路径,可在 VuePress 配置中指定:
```ts title=".vuepress/config.ts" twoslash
import path from 'node:path'
import { defineUserConfig } from 'vuepress'
import { plumeTheme } from 'vuepress-theme-plume'
export default defineUserConfig({
theme: plumeTheme({
// 自定义配置文件路径
configFile: path.join(__dirname, 'custom/config.ts'), // [!code ++]
}),
})
```
::: warning 新手不建议自定义路径,可能引发意外问题
:::
## 页面配置
通过页面顶部的 YAML Frontmatter可为每个页面单独配置主题
```md {1,5} title="article.md"
---
title: 文章标题
createTime: 2024/09/08 22:53:34
permalink: /article/xxx/
---
```
在 Markdown 文件顶部,使用 `---` 分隔符包裹的部分即为 Frontmatter采用 YAML 语法配置。
:::tip 如需了解 YAML 基础语法,可参考[这篇博客](/article/ecxnxxd0/)
:::

View File

@ -19,6 +19,7 @@ permalink: /config/locales/
- 德语 (`de-DE`) - `/de/` - 德语 (`de-DE`) - `/de/`
- 俄语 (`ru-RU`) - `/ru/` - 俄语 (`ru-RU`) - `/ru/`
- 日语 (`ja-JP`) - `/ja/` - 日语 (`ja-JP`) - `/ja/`
- 韩语 (`ko-KR`) - `/ko/`
## 配置 ## 配置
@ -110,14 +111,14 @@ export default defineThemeConfig({
- 主题默认导航栏中的首页链接的文本。 - 主题默认导航栏中的首页链接的文本。
- 面包屑导航中的首页链接的文本。 - 面包屑导航中的首页链接的文本。
### blogText ### postsText
- 类型: `string` - 类型: `string`
- 默认值: `'Blog'` - 默认值: `'Posts'`
- 详情: 博客链接的文本。 - 详情: 文章列表页链接的文本。
- 主题默认导航栏中的博客链接的文本。 - 主题默认导航栏中的文章列表页链接的文本。
- 面包屑导航中的博客链接的文本。 - 面包屑导航中的文章列表页链接的文本。
### tagText ### tagText

View File

@ -9,7 +9,7 @@ permalink: /config/navigation/
::: tip 导航栏配置支持在 `.vuepress/config.ts` ,或者在 `plume.config.ts` 中进行配置。 ::: tip 导航栏配置支持在 `.vuepress/config.ts` ,或者在 `plume.config.ts` 中进行配置。
::: :::
主题默认会自动生成最简单的导航栏配置,仅包括 **首页****博客文章列表页** 。 主题默认会自动生成最简单的导航栏配置,仅包括 **首页****文章列表页** 。
你也可以自己配置导航栏,覆盖默认的的导航栏配置。 你也可以自己配置导航栏,覆盖默认的的导航栏配置。
@ -87,7 +87,7 @@ export default defineUserConfig({
}) })
``` ```
随着站点内容变得越来越丰富,包括了 博客文章列表、notes、友情链接、 外部链接等等, 随着站点内容变得越来越丰富,如通过 集合 配置了 博客、笔记、文档、友情链接、 外部链接等等,
默认生成的导航栏配置满足不了您的需求。 默认生成的导航栏配置满足不了您的需求。
这时候,您可以通过 `navbar` 字段来完全自定义导航栏,它将直接覆盖默认的导航栏配置。 这时候,您可以通过 `navbar` 字段来完全自定义导航栏,它将直接覆盖默认的导航栏配置。

115
docs/config/sidebar.md Normal file
View File

@ -0,0 +1,115 @@
---
title: 侧边栏配置
createTime: 2024/08/15 21:05:36
permalink: /config/sidebar/
---
## 概述
侧边栏是主题中位于页面最左侧的核心导航区域,承担着引导用户在不同页面间跳转的重要功能。
在 VuePress 生态中,默认主题 `@vuepress/theme-default` 通过 `sidebar` 配置项管理侧边栏。本主题在保留这一经典配置方式的基础上还提供了更为灵活的集合Collections级侧边栏配置方案。
## 集合级侧边栏配置
集合Collections是主题中组织系列文档的核心概念。当集合类型设置为 `doc` 时,您可以在 `collection.sidebar` 中定义专属的侧边栏导航。
以下示例展示了如何在 `docs` 目录下创建类型为 `doc` 的集合,并配置其侧边栏:
::: code-tabs#configs
@tab .vuepress/config.ts
```ts twoslash
import { defineUserConfig } from 'vuepress'
import { defineCollection, plumeTheme } from 'vuepress-theme-plume'
// 定义文档集合配置 // [!code hl:10]
const demo = defineCollection({
type: 'doc',
dir: 'demo', // 文档目录
title: 'Demo', // 集合名称
sidebar: [ // 侧边栏配置 // [!code ++:4]
{ text: 'one item', link: 'one' },
{ text: 'two item', link: 'two' },
]
})
export default defineUserConfig({
theme: plumeTheme({
collections: [demo], // 注册集合 // [!code hl]
})
})
```
@tab .vuepress/plume.config.ts
```ts twoslash
import { defineCollection, defineThemeConfig } from 'vuepress-theme-plume'
// 使用独立配置文件定义集合 // [!code hl:10]
const demo = defineCollection({
type: 'doc',
dir: 'demo',
title: 'Demo',
sidebar: [
{ text: 'one item', link: 'one' },
{ text: 'two item', link: 'two' },
]
})
export default defineThemeConfig({
collections: [demo], // [!code hl]
})
```
:::
主题提供的 `defineCollection` 工具函数简化了集合配置过程。如需了解完整的集合配置选项,请参阅[集合配置文档](./collections.md)。
## 全局侧边栏配置
如果您希望采用传统的全局配置方式管理侧边栏,可以直接在主题配置中使用 `sidebar` 选项。这种方式适合不需要按集合分组导航的场景。
::: code-tabs#configs
@tab .vuepress/config.ts
```ts twoslash
import { defineUserConfig } from 'vuepress'
import { plumeTheme } from 'vuepress-theme-plume'
export default defineUserConfig({
theme: plumeTheme({
// 全局侧边栏配置 // [!code hl:7]
sidebar: {
'/config/': [ // 匹配/config/路径
{ text: '侧边栏配置', link: 'sidebar-1' },
{ text: '侧边栏配置', link: 'sidebar-2' },
]
}
})
})
```
@tab .vuepress/plume.config.ts
```ts twoslash
import { defineThemeConfig } from 'vuepress-theme-plume'
export default defineThemeConfig({
// 在独立配置文件中定义全局侧边栏 // [!code hl:7]
sidebar: {
'/config/': [
{ text: '侧边栏配置', link: 'sidebar-1' },
{ text: '侧边栏配置', link: 'sidebar-2' },
]
}
})
```
:::
两种配置方式各有优势:集合级配置适合模块化文档结构,全局配置则便于统一管理简单项目的导航。
如需了解侧边栏的完整配置选项和使用技巧,请参阅[侧边栏配置指南](../guide/quick-start/sidebar.md)。

View File

@ -177,165 +177,6 @@ export default defineThemeConfig({
::: warning 该字段不支持在 [主题配置文件 `plume.config.js`](./intro.md#主题配置文件) 中进行配置。 ::: warning 该字段不支持在 [主题配置文件 `plume.config.js`](./intro.md#主题配置文件) 中进行配置。
::: :::
### blog
- **类型:** `false | BlogOptions`
- **默认值:** `{ link: '/blog/', include: ['**/*.md'], exclude: [] }`
- **详情:**
博客配置。
::: warning 该字段不支持在 [主题配置文件 `plume.config.js`](./intro.md#主题配置文件) 中进行配置。
:::
```ts
interface BlogOptions {
/**
* blog list link
*
* @default '/blog/'
*/
link?: string
/**
* 在 `{sourceDir}` 目录中,通过 glob string 配置包含文件
*
* @default - ['**\*.md']
*/
include?: string[]
/**
* 在 `{sourceDir}` 目录中,通过 glob string 配置排除的文件
*
* @default - ['.vuepress/', 'node_modules/']
*/
exclude?: string[]
/**
* 分页配置
*
* - `false` - 不启用分页
* - `number` - 每页显示的文章数量
*/
pagination?: false | number | {
/**
* 每页显示的文章数量
* @default 10
*/
perPage?: number
}
/**
* 是否启用标签页
* @default true
*/
tags?: boolean
/**
* 自定义标签页链接
*
* @default '/blog/tags/'
*/
tagsLink?: string
/**
* 标签颜色主题
*
* - `colored` 彩色标签,不同标签颜色不同
* - `brand`: 使用主题颜色作为标签颜色
* - `gray`: 使用 灰色 作为标签颜色
*
* @default 'colored'
*/
tagsTheme?: 'colored' | 'gray' | 'brand'
/**
* 是否启用归档页
* @default true
*/
archives?: boolean
/**
* 自定义归档页链接
*
* @default '/blog/archives/'
*/
archivesLink?: string
/**
* 是否启用分类页
* @default true
*/
categories?: boolean
/**
* 自定义分类页链接
*
* @default '/blog/categories/'
*/
categoriesLink?: string
/**
* 分类页展开深度
*
* @default 'deep'
*/
categoriesExpand?: number | 'deep'
/**
* 文章分类列表转换函数,比如排除不需要的一级分类
* @param categories 分类列表
* @returns 返回一个新的分类列表
*/
categoriesTransform?: (categories: PageCategoryData[]) => PageCategoryData[]
/**
* 博客文章封面图
*
* 配置封面图的位置,支持 `'left'``'right'``'top'``'top-inside'`
*
* @default 'right'
*/
postCover?: BlogPostCoverLayout | BlogPostCoverStyle
}
type BlogPostCoverLayout = 'left' | 'right' | 'odd-left' | 'odd-right' | 'top'
interface BlogPostCoverStyle {
/**
* 博客文章封面图的位置
*/
layout?: BlogPostCoverLayout
/**
* 博客文章封面图的比例
*
* @default '4:3'
*/
ratio?: number | `${number}:${number}`
/**
* 封面图的宽度, 仅在 layout 为 'left' 或 'right' 时生效
*
* @default 240
*/
width?: number
/**
* 是否使用紧凑模式,紧凑模式下,封面图紧贴容器边缘
* @default false
*/
compact?: boolean
}
```
### article
- **类型:** `string`
- **默认值:** `/article/`
- **详情:** 文章链接前缀
::: warning 该字段不支持在 [主题配置文件 `plume.config.js`](./intro.md#主题配置文件) 中进行配置。
:::
### autoFrontmatter ### autoFrontmatter
- **类型:** `false | AutoFrontmatterOptions` - **类型:** `false | AutoFrontmatterOptions`
@ -345,18 +186,6 @@ interface BlogPostCoverStyle {
```ts ```ts
interface AutoFrontmatterOptions { interface AutoFrontmatterOptions {
/**
* glob 匹配,被匹配的文件将会自动生成 frontmatter
*
* @default ['**\/*.md']
*/
include?: string | string[]
/**
* glob 匹配,被匹配的文件将不会自动生成 frontmatter
*/
exclude?: string | string[]
/** /**
* 是否自动生成 permalink * 是否自动生成 permalink
* *
@ -714,27 +543,13 @@ type NavItem = string | {
}) })
``` ```
### notes
- **类型:** `false | NotesOptions`
- **默认值:** `{ link: '/note', dir: 'notes', notes: [] }`
- **详情:**
笔记配置, 笔记中的文章默认不会出现在首页文章列表
你可以将配置的notes 配置到 navbar中以便浏览查看
详细配置请查看 [此文档](./notes.md)
### sidebar ### sidebar
- **类型:** `false | SidebarMulti` - **类型:** `false | SidebarMulti`
- **详情:** - **详情:**
侧边栏配置。**主题更推荐在 [notes 配置](./notes.md) 中进行侧边栏配置。** 侧边栏配置。**主题更推荐在 [collections 配置](./collections.md) 中进行侧边栏配置。**
当你不希望使用 `notes` 功能,但又期望给文档增加侧边栏时,可以使用此配置。
配置对象的 `key` 为侧边栏公共访问路径前缀。 配置对象的 `key` 为侧边栏公共访问路径前缀。
@ -775,9 +590,7 @@ interface SidebarItem {
/** /**
* 如果未指定,组不可折叠。 * 如果未指定,组不可折叠。
*
* 如果为`true`,组可折叠,并默认折叠。 * 如果为`true`,组可折叠,并默认折叠。
*
* 如果为`false`,组可折叠,但默认展开。 * 如果为`false`,组可折叠,但默认展开。
*/ */
collapsed?: boolean collapsed?: boolean
@ -909,10 +722,10 @@ interface SidebarItem {
### createTime ### createTime
- **类型:** `boolean | 'only-blog'` - **类型:** `boolean | 'only-posts'`
- **默认值:** `true` - **默认值:** `true`
- **详情:** 是否显示创建时间 - **详情:** 是否显示创建时间
- `false` - 不显示 - `false` - 不显示
- `'only-blog'` - 只显示在博客文章页面 - `'only-posts'` - 只显示在文章列表页面
- `true` - 显示在所有文章页面 - `true` - 显示在所有文章页面

Some files were not shown because too many files have changed in this diff Show More