From 5a600048d502f633d89cd2526b2b72658abae375 Mon Sep 17 00:00:00 2001 From: pengzhanbo Date: Mon, 8 Jul 2024 02:40:54 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E6=94=B9=E8=BF=9B=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- theme/src/shared/auto-frontmatter.ts | 40 +++++++++++++++++++ theme/src/shared/base.ts | 2 + theme/src/shared/blog.ts | 23 +++++++---- theme/src/shared/index.ts | 3 ++ theme/src/shared/navbar.ts | 58 ++++++++++++++++++++++++---- theme/src/shared/notes.ts | 37 ++++++++++++++++++ theme/src/shared/options/index.ts | 16 ++++++-- theme/src/shared/options/locale.ts | 10 ++++- theme/src/shared/options/plugins.ts | 7 +++- theme/src/shared/resolved/navbar.ts | 39 +++++++++++++++++++ theme/src/shared/resolved/sidebar.ts | 52 +++++++++++++++++++++++++ theme/src/shared/sidebar.ts | 54 ++++++++++++++++++++++++++ theme/src/shared/theme-data.ts | 19 +++++++++ 13 files changed, 337 insertions(+), 23 deletions(-) create mode 100644 theme/src/shared/auto-frontmatter.ts create mode 100644 theme/src/shared/notes.ts create mode 100644 theme/src/shared/resolved/navbar.ts create mode 100644 theme/src/shared/resolved/sidebar.ts create mode 100644 theme/src/shared/sidebar.ts create mode 100644 theme/src/shared/theme-data.ts diff --git a/theme/src/shared/auto-frontmatter.ts b/theme/src/shared/auto-frontmatter.ts new file mode 100644 index 00000000..d8f83b79 --- /dev/null +++ b/theme/src/shared/auto-frontmatter.ts @@ -0,0 +1,40 @@ +import type { Stats } from 'node:fs' + +export interface AutoFrontmatterMarkdownFile { + filepath: string + relativePath: string + content: string + createTime: Date + stats: Stats +} + +export type FrontmatterFn = ( + value: T, + file: AutoFrontmatterMarkdownFile, + data: K +) => T | PromiseLike + +export type AutoFrontmatterObject = Record> + +export type AutoFrontmatterArray = { + include: string | string[] + frontmatter: AutoFrontmatterObject +}[] + +export interface AutoFrontmatter { + /** + * FilterPattern + */ + include?: string | string[] + + exclude?: string | string[] + + /** + * { + * key(value, file, data) { + * return value + * } + * } + */ + frontmatter?: AutoFrontmatterArray | AutoFrontmatterObject +} diff --git a/theme/src/shared/base.ts b/theme/src/shared/base.ts index 6b9bf943..7b4c712d 100644 --- a/theme/src/shared/base.ts +++ b/theme/src/shared/base.ts @@ -3,6 +3,8 @@ export type ThemeImage = | { src: string, alt?: string } | { dark: string, light: string, alt?: string } +export type ThemeIcon = string | { svg: string } + export type ThemeColor = string | { light: string, dark: string } export type ThemeOutline = false | number | [number, number] | 'deep' diff --git a/theme/src/shared/blog.ts b/theme/src/shared/blog.ts index 1b8a72e0..339a6292 100644 --- a/theme/src/shared/blog.ts +++ b/theme/src/shared/blog.ts @@ -1,10 +1,12 @@ -import type { BlogPostDataItem } from '@vuepress-plume/plugin-blog-data' import type { PageCategoryData } from './page-data.js' -export interface PlumeThemeBlogPostItem extends BlogPostDataItem { - tags: string[] - sticky: boolean - categoryList: PageCategoryData[] +export interface PlumeThemeBlogPostItem { + title: string + excerpt: string + path: string + tags?: string[] + sticky?: boolean | number + categoryList?: PageCategoryData[] createTime: string lang: string encrypt?: boolean @@ -15,16 +17,21 @@ export type PlumeThemeBlogPostData = PlumeThemeBlogPostItem[] export interface PlumeThemeBlog { /** - * blog list link + * 博客文章列表页链接 * * @default '/blog/' */ link?: string /** - * 通过 glob string 配置包含文件 + * 通过 glob string 配置包含文件, * - * @default - ['**\*.md'] + * 默认读取 源目录中的所有 `.md` 文件,但会排除 `notes` 配置中用于笔记的目录。 + * + * 如果希望只将某个目录下的文章读取为博客文章,比如 `blog` 目录,可以配置为: + * `['blog/**\/*.md']` + * + * @default - ['**\/*.md'] */ include?: string[] diff --git a/theme/src/shared/index.ts b/theme/src/shared/index.ts index 0cbe809d..6a5e025d 100644 --- a/theme/src/shared/index.ts +++ b/theme/src/shared/index.ts @@ -3,4 +3,7 @@ export * from './frontmatter/index.js' export * from './options/index.js' export * from './page-data.js' export * from './blog.js' +export * from './sidebar.js' export * from './navbar.js' +export * from './notes.js' +export * from './auto-frontmatter.js' diff --git a/theme/src/shared/navbar.ts b/theme/src/shared/navbar.ts index 5f812131..6e628efc 100644 --- a/theme/src/shared/navbar.ts +++ b/theme/src/shared/navbar.ts @@ -1,33 +1,75 @@ -export type NavItem = NavItemWithLink | NavItemWithChildren +import type { ThemeIcon } from './base.js' + +export type NavItem = string | NavItemWithLink | NavItemWithChildren export interface NavItemWithLink { + /** + * 导航文本 + */ text: string + /** + * 导航链接 + */ link: string - icon?: string | { svg: string } - rel?: string - target?: string + /** + * 导航图标 + */ + icon?: ThemeIcon + + prefix?: never + items?: never /** * `activeMatch` is expected to be a regex string. We can't use actual * RegExp object here because it isn't serializable */ activeMatch?: string + rel?: string + target?: string + noIcon?: boolean } export interface NavItemChildren { + /** + * 下拉菜单的文本 + */ text?: string - icon?: string | { svg: string } - items: NavItemWithLink[] + + /** + * + * 当前分组的页面前缀 + */ + prefix?: string + + /** + * 导航栏下拉菜单 + */ + items: (string | NavItemWithLink)[] } export interface NavItemWithChildren { text?: string - icon?: string | { svg: string } - items: (NavItemChildren | NavItemWithLink)[] + /** + * 当前分组的页面前缀 + */ + prefix?: string + + /** + * 导航图标 + */ + icon?: ThemeIcon + + /** + * 导航栏下拉菜单 + */ + items: (string | NavItemChildren | NavItemWithLink)[] /** * `activeMatch` is expected to be a regex string. We can't use actual * RegExp object here because it isn't serializable + * + * `activeMatch` 应为正则表达式字符串,但必须将其定义为字符串。 + * 我们不能在这里使用实际的 RegExp 对象,因为它在构建期间不可序列化。 */ activeMatch?: string } diff --git a/theme/src/shared/notes.ts b/theme/src/shared/notes.ts new file mode 100644 index 00000000..2219a337 --- /dev/null +++ b/theme/src/shared/notes.ts @@ -0,0 +1,37 @@ +import type { SidebarItem } from './sidebar.js' + +export interface NotesOptions { + /** + * 保存所有笔记的目录 + * @default '/notes/' + */ + dir: string + /** + * 所有笔记的默认链接前缀 + * @default '/' + */ + link: string + /** + * 笔记配置 + */ + notes: NoteItem[] +} + +export interface NoteItem { + /** + * 保存笔记的目录 + */ + dir: string + /** + * 当前笔记的链接前缀,将会与 `notes.link` 合并 + */ + link: string + /** + * 当前笔记名称 + */ + text?: string + /** + * 当前笔记的侧边栏配置 + */ + sidebar?: 'auto' | (string | SidebarItem)[] +} diff --git a/theme/src/shared/options/index.ts b/theme/src/shared/options/index.ts index 0d1147f4..8181f71c 100644 --- a/theme/src/shared/options/index.ts +++ b/theme/src/shared/options/index.ts @@ -1,4 +1,5 @@ -import type { ThemeData } from '@vuepress/plugin-theme-data' +import type { LocaleConfig } from 'vuepress/shared' +import type { AutoFrontmatter } from '../auto-frontmatter.js' import type { PlumeThemeLocaleData } from './locale.js' import type { PlumeThemePluginOptions } from './plugins.js' import type { PlumeThemeEncrypt } from './encrypt.js' @@ -23,15 +24,24 @@ export interface PlumeThemeOptions extends PlumeThemeLocaleOptions { hostname?: string /** - * 加密 + * 加密配置 */ encrypt?: PlumeThemeEncrypt + /** + * 自定义主题配置文件路径 + */ + configFile?: string + + autoFrontmatter?: false | Omit + } export type PlumeThemeLocaleOptions = PlumeThemeData -export type PlumeThemeData = ThemeData +export type PlumeThemeData = PlumeThemeLocaleData & { + locales?: LocaleConfig> +} export * from './locale.js' export * from './plugins.js' diff --git a/theme/src/shared/options/locale.ts b/theme/src/shared/options/locale.ts index 167f880a..47af52a4 100644 --- a/theme/src/shared/options/locale.ts +++ b/theme/src/shared/options/locale.ts @@ -1,8 +1,9 @@ import type { LocaleData } from 'vuepress/core' -import type { NotesDataOptions } from '@vuepress-plume/plugin-notes-data' import type { SocialLink, SocialLinkIconUnion, ThemeOutline, ThemeTransition } from '../base.js' import type { PlumeThemeBlog } from '../blog.js' import type { NavItem } from '../navbar.js' +import type { SidebarMulti } from '../sidebar.js' +import type { NotesOptions } from '../notes.js' export interface PlumeThemeLocaleData extends LocaleData { /** @@ -77,7 +78,12 @@ export interface PlumeThemeLocaleData extends LocaleData { * * 注:也可以将notes配置到navbar中 */ - notes?: false | NotesDataOptions + notes?: false | NotesOptions + + /** + * 侧边栏配置 + */ + sidebar?: SidebarMulti /** * 要显示的标题级别。 diff --git a/theme/src/shared/options/plugins.ts b/theme/src/shared/options/plugins.ts index 4df5c49a..1daa63fa 100644 --- a/theme/src/shared/options/plugins.ts +++ b/theme/src/shared/options/plugins.ts @@ -1,6 +1,5 @@ import type { DocsearchOptions } from '@vuepress/plugin-docsearch' import type { SearchPluginOptions } from '@vuepress-plume/plugin-search' -import type { AutoFrontmatterOptions } from '@vuepress-plume/plugin-auto-frontmatter' import type { BaiduTongjiOptions } from '@vuepress-plume/plugin-baidu-tongji' import type { ShikiPluginOptions } from '@vuepress-plume/plugin-shikiji' import type { CommentPluginOptions } from '@vuepress/plugin-comment' @@ -8,6 +7,7 @@ import type { MarkdownEnhancePluginOptions } from 'vuepress-plugin-md-enhance' import type { ReadingTimePluginOptions } from '@vuepress/plugin-reading-time' import type { MarkdownPowerPluginOptions } from 'vuepress-plugin-md-power' import type { WatermarkPluginOptions } from '@vuepress/plugin-watermark' +import type { AutoFrontmatter } from '../auto-frontmatter.js' export interface PlumeThemePluginOptions { /** @@ -59,7 +59,10 @@ export interface PlumeThemePluginOptions { baiduTongji?: false | BaiduTongjiOptions - frontmatter?: Omit + /** + * @deprecated 使用 `autoFrontmatter` 代替 + */ + frontmatter?: Omit readingTime?: false | ReadingTimePluginOptions diff --git a/theme/src/shared/resolved/navbar.ts b/theme/src/shared/resolved/navbar.ts new file mode 100644 index 00000000..39833535 --- /dev/null +++ b/theme/src/shared/resolved/navbar.ts @@ -0,0 +1,39 @@ +import type { ThemeIcon } from '../base.js' + +export type ResolvedNavItem = + | ResolvedNavItemWithLink + | ResolvedNavItemWithChildren + +export interface ResolvedNavItemWithLink { + text: string + link: string + icon?: ThemeIcon + items?: never + + /** + * `activeMatch` is expected to be a regex string. We can't use actual + * RegExp object here because it isn't serializable + */ + activeMatch?: string + rel?: string + target?: string + noIcon?: boolean +} + +export interface ResolvedNavItemChildren { + text?: string + icon?: ThemeIcon + items: ResolvedNavItemWithLink[] +} + +export interface ResolvedNavItemWithChildren { + text?: string + icon?: ThemeIcon + items: (ResolvedNavItemChildren | ResolvedNavItemWithLink)[] + + /** + * `activeMatch` is expected to be a regex string. We can't use actual + * RegExp object here because it isn't serializable + */ + activeMatch?: string +} diff --git a/theme/src/shared/resolved/sidebar.ts b/theme/src/shared/resolved/sidebar.ts new file mode 100644 index 00000000..3e2f5f12 --- /dev/null +++ b/theme/src/shared/resolved/sidebar.ts @@ -0,0 +1,52 @@ +import type { ThemeIcon } from '../base.js' + +export type ResolvedSidebar = ResolvedSidebarItem[] | ResolvedSidebarMulti + +export type ResolvedSidebarMulti = Record< + string, + ResolvedSidebarItem[] | { items: ResolvedSidebarItem[] } +> + +export interface ResolvedSidebarItem { + /** + * 侧边栏文本 + */ + text?: string + + /** + * 侧边栏链接 + */ + link?: string + + /** + * 侧边栏图标 + */ + icon?: ThemeIcon + + /** + * 次级侧边栏分组 + */ + items?: ResolvedSidebarItem[] + + /** + * 如果未指定,组不可折叠。 + * + * 如果为`true`,组可折叠,并默认折叠。 + * + * 如果为`false`,组可折叠,但默认展开。 + */ + collapsed?: boolean + + /** + * 当前分组的链接前缀 + */ + prefix?: string + + /** + * @deprecated 使用 `prefix` 替代 + */ + dir?: string + + rel?: string + target?: string +} diff --git a/theme/src/shared/sidebar.ts b/theme/src/shared/sidebar.ts new file mode 100644 index 00000000..1e9b179c --- /dev/null +++ b/theme/src/shared/sidebar.ts @@ -0,0 +1,54 @@ +import type { ThemeIcon } from './base.js' + +export type Sidebar = 'auto' | (string | SidebarItem)[] | SidebarMulti + +export type SidebarMulti = Record< + string, + | 'auto' + | (string | SidebarItem)[] + | { items: 'auto' | (string | SidebarItem)[], prefix?: string } +> + +export interface SidebarItem { + /** + * 侧边栏文本 + */ + text?: string + + /** + * 侧边栏链接 + */ + link?: string + + /** + * 侧边栏图标 + */ + icon?: ThemeIcon + + /** + * 次级侧边栏分组 + */ + items?: 'auto' | (string | SidebarItem)[] + + /** + * 如果未指定,组不可折叠。 + * + * 如果为`true`,组可折叠,并默认折叠。 + * + * 如果为`false`,组可折叠,但默认展开。 + */ + collapsed?: boolean + + /** + * 当前分组的链接前缀 + */ + prefix?: string + + /** + * @deprecated 使用 `prefix` 替代 + */ + dir?: string + + rel?: string + target?: string +} diff --git a/theme/src/shared/theme-data.ts b/theme/src/shared/theme-data.ts new file mode 100644 index 00000000..6491bc01 --- /dev/null +++ b/theme/src/shared/theme-data.ts @@ -0,0 +1,19 @@ +import type { LocaleConfig } from 'vuepress/shared' +import type { PlumeThemeLocaleData } from './options/locale.js' +import type { PlumeThemeEncrypt } from './options/encrypt.js' +import type { AutoFrontmatter } from './auto-frontmatter.js' + +export type ThemeConfig = PlumeThemeLocaleData & { + + locales?: LocaleConfig> + + /** + * 自动插入 frontmatter + */ + autoFrontmatter?: false | Omit + + /** + * 站点加密配置 + */ + encrypt?: PlumeThemeEncrypt +}