diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 11862493..b22fcbab 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,12 +11,7 @@ 在 `plugins` 目录中: -- `plugin-auto-frontmatter` : 为 md 文件自动添加 frontmatter。 -- `plugin-blog-data`: 生成 blog 文章列表数据 -- `plugin-notes-data`: 生成 notes 数据,管理不同 note 的 `sidebar` 的数据 -- ~~`plugin-caniuse`: 添加 `caniuse` 内容容器,已弃用,不再维护~~ - `plugin-content-update`: 重写 `Content` 组件,提供 `onContentUpdated` 钩子 -- ~~`plugin-copy-code`: 为 代码块添加 复制 按钮,并适配 `shikiji`,已弃用,不再维护~~ - `plugin-search`: 为主题提供 全文模糊搜索 功能 - `plugin-shikiji`: 代码高亮插件,支持 highlight、diff、focus、error level - `plugin-iconify`: 添加全局组件 `Iconify` diff --git a/docs/.vuepress/notes.ts b/docs/.vuepress/notes.ts index 98c9bd90..8e0003b6 100644 --- a/docs/.vuepress/notes.ts +++ b/docs/.vuepress/notes.ts @@ -108,7 +108,7 @@ export const zhNotes = definePlumeNotesConfig({ { text: '插件', items: [ - 'caniuse', + // 'caniuse', 'iconify', 'shiki', 'md-power', diff --git a/docs/notes/theme/config/plugins/百度统计.md b/docs/notes/theme/config/plugins/百度统计.md index e13f89a7..63b8b470 100644 --- a/docs/notes/theme/config/plugins/百度统计.md +++ b/docs/notes/theme/config/plugins/百度统计.md @@ -5,6 +5,10 @@ createTime: 2024/03/06 12:22:57 permalink: /config/plugins/baidu-tongji/ --- +::: caution +主题计划在 未来的版本中 从内置插件中移除此插件。 +::: + ## 概述 为站点添加 百度统计。该插件默认不启用。 diff --git a/docs/notes/theme/config/主题配置.md b/docs/notes/theme/config/主题配置.md index d89793f5..4304398f 100644 --- a/docs/notes/theme/config/主题配置.md +++ b/docs/notes/theme/config/主题配置.md @@ -7,15 +7,31 @@ permalink: /config/basic/ ## 基础配置 +### configFile + +- 类型: `string` +- 默认值: `''` +- 详情: + + 自定义主题配置文件的路径。 + + 查看 [主题配置文件 `plume.config.js`](./配置说明.md#主题配置文件) 了解更多。 + ### plugins - 类型:`PlumeThemePluginOptions` - 默认值: `{}` -- 详情: 对主题内部使用的插件进行自定义配置。 +- 详情: -主题使用的插件默认已进行了配置,大多数情况下您不需要进行任何修改,如果需要使用到细致的定制化,请查阅 + 对主题内部使用的插件进行自定义配置。 + + 主题使用的插件默认已进行了配置,大多数情况下您不需要进行修改,如果需要使用到细致的定制化,请查阅 [此文档](/config/plugins/) + ::: warning + 该字段不支持在 [主题配置文件 `plume.config.js`](./配置说明.md#主题配置文件) 中进行配置。 + ::: + ### hostname - 类型: `string` @@ -26,6 +42,10 @@ permalink: /config/basic/ 当 `hostname` 配置为有效域名时,主题将会生成 `sitemap` 和 `seo` 相关的内容。 + ::: warning + 该字段不支持在 [主题配置文件 `plume.config.js`](./配置说明.md#主题配置文件) 中进行配置。 + ::: + ### blog - 类型: `false | BlogOptions` @@ -44,18 +64,16 @@ interface BlogOptions { link?: string /** - * 在 `blog.dir` 目录中,通过 glob string 配置包含文件 + * 在 `{sourceDir}` 目录中,通过 glob string 配置包含文件 * * @default - ['**\*.md'] */ include?: string[] /** - * 在 `blog.dir` 目录中,通过 glob string 配置排除的文件 + * 在 `{sourceDir}` 目录中,通过 glob string 配置排除的文件 * - * README.md 文件一般作为主页或者某个目录下的主页,不应该被读取为 blog文章 - * - * @default - ['.vuepress/', 'node_modules/', '{README,index}.md'] + * @default - ['.vuepress/', 'node_modules/'] */ exclude?: string[] @@ -89,6 +107,54 @@ interface BlogOptions { - 默认值: `/article/` - 详情: 文章链接前缀 +### autoFrontmatter + +- 类型: `false | AutoFrontmatter` +- 详情: + + 是否为 markdown 文件自动添加 frontmatter 配置 + + ```ts + interface AutoFrontmatter { + /** + * 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 + } + ``` + ### locales - 类型: `Record` @@ -235,13 +301,22 @@ export default { - 默认值: `[]` - 详情: 导航栏配置。 - 为了配置导航栏元素,你可以将其设置为 导航栏数组 ,其中的每个元素是 `NavItem` 对象、 + 为了配置导航栏元素,你可以将其设置为 导航栏数组 ,其中的每个元素是 `string` 或 `NavItem` 对象、 - `NavItem` 对象应该有一个 text 字段和一个 link 字段,还有一个可选的 `activeMatch` 字段。 + - `string` 表示是一个页面文件路径,或者是一个页面的访问路径。 ``` ts type NavItem = string | { text: string link: string + + /** + * 当前分组的页面前缀 + */ + prefix?: string + /** + * 该分组下的导航项 + */ items?: NavItem[] /** * 支持 iconify 图标,直接使用 iconify name 即可自动加载 @@ -267,10 +342,11 @@ type NavItem = string | { // NavbarGroup { text: 'Group', - item: ['/group/foo/', '/group/bar/'], + prefix: '/group/', + item: ['foo/', 'bar/'], }, // 字符串 - 页面文件路径 - '/bar/', + '/bar', // 可以直接省略后缀 `.md` ], }), } diff --git a/docs/notes/theme/config/多语言配置.md b/docs/notes/theme/config/多语言配置.md index a03f8c9a..d4ea24b7 100644 --- a/docs/notes/theme/config/多语言配置.md +++ b/docs/notes/theme/config/多语言配置.md @@ -61,11 +61,18 @@ export default defineUserConfig({ - 简体中文 (zh-CN) - 英文(美国) (en-US) +::: tip + +如果您希望支持更多语言,欢迎通过 +[PR](https://github.com/pengzhanbo/vuepress-theme-plume/pulls?q=sort%3Aupdated-desc+is%3Apr+is%3Aopen) 在 主题仓库的 `/theme/src/node/locales` 目录中按照相同的方式添加语言。 + +::: + ## 为每个语言设置主题选项 与站点配置和 `@vuepress/theme-default` 的主题配置相同,`vuepress-theme-plume` 也支持你在主题选项中设置 locale 选项,并为每种语言设置不同的配置。 -```ts +```ts :no-line-numbers import { defineUserConfig } from 'vuepress' import { plumeTheme } from 'vuepress-theme-plume' @@ -95,3 +102,49 @@ export default defineUserConfig({ }), }) ``` + +**使用主题配置文件:** + +::: code-tabs +@tab .vuepress/config.ts + +```ts +import { defineUserConfig } from 'vuepress' +import { plumeTheme } from 'vuepress-theme-plume' + +export default defineUserConfig({ + locales: { + '/': { + lang: 'en-US', + }, + '/zh/': { + lang: 'zh-CN', + }, + }, + + theme: plumeTheme(), +}) +``` + +@tab .vuepress/plume.config.ts + +```ts +import { defineThemeConfig } from 'vuepress-theme-plume' + +export default defineThemeConfig({ + // 通用配置 + // ... + locales: { + '/': { + // 英文配置 + // ... + }, + '/zh/': { + // 中文配置 + // ... + }, + }, +}) +``` + +::: diff --git a/docs/notes/theme/config/配置说明.md b/docs/notes/theme/config/配置说明.md index c4003ffb..c24c5fec 100644 --- a/docs/notes/theme/config/配置说明.md +++ b/docs/notes/theme/config/配置说明.md @@ -5,7 +5,9 @@ createTime: 2024/03/02 10:48:14 permalink: /config/intro/ --- -## 概述 +## VuePress 配置文件 + +### 概述 VuePress 站点的基本配置文件是 `.vuepress/config.js` ,但也同样支持 TypeScript 配置文件。 你可以使用 `.vuepress/config.ts` 来得到更好的类型提示。 @@ -33,7 +35,10 @@ import { defineUserConfig } from 'vuepress' export default defineUserConfig({ bundler: viteBundler(), - theme: plumeTheme(), + + theme: plumeTheme({ + // 在这里配置主题 + }), lang: 'zh-CN', title: '你好, VuePress !', @@ -41,10 +46,94 @@ export default defineUserConfig({ }) ``` -## 类型 +### 类型 在 VuePress 中,有三种配置类型: - 站点配置: 这是你在 配置文件 中直接导出的对象 - 主题配置: 传递给 `plumeTheme` 的对象参数 - 页面配置: 由在页面顶部基于 YAML 语法的 Frontmatter 提供 + +## 主题配置文件 + +### 概述 + +一般我们使用 `.vuepress/config.js` 或者 `.vuepress/config.ts` 来配置主题。 + +```ts +import { plumeTheme } from 'vuepress-theme-plume' +import { defineUserConfig } from 'vuepress' + +export default defineUserConfig({ + theme: plumeTheme({ + // 在这里配置主题 + }), +}) +``` + +但是当我们已经启动了 VuePress 服务,对该文件的修改会导致 VuePres 服务重启,然后站点进行全量刷新, +这可能需要等待一段时间才能恢复, 如果你的站点内容不多还能够接受, +而对于一些较大的站点,可能需要等待漫长的时间。 + +特别是当我们频繁修改,或者修改的间隔较短时,很容易使 VuePress 服务 崩溃,我们不得不手动重启。 + +**这给我们在编写站点内容时带来的极大的不便。** + +为了解决这一问题,主题支持在 单独的 主题配置文件中进行配置。 + +**对该文件的修改将通过热更新的方式实时生效。** + +### 配置 + +你可以直接在 [VuePress 配置文件](#vuepress-配置文件) 相同的路径下创建一个 `plume.config.js` 文件,这样就可以在该文件中进行主题配置。 +你也可以使用 TypeScript 来创建一个 `plume.config.ts` 文件,以获得更好的类型提示。 + +```txt :no-line-numbers +{sourceDir}/.vuepress/ +├── config.ts +└── plume.config.ts // [!code ++] +``` + +::: code-tabs +@tab plume.config.ts + +```ts +import { defineThemeConfig } from 'vuepress-theme-plume' +import navbar from './navbar' + +export default defineThemeConfig({ + // 在这里配置主题 + profile: { + name: 'Your name', + }, + navbar, +}) +``` + +::: + +主题提供了 `defineThemeConfig(config)` 函数,为主题使用者提供主题配置的类型帮助。 +你可以直接在这个文件中配置除了 `plugins` 字段外的其他配置。 + +### 自定义配置文件路径 + +如果你不希望按照 VuePress 默认的配置文件路径管理你的主题配置文件, +你也可以在 VuePress 配置文件中指定自己的主题配置文件路径。 + +```ts +import path from 'node:path' +import { plumeTheme } from 'vuepress-theme-plume' +import { defineUserConfig } from 'vuepress' + +export default defineUserConfig({ + theme: plumeTheme({ + // 在这里定义自己的主题配置文件路径 + configFile: path.join(__dirname, 'custom/config.ts'), // [!code ++] + }), +}) +``` + +::: tip +更推荐 使用 主题配置文件 来单独管理 主题配置,你不必再为频繁修改配置而一直等待 +VuePress 重启。 +::: diff --git a/docs/notes/theme/guide/介绍.md b/docs/notes/theme/guide/介绍.md index 4af1d6d4..3ab2b410 100644 --- a/docs/notes/theme/guide/介绍.md +++ b/docs/notes/theme/guide/介绍.md @@ -11,19 +11,22 @@ tags: ## 介绍 -vuepress-theme-plume 是一个基于 VuePress 的主题。适用于 博客、文档 和 知识笔记 。 +**vuepress-theme-plume** 是一个基于 VuePress 的主题,适用于 博客、文档 和 知识笔记 。 VuePress 是一个 [静态站点生成器](https://en.wikipedia.org/wiki/Static_site_generator) (SSG) 。 专为构建快速、以内容为中心的站点而设计。 简而言之,VuePress 获取用 Markdown 编写的内容,对其应用主题,并生成可以轻松部署到任何地方的静态 HTML 页面。 ::: tip + 本主题 基于 [vuepress-next](https://github.com/vuepress/vuepress-next), 目前处于 RC 阶段。 当前主题 功能和 API 趋于稳定,但在未来的更新中仍有小概率出现破坏更改。 -如果您在使用过程中遇到问题,或者有新的想法,请在 [Issues](https://github.com/pengzhanbo/vuepress-theme-plume/issues) 里提出, +如果您在使用过程中遇到问题,或者有新的想法, +请在 [Issues](https://github.com/pengzhanbo/vuepress-theme-plume/issues) 里提出, 也欢迎 通过 [PR](https://github.com/pengzhanbo/vuepress-theme-plume/pulls) 帮助完善主题。 + ::: ## 优势 @@ -33,6 +36,8 @@ VuePress 是一个 [静态站点生成器](https://en.wikipedia.org/wiki/Static_ - 大幅度优化了界面、交互,更具美观度,更好的用户体验。 - 同时,还添加了大量的丰富实用的功能,如 代码分组、提示容器、任务列表、数学公式、代码演示、 内容搜索、文章评论、加密 等。 +- 新增编译缓存,加快启动速度。 +- 支持使用单独的主题配置文件,避免修改配置导致频繁重启 VuePress 服务。 - 大幅度简化了配置,更易于使用,同时还保留了丰富灵活的配置项,满足个性化的需求。 `plume` 主题尽可能的内置你可能需要的功能,以及搭建站点所需要的一般性配置,您无需关注这些细节。 diff --git a/docs/notes/theme/guide/博客.md b/docs/notes/theme/guide/博客.md index 745a3193..369c0800 100644 --- a/docs/notes/theme/guide/博客.md +++ b/docs/notes/theme/guide/博客.md @@ -89,10 +89,27 @@ tags: | sticky | `boolean \| number` | false | 是否置顶, 如果为数字,则数字越大,置顶越靠前 | | draft | `boolean` | false | 是否为草稿,草稿文章不会被展示 | +除了以上的字段,你还可以使用 [通用 frontmatter 配置](../config/frontmatter/basic.md) 中的字段, +灵活的控制当前页面的行为。 + ## 文章摘要 如果你想要为文章添加摘要,你可以使用 `` 注释来标记它。任何在此注释之前的内容会被视为摘要。 +***示例:** + +```md +--- +title: 标题 +--- + +这里的内容会被作为摘要 + + + +这里的内容不会被作为摘要 +``` + ## 标签页和归档页 主题除了自动生成 **博客文章列表页** 以外,还会自动生成 **标签页** 和 **归档页**。 diff --git a/docs/notes/theme/guide/知识笔记.md b/docs/notes/theme/guide/知识笔记.md index 428b7c0d..7504ff54 100644 --- a/docs/notes/theme/guide/知识笔记.md +++ b/docs/notes/theme/guide/知识笔记.md @@ -11,10 +11,10 @@ tags: ## 概述 -在本主题满足了 Blog的基本功能后,期望能够 以 note 或者 book 的形式聚合文章,形式上类似于 vuepress 默认主题。 +在本主题满足了 Blog 的基本功能后,期望能够 以 note 或者 book 的形式聚合文章,形式上类似于 vuepress 默认主题。 同时也减少配置的复杂度。 -它能够让你以更加友好的方式,组织管理你的文档,或者 知识笔记。 +它能够让你以更加友好的方式,组织管理你的文档。 ## 目录 @@ -72,8 +72,10 @@ export default defineUserConfig({ 主题会根据配置,为对应目录中的 md 文件,生成 永久链接,以及侧边栏。 ::: tip + 你应该在创建文件之前,先把笔记的目录和链接前缀等配置好,主题需要根据配置, 为目录中的 md 文件生成永久链接,以及侧边栏。 + ::: 完整配置查看 [notes配置](/config/notes/) diff --git a/plugins/plugin-auto-frontmatter/LICENSE b/plugins/plugin-auto-frontmatter/LICENSE deleted file mode 100644 index 9f677c90..00000000 --- a/plugins/plugin-auto-frontmatter/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (C) 2021 - PRESENT by pengzhanbo - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/plugins/plugin-auto-frontmatter/README.md b/plugins/plugin-auto-frontmatter/README.md deleted file mode 100644 index 78877dc5..00000000 --- a/plugins/plugin-auto-frontmatter/README.md +++ /dev/null @@ -1,126 +0,0 @@ -# `@vuepress-plume/plugin-auto-frontmatter` - -自动生成 `*.md` 文件的 `frontmatter` 配置。 - -## Install - -```sh -npm install @vuepress-plume/plugin-auto-frontmatter -# or -pnpm add @vuepress-plume/plugin-auto-frontmatter -# or -yarn add @vuepress-plume/plugin-auto-frontmatter -``` - -## Usage - -``` js -// .vuepress/config.[jt]s -import { autoFrontmatterPlugin } from '@vuepress-plume/plugin-auto-frontmatter' - -export default { - // ... - plugins: [ - autoFrontmatterPlugin({ - formatter: { - createTime(formatTime, file, matter) { - if (formatTime) - return formatTime - return file.createTime - } - } - }) - ] - // ... -} -``` - -## `autoFrontmatterPlugin([options])` - -### options - -`{ include?: string | string[]; exclude?: string | string[]; formatter: Formatter }` - -- `include` - include 匹配字符串或数组,匹配需要自动生成 `frontmatter` 的 md文件。 - 默认预设为 `['**/*.md']`。 - -- `exclude` - exclude 排除不需要的文件 - 默认预设为: `['!.vuepress/', '!node_modules/']` - -- `formatter` - 配置`frontmatter`每个字段的生成规则。 - - ```ts - interface MarkdownFile { - filepath: string - relativePath: string - content: string - createTime: Date - stats: fs.Stats - } - - interface FormatterFn { - (value: T, file: MarkdownFile, data: K): T - } - - type FormatterObject = Record< - string, - FormatterFn - > - - type FormatterArray = { - include: string | string[] - formatter: FormatterObject - }[] - - type Formatter = FormatterObject | FormatterArray - - /** - * formatterObj 对象中的 key 即为 frontmatter 配置中的key - * 其方法返回的值将作为 frontmatter[key] 的值 - * .md - * --- - * createTime: 2022-03-26T11:46:50.000Z - * --- - */ - const formatterObj: Formatter = { - createTime(formatTime, file, matter) { - if (formatTime) - return formatTime - return file.createTime - } - } - - const formatterArr: Formatter = [ - { - // 更精细化的匹配某个 md文件,支持glob 匹配字符串 - include: '**/{README,index}.md', - // formatter 仅对 glob命中的文件有效 - formatter: { - home(value, file, matter) { - return value - } - }, - }, - { - // 通配,如果文件没有被其他精细glob命中, - // 则使用 通配 formatter - // 如果是数组,必须有且用一个 include 为 * 的 项 - include: '*', - formatter: { - title(title) { - return title || '默认标题' - } - } - } - ] - ``` - -## Why ? - -- **为什么需要这个插件?** - - 有时候在开发一些主题时,期望使用户更专注于内容的编写,尽可能减少配置性的工作,可以将一些重复性的必要的配置 - 直接通过本插件自动生成。 diff --git a/plugins/plugin-auto-frontmatter/package.json b/plugins/plugin-auto-frontmatter/package.json deleted file mode 100644 index c89628ed..00000000 --- a/plugins/plugin-auto-frontmatter/package.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "name": "@vuepress-plume/plugin-auto-frontmatter", - "type": "module", - "version": "1.0.0-rc.75", - "private": true, - "description": "The Plugin for VuePress 2 - auto frontmatter", - "author": "pengzhanbo ", - "license": "MIT", - "homepage": "https://github.com/pengzhanbo/vuepress-theme-plume#readme", - "repository": { - "type": "git", - "url": "git+https://github.com/pengzhanbo/vuepress-theme-plume.git", - "directory": "plugins/plugin-auto-frontmatter" - }, - "bugs": { - "url": "https://github.com/pengzhanbo/vuepress-theme-plume/issues" - }, - "exports": { - ".": { - "types": "./lib/node/index.d.ts", - "import": "./lib/node/index.js" - }, - "./package.json": "./package.json" - }, - "main": "lib/node/index.js", - "types": "./lib/node/index.d.ts", - "files": [ - "lib" - ], - "scripts": { - "build": "pnpm run copy && pnpm run ts", - "clean": "rimraf --glob ./lib ./*.tsbuildinfo", - "copy": "cpx \"src/**/*.{d.ts,vue,css,scss,jpg,png}\" lib", - "ts": "tsc -b tsconfig.build.json" - }, - "peerDependencies": { - "vuepress": "2.0.0-rc.14" - }, - "dependencies": { - "@pengzhanbo/utils": "^1.1.2", - "chokidar": "^3.6.0", - "create-filter": "^1.1.0", - "fast-glob": "^3.3.2", - "gray-matter": "^4.0.3", - "json2yaml": "^1.1.0" - }, - "publishConfig": { - "access": "public" - }, - "keyword": [ - "VuePress", - "vuepress plugin", - "autoFrontmatter", - "vuepress-plugin-plugin-auto-frontmatter" - ] -} diff --git a/plugins/plugin-auto-frontmatter/src/node/env.d.ts b/plugins/plugin-auto-frontmatter/src/node/env.d.ts deleted file mode 100644 index 5591cb30..00000000 --- a/plugins/plugin-auto-frontmatter/src/node/env.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -declare module 'json2yaml' { - const result: any - - export default result -} diff --git a/plugins/plugin-auto-frontmatter/src/node/index.ts b/plugins/plugin-auto-frontmatter/src/node/index.ts deleted file mode 100644 index 6d08b744..00000000 --- a/plugins/plugin-auto-frontmatter/src/node/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { - AutoFrontmatterOptions, - FrontmatterArray, - FrontmatterObject, -} from '../shared/index.js' -import { autoFrontmatterPlugin } from './plugin.js' - -export * from './plugin.js' - -export type { AutoFrontmatterOptions, FrontmatterArray, FrontmatterObject } - -export default autoFrontmatterPlugin diff --git a/plugins/plugin-auto-frontmatter/src/node/plugin.ts b/plugins/plugin-auto-frontmatter/src/node/plugin.ts deleted file mode 100644 index 2785709a..00000000 --- a/plugins/plugin-auto-frontmatter/src/node/plugin.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { colors, fs, logger } from 'vuepress/utils' -import type { Plugin } from 'vuepress/core' -import chokidar from 'chokidar' -import { createFilter } from 'create-filter' -import grayMatter from 'gray-matter' -import jsonToYaml from 'json2yaml' -import { promiseParallel } from '@pengzhanbo/utils' -import type { - AutoFrontmatterOptions, - FrontmatterArray, - FrontmatterObject, - MarkdownFile, -} from '../shared/index.js' -import { readMarkdown, readMarkdownList } from './readFiles.js' -import { ensureArray, isEmptyObject } from './utils.js' - -const PLUGIN_NAME = '@vuepress-plume/plugin-auto-frontmatter' - -export function autoFrontmatterPlugin({ - include = ['**/*.md'], - exclude = ['.vuepress/**/*', 'node_modules'], - frontmatter = {}, -}: AutoFrontmatterOptions = {}): Plugin { - include = ensureArray(include) - exclude = ensureArray(exclude) - - const globFilter = createFilter(include, exclude, { resolve: false }) - - const matterFrontmatter: FrontmatterArray = Array.isArray(frontmatter) - ? frontmatter - : [{ include: '*', frontmatter }] - - const globFormatter: FrontmatterObject - = matterFrontmatter.find(({ include }) => include === '*')?.frontmatter || {} - - const otherFormatters = matterFrontmatter - .filter(({ include }) => include !== '*') - .map(({ include, frontmatter }) => { - return { - include, - filter: createFilter(ensureArray(include), [], { resolve: false }), - frontmatter, - } - }) - - async function formatMarkdown(file: MarkdownFile): Promise { - const { filepath, relativePath } = file - - const current = otherFormatters.find(({ filter }) => filter(relativePath)) - const formatter = current?.frontmatter || globFormatter - const { data, content } = grayMatter(file.content) - - for (const key in formatter) { - const value = await formatter[key](data[key], file, data) - data[key] = value ?? data[key] - } - - try { - const yaml = isEmptyObject(data) - ? '' - : jsonToYaml - .stringify(data) - .replace(/\n\s{2}/g, '\n') - .replace(/"/g, '') - .replace(/\s+\n/g, '\n') - const newContent = yaml ? `${yaml}---\n${content}` : content - - fs.writeFileSync(filepath, newContent, 'utf-8') - } - catch (e) { - console.error(e) - } - } - - return { - name: PLUGIN_NAME, - onInitialized: async (app) => { - const start = performance.now() - const markdownList = await readMarkdownList(app.dir.source(), globFilter) - await promiseParallel( - markdownList.map(file => () => formatMarkdown(file)), - 64, - ) - if (app.env.isDebug) - logger.info(`\n[${colors.green(PLUGIN_NAME)}] Init time spent: ${(performance.now() - start).toFixed(2)}ms`) - }, - onWatched: async (app, watchers) => { - const watcher = chokidar.watch('**/*.md', { - cwd: app.dir.source(), - ignoreInitial: true, - ignored: /(node_modules|\.vuepress)\//, - }) - - watcher.on('add', async (relativePath) => { - if (!globFilter(relativePath)) - return - await formatMarkdown(readMarkdown(app.dir.source(), relativePath)) - }) - - watchers.push(watcher) - }, - } -} diff --git a/plugins/plugin-auto-frontmatter/src/node/readFiles.ts b/plugins/plugin-auto-frontmatter/src/node/readFiles.ts deleted file mode 100644 index ed4b2e07..00000000 --- a/plugins/plugin-auto-frontmatter/src/node/readFiles.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { fs, path } from 'vuepress/utils' -import fg from 'fast-glob' -import type { MarkdownFile } from '../shared/index.js' - -type MarkdownFileList = MarkdownFile[] - -export async function readMarkdownList(sourceDir: string, filter: (id: string) => boolean): Promise { - const files: string[] = await fg(['**/*.md'], { - cwd: sourceDir, - ignore: ['node_modules', '.vuepress'], - }) - - return files - .filter(file => filter(file)) - .map(file => readMarkdown(sourceDir, file)) -} - -export function readMarkdown(sourceDir: string, relativePath: string): MarkdownFile { - const filepath = path.join(sourceDir, relativePath) - const stats = fs.statSync(filepath) - return { - filepath, - relativePath, - content: fs.readFileSync(filepath, 'utf-8'), - createTime: getFileCreateTime(stats), - stats, - } -} - -export function getFileCreateTime(stats: fs.Stats): Date { - return stats.birthtime.getFullYear() !== 1970 ? stats.birthtime : stats.atime -} diff --git a/plugins/plugin-auto-frontmatter/src/node/utils.ts b/plugins/plugin-auto-frontmatter/src/node/utils.ts deleted file mode 100644 index 4ba1705d..00000000 --- a/plugins/plugin-auto-frontmatter/src/node/utils.ts +++ /dev/null @@ -1,11 +0,0 @@ -export function ensureArray(thing: T | T[] | null | undefined): T[] { - if (Array.isArray(thing)) - return thing - if (thing === null || thing === undefined) - return [] - return [thing] -} - -export function isEmptyObject(obj: object) { - return Object.keys(obj).length === 0 -} diff --git a/plugins/plugin-auto-frontmatter/src/shared/index.ts b/plugins/plugin-auto-frontmatter/src/shared/index.ts deleted file mode 100644 index cd1f8cf7..00000000 --- a/plugins/plugin-auto-frontmatter/src/shared/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type fs from 'node:fs' - -export interface MarkdownFile { - filepath: string - relativePath: string - content: string - createTime: Date - stats: fs.Stats -} - -export type FrontmatterFn = ( - value: T, - file: MarkdownFile, - data: K -) => T | PromiseLike - -export type FrontmatterObject = Record> - -export type FrontmatterArray = { - include: string | string[] - frontmatter: FrontmatterObject -}[] - -export interface AutoFrontmatterOptions { - /** - * FilterPattern - */ - include?: string | string[] - - exclude?: string | string[] - - /** - * { - * key(value, file, data) { - * return value - * } - * } - */ - frontmatter?: FrontmatterArray | FrontmatterObject -} diff --git a/plugins/plugin-auto-frontmatter/tsconfig.build.json b/plugins/plugin-auto-frontmatter/tsconfig.build.json deleted file mode 100644 index 809551b3..00000000 --- a/plugins/plugin-auto-frontmatter/tsconfig.build.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../tsconfig.build.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./lib" - }, - "files": [], - "include": ["./src"] -} diff --git a/plugins/plugin-blog-data/LICENSE b/plugins/plugin-blog-data/LICENSE deleted file mode 100644 index 9f677c90..00000000 --- a/plugins/plugin-blog-data/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (C) 2021 - PRESENT by pengzhanbo - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/plugins/plugin-blog-data/README.md b/plugins/plugin-blog-data/README.md deleted file mode 100644 index fdb0e6d7..00000000 --- a/plugins/plugin-blog-data/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# `@vuepress-plume/plugin-blog-data` - -## Install - -```sh -npm install @vuepress-plume/plugin-blog-data -# or -pnpm add @vuepress-plume/plugin-blog-data -# or -yarn add @vuepress-plume/plugin-blog-data -``` - -## Usage - -``` js -// .vuepress/config.[jt]s -import { blogDataPlugin } from '@vuepress-plume/plugin-blog-data' - -export default { - // ... - plugins: [ - blogDataPlugin() - ] - // ... -} -``` - -## Options - -```ts -interface BlogDataPluginOptions { - include?: string | string[] - exclude?: string | string[] - sortBy?: 'createTime' | false | ((prev: T, next: T) => boolean) - excerpt?: boolean - extendBlogData?: (page: T) => Record -} -``` diff --git a/plugins/plugin-blog-data/package.json b/plugins/plugin-blog-data/package.json deleted file mode 100644 index d7eb5986..00000000 --- a/plugins/plugin-blog-data/package.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "name": "@vuepress-plume/plugin-blog-data", - "type": "module", - "version": "1.0.0-rc.75", - "private": "true", - "description": "The Plugin for VuePress 2 - blog data", - "author": "pengzhanbo ", - "license": "MIT", - "homepage": "https://github.com/pengzhanbo/vuepress-theme-plume#readme", - "repository": { - "type": "git", - "url": "git+https://github.com/pengzhanbo/vuepress-theme-plume.git", - "directory": "plugins/plugin-blog-data" - }, - "bugs": { - "url": "https://github.com/pengzhanbo/vuepress-theme-plume/issues" - }, - "exports": { - ".": { - "types": "./lib/node/index.d.ts", - "import": "./lib/node/index.js" - }, - "./client": { - "types": "./lib/client/index.d.ts", - "import": "./lib/client/index.js" - }, - "./package.json": "./package.json" - }, - "main": "lib/node/index.js", - "types": "./lib/node/index.d.ts", - "files": [ - "lib" - ], - "scripts": { - "build": "pnpm run copy && pnpm run ts", - "clean": "rimraf --glob ./lib ./*.tsbuildinfo", - "copy": "cpx \"src/**/*.{d.ts,vue,css,scss,jpg,png}\" lib", - "ts": "tsc -b tsconfig.build.json" - }, - "peerDependencies": { - "vuepress": "2.0.0-rc.14" - }, - "dependencies": { - "@vue/devtools-api": "6.6.3", - "chokidar": "^3.6.0", - "create-filter": "^1.1.0", - "vue": "^3.4.31" - }, - "publishConfig": { - "access": "public" - }, - "keyword": [ - "VuePress", - "vuepress plugin", - "blogData", - "vuepress-plugin-plugin-blog-data" - ] -} diff --git a/plugins/plugin-blog-data/src/client/blogPostData.d.ts b/plugins/plugin-blog-data/src/client/blogPostData.d.ts deleted file mode 100644 index 52fa5598..00000000 --- a/plugins/plugin-blog-data/src/client/blogPostData.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { BlogPostData } from '../shared/index.js' - -declare module '@internal/blogData' { - const blogPostData: BlogPostData - - export { blogPostData } -} diff --git a/plugins/plugin-blog-data/src/client/composables/index.ts b/plugins/plugin-blog-data/src/client/composables/index.ts deleted file mode 100644 index 43aec1ef..00000000 --- a/plugins/plugin-blog-data/src/client/composables/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './useBlogPostData.js' diff --git a/plugins/plugin-blog-data/src/client/composables/useBlogPostData.ts b/plugins/plugin-blog-data/src/client/composables/useBlogPostData.ts deleted file mode 100644 index fc2f2eae..00000000 --- a/plugins/plugin-blog-data/src/client/composables/useBlogPostData.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { - blogPostData as blogPostDataRaw, -} from '@internal/blogData' -import { ref } from 'vue' -import type { Ref } from 'vue' -import type { BlogPostData } from '../../shared/index.js' - -declare const __VUE_HMR_RUNTIME__: Record - -export type BlogDataRef = Ref - -export const blogPostData: BlogDataRef = ref(blogPostDataRaw) - -export function useBlogPostData< - T extends BlogPostData = BlogPostData, ->(): BlogDataRef { - return blogPostData as BlogDataRef -} - -if (__VUEPRESS_DEV__ && (import.meta.webpackHot || import.meta.hot)) { - __VUE_HMR_RUNTIME__.updateBlogData = (data: BlogPostData) => { - blogPostData.value = data - } -} diff --git a/plugins/plugin-blog-data/src/client/config.ts b/plugins/plugin-blog-data/src/client/config.ts deleted file mode 100644 index 09d2f231..00000000 --- a/plugins/plugin-blog-data/src/client/config.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { setupDevtoolsPlugin } from '@vue/devtools-api' -import { defineClientConfig } from 'vuepress/client' -import type { ClientConfig } from 'vuepress/client' -import { useBlogPostData } from './composables/index.js' - -declare const __VUE_PROD_DEVTOOLS__: boolean - -export default defineClientConfig({ - enhance({ app }) { - const blogPostData = useBlogPostData() - - Object.defineProperties(app.config.globalProperties, { - $blogPostData: { - get() { - return blogPostData.value - }, - }, - }) - - // setup devtools in dev mode - if (__VUEPRESS_DEV__ || __VUE_PROD_DEVTOOLS__) { - const PLUGIN_ID = 'org.vuejs.vuepress' - const PLUGIN_LABEL = 'VuePress' - const INSPECTOR_ID = PLUGIN_ID - - setupDevtoolsPlugin( - { - // fix recursive reference - app: app as any, - id: PLUGIN_ID, - label: PLUGIN_LABEL, - packageName: '@vuepress-plume/plugin-blog-data', - homepage: 'https://pengzhanbo.cn', - logo: 'https://v2.vuepress.vuejs.org/images/hero.png', - componentStateTypes: ['VuePress'], - }, - (api) => { - api.on.inspectComponent((payload) => { - payload.instanceData.state.push({ - type: 'VuePress', - key: 'blogPostData', - editable: false, - value: blogPostData.value, - }) - }) - api.on.getInspectorTree((payload) => { - if (payload.inspectorId !== INSPECTOR_ID) - return - payload.rootNodes.push({ - id: 'blog_post_data', - label: 'Blog Post Data', - }) - }) - api.on.getInspectorState((payload) => { - if (payload.inspectorId !== INSPECTOR_ID) - return - if (payload.nodeId === 'blog_post_data') { - payload.state = { - BlogPostData: [{ - key: 'blogPostData', - value: blogPostData.value, - }], - } - } - }) - }, - ) - } - }, -}) as ClientConfig diff --git a/plugins/plugin-blog-data/src/client/index.ts b/plugins/plugin-blog-data/src/client/index.ts deleted file mode 100644 index f07e6cc1..00000000 --- a/plugins/plugin-blog-data/src/client/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { BlogPostData, BlogPostDataItem } from '../shared/index.js' - -export * from './composables/index.js' - -export type { BlogPostData, BlogPostDataItem } diff --git a/plugins/plugin-blog-data/src/node/index.ts b/plugins/plugin-blog-data/src/node/index.ts deleted file mode 100644 index 289ed329..00000000 --- a/plugins/plugin-blog-data/src/node/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { blogDataPlugin } from './plugin.js' - -export * from '../shared/index.js' -export { blogDataPlugin } - -export default blogDataPlugin diff --git a/plugins/plugin-blog-data/src/node/plugin.ts b/plugins/plugin-blog-data/src/node/plugin.ts deleted file mode 100644 index 5d6ac8bd..00000000 --- a/plugins/plugin-blog-data/src/node/plugin.ts +++ /dev/null @@ -1,52 +0,0 @@ -import type { Plugin } from 'vuepress/core' -import { getDirname, path } from 'vuepress/utils' -import chokidar from 'chokidar' -import { createFilter } from 'create-filter' -import { preparedBlogData } from './prepareBlogData.js' -import type { BlogDataPluginOptions } from './index.js' - -const __dirname = getDirname(import.meta.url) - -export type PluginOption = Omit - -export function blogDataPlugin({ - include, - exclude, - ...pluginOptions -}: BlogDataPluginOptions = {}): Plugin { - const pageFilter = createFilter(toArray(include), toArray(exclude), { - resolve: false, - }) - - return { - name: '@vuepress-plume/plugin-blog-data', - clientConfigFile: path.resolve(__dirname, '../client/config.js'), - extendsPage(page) { - if (page.filePathRelative && pageFilter(page.filePathRelative)) { - ;(page.data as any).isBlogPost = true - } - }, - onPrepared: async app => - await preparedBlogData(app, pageFilter, pluginOptions), - onWatched(app, watchers) { - const watcher = chokidar.watch('pages/**/*', { - cwd: app.dir.temp(), - ignoreInitial: true, - }) - - const handler = () => preparedBlogData(app, pageFilter, pluginOptions) - - watcher.on('add', handler) - watcher.on('change', handler) - watcher.on('unlink', handler) - - watchers.push(watcher) - }, - } -} - -function toArray(likeArr: string | string[] | undefined): string[] { - if (Array.isArray(likeArr)) - return likeArr - return likeArr ? [likeArr] : [] -} diff --git a/plugins/plugin-blog-data/src/node/prepareBlogData.ts b/plugins/plugin-blog-data/src/node/prepareBlogData.ts deleted file mode 100644 index c8edc603..00000000 --- a/plugins/plugin-blog-data/src/node/prepareBlogData.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { createHash } from 'node:crypto' -import type { App, Page } from 'vuepress/core' -import { colors, logger } from 'vuepress/utils' -import type { BlogPostData, BlogPostDataItem } from '../shared/index.js' -import type { PluginOption } from './plugin.js' - -const HMR_CODE = ` -if (import.meta.webpackHot) { - import.meta.webpackHot.accept() - if (__VUE_HMR_RUNTIME__.updateBlogData) { - __VUE_HMR_RUNTIME__.updateBlogData(blogPostData) - } -} - -if (import.meta.hot) { - import.meta.hot.accept(({ blogPostData }) => { - __VUE_HMR_RUNTIME__.updateBlogData(blogPostData) - }) -} -` - -const headingRe = /]*>.*?<\/h\1>/gi - -const EXCERPT_SPLIT = '' -let contentHash: string | undefined - -export async function preparedBlogData(app: App, pageFilter: (id: string) => boolean, options: PluginOption): Promise { - const start = performance.now() - - let pages = app.pages.filter((page) => { - return page.filePathRelative && pageFilter(page.filePathRelative) - }) - if (options.pageFilter) - pages = pages.filter(options.pageFilter) - - if (options.sortBy) { - pages = pages.sort((prev, next) => { - if (options.sortBy === 'createTime') { - return getTimestamp(prev.frontmatter.createTime as Date) - < getTimestamp(next.frontmatter.createTime as Date) - ? 1 - : -1 - } - else { - return typeof options.sortBy === 'function' - && options.sortBy(prev, next) - ? 1 - : -1 - } - }) - } - - const blogData: BlogPostData = pages.map((page: Page) => { - let extended: Partial = {} - if (typeof options.extendBlogData === 'function') - extended = options.extendBlogData(page) - - const data = { - path: page.path, - title: page.title, - ...extended, - } - - if (options.excerpt && page.contentRendered.includes(EXCERPT_SPLIT)) { - const contents = page.contentRendered.split(EXCERPT_SPLIT) - let excerpt = contents[0] - // 删除摘要中的标题 - excerpt = excerpt.replace(headingRe, '') - data.excerpt = excerpt - } - - return data as BlogPostDataItem - }) - - let content = `\ -export const blogPostData = ${JSON.stringify(blogData)}; -` - - // inject HMR code - if (app.env.isDev) - content += HMR_CODE - - const currentHash = hash(content) - if (!contentHash || contentHash !== currentHash) { - contentHash = currentHash - await app.writeTemp('internal/blogData.js', content) - } - - if (app.env.isDebug) - logger.info(`\n[${colors.green('@vuepress-plume/plugin-blog-data')}] prepare blog data time spent: ${(performance.now() - start).toFixed(2)}ms`) -} - -function getTimestamp(time: Date): number { - return new Date(time).getTime() -} - -function hash(content: string): string { - return createHash('md5').update(content).digest('hex') -} diff --git a/plugins/plugin-blog-data/src/shared/index.ts b/plugins/plugin-blog-data/src/shared/index.ts deleted file mode 100644 index 86af918c..00000000 --- a/plugins/plugin-blog-data/src/shared/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { Page } from 'vuepress/core' - -export interface BlogDataPluginOptions { - include?: string | string[] - exclude?: string | string[] - sortBy?: 'createTime' | false | ((prev: T, next: T) => boolean) - excerpt?: boolean - extendBlogData?: (page: T) => Record - pageFilter?: (page: Page) => boolean -} - -export type BlogPostData = BlogPostDataItem[] - -export type BlogPostDataItem = { - path: string - title: string - excerpt: string - [x: string]: any -} & T diff --git a/plugins/plugin-blog-data/tsconfig.build.json b/plugins/plugin-blog-data/tsconfig.build.json deleted file mode 100644 index 3f0244f8..00000000 --- a/plugins/plugin-blog-data/tsconfig.build.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../tsconfig.build.json", - "compilerOptions": { - "baseUrl": ".", - "rootDir": "./src", - "paths": { - "@internal/blogData": ["./src/client/blogPostData.d.ts"] - }, - "types": ["vuepress/client-types", "vite/client", "webpack-env"], - "outDir": "./lib" - }, - "include": ["./src"] -} diff --git a/plugins/plugin-caniuse/LICENSE b/plugins/plugin-caniuse/LICENSE deleted file mode 100644 index 9f677c90..00000000 --- a/plugins/plugin-caniuse/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (C) 2021 - PRESENT by pengzhanbo - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/plugins/plugin-caniuse/README.md b/plugins/plugin-caniuse/README.md deleted file mode 100644 index 4015b7ce..00000000 --- a/plugins/plugin-caniuse/README.md +++ /dev/null @@ -1,71 +0,0 @@ -# vuepress-plugin-caniuse - -VuePress 2 Plugin - -VuePress 2 插件 - -在Markdown中添加 [can-i-use](https://caniuse.com/) 支持,这对于你在写前端技术博客时,说明某个feature的兼容性时特别有用。 - -## Install - -``` sh -npm install @vuepress-plume/plugin-caniuse -# or -pnpm add @vuepress-plume/plugin-caniuse -# or -yarn add @vuepress-plume/plugin-caniuse -``` - -## Usage - -### 在VuePress 配置文件中添加插件 - -``` js -// .vuepress/config.[jt]s -import { caniusePlugin } from '@vuepress-plume/plugin-caniuse' - -export default { - // ... - plugins: [ - caniusePlugin({ mode: 'image' }), - ] - // ... -} -``` - -### 在markdown中编写 - -``` md -::: caniuse {{browser_versions}} -::: -``` - -### Options - -- `options.mode`: can-i-use插入文档的模式, 支持 `embed` 和`image`, 默认值是 `image`。 - - `image`: 插入图片 - - `embed`: 使用iframe嵌入 can-i-use - -### \ - -正确取值请参考 [https://caniuse.bitsofco.de/](https://caniuse.bitsofco.de/) - -### \{browser_versions\}` - -可选。当前特性在多个版本中的支持情况。 - -格式: `{number,number,...}` 取值范围为 `-5 ~ 3` - -- 小于`0` 表示低于当前浏览器版本的支持情况 -- `0` 表示当前浏览器版本的支持情况 -- 大于`0` 表示高于当前浏览器版本的支持情况 - -## Example - -``` md -::: caniuse css-matches-pseudo {-2,-1,1} -::: -``` - -效果: -![can-i-use css-matches-pseudo](https://caniuse.bitsofco.de/image/css-dir-pseudo.webp) diff --git a/plugins/plugin-caniuse/package.json b/plugins/plugin-caniuse/package.json deleted file mode 100644 index f509a4d3..00000000 --- a/plugins/plugin-caniuse/package.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "name": "@vuepress-plume/plugin-caniuse", - "type": "module", - "version": "1.0.0-rc.75", - "private": "true", - "description": "The Plugin for VuePress 2, Support Can-I-Use feature", - "author": "pengzhanbo ", - "license": "MIT", - "homepage": "https://github.com/pengzhanbo/vuepress-theme-plume#readme", - "repository": { - "type": "git", - "url": "git+https://github.com/pengzhanbo/vuepress-theme-plume.git", - "directory": "plugins/plugin-caniuse" - }, - "bugs": { - "url": "https://github.com/pengzhanbo/vuepress-theme-plume/issues" - }, - "keywords": [ - "VuePress", - "plugin", - "vuepress-plugin", - "can-i-use", - "caniuse" - ], - "exports": { - ".": { - "types": "./lib/node/index.d.ts", - "import": "./lib/node/index.js" - }, - "./client": { - "types": "./lib/client/index.d.ts", - "import": "./lib/client/index.js" - }, - "./package.json": "./package.json" - }, - "main": "lib/node/index.js", - "types": "./lib/node/index.d.ts", - "files": [ - "lib" - ], - "scripts": { - "build": "pnpm run ts", - "clean": "rimraf --glob ./lib ./*.tsbuildinfo", - "ts": "tsc -b tsconfig.build.json" - }, - "peerDependencies": { - "vuepress": "2.0.0-rc.14" - }, - "dependencies": { - "markdown-it-container": "^4.0.0" - }, - "devDependencies": { - "@types/markdown-it": "^14.1.1" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/plugins/plugin-caniuse/src/client/clientConfig.ts b/plugins/plugin-caniuse/src/client/clientConfig.ts deleted file mode 100644 index cf788296..00000000 --- a/plugins/plugin-caniuse/src/client/clientConfig.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { defineClientConfig } from 'vuepress/client' -import type { ClientConfig } from 'vuepress/client' -import type { CanIUseMode } from '../shared/index.js' -import { resolveCanIUse } from './resolveCanIUse.js' - -declare const __CAN_I_USE_INJECT_MODE__: CanIUseMode -declare const __VUEPRESS_SSR__: boolean - -const mode = __CAN_I_USE_INJECT_MODE__ - -export default defineClientConfig({ - enhance({ router }) { - if (__VUEPRESS_SSR__) - return - - router.afterEach(() => { - if (mode === 'embed') - resolveCanIUse() - }) - }, -}) as ClientConfig diff --git a/plugins/plugin-caniuse/src/client/index.ts b/plugins/plugin-caniuse/src/client/index.ts deleted file mode 100644 index 72593733..00000000 --- a/plugins/plugin-caniuse/src/client/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '../shared/index.js' diff --git a/plugins/plugin-caniuse/src/client/resolveCanIUse.ts b/plugins/plugin-caniuse/src/client/resolveCanIUse.ts deleted file mode 100644 index 6c60b7ac..00000000 --- a/plugins/plugin-caniuse/src/client/resolveCanIUse.ts +++ /dev/null @@ -1,20 +0,0 @@ -let isBind = false -export function resolveCanIUse(): void { - if (isBind) - return - isBind = true - - window.addEventListener('message', (message) => { - const data = message.data - - if (typeof data === 'string' && data.includes('ciu_embed')) { - const [, feature, height] = data.split(':') - const el = document.querySelector(`.ciu_embed[data-feature="${feature}"]:not([data-skip])`) - if (el) { - const h = Number.parseInt(height) + 30 - ;(el.childNodes[0] as any).height = `${h}px` - el.setAttribute('data-skip', 'true') - } - } - }) -} diff --git a/plugins/plugin-caniuse/src/node/index.ts b/plugins/plugin-caniuse/src/node/index.ts deleted file mode 100644 index d83b030d..00000000 --- a/plugins/plugin-caniuse/src/node/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { caniusePlugin } from './plugin.js' - -export * from './plugin.js' -export * from '../shared/index.js' - -export default caniusePlugin diff --git a/plugins/plugin-caniuse/src/node/markdown-it-container.d.ts b/plugins/plugin-caniuse/src/node/markdown-it-container.d.ts deleted file mode 100644 index 44347be7..00000000 --- a/plugins/plugin-caniuse/src/node/markdown-it-container.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module 'markdown-it-container' { - import type { PluginWithParams } from 'markdown-it' - - const container: PluginWithParams - export = container -} diff --git a/plugins/plugin-caniuse/src/node/plugin.ts b/plugins/plugin-caniuse/src/node/plugin.ts deleted file mode 100644 index 4941687c..00000000 --- a/plugins/plugin-caniuse/src/node/plugin.ts +++ /dev/null @@ -1,48 +0,0 @@ -import type { Plugin, PluginObject } from 'vuepress/core' -import { getDirname, path } from 'vuepress/utils' -import type Token from 'markdown-it/lib/token.mjs' -import container from 'markdown-it-container' -import type { CanIUseMode, CanIUsePluginOptions } from '../shared/index.js' -import { resolveCanIUse } from './resolveCanIUse.js' - -const __dirname = getDirname(import.meta.url) -const modeMap: CanIUseMode[] = ['image', 'embed'] -const isMode = (mode: CanIUseMode): boolean => modeMap.includes(mode) - -export function caniusePlugin({ - mode = modeMap[0], -}: CanIUsePluginOptions): Plugin { - mode = isMode(mode) ? mode : modeMap[0] - const type = 'caniuse' - const validateReg = new RegExp(`^${type}(?:$|\s)`) - const pluginObj: PluginObject = { - name: '@vuepress-plume/plugin-caniuse', - clientConfigFile: path.resolve(__dirname, '../client/clientConfig.js'), - define: { - __CAN_I_USE_INJECT_MODE__: mode, - }, - } - - const validate = (info: string): boolean => { - return validateReg.test(info.trim()) - } - - const render = (tokens: Token[], index: number): string => { - const token = tokens[index] - if (token.nesting === 1) { - const info = token.info.trim().slice(type.length).trim() || '' - const feature = info.split(/\s+/)[0] - const versions = info.match(/\{(.*)\}/)?.[1] || '' - return feature ? resolveCanIUse(feature, mode, versions) : '' - } - else { - return '' - } - } - - pluginObj.extendsMarkdown = (md) => { - md.use(container as any, type, { validate, render }) - } - - return pluginObj -} diff --git a/plugins/plugin-caniuse/src/node/resolveCanIUse.ts b/plugins/plugin-caniuse/src/node/resolveCanIUse.ts deleted file mode 100644 index 9c4a9994..00000000 --- a/plugins/plugin-caniuse/src/node/resolveCanIUse.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { CanIUseMode } from '../shared/index.js' - -export function resolveCanIUse(feature: string, mode: CanIUseMode, versions: string): string { - if (!feature) - return '' - - if (mode === 'image') { - return ` - - - Data on support for the ${feature} feature across the major browsers from caniuse.com - ` - } - - const periods = resolveVersions(versions) - const accessible = 'false' - const image = 'none' - const url = 'https://caniuse.bitsofco.de/embed/index.html' - const src = `${url}?feat=${feature}&periods=${periods}&accessible-colours=${accessible}&image-base=${image}` - - return `
` -} - -function resolveVersions(versions: string): string { - if (!versions) - return 'future_1,current,past_1,past_2' - - const list = versions - .split(',') - .map(v => Number(v.trim())) - .filter(v => !Number.isNaN(v) && v >= -5 && v <= 3) - - list.push(0) - - const uniq = [...new Set(list)].sort((a, b) => b - a) - const result: string[] = [] - uniq.forEach((v) => { - if (v < 0) - result.push(`past_${Math.abs(v)}`) - if (v === 0) - result.push('current') - if (v > 0) - result.push(`future_${v}`) - }) - return result.join(',') -} diff --git a/plugins/plugin-caniuse/src/shared/caniuse.ts b/plugins/plugin-caniuse/src/shared/caniuse.ts deleted file mode 100644 index 65d37638..00000000 --- a/plugins/plugin-caniuse/src/shared/caniuse.ts +++ /dev/null @@ -1,15 +0,0 @@ -export type CanIUseMode = 'embed' | 'image' - -/** - * can-i-use plugin options - */ -export interface CanIUsePluginOptions { - /** - * 嵌入模式 - * - * embed 通过iframe嵌入,提供可交互视图 - * - * image 通过图片嵌入,静态 - */ - mode: CanIUseMode -} diff --git a/plugins/plugin-caniuse/src/shared/index.ts b/plugins/plugin-caniuse/src/shared/index.ts deleted file mode 100644 index 3a1fb664..00000000 --- a/plugins/plugin-caniuse/src/shared/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './caniuse.js' diff --git a/plugins/plugin-caniuse/tsconfig.build.json b/plugins/plugin-caniuse/tsconfig.build.json deleted file mode 100644 index 6bf67375..00000000 --- a/plugins/plugin-caniuse/tsconfig.build.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../tsconfig.build.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./lib" - }, - "include": ["./src"] -} diff --git a/plugins/plugin-copy-code/LICENSE b/plugins/plugin-copy-code/LICENSE deleted file mode 100644 index 9f677c90..00000000 --- a/plugins/plugin-copy-code/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (C) 2021 - PRESENT by pengzhanbo - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/plugins/plugin-copy-code/README.md b/plugins/plugin-copy-code/README.md deleted file mode 100644 index 99c57123..00000000 --- a/plugins/plugin-copy-code/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# `@vuepress-plume/plugin-copy-code` - -## Install - -```sh -npm install @vuepress-plume/plugin-copy-code -# or -pnpm add @vuepress-plume/plugin-copy-code -# or -yarn add @vuepress-plume/plugin-copy-code -``` - -## Usage - -``` js -// .vuepress/config.js -import { copyCodePlugin } from '@vuepress-plume/plugin-copy-code' - -export default { - // ... - plugins: [ - copyCodePlugin() - ] - // ... -} -``` diff --git a/plugins/plugin-copy-code/package.json b/plugins/plugin-copy-code/package.json deleted file mode 100644 index 07c7af74..00000000 --- a/plugins/plugin-copy-code/package.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "name": "@vuepress-plume/plugin-copy-code", - "type": "module", - "version": "1.0.0-rc.75", - "private": "true", - "description": "The Plugin for VuePress 2 - copy code", - "author": "pengzhanbo ", - "license": "MIT", - "homepage": "https://github.com/pengzhanbo/vuepress-theme-plume#readme", - "repository": { - "type": "git", - "url": "git+https://github.com/pengzhanbo/vuepress-theme-plume.git", - "directory": "plugins/plugin-copy-code" - }, - "bugs": { - "url": "https://github.com/pengzhanbo/vuepress-theme-plume/issues" - }, - "exports": { - ".": { - "types": "./lib/node/index.d.ts", - "import": "./lib/node/index.js" - }, - "./client": { - "types": "./lib/client/index.d.ts", - "import": "./lib/client/index.js" - }, - "./package.json": "./package.json" - }, - "main": "lib/node/index.js", - "types": "./lib/node/index.d.ts", - "files": [ - "lib" - ], - "scripts": { - "build": "pnpm run copy && pnpm run ts", - "clean": "rimraf --glob ./lib ./*.tsbuildinfo", - "copy": "cpx \"src/**/*.{d.ts,vue,css,scss,jpg,png}\" lib", - "ts": "tsc -b tsconfig.build.json" - }, - "peerDependencies": { - "vuepress": "2.0.0-rc.14" - }, - "dependencies": { - "@vuepress-plume/plugin-content-update": "workspace:~", - "vue": "^3.4.31" - }, - "publishConfig": { - "access": "public" - }, - "keyword": [ - "VuePress", - "vuepress plugin", - "copyCode", - "vuepress-plugin-plugin-copy-code" - ] -} diff --git a/plugins/plugin-copy-code/src/client/clientConfig.ts b/plugins/plugin-copy-code/src/client/clientConfig.ts deleted file mode 100644 index 3a44ee3f..00000000 --- a/plugins/plugin-copy-code/src/client/clientConfig.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { defineClientConfig } from 'vuepress/client' -import type { ClientConfig } from 'vuepress/client' -import { setupCopyCode } from './setupCopyCode.js' - -import './styles/button.css' - -export default defineClientConfig({ - setup() { - setupCopyCode() - }, -}) as ClientConfig diff --git a/plugins/plugin-copy-code/src/client/index.ts b/plugins/plugin-copy-code/src/client/index.ts deleted file mode 100644 index 72593733..00000000 --- a/plugins/plugin-copy-code/src/client/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '../shared/index.js' diff --git a/plugins/plugin-copy-code/src/client/setupCopyCode.ts b/plugins/plugin-copy-code/src/client/setupCopyCode.ts deleted file mode 100644 index a7cbadeb..00000000 --- a/plugins/plugin-copy-code/src/client/setupCopyCode.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { nextTick, onMounted } from 'vue' -import { onContentUpdated } from '@vuepress-plume/plugin-content-update/client' -import type { CopyCodeOptions } from '../shared/index.js' - -declare const __COPY_CODE_OPTIONS__: CopyCodeOptions - -const options = __COPY_CODE_OPTIONS__ -const RE_LANGUAGE = /language-(\w+)/ -const RE_START_CODE = /^ *(\$|>)/gm -const shells = ['shellscript', 'shell', 'bash', 'sh', 'zsh'] -const ignoredNodes = ['.diff.remove', '.vp-copy-ignore'] - -function isMobile(): boolean { - return navigator - ? /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/iu.test( - navigator.userAgent, - ) - : false -} - -function sleep(ms: number): Promise { - return new Promise(resolve => setTimeout(resolve, ms)) -} - -export function setupCopyCode(): void { - const insertBtn = (codeBlockEl: HTMLElement): void => { - if (codeBlockEl.hasAttribute('has-copy-code')) - return - const button = document.createElement('button') - button.className = 'copy-code-button' - const parent = codeBlockEl.parentElement - - if (parent) { - parent.insertBefore(button, codeBlockEl) - const classes = parent.className - const match = classes.match(RE_LANGUAGE) || [] - if (match[1]) - button.setAttribute('data-lang', match[1]) - } - - codeBlockEl.setAttribute('has-copy-code', '') - } - - const generateButton = async () => { - const { selector, delay } = options - await nextTick() - await sleep(delay || 0) - const selectors = Array.isArray(selector) ? selector : [selector!] - selectors.forEach((item) => { - document.querySelectorAll(item).forEach(insertBtn) - }) - } - - onMounted(async () => { - if (!isMobile() || options.showInMobile) { - await generateButton() - - const timeoutIdMap: WeakMap = new WeakMap() - window.addEventListener('click', (e) => { - const el = e.target as HTMLElement - if (el.matches('div[class*="language-"] > button.copy-code-button')) { - const parent = el.parentElement - const sibling = el.nextElementSibling - if (!parent || !sibling) - return - - // Clone the node and remove the ignored nodes - const clone = sibling.cloneNode(true) as HTMLElement - clone - .querySelectorAll(ignoredNodes.join(',')) - .forEach(node => node.remove()) - - let text = clone.textContent || '' - const lang = el.getAttribute('data-lang') || '' - if (lang && shells.includes(lang)) - text = text.replace(RE_START_CODE, '').trim() - - copyToClipboard(text).then(() => { - el.classList.add('copied') - clearTimeout(timeoutIdMap.get(el)) - const timeoutId = setTimeout(() => { - el.classList.remove('copied') - el.blur() - timeoutIdMap.delete(el) - }, options.duration) - timeoutIdMap.set(el, timeoutId) - }) - } - }) - } - }) - - onContentUpdated(() => { - if (!isMobile() || options.showInMobile) - generateButton() - }) -} - -async function copyToClipboard(text: string) { - try { - return navigator.clipboard.writeText(text) - } - catch { - const element = document.createElement('textarea') - const previouslyFocusedElement = document.activeElement - - element.value = text - - // Prevent keyboard from showing on mobile - element.setAttribute('readonly', '') - - element.style.contain = 'strict' - element.style.position = 'absolute' - element.style.left = '-9999px' - element.style.fontSize = '12pt' // Prevent zooming on iOS - - const selection = document.getSelection() - const originalRange = selection - ? selection.rangeCount > 0 && selection.getRangeAt(0) - : null - - document.body.appendChild(element) - element.select() - - // Explicit selection workaround for iOS - element.selectionStart = 0 - element.selectionEnd = text.length - - document.execCommand('copy') - document.body.removeChild(element) - - if (originalRange) { - selection!.removeAllRanges() // originalRange can't be truthy when selection is falsy - selection!.addRange(originalRange) - } - - // Get the focus back on the previously focused element, if any - if (previouslyFocusedElement) { - ; (previouslyFocusedElement as HTMLElement).focus() - } - } -} diff --git a/plugins/plugin-copy-code/src/client/styles/button.css b/plugins/plugin-copy-code/src/client/styles/button.css deleted file mode 100644 index bf2f8fab..00000000 --- a/plugins/plugin-copy-code/src/client/styles/button.css +++ /dev/null @@ -1,100 +0,0 @@ -:root { - --vp-icon-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2'/%3E%3C/svg%3E"); - --vp-icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m-6 9 2 2 4-4'/%3E%3C/svg%3E"); -} - -:root { - --vp-code-copy-code-border-color: #e2e2e3; - --vp-code-copy-code-bg: #f6f6f7; - --vp-code-copy-code-hover-border-color: #e2e2e3; - --vp-code-copy-code-hover-bg: #fff; - --vp-code-copy-code-active-text: rgba(60, 60, 67, 0.78); - --vp-code-copy-copied-text-content: "Copied"; -} - -html[lang="zh-CN"] { - --vp-code-copy-copied-text-content: "已复制"; -} - -.dark { - --vp-code-copy-code-border-color: #2e2e32; - --vp-code-copy-code-bg: #202127; - --vp-code-copy-code-hover-bg: #1b1b1f; - --vp-code-copy-code-hover-border-color: #2e2e32; - --vp-code-copy-code-active-text: rgba(235, 235, 245, 0.6); -} - -.copy-code-button { - position: absolute; - top: 12px; - - /* rtl:ignore */ - right: 12px; - z-index: 3; - width: 40px; - height: 40px; - cursor: pointer; - background-color: var(--vp-code-copy-code-bg); - background-image: var(--vp-icon-copy); - background-repeat: no-repeat; - background-position: 50%; - background-size: 20px; - border: 1px solid var(--vp-code-copy-code-border-color); - border-radius: 4px; - opacity: 0; - transition: - border-color 0.25s, - background-color 0.25s, - opacity 0.25s; - - /* rtl:ignore */ - direction: ltr; -} - -[class*="language-"]:hover > .copy-code-button, -[class*="language-"] > .copy-code-button:focus, -[class*="language-"] > .copy-code-button.copied { - opacity: 1; -} - -[class*="language-"] > .copy-code-button:hover, -[class*="language-"] > .copy-code-button.copied { - background-color: var(--vp-code-copy-code-hover-bg); - border-color: var(--vp-code-copy-code-hover-border-color); -} - -[class*="language-"] > .copy-code-button.copied, -[class*="language-"] > .copy-code-button:hover.copied { - background-color: var(--vp-code-copy-code-hover-bg); - background-image: var(--vp-icon-copied); - - /* rtl:ignore */ - border-radius: 0 4px 4px 0; -} - -[class*="language-"] > .copy-code-button.copied::before, -[class*="language-"] > .copy-code-button:hover.copied::before { - position: relative; - top: -1px; - display: flex; - align-items: center; - justify-content: center; - width: fit-content; - height: 40px; - padding: 0 10px; - font-size: 12px; - font-weight: 500; - color: var(--vp-code-copy-code-active-text); - text-align: center; - white-space: nowrap; - content: var(--vp-code-copy-copied-text-content); - background-color: var(--vp-code-copy-code-hover-bg); - border: 1px solid var(--vp-code-copy-code-hover-border-color); - - /* rtl:ignore */ - border-right: 0; - border-radius: 4px 0 0 4px; - - /* rtl:ignore */ - transform: translateX(calc(-100% - 1px)); -} diff --git a/plugins/plugin-copy-code/src/node/index.ts b/plugins/plugin-copy-code/src/node/index.ts deleted file mode 100644 index 6b3df8a9..00000000 --- a/plugins/plugin-copy-code/src/node/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { copyCodePlugin } from './plugin.js' - -export * from './plugin.js' -export * from '../shared/index.js' - -export default copyCodePlugin diff --git a/plugins/plugin-copy-code/src/node/plugin.ts b/plugins/plugin-copy-code/src/node/plugin.ts deleted file mode 100644 index 1f8bd3fd..00000000 --- a/plugins/plugin-copy-code/src/node/plugin.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { Plugin } from 'vuepress/core' -import { getDirname, path } from 'vuepress/utils' -import type { CopyCodeOptions } from '../shared/index.js' - -const __dirname = getDirname(import.meta.url) - -const defaultOptions: CopyCodeOptions = { - selector: '.theme-default-content div[class*="language-"] pre', - duration: 1500, - delay: 500, - showInMobile: false, -} - -export function copyCodePlugin(options: CopyCodeOptions): Plugin { - options = Object.assign({}, defaultOptions, options) - - return { - name: '@vuepress-plume/plugin-copy-code', - - define: (): Record => ({ - __COPY_CODE_OPTIONS__: options, - }), - - clientConfigFile: path.resolve(__dirname, '../client/clientConfig.js'), - } -} diff --git a/plugins/plugin-copy-code/src/shared/index.ts b/plugins/plugin-copy-code/src/shared/index.ts deleted file mode 100644 index 1af4b158..00000000 --- a/plugins/plugin-copy-code/src/shared/index.ts +++ /dev/null @@ -1,29 +0,0 @@ -export interface CopyCodeOptions { - /** - * 代码块选择器 - * - * @default '.theme-default-content dev[class*="language-"] pre' - */ - selector?: string | string[] - - /** - * 提示消息显示时间 - * - * @description 设置为 `0` 将会禁用提示 - * - * @default 1500 - */ - duration?: number - - /** - * 是否展示在移动端 - */ - showInMobile?: boolean - - /** - * 注册复制按钮的延时,单位 ms - * - * @default 500 - */ - delay?: number -} diff --git a/plugins/plugin-copy-code/tsconfig.build.json b/plugins/plugin-copy-code/tsconfig.build.json deleted file mode 100644 index 6bf67375..00000000 --- a/plugins/plugin-copy-code/tsconfig.build.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../tsconfig.build.json", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./lib" - }, - "include": ["./src"] -} diff --git a/plugins/plugin-notes-data/LICENSE b/plugins/plugin-notes-data/LICENSE deleted file mode 100644 index 9f677c90..00000000 --- a/plugins/plugin-notes-data/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (C) 2021 - PRESENT by pengzhanbo - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/plugins/plugin-notes-data/README.md b/plugins/plugin-notes-data/README.md deleted file mode 100644 index ef52022f..00000000 --- a/plugins/plugin-notes-data/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# `@vuepress-plume/plugin-notes-data` - -## Install - -```sh -npm install @vuepress-plume/plugin-notes-data -# or -pnpm add @vuepress-plume/plugin-notes-data -# or -yarn add @vuepress-plume/plugin-notes-data -``` - -## Usage - -``` js -// .vuepress/config.[jt]s -import { notesDataPlugin } from '@vuepress-plume/plugin-notes-data' - -export default { - // ... - plugins: [ - notesDataPlugin() - ] - // ... -} -``` - -## Options - -``` ts -interface NotesDataOptions { - dir: string - link: string - include?: string | string[] - exclude?: string | string[] - notes: NotesItem[] -} - -interface NotesItem { - dir: string - link: string - text: string - sidebar?: NotesSidebar | 'auto' -} - -type NotesSidebar = (NotesSidebarItem | string)[] - -interface NotesSidebarItem { - text?: string - link?: string - dir?: string - collapsed?: boolean - items?: NotesSidebar -} -``` diff --git a/plugins/plugin-notes-data/package.json b/plugins/plugin-notes-data/package.json deleted file mode 100644 index 9a650afe..00000000 --- a/plugins/plugin-notes-data/package.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "name": "@vuepress-plume/plugin-notes-data", - "type": "module", - "version": "1.0.0-rc.75", - "private": "true", - "description": "The Plugin for VuePress 2 - notes data", - "author": "pengzhanbo ", - "license": "MIT", - "homepage": "https://github.com/pengzhanbo/vuepress-theme-plume#readme", - "repository": { - "type": "git", - "url": "git+https://github.com/pengzhanbo/vuepress-theme-plume.git", - "directory": "plugins/plugin-notes-data" - }, - "bugs": { - "url": "https://github.com/pengzhanbo/vuepress-theme-plume/issues" - }, - "exports": { - ".": { - "types": "./lib/node/index.d.ts", - "import": "./lib/node/index.js" - }, - "./client": { - "types": "./lib/client/index.d.ts", - "import": "./lib/client/index.js" - }, - "./package.json": "./package.json" - }, - "main": "lib/node/index.js", - "types": "./lib/node/index.d.ts", - "files": [ - "lib" - ], - "scripts": { - "build": "pnpm run copy && pnpm run ts", - "clean": "rimraf --glob ./lib ./*.tsbuildinfo", - "copy": "cpx \"src/**/*.{d.ts,vue,css,scss,jpg,png}\" lib", - "ts": "tsc -b tsconfig.build.json" - }, - "peerDependencies": { - "vuepress": "2.0.0-rc.14" - }, - "dependencies": { - "@vue/devtools-api": "6.6.3", - "chokidar": "^3.6.0", - "create-filter": "^1.1.0", - "vue": "^3.4.31" - }, - "publishConfig": { - "access": "public" - }, - "keyword": [ - "VuePress", - "vuepress plugin", - "notesData", - "vuepress-plugin-plugin-notes-data" - ] -} diff --git a/plugins/plugin-notes-data/src/client/clientConfig.ts b/plugins/plugin-notes-data/src/client/clientConfig.ts deleted file mode 100644 index 4cd6b0e1..00000000 --- a/plugins/plugin-notes-data/src/client/clientConfig.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { setupDevtoolsPlugin } from '@vue/devtools-api' -import { defineClientConfig } from 'vuepress/client' -import type { ClientConfig } from 'vuepress/client' -import { useNotesData } from './composables/index.js' - -declare const __VUE_PROD_DEVTOOLS__: boolean - -export default defineClientConfig({ - enhance({ app }) { - const notesData = useNotesData() - - Object.defineProperties(app.config.globalProperties, { - $notesData: { - get() { - return notesData.value - }, - }, - }) - - // setup devtools in dev mode - if (__VUEPRESS_DEV__ || __VUE_PROD_DEVTOOLS__) { - const PLUGIN_ID = 'org.vuejs.vuepress' - const PLUGIN_LABEL = 'VuePress' - const INSPECTOR_ID = PLUGIN_ID - - setupDevtoolsPlugin( - { - // fix recursive reference - app: app as any, - id: PLUGIN_ID, - label: PLUGIN_LABEL, - packageName: '@vuepress-plume/plugin-notes-data', - homepage: 'https://theme-plume.vuejs.press/', - logo: 'https://v2.vuepress.vuejs.org/images/hero.png', - componentStateTypes: ['VuePress'], - }, - (api) => { - api.on.inspectComponent((payload) => { - payload.instanceData.state.push({ - type: 'VuePress', - key: 'notesData', - editable: false, - value: notesData.value, - }) - }) - api.on.getInspectorTree((payload) => { - if (payload.inspectorId !== INSPECTOR_ID) - return - payload.rootNodes.push({ - id: 'notes_data', - label: 'Notes Data', - }) - }) - api.on.getInspectorState((payload) => { - if (payload.inspectorId !== INSPECTOR_ID) - return - if (payload.nodeId === 'notes_data') { - payload.state = { - NotesData: [{ - key: 'notesData', - value: notesData.value, - }], - } - } - }) - }, - ) - } - }, -}) as ClientConfig diff --git a/plugins/plugin-notes-data/src/client/composables/index.ts b/plugins/plugin-notes-data/src/client/composables/index.ts deleted file mode 100644 index 6434f5b2..00000000 --- a/plugins/plugin-notes-data/src/client/composables/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './notesDate.js' diff --git a/plugins/plugin-notes-data/src/client/composables/notesDate.ts b/plugins/plugin-notes-data/src/client/composables/notesDate.ts deleted file mode 100644 index bf357409..00000000 --- a/plugins/plugin-notes-data/src/client/composables/notesDate.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { notesData as notesDataRaw } from '@internal/notesData' -import { ref } from 'vue' -import type { Ref } from 'vue' -import type { NotesData } from '../../shared/index.js' - -declare const __VUE_HMR_RUNTIME__: Record - -export type NotesDataRef = Ref - -export const notesData: NotesDataRef = ref(notesDataRaw) - -export function useNotesData< - T extends NotesData = NotesData, ->(): NotesDataRef { - return notesData as NotesDataRef -} - -if (__VUEPRESS_DEV__ && (import.meta.webpackHot || import.meta.hot)) { - __VUE_HMR_RUNTIME__.updateNotesData = (data: NotesData) => { - notesData.value = data - } -} diff --git a/plugins/plugin-notes-data/src/client/index.ts b/plugins/plugin-notes-data/src/client/index.ts deleted file mode 100644 index 16748f83..00000000 --- a/plugins/plugin-notes-data/src/client/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export type { NotesData, NotesSidebarItem } from '../shared/index.js' -export * from './composables/index.js' diff --git a/plugins/plugin-notes-data/src/client/notesData.d.ts b/plugins/plugin-notes-data/src/client/notesData.d.ts deleted file mode 100644 index f5258ec2..00000000 --- a/plugins/plugin-notes-data/src/client/notesData.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { NotesData } from '../shared/index.js' - -declare module '@internal/notesData' { - const notesData: NotesData - - export { notesData } -} diff --git a/plugins/plugin-notes-data/src/node/index.ts b/plugins/plugin-notes-data/src/node/index.ts deleted file mode 100644 index 69e663e0..00000000 --- a/plugins/plugin-notes-data/src/node/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { notesDataPlugin } from './plugin.js' - -export * from './plugin.js' -export * from '../shared/index.js' - -export default notesDataPlugin diff --git a/plugins/plugin-notes-data/src/node/plugin.ts b/plugins/plugin-notes-data/src/node/plugin.ts deleted file mode 100644 index 62b1f47f..00000000 --- a/plugins/plugin-notes-data/src/node/plugin.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { Plugin } from 'vuepress/core' -import { getDirname, path } from 'vuepress/utils' -import type { NotesDataOptions } from '../shared/index.js' -import { prepareNotesData, watchNotesData } from './prepareNotesData.js' -import { wait } from './utils.js' - -export function notesDataPlugin(options: NotesDataOptions | NotesDataOptions[]): Plugin { - return { - name: '@vuepress-plume/plugin-notes-data', - - clientConfigFile: path.join( - getDirname(import.meta.url), - '../client/clientConfig.js', - ), - - onPrepared: async (app) => { - await wait(50) - await prepareNotesData(app, options) - }, - onWatched: (app, watchers) => watchNotesData(app, watchers, options), - } -} diff --git a/plugins/plugin-notes-data/src/node/prepareNotesData.ts b/plugins/plugin-notes-data/src/node/prepareNotesData.ts deleted file mode 100644 index 557c623e..00000000 --- a/plugins/plugin-notes-data/src/node/prepareNotesData.ts +++ /dev/null @@ -1,246 +0,0 @@ -import { colors, logger, path } from 'vuepress/utils' -import type { App } from 'vuepress/core' -import * as chokidar from 'chokidar' -import { createFilter } from 'create-filter' -import type { - NotesData, - NotesDataOptions, - NotesItemOptions, - NotesSidebar, - NotesSidebarItem, -} from '../shared/index.js' -import { ensureArray, hash, normalizePath } from './utils.js' - -const HMR_CODE = ` -if (import.meta.webpackHot) { - import.meta.webpackHot.accept() - if (__VUE_HMR_RUNTIME__.updateNotesData) { - __VUE_HMR_RUNTIME__.updateNotesData(notesData) - } -} - -if (import.meta.hot) { - import.meta.hot.accept(({ notesData }) => { - __VUE_HMR_RUNTIME__.updateNotesData(notesData) - }) -} -` - -interface NotePage { - relativePath: string - title: string - link: string - frontmatter: Record -} - -function resolvedNotesData(app: App, options: NotesDataOptions, result: NotesData) { - const { include, exclude, notes, dir: _dir, link } = options - if (!notes || notes.length === 0) - return - const dir = normalizePath(_dir).replace(/^\//, '') - const filter = createFilter(ensureArray(include), ensureArray(exclude), { - resolve: false, - }) - const DIR_PATTERN = new RegExp(`^${normalizePath(path.join(dir, '/'))}`) - const notesPageList: NotePage[] = app.pages - .filter( - page => - page.filePathRelative - && page.filePathRelative.startsWith(dir) - && filter(page.filePathRelative), - ) - .map(page => ({ - relativePath: page.filePathRelative?.replace(DIR_PATTERN, '') || '', - title: page.title, - link: page.path, - frontmatter: page.frontmatter, - })) - notes.forEach((note) => { - result[normalizePath(path.join('/', link, note.link))] = initSidebar( - note, - notesPageList.filter(page => - page.relativePath.startsWith(note.dir.trim().replace(/^\/|\/$/g, '')), - ), - ) - }) -} - -let contentHash: string | undefined -export async function prepareNotesData(app: App, options: NotesDataOptions | NotesDataOptions[]) { - const start = performance.now() - const notesData: NotesData = {} - const allOptions = ensureArray(options) - - allOptions.forEach(option => resolvedNotesData(app, option, notesData)) - - let content = ` -export const notesData = ${JSON.stringify(notesData, null, 2)} -` - if (app.env.isDev) - content += HMR_CODE - - const currentHash = hash(content) - if (!contentHash || contentHash !== currentHash) { - contentHash = currentHash - await app.writeTemp('internal/notesData.js', content) - } - - if (app.env.isDebug) { - logger.info( - `\n[${colors.green('@vuepress-plume/plugin-notes-data')}] prepare notes data time spent: ${(performance.now() - start).toFixed(2)}ms`, - ) - } -} - -export function watchNotesData(app: App, watchers: any[], options: NotesDataOptions | NotesDataOptions[]): void { - const allOptions = ensureArray(options) - if (!allOptions.length) - return - - const [firstLink, ...links] = allOptions.map(option => option.link).filter(Boolean) - - if (!firstLink) - return - - const dir = path.join('pages', firstLink, '**/*') - const watcher = chokidar.watch(dir, { - cwd: app.dir.temp(), - ignoreInitial: true, - }) - - links.length && watcher.add(links.map(link => path.join('pages', link, '**/*'))) - - watcher.on('add', () => prepareNotesData(app, options)) - watcher.on('change', () => prepareNotesData(app, options)) - watcher.on('unlink', () => prepareNotesData(app, options)) - watchers.push(watcher) -} - -function initSidebar(note: NotesItemOptions, pages: NotePage[]): NotesSidebarItem[] { - if (!note.sidebar) - return [] - if (note.sidebar === 'auto') - return initSidebarByAuto(note, pages) - return initSidebarByConfig(note, pages) -} - -function initSidebarByAuto( - note: NotesItemOptions, - pages: NotePage[], -): NotesSidebarItem[] { - let tempPages = pages.map((page) => { - return { ...page, splitPath: page.relativePath.split('/') } - }) - - const maxIndex = Math.max(...tempPages.map(page => page.splitPath.length)) - let nowIndex = 0 - - while (nowIndex < maxIndex) { - tempPages = tempPages.sort((prev, next) => { - const pi = prev.splitPath?.[nowIndex]?.match(/(\d+)\.(?=[^/]+$)/)?.[1] - const ni = next.splitPath?.[nowIndex]?.match(/(\d+)\.(?=[^/]+$)/)?.[1] - if (!pi || !ni) - return 0 - return Number.parseFloat(pi) < Number.parseFloat(ni) ? -1 : 1 - }) - - nowIndex++ - } - - pages = tempPages.map((page) => { - delete (page as any).splitPath - return page - }) - - const RE_INDEX = ['index.md', 'README.md', 'readme.md'] - const result: NotesSidebarItem[] = [] - for (const page of pages) { - const { relativePath, title, link, frontmatter } = page - const paths = relativePath - .slice(note.dir.replace(/^\/|\/$/g, '').length + 1) - .split('/') - let index = 0 - let dir: string - let items = result - // eslint-disable-next-line no-cond-assign - while ((dir = paths[index])) { - const text = dir.replace(/\.md$/, '').replace(/^\d+\./, '') - let current = items.find(item => item.text === text) - if (!current) { - current = { text, link: undefined, items: [] } - !RE_INDEX.includes(dir) ? items.push(current) : items.unshift(current) - } - if (dir.endsWith('.md')) { - current.link = link - current.text = title - } - if (frontmatter.icon) - current.icon = frontmatter.icon - - items = current.items as NotesSidebarItem[] - index++ - } - } - return result -} - -function initSidebarByConfig( - { text, dir, sidebar }: NotesItemOptions, - pages: NotePage[], -): NotesSidebarItem[] { - return (sidebar as NotesSidebar).map((item) => { - if (typeof item === 'string') { - const current = findNotePage(item, dir, pages) - return { - text: current?.title || text, - link: current?.link, - icon: current?.frontmatter.icon, - // items: [], - } - } - else { - const current = findNotePage(item.link || '', dir, pages) - return { - text: item.text || item.dir || current?.title, - collapsed: item.collapsed, - icon: item.icon || current?.frontmatter.icon, - link: item.link, - items: initSidebarByConfig( - { - link: item.link || '', - text: item.text || '', - sidebar: item.items, - dir: normalizePath(path.join(dir, item.dir || '')), - }, - pages, - ), - } - } - }) -} - -function findNotePage( - sidebar: string, - dir: string, - notePageList: NotePage[], -): NotePage | undefined { - if (sidebar === '' || sidebar === 'README.md' || sidebar === 'index.md') { - return notePageList.find((page) => { - const relative = page.relativePath - return ( - relative === normalizePath(path.join(dir, 'README.md')) - || relative === normalizePath(path.join(dir, 'index.md')) - ) - }) - } - else { - return notePageList.find((page) => { - const relative = page.relativePath - return ( - relative === normalizePath(path.join(dir, sidebar)) - || relative === normalizePath(path.join(dir, `${sidebar}.md`)) - || page.link === sidebar - ) - }) - } -} diff --git a/plugins/plugin-notes-data/src/node/utils.ts b/plugins/plugin-notes-data/src/node/utils.ts deleted file mode 100644 index 8e3da042..00000000 --- a/plugins/plugin-notes-data/src/node/utils.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { createHash } from 'node:crypto' - -export function ensureArray(thing: T | T[] | null | undefined): T[] { - if (Array.isArray(thing)) - return thing - if (thing === null || thing === undefined) - return [] - return [thing] -} - -export function normalizePath(str: string) { - return str.replace(/\\+/g, '/') -} - -export function wait(time: number) { - return new Promise(resolve => setTimeout(resolve, time)) -} - -export function hash(content: string): string { - return createHash('md5').update(content).digest('hex') -} diff --git a/plugins/plugin-notes-data/src/shared/index.ts b/plugins/plugin-notes-data/src/shared/index.ts deleted file mode 100644 index 0253d665..00000000 --- a/plugins/plugin-notes-data/src/shared/index.ts +++ /dev/null @@ -1,77 +0,0 @@ -export interface NotesDataOptions { - /** - * 保存所有笔记的目录 - * @default '/notes/' - */ - dir: string - /** - * 所有笔记的默认链接前缀 - * @default '/' - */ - link: string - /** - * global include,只加载需要加载到笔记中的文件 - */ - include?: string | string[] - /** - * global exclude,排除不需要加载到笔记中的文件 - */ - exclude?: string | string[] - /** - * 笔记配置 - */ - notes: NotesItemOptions[] -} - -export type NotesItemOptions = (Omit & { text?: string }) - -export interface NotesItem { - /** - * 保存笔记的目录 - */ - dir: string - /** - * 当前笔记的链接前缀,将会与 `notes.link` 合并 - */ - link: string - /** - * 当前笔记名称 - */ - text: string - /** - * 当前笔记的侧边栏配置 - */ - sidebar?: NotesSidebar | 'auto' -} - -export type NotesSidebar = (NotesSidebarItem | string)[] - -export interface NotesSidebarItem { - /** - * 侧边栏文本,如果为空,则使用 `dir` - */ - text?: string - /** - * 侧边栏链接 - */ - link?: string - /** - * 次级侧边栏所在目录 - */ - dir?: string - /** - * 是否折叠, 未定义时不可折叠 - * @default undefined - */ - collapsed?: boolean - /** - * 次级侧边栏 - */ - items?: NotesSidebar - /** - * 侧边栏图标 - */ - icon?: string | { svg: string } -} - -export type NotesData = Record diff --git a/plugins/plugin-notes-data/tsconfig.build.json b/plugins/plugin-notes-data/tsconfig.build.json deleted file mode 100644 index e2bd7e8d..00000000 --- a/plugins/plugin-notes-data/tsconfig.build.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "../tsconfig.build.json", - "compilerOptions": { - "rootDir": "./src", - "paths": { - "@internal/notesData": ["./src/client/notesData.d.ts"] - }, - "types": ["vuepress/client-types", "vite/client", "webpack-env"], - "outDir": "./lib" - }, - "include": ["./src"] -} diff --git a/plugins/tsconfig.build.json b/plugins/tsconfig.build.json index 7f254e32..79fcf8d6 100644 --- a/plugins/tsconfig.build.json +++ b/plugins/tsconfig.build.json @@ -4,13 +4,9 @@ "composite": true }, "references": [ - { "path": "./plugin-auto-frontmatter/tsconfig.build.json" }, { "path": "./plugin-baidu-tongji/tsconfig.build.json" }, - { "path": "./plugin-blog-data/tsconfig.build.json" }, - { "path": "./plugin-caniuse/tsconfig.build.json" }, - { "path": "./plugin-copy-code/tsconfig.build.json" }, { "path": "./plugin-iconify/tsconfig.build.json" }, - { "path": "./plugin-notes-data/tsconfig.build.json" }, + { "path": "./plugin-fonts/tsconfig.build.json" }, { "path": "./plugin-shikiji/tsconfig.build.json" }, { "path": "./plugin-content-update/tsconfig.build.json" }, { "path": "./plugin-search/tsconfig.build.json" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2632c5a4..40ada0cf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -106,67 +106,12 @@ importers: specifier: ^4.17.21 version: 4.17.21 - plugins/plugin-auto-frontmatter: - dependencies: - '@pengzhanbo/utils': - specifier: ^1.1.2 - version: 1.1.2 - chokidar: - specifier: ^3.6.0 - version: 3.6.0 - create-filter: - specifier: ^1.1.0 - version: 1.1.0 - fast-glob: - specifier: ^3.3.2 - version: 3.3.2 - gray-matter: - specifier: ^4.0.3 - version: 4.0.3 - json2yaml: - specifier: ^1.1.0 - version: 1.1.0 - vuepress: - specifier: 2.0.0-rc.14 - version: 2.0.0-rc.14(@vuepress/bundler-vite@2.0.0-rc.14(@types/node@20.12.10)(typescript@5.5.3))(typescript@5.5.3)(vue@3.4.31(typescript@5.5.3)) - plugins/plugin-baidu-tongji: dependencies: vuepress: specifier: 2.0.0-rc.14 version: 2.0.0-rc.14(@vuepress/bundler-vite@2.0.0-rc.14(@types/node@20.12.10)(typescript@5.5.3))(typescript@5.5.3)(vue@3.4.31(typescript@5.5.3)) - plugins/plugin-blog-data: - dependencies: - '@vue/devtools-api': - specifier: 6.6.3 - version: 6.6.3 - chokidar: - specifier: ^3.6.0 - version: 3.6.0 - create-filter: - specifier: ^1.1.0 - version: 1.1.0 - vue: - specifier: ^3.4.31 - version: 3.4.31(typescript@5.5.3) - vuepress: - specifier: 2.0.0-rc.14 - version: 2.0.0-rc.14(@vuepress/bundler-vite@2.0.0-rc.14(@types/node@20.12.10)(typescript@5.5.3))(typescript@5.5.3)(vue@3.4.31(typescript@5.5.3)) - - plugins/plugin-caniuse: - dependencies: - markdown-it-container: - specifier: ^4.0.0 - version: 4.0.0 - vuepress: - specifier: 2.0.0-rc.14 - version: 2.0.0-rc.14(@vuepress/bundler-vite@2.0.0-rc.14(@types/node@20.12.10)(typescript@5.5.3))(typescript@5.5.3)(vue@3.4.31(typescript@5.5.3)) - devDependencies: - '@types/markdown-it': - specifier: ^14.1.1 - version: 14.1.1 - plugins/plugin-content-update: dependencies: vue: @@ -176,18 +121,6 @@ importers: specifier: 2.0.0-rc.14 version: 2.0.0-rc.14(@vuepress/bundler-vite@2.0.0-rc.14(@types/node@20.12.10)(typescript@5.5.3))(typescript@5.5.3)(vue@3.4.31(typescript@5.5.3)) - plugins/plugin-copy-code: - dependencies: - '@vuepress-plume/plugin-content-update': - specifier: workspace:~ - version: link:../plugin-content-update - vue: - specifier: ^3.4.31 - version: 3.4.31(typescript@5.5.3) - vuepress: - specifier: 2.0.0-rc.14 - version: 2.0.0-rc.14(@vuepress/bundler-vite@2.0.0-rc.14(@types/node@20.12.10)(typescript@5.5.3))(typescript@5.5.3)(vue@3.4.31(typescript@5.5.3)) - plugins/plugin-fonts: dependencies: vuepress: @@ -249,24 +182,6 @@ importers: specifier: ^14.1.1 version: 14.1.1 - plugins/plugin-notes-data: - dependencies: - '@vue/devtools-api': - specifier: 6.6.3 - version: 6.6.3 - chokidar: - specifier: ^3.6.0 - version: 3.6.0 - create-filter: - specifier: ^1.1.0 - version: 1.1.0 - vue: - specifier: ^3.4.31 - version: 3.4.31(typescript@5.5.3) - vuepress: - specifier: 2.0.0-rc.14 - version: 2.0.0-rc.14(@vuepress/bundler-vite@2.0.0-rc.14(@types/node@20.12.10)(typescript@5.5.3))(typescript@5.5.3)(vue@3.4.31(typescript@5.5.3)) - plugins/plugin-search: dependencies: '@vuepress/helper': diff --git a/theme/src/client/components/VPDoc.vue b/theme/src/client/components/VPDoc.vue index 9d8b7470..34a1f6b3 100644 --- a/theme/src/client/components/VPDoc.vue +++ b/theme/src/client/components/VPDoc.vue @@ -173,8 +173,8 @@ watch( max-width: 784px; } - .vp-doc-container:not(.has-sidebar.has-aside) .content { - max-width: 884px; + .vp-doc-container.is-blog:not(.has-sidebar.has-aside) .content { + max-width: 985px; } .vp-doc-container:not(.has-sidebar) .container { diff --git a/theme/src/node/autoFrontmatter/resolveOptions.ts b/theme/src/node/autoFrontmatter/resolveOptions.ts index 37e1a25d..ffd2d9f9 100644 --- a/theme/src/node/autoFrontmatter/resolveOptions.ts +++ b/theme/src/node/autoFrontmatter/resolveOptions.ts @@ -2,7 +2,7 @@ import { path } from 'vuepress/utils' import { removeLeadingSlash, resolveLocalePath } from 'vuepress/shared' import { ensureLeadingSlash } from '@vuepress/helper' import { format } from 'date-fns' -import { uniq } from '@pengzhanbo/utils' +import { toArray, uniq } from '@pengzhanbo/utils' import type { AutoFrontmatter, AutoFrontmatterArray, @@ -194,6 +194,36 @@ export function resolveOptions( include: '**/{readme,README,index}.md', frontmatter: {}, }, + toArray(localeOptions.blog?.include).length + ? { + include: localeOptions.blog?.include, + frontmatter: { + ...options.title !== false + ? { + title(title: string, { relativePath }) { + if (title) + return title + const basename = path.basename(relativePath || '', '.md') + return basename + }, + } as AutoFrontmatterObject + : undefined, + ...baseFrontmatter, + ...options.permalink !== false + ? { + permalink(permalink: string, { relativePath }) { + if (permalink) + return permalink + const locale = resolveLocale(relativePath) + const prefix = withBase(articlePrefix, locale) + + return normalizePath(`${prefix}/${nanoid()}/`) + }, + } as AutoFrontmatterObject + : undefined, + }, + } + : '', { include: '*', frontmatter: { @@ -213,10 +243,7 @@ export function resolveOptions( permalink(permalink: string, { relativePath }) { if (permalink) return permalink - const locale = resolveLocale(relativePath) - const prefix = withBase(articlePrefix, locale) - - return normalizePath(`${prefix}/${nanoid()}/`) + return ensureLeadingSlash(normalizePath(relativePath.replace(/\.md$/, '/'))) }, } as AutoFrontmatterObject : undefined, diff --git a/theme/src/node/loadConfig/findConfigPath.ts b/theme/src/node/loadConfig/findConfigPath.ts index 460fc947..5a636313 100644 --- a/theme/src/node/loadConfig/findConfigPath.ts +++ b/theme/src/node/loadConfig/findConfigPath.ts @@ -21,7 +21,7 @@ export async function findConfigPath(app: App, configPath?: string): Promise { - paths.push(resolve(cwd, `./${configPath}.${ext}`)) + paths.push(resolve(cwd, `./${CONFIG_FILE_NAME}.${ext}`)) paths.push(resolve(cwd, `${source}/${CONFIG_FILE_NAME}.${ext}`)) paths.push(resolve(cwd, `./.vuepress/${CONFIG_FILE_NAME}.${ext}`)) }) diff --git a/theme/src/shared/index.ts b/theme/src/shared/index.ts index 6a5e025d..056fb3cd 100644 --- a/theme/src/shared/index.ts +++ b/theme/src/shared/index.ts @@ -7,3 +7,4 @@ export * from './sidebar.js' export * from './navbar.js' export * from './notes.js' export * from './auto-frontmatter.js' +export * from './theme-data.js' diff --git a/theme/src/shared/options/index.ts b/theme/src/shared/options/index.ts index 8181f71c..fcc83290 100644 --- a/theme/src/shared/options/index.ts +++ b/theme/src/shared/options/index.ts @@ -40,7 +40,7 @@ export interface PlumeThemeOptions extends PlumeThemeLocaleOptions { export type PlumeThemeLocaleOptions = PlumeThemeData export type PlumeThemeData = PlumeThemeLocaleData & { - locales?: LocaleConfig> + locales?: LocaleConfig> } export * from './locale.js' diff --git a/tsconfig.json b/tsconfig.json index 7b9356ef..c267a5ab 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,12 +4,6 @@ "jsx": "preserve", "baseUrl": ".", "paths": { - "@internal/blogData": [ - "./plugins/plugin-blog-data/src/client/blogPostData.d.ts" - ], - "@internal/notesData": [ - "./plugins/plugin-notes-data/src/client/notesData.d.ts" - ], "@internal/md-power/replEditorData": [ "./plugins/plugin-md-power/src/client/shim.d.ts" ], @@ -22,9 +16,7 @@ "vuepress-plugin-md-power": [ "./plugins/plugin-md-power/src/node/index.ts" ], - "@theme/*": [ - "./theme/src/client/components/*" - ] + "@theme/*": ["./theme/src/client/components/*"] }, "types": ["webpack-env", "vite/client", "vuepress/client-types"] },