fix: 优化皮肤主题交互

1. 修复caniuse插件在hash更新时重新渲染的问题;
2. 优化皮肤主题样式;
3.修复归档排序问题
This commit is contained in:
pengzhanbo 2022-05-14 20:31:54 +08:00
parent b18464fe0e
commit 1bf2c82d01
40 changed files with 2506 additions and 247 deletions

View File

@ -3,6 +3,7 @@ import { themePlume } from '@vuepress-plume/vuepress-theme-plume'
import { viteBundler } from '@vuepress/bundler-vite'
import { webpackBundler } from '@vuepress/bundler-webpack'
import { defineUserConfig } from '@vuepress/cli'
import notes from './notes'
export default defineUserConfig({
base: '/',
@ -33,61 +34,22 @@ export default defineUserConfig({
twitter: 'https://baidu.com',
linkedin: 'https://baidu.com',
},
notes: {
notes: [
{
link: 'typescript',
dir: 'typescript',
text: 'Typescript',
sidebar: [
'',
{
text: '123',
children: ['1', '2'],
},
{
text: 'css',
dir: 'css',
children: ['1', '2'],
},
],
},
{
link: '/interview-question',
text: '面试题解析',
dir: '面试题',
sidebar: [
{
text: 'HTML',
dir: 'HTML',
children: [],
},
{
text: 'CSS',
dir: 'CSS',
children: ['盒模型'],
},
{
text: 'JavaScript',
dir: 'JavaScript',
children: [],
},
],
},
],
},
notes,
darkMode: true,
navbar: [
{
text: '笔记',
text: 'VuePress',
children: [
{ text: 'theme-plume', link: '/note/vuepress-theme-plume/' },
{
text: 'typescript',
link: '/note/typescript/',
},
{
text: '面试题',
link: '/note/interview-question',
text: 'Plugin',
children: [
{ text: 'caniuse', link: '/note/vuepress-plugin/caniuse/' },
{
text: 'netlify-functions',
link: '/note/vuepress-plugin/netlify-functions/',
},
],
},
],
},
@ -97,9 +59,6 @@ export default defineUserConfig({
content: '',
},
themePlugins: {
caniuse: {
mode: 'embed',
},
search: {
locales: {
'/': {

47
docs/.vuepress/notes.ts Normal file
View File

@ -0,0 +1,47 @@
import { definePlumeNotesConfig } from '@vuepress-plume/vuepress-theme-plume'
export default definePlumeNotesConfig({
notes: [
{
text: '',
dir: 'vuepress-theme-plume',
link: '/vuepress-theme-plume/',
sidebar: [
'',
{
text: '指南',
children: ['快速开始', '编写文章'],
},
{
text: '配置',
children: [
{
text: '主题配置',
link: '主题配置',
children: ['主题插件配置', 'notes配置'],
},
'页面配置',
],
},
{
text: '功能',
children: ['基础功能', 'markdown增强'],
},
],
},
{
dir: 'vuepress-plugin',
text: '',
link: '/vuepress-plugin/',
sidebar: [
'caniuse/README',
{
dir: 'netlify-functions',
text: 'plugin-netlify-functions',
link: 'netlify-functions',
children: ['', '介绍', '使用', '功能', 'API', 'functions开发指南'],
},
],
},
],
})

View File

@ -1,6 +0,0 @@
---
title: md
createTime: 2022/04/04 01:56:31
author: pengzhanbo
permalink: /note/typescript/5j2ggf0m
---

View File

@ -1,6 +0,0 @@
---
title: md
createTime: 2022/04/04 01:57:39
author: pengzhanbo
permalink: /note/typescript/casr1ibn
---

View File

@ -1,40 +0,0 @@
---
title: Typescript
createTime: 2022/04/04 09:45:31
author: pengzhanbo
permalink: /note/typescript/
---
## typescript
### haha
内容
::: tip
提示
:::
::: info
信息
:::
::: note
注释
:::
::: warning
警告
:::
::: danger
危险
:::
::: details
详情
:::
- [ ] todo
- [x] todo

View File

@ -1,6 +0,0 @@
---
title: md
createTime: 2022/04/12 12:09:10
author: pengzhanbo
permalink: /note/typescript/g86ae1b3/
---

View File

@ -1,6 +0,0 @@
---
title: md
createTime: 2022/04/12 12:09:15
author: pengzhanbo
permalink: /note/typescript/vruetr0c/
---

View File

@ -0,0 +1,102 @@
---
title: plugin-caniuse
createTime: 2022/05/13 01:02:51
author: pengzhanbo
permalink: /note/vuepress-plugin/caniuse/
---
项目地址: [vuepress-plugin-caniuse](https://github.com/pengzhanbo/vuepress-theme-plume/tree/main/packages/plugin-caniuse)
![npm version](https://badge.fury.io/js/@vuepress-plume%2Fvuepress-plugin-caniuse.svg)
![npm download](https://img.shields.io/npm/dy/@vuepress-plume/vuepress-plugin-caniuse)
## 指南
为你的 vuepress 站点,在编辑 技术文章时, 提供 嵌入 [can-i-use](https://caniuse.com/) WEB feature 各平台支持说明图标 的功能。
方便在描述某个 WEB feature 时,能更直观的表述 该特性的支持程度。
## 安装
:::: code-group
::: code-group-item npm
``` sh
npm install @vuepress-plume/vuepress-plugin-caniuse
```
:::
::: code-group-item yarn:active
``` sh
yarn add @vuepress-plume/vuepress-plugin-caniuse
```
:::
::: code-group-item pnpm
``` sh
pnpm add @vuepress-plume/vuepress-plugin-caniuse
```
:::
::::
## 使用
### Step1添加插件
将插件添加到你的 vuepress 项目的配置文件中:
:::: code-group
::: code-group-item .vuepress/config.ts
``` ts {2,6}
import { defineUserConfig } from 'vuepress'
import { caniusePlugin } from '@vuepress-plume/vuepress-plugin-caniuse'
export default defineUserConfig({
plugins: [
caniusePlugin()
]
})
```
:::
::: code-group-item .vuepress/config.js
``` js {1,5}
const { caniusePlugin } = require('@vuepress-plume/vuepress-plugin-caniuse')
module.exports = {
plugins: [
caniusePlugin()
]
}
```
:::
::::
### Step2在markdown中使用
在你的 文章 markdown文件中使用以下格式
``` md
::: caniuse <feature>
:::
```
__示例 获取 css 伪类选择器 `:dir()` 在各个浏览器的支持情况图标__
``` md
::: caniuse css-matches-pseudo
:::
```
效果:
::: caniuse css-matches-pseudo
:::
## Method
`caniusePlugin([options])`
插件注册函数
__options:__ `[CanIUsePluginOptions]`
- `options.mode`: 配置 can-i-use 在 文章中的 嵌入模式, 默认: `image`
- `image` 嵌入 特性图表图片
- `embed`: 嵌入 iframe 实时的,可交互的模式

View File

@ -0,0 +1,86 @@
---
title: API
createTime: 2022/05/13 05:49:14
author: pengzhanbo
permalink: /note/vuepress-plugin/netlify-functions/api/
---
## netlifyFunctionsPlugin(options)
在 vuepress 项目中使用, 或者 开发vuepress-theme时使用提供 netlify-functions 开发时服务。
该插件应该优先于其他有依赖该插件的其他插件之前调用。
``` js
netlifyFunctionsPlugin({
sourceDirectory: '',
destDirectory: '',
proxyPrefix: '',
})
```
### options
__类型__ `{ sourceDirectory: string, destDirectory: string, proxyPrefix: string }`
- `options.sourceDirectory`:
`functions` 开发时所在目录, 默认值: `app.dir.source('.vuepress/functions')`,
如果你的vuepress项目源码目录是 `src` 那么 `sourceDirectory` 默认为 `src/.vuepress/functions/`
- `options.destDirectory`:
`functions` 构建后输出目录,默认值: `app.dir.dest('functions')`,
即,如果你的 vuepress项目配置的 `dest` 输出目录为 `docs` 那么默认输出目录为 `docs/functions`,
一般来说,这个配置不需要手动修改。
- `options.proxyPrefix`:
在开发环境中, `Netlify Functions` 服务的默认路径是 `/.netlify/functions/*`, 但这并不能保持开发环境和
生产部署环境一致,所以需要将路径重写。
默认值: `/api`
`^/api/*` 的请求会被转发到 `/.netlify/functions/*`
如, `functions/my_function.ts` ,则请求 `/api/my_function` 将会转发到 `/.netlify/functions/my_function`
## useNetlifyFunctionsPlugin(app, options)
在开发 vuepress plugin 时使用,为插件提供 `netlify functiosn` 支持
``` ts
import { useNetlifyFunctionsPlugin } from '@vuepress-plume/vuepress-plugin-netlify-functions'
const myPlugin = (): Plugin => {
return (app: App) => {
const {
// 请求前缀, 默认 /api
proxyPrefix,
preparePluginFunctions,
generatePluginFunctions
} = useNetlifyFunctionsPlugin(app, {
// 指定插件的functions目录相关脚本在此目录中开发
directory: path.resolve(__dirname, 'functions')
})
return {
name: 'vuepress-plugin-myPlugin',
onPrepared:() => preparePluginFunctions(),
onGenerated: () => generatePluginFunctions(),
}
}
}
```
### options
__类型__ `{ directory: string }`
- `options.directory`
插件中的 functions 开发目录。
一般来说,它的值都设置为 `path.resolve(__dirname, 'functions')`

View File

@ -0,0 +1,41 @@
---
title: 指南
createTime: 2022/05/13 01:28:38
author: pengzhanbo
permalink: /note/vuepress-plugin/netlify-functions/
---
项目地址: [vuepress-plugin-caniuse](https://github.com/pengzhanbo/vuepress-theme-plume/tree/main/packages/plugin-netlify-functions)
![npm version](https://badge.fury.io/js/@vuepress-plume%2Fvuepress-plugin-netlify-functions.svg)
![npm download](https://img.shields.io/npm/dy/@vuepress-plume/vuepress-plugin-netlify-functions)
如果你的 vuepress 站点是部署在 netlify 的而且希望能够使用netlify functions 来做 serverless。
那么你可能需要本插件提供支持。
本插件仅 提供 `Netlify Functions` 开发环境和 打包构建 支持,不提供具体的 `functions` 函数。
- 你可以基于此插件 在你的 vuepress 项目中 自定义 `functions`
- 也可以基于此插件作为你的 vuepress plugin 依赖,开发自定义 `functions` 提供给其他 vuepress项目使用。
## 安装
:::: code-group
::: code-group-item npm
``` sh
npm install @vuepress-plume/vuepress-plugin-netlify-functions
```
:::
::: code-group-item yarn:active
``` sh
yarn add @vuepress-plume/vuepress-plugin-netlify-functions
```
:::
::: code-group-item pnpm
``` sh
pnpm add @vuepress-plume/vuepress-plugin-netlify-functions
```
:::
::::

View File

@ -0,0 +1,95 @@
---
title: functions开发指南
createTime: 2022/05/13 05:45:24
author: pengzhanbo
permalink: /note/vuepress-plugin/netlify-functions/develop-functions/
---
## 说明
### 在一个 vuepress 项目中
在默认配置下,如果你 packages.json
``` json
{
"scripts": {
"serve": "vuepress dev src",
"build": "vuepress build src"
}
}
```
即, 你的 `sourceDir``src` 目录, 那么你的functions目录则为 `src/.vuepress/functions`
在这个目录下,直属的 `ts/js` 文件,均为一个个独立的 `function` 不包括这个目录下的子目录。
``` sh
src/.vuepress/functions
├─my_function.ts # 这是一个function 通过 /api/my_function 调用
├─verify_phone.ts # 这是一个 function 通过 /api/verify_phone 调用
└─utils # 子目录中的不会被识别为function
└─index.ts
```
### 在一个 vuepress plugin 项目中
以官方仓库插件的基本组织结构为例
``` sh
src/node
├─functions
│ ├─my_function.ts # 这是一个function 通过 /api/my_function 调用
│ ├─verify_phone.ts # 这是一个 function 通过 /api/verify_phone 调用
│ └─utils # 子目录中的不会被识别为function
│ └─index.ts
├─index.ts
└─plugin.ts # 在这个文件中配置了 directory 为 path.resolve(__dirname, 'functions')
```
## 依赖
如果你是使用 typescript 作为开发语言,那么可以引入 `@netlify/functions` 模块提供类型检查支持。
如果你的 function 依赖其他的第三方模块,请在配置在项目`package.json``dependencies` 字段中作为生产依赖。
如果你是通过插件提供 function请在 插件的使用指南中 说明你的插件function依赖了哪些第三方模块
提醒使用者安装这些依赖。
## function
`functions` 通过 导出一个 `handler` 函数 提供给 云函数服务调用。
一个 function 的内容一般如下:
- 异步函数
在异步函数中,支持直接返回一个对象作为 响应体报文
``` ts
import { Handler } from '@netlify/functions'
export const handler: Handler = async function (event, context) {
// do something
return {
statusCode: 200,
body: JSON.stringify({})
}
}
```
- 非异步函数
在非异步函数中,通过 `callback` 函数参数返回响应体报文
``` ts
import { Handler } from '@netlify/functions'
export const handler: Handler = function (event, context, callback) {
// do something
callback{
statusCode: 200,
body: JSON.stringify({})
})
}
```
## 示例
[plugin-page-collection](https://github.com/pengzhanbo/vuepress-theme-plume/tree/main/packages/plugin-page-collection)
页面访问次数插件

View File

@ -0,0 +1,62 @@
---
title: 介绍
createTime: 2022/05/13 05:47:06
author: pengzhanbo
permalink: /note/vuepress-plugin/netlify-functions/intro/
---
## Why
### Netlify
[Netlify](https://www.netlify.com/) 是一个提供了免费部署静态站点的平台,可用于作为 `github page` 的替代工具。
`Netlify` 上面部署站点也非常方便,可以直接使用 `github` 仓库进行 构建并部署,同时支持 自定义域名。
还提供了 `Netlify Functions` 等工具,可以用于给站点提供 自定义云函数。
### VuePress
`vuepress` 是一个很方便的静态网站构建工具,使我们可以直接书写 markdown后构建为一个高可用的静态站点。
### 部署
一般情况下,当我们不希望购买一个服务器用于部署我们的站点时,通常都会选择使用 `github page` 来进行免费部署。
`Netlify` 是一种替代方案,而且当使用 `Netlify` 部署时,还可以利用 `Netlify Functions` 提供的云函数功能,
使站点能够进行更为丰富的交互。
### 场景
通过 `Functions` 连接到 一些提供了 免费服务的 云存储服务,比如 `FireBase` `Lean Cloud` 等。
虽然这些云存储服务提供了 Web 客户端直连服务的功能。但毕竟我们的站点源码是直接放在 `github`开源仓库中,
我们不希望将 这些 云存储服务 提供的一些 鉴权信息 直接 保存在 仓库代码中,带来某些安全风险。
在这种场景下,就可以借助 `Netlify Functions` ,将这些鉴权信息,作为 `环境变量`
托管在 `Netlify Environment Variables` 中,然后通过 站点调用 `Functions` 来获取这些鉴权信息。
或者进一步的,直接将 云存储服务的 连接、功能等,都在 `Netlify Functions` 中完成,
站点再调用 `Functions` 接口, 获取返回的数据。
有了 `Netlify Functions` 加上 一些 第三方的 云服务支持, 可以为我们的 vuepress 站点提供更强大的支持。
## 如何整合?
在基于以上的背景,下一步就是需要将 `Netlify Functions` 能够在 我们的 `Vuepress` 项目中进行 整合了。
- 如何使 `Netlify Functions` 能够在本地开发环境中进行调试。
- 如何将 已开发好的 `Functions` 作为 `vuepress plugin` 提供给 其他 `vuepress theme``vuepress` 站点中使用。
### 开发环境
本插件在 vuepress 的开发服务的基础上, 启动了一个 由 `netlify-cli` 提供的 服务,并将该服务通过代理的方式,
代理到 vuepress开发服务上统合开发环境。
并且监听 functions 内容变更,实现热更新。
### 打包
在打包阶段, 生成一个 `netlify.toml` 配置文件,配置 functions 相关内容。
并且将 所有 functions 添加在 vuepress 的构建包中。
如何使用插件,请查看 [使用文档](/note/vuepress-plugin/netlify-functions/usage/)

View File

@ -0,0 +1,196 @@
---
title: 使用
createTime: 2022/05/13 05:45:01
author: pengzhanbo
permalink: /note/vuepress-plugin/netlify-functions/usage/
---
## 安装
:::: code-group
::: code-group-item npm
``` sh
npm install @vuepress-plume/vuepress-plugin-netlify-functions
```
:::
::: code-group-item yarn:active
``` sh
yarn add @vuepress-plume/vuepress-plugin-netlify-functions
```
:::
::: code-group-item pnpm
``` sh
pnpm add @vuepress-plume/vuepress-plugin-netlify-functions
```
:::
::::
## 在vuepress中使用
### 添加插件
在vuepress 的配置文件中 引入并 在 `plugins` 字段中添加插件。
:::: code-group
::: code-group-item .vuepress/config.ts
``` ts
import { defineUserConfig } from 'vuepress'
import { netlifyFunctionsPlugin } from '@vuepress-plume/vuepress-plugin-netlify-functions'
export default defineUserConfig({
//...
plugins: [
netlifyFunctionsPlugin(),
]
// ...
})
```
:::
::: code-group-item .vuepress/config.js
```js
const { netlifyFunctionsPlugin } = require('@vuepress-plume/vuepress-plugin-netlify-functions')
module.exports = {
//...
plugins: [
netlifyFunctionsPlugin(),
]
// ...
}
```
:::
::::
### 编写 functions
启动 vuepress 开发服务后, 就可以在你的 `.vuepress/functions/` 目录中,新建并开发你的 `function`
[`functions` 开发指南](https://docs.netlify.com/functions/overview/)
## 在 vuepress plugin 中使用
### 添加插件钩子
:::: code-group
::: code-group-item typescript
``` ts
import * as path from 'path'
import { App } from '@vuepress/core'
import { useNetlifyFunctionsPlugin } from '@vuepress-plume/vuepress-plugin-netlify-functions'
const myPlugin = (): Plugin => {
return (app: App) => {
const {
// 请求前缀, 默认 /api
proxyPrefix,
preparePluginFunctions,
generatePluginFunctions
} = useNetlifyFunctionsPlugin(app, {
// 指定插件的functions目录相关脚本在此目录中开发
directory: path.resolve(__dirname, 'functions')
})
return {
name: 'vuepress-plugin-myPlugin',
onPrepared:() => preparePluginFunctions(),
onGenerated: () => generatePluginFunctions(),
}
}
}
```
:::
::: code-group-item javascript
``` js
const path = require('path')
const { useNetlifyFunctionsPlugin } = require('@vuepress-plume/vuepress-plugin-netlify-functions')
const myPlugin = () => {
return (app) => {
const {
// 请求前缀, 默认 /api
proxyPrefix,
preparePluginFunctions,
generatePluginFunctions
} = useNetlifyFunctionsPlugin(app, {
// 指定插件的functions目录相关脚本在此目录中开发
directory: path.resolve(__dirname, 'functions')
})
return {
name: 'vuepress-plugin-myPlugin',
onPrepared:() => preparePluginFunctions(),
onGenerated: () => generatePluginFunctions(),
}
}
}
```
:::
::::
在你的插件开发目录,假如是以下结构:
``` sh
.
└─src # 开发目录
├─shared
└─node # node 端
├─functions # functions目录
│ └─my_function.ts # functions脚本
├─plugin.ts
└─index.ts
```
那么,就在你的 `src/node/functions` 目录下进行 functions 开发
[`functions` 开发指南](https://docs.netlify.com/functions/overview/)
如果你已经开发好了一个 `functions/my_function.ts` 的function。
那么你可以在 client端通过以下方式调用
``` ts
async function fetchMyFunction() {
const result = await fetch('/api/my_functions')
// do something
}
```
就像调用一个普通接口一个样简单。
## 环境变量
你可以在项目根目录中,新建一个 `.env` 文件,用于配置开发时环境变量
::: warning
这些环境变量仅用于开发环境时使用,部署生产时不会被加载。
是用于在开发环境中 代替 `Netlify Environment Variables`
在生产环境中,应该使用 `Netlify Environment Variables` 设置这些环境变量。
如果你的 `.env` 文件中有比较私密的信息,建议将 `.env` 文件添加到 `.gitignore` 中,避免提交到 仓库中。
:::
:::: code-group
::: code-group-item .env
```
YOUR_ENV_VAR='your env var'
```
:::
::: code-group-item functions/my_function.ts
``` ts
const YOUR_ENV_VAR = process.env.YOUR_ENV_VAR
```
:::
::::
## 示例
如何使用本插件开发一个 提供 functions 的插件,这里提供了一个 例子:
[plugin-page-collection](https://github.com/pengzhanbo/vuepress-theme-plume/tree/main/packages/plugin-page-collection)
可以参考此例子进行插件开发。
该例子提供了以下功能:
- 连接 `lean cloud`
- 记录页面访问次数,并上报到 `lean cloud` 数据库。
- 查询 当前页面访问次数,并提供组件嵌入到页面中。

View File

@ -0,0 +1,20 @@
---
title: 功能
createTime: 2022/05/13 05:45:11
author: pengzhanbo
permalink: /note/vuepress-plugin/netlify-functions/feature/
---
## 功能
在启动 vuepress 开发环境后,`vuepress-plugin-netlify-functions` 插件会在 vuepress 开发服务中,
启动一个 `netlify-functions` 服务,然后,将通过 vuepress 开发服务代理该服务。
同时,启动对 `functions` 的文件监听,实现服务热更新,从而获得与 vuepress 开发服务环境一致的体验。
## 服务
考虑到通用性,本插件仅提供对于 `netlify functions` 的开发时和构建时支持,并不提供具体的 `functions`功能支持。
一切`functions` 功能由插件使用者自定义。
同时,还提供了给其他插件使用本插件的钩子,这使得多个插件之间或者主题,能够共享 本插件提供的基础服务。

View File

@ -0,0 +1,110 @@
---
title: vuepress-theme-plume
createTime: 2022/04/08 08:52:12
author: pengzhanbo
permalink: /note/vuepress-theme-plume/
article: true
sticky: true
---
项目地址:[Vuepress-theme-plume](https://github.com/pengzhanbo/vuepress-theme-plume)
![npm version](https://badge.fury.io/js/@vuepress-plume%2Fvuepress-theme-plume.svg)
![npm](https://img.shields.io/npm/dy/@vuepress-plume/vuepress-theme-plume?style=flat)
__基于 `vuepress 2.0` 制作的 `Blog` 主题。__
::: warning 提示
基于 VuePress@v2, 仍处于 Beta 阶段。
这意味着功能和API尚未固定在未来的更新中仍有概率出现破坏更改。
:::
- [快速开始](/note/vuepress-theme-plume/quick-start/)
- [配置](/note/vuepress-theme-plume/theme-config/)
- [编写文章](/note/vuepress-theme-plume/write-article/)
## 功能
- 低配置化,安装后仅需少量的配置即可使用
- markdown功能增强支持 代码分组、嵌入代码demo、内容增强容器。
- 支持 文章分类、标签、归档
- 支持以文档形式整合同体系文章。
- 支持搜索、评论
- 自动生成文章永久链接
## 安装
:::: code-group
::: code-group-item yarn
``` sh
yarn add @vuepress-plume/vuepress-theme-plume
```
:::
::: code-group-item npm
``` sh
npm i @vuepress-plume/vuepress-theme-plume
```
:::
::::
## 使用
:::: code-group
::: code-group-item ts
``` ts
// .vuepress/config.ts
import { defineUserConfig } from 'vuepress'
import { themePlume } from '@vuepress-plume/vuepress-theme-plume'
export default defineUserConfig({
theme: themePlume({
// more...
})
})
```
:::
::: code-group-item js
``` js
// .vuepress/config.js
import { themePlume } from '@vuepress-plume/vuepress-theme-plume'
module.exports = {
theme: themePlume({
// more...
})
}
```
:::
::::
## 示例
- [鹏展博 的个人博客](https://pengzhanbo.cn)
## 作者的话
### 背景
开发本主题的原因,是在我个人学习 `vue@3`以及 `vite` 时,想做一个学习的笔记。
在我之前使用的 vuepress1时发现版本挺长时间没升级了想顺手做下升级发现 `vuepress@2` 已经出于 beta阶段而且还是在`vue3``vite` 等的基础上做的重构,而且还是使用 `typescript` 编写的代码。
这刚好跟我的学习计划都撞上了,于是就开始阅读 `vuepress@2` 的相关源码,然后着手开始重构我的个人站点,并通过开发一款 主题的方式,熟悉 `vuepress2``vue3`的相关内容,简直是一举多得。
当然也由于本主题是 学习过程中的作品, 很多内容在一开始并没有做完备的规划,仅是一个大概的想法,然后就进行了开发,所以截止到目前阶段,项目代码还没有进行比较严格的整理,稍显散乱;部分功能也还没有完善,出于开发中,可能在使用过程中出现一些意外情况。
`vuepress`一直是我非常喜欢的一个静态文档站点制作工具,我用它在我工作中的不少项目中建立文档站点,以及编写自己的个人博客(虽然很懒经常没写...)。
### 想法
开发这个主题,我一开始的想法是希望做一个能够尽可能的少配置化的,能够更关注于写作的主题。不需要去配置 navbar、不需要去关注链接不需要去关注配置文件中怎么去编排文章。能够仅仅通过一些简单的约定根据目录以及文件名称自动生成文章列表以及自动生成文章的默认配置。
以目前的进度,初期的想法基本都按照我的预期实现了,后续如果有新的想法,还会继续添加。
在达到一个合适的阶段后,会将重点放在代码的整理上,希望能够让本主题也称为喜欢`vuepress`并考虑自行开发一个主题或者插件的人,给到一个项目示例的参考。
::: tip 寄语
欢迎各位使用本主题;
也欢迎各位fork本主题后自行修改
也欢迎各位参考本主题,制作自己的主题。
:::

View File

@ -0,0 +1,571 @@
---
title: markdown增强
createTime: 2022/04/09 06:43:32
author: pengzhanbo
permalink: /note/vuepress-theme-plume/markdown-enhance/
---
markdown 增强 由 [vuepress-plugin-md-enhance](https://vuepress-theme-hope.github.io/v2/md-enhance/zh) 提供支持。
## 内容容器
支持多种内容容器,更好的表达文章内容。
1. tip 提示
2. note 注释
3. info 信息
4. warning 警告
5. danger 危险
6. details 详情
- 提示
``` md
::: tip 提示
提示内容
:::
```
::: tip 提示
提示内容
:::
- 注释
``` md
::: note 注释
注释内容
:::
```
::: note 注释
注释内容
:::
- 信息
``` md
::: info 信息
信息内容
:::
```
::: info 信息
信息内容
:::
- 警告
``` md
::: warning 警告
警告内容
:::
```
::: warning 警告
警告内容
:::
- 详情
``` md
::: details 详情
详情信息
:::
```
::: details 详情
详情信息
:::
## 自定义对齐
- 左对齐
``` md
::: left
这是左对齐
:::
```
::: left
这是左对齐
:::
- 右对齐
``` md
::: right
这是右对齐
:::
```
::: right
这是右对齐
:::
- 居中
``` md
::: center
这是居中对齐
:::
```
::: center
这是居中对齐
:::
## 任务列表
``` md
- [ ] todo1
- [x] todo2
```
- [ ] todo1
- [x] todo2
## 标记
``` md
将这个内容进行 ==标记== ,变成高亮。
```
将这个内容进行 ==标记== ,变成高亮。
## 代码块分组
你需要在 外围使用`code-group` 容器,内部使用`code-group-item` 将代码块进行包裹。
需要给 `code-group-item` 容器设置标题
如果需要给先让某个选项卡被激活,在标题后面补充`:active`后缀。
````md
:::: code-group
::: code-group-item yarn
```sh
yarn version
```
:::
::: code-group-item npm:active
```sh
npm version
```
:::
::::
````
:::: code-group
::: code-group-item yarn
``` sh
yarn version
```
:::
::: code-group-item npm:active
``` sh
npm version
```
:::
::::
## 代码演示
```` md
::: demo [类型] 可选的标题文字
```html
<!-- ↑ 使用可用的语言 -->
<!-- 在代码块中放置你对应语言的代码,一个语言不能出现多个块 -->
<!-- 你可以有多个代码块,并且 html, js, css 都是视情况可选的 -->
```
```json
// json block 作为插件配置存放处
{
// 放置你的配置 (可选的)
}
```
:::
````
::: tip 提示
JSON 块是可选的,可用的配置详见[配置](https://vuepress-theme-hope.github.io/v2/md-enhance/zh/config.html)
:::
插件支持三种类型
- normal(默认)
- vue
- react
### 可用的语言
你可以在演示块中使用不同语言。
当你设置一些不能在浏览器上直接运行的语言时,由于插件无法解析它们,因此网页演示将被禁用。插件只显示代码。同时提供一个 "在 CodePen 中打开" 按钮允许用户直接在 CodePen 打开并浏览代码。
可用的 HTML 语言:
- `"html"` (默认)
- `"slim"`
- `"haml"`
- `"markdown"`
可用的 JS 语言:
- `"javascript"` (default)
- `"coffeescript"`
- `"babel"`
- `"livescript"`
- `"typescript"`
> 你也可以在代码块中使用 `js`, `ts`, `coffee``ls。`
可用的 CSS 语言:
- `"css"` (default)
- `"less"`
- `"scss"`
- `"sass"`
- `"stylus"`
### 不支持的语言
::: demo 一个使用浏览器不支持解析语言 Demo
```md
# 标题
十分强大
```
```ts
const message: string = "VuePress Theme Hope";
document.querySelector("h1").innerHTML = message;
```
```scss
h1 {
font-style: italic;
+ p {
color: red;
}
}
```
:::
:::: details 代码
```` md
::: demo 一个使用浏览器不支持解析语言 Demo
```md
# 标题
十分强大
```
```ts
const message: string = "VuePress Theme Hope";
document.querySelector("h1").innerHTML = message;
```
```scss
h1 {
font-style: italic;
+ p {
color: red;
}
}
```
:::
````
::::
### 普通代码演示
格式:
```` md
::: demo 可选的标题文字
```html
<!-- html code -->
```
```js
// js code
```
```css
/* css code */
```
```json
// 配置 (可选)
{
"jsLib": [
...
],
"cssLib":[
...
]
}
```
:::
````
::: warning 注意事项
我们使用 `"ShadowDOM"` 进行样式隔离,并已经将 `document` 替换为了 `shadowRoot` 对象。如果需要访问页面的 `document请访问` `window.document`
:::
#### 例子
::: demo Demo 演示
```html
<h1>Hello Word!</h1>
<p><span id="very">非常</span>强大!</p>
```
```js
document.querySelector("#very").addEventListener("click", () => {
alert("非常强大");
});
```
```css
span {
color: red;
}
```
:::
:::: details 代码
```` md
::: demo Demo 演示
```html
<h1>Hello Word!</h1>
<p><span id="very">非常</span>强大!</p>
```
```js
document.querySelector("#very").addEventListener("click", () => {
alert("非常强大");
});
```
```css
span {
color: red;
}
```
:::
````
::::
### Vue 代码演示
#### 格式
```` md
::: demo [vue] 可选的标题文字
```vue
<!-- ↑ 你也可以使用 html -->
<template>
<!-- vue 模板 -->
</template>
<script>
export default {
// vue 组件
};
</script>
<style>
/* css 代码 */
</style>
```
```json
// 配置 (可选)
```
:::
````
::: warning 注意事项
- 你只能使用 `Vue3`
- 必须将组件通过 `export default` 默认导出
- 我们使用 `"ShadowDOM"` 进行样式隔离,并已经将 `document` 替换为了 `shadowRoot` 对象。如果需要访问页面的 `document`,请访问 `window.document`
:::
#### 演示
::: demo [vue] 一个 Vue Composition 演示
```vue
<template>
<div class="box">
<code>Hello Word</code> is
<span @click="handler">{{ message }}</span
>!
</div>
</template>
<script>
const { ref } = Vue;
export default {
setup() {
const message = ref("powerful");
const handler = () => {
message.value = "very " + message.value;
};
return {
message,
handler,
};
},
};
</script>
<style>
.box span {
color: red;
}
</style>
```
:::
:::: details 代码
```` md
::: demo [vue] 一个 Vue Composition 演示
```vue
<template>
<div class="box">
<code>Hello Word</code> is
<span @click="handler">{{ message }}</span
>!
</div>
</template>
<script>
const { ref } = Vue;
export default {
setup() {
const message = ref("powerful");
const handler = () => {
message.value = "very " + message.value;
};
return {
message,
handler,
};
},
};
</script>
<style>
.box span {
color: red;
}
</style>
```
:::
````
::::
### React 代码演示
#### 格式
```` md
::: demo [react] 可选的标题文字
```js
// 放置脚本,并通过 `export default` 导出你的 react 组件
```
```css
/* 你的 css 内容 */
```
```json
// 配置 (可选)
```
:::
````
::: warning 注意事项
- 使用 React 的时候,为了解析 JSX 必须引入 Babel此过程由插件自动完成。
- 必须将组件通过 `export default` 默认导出
- 我们使用 `"ShadowDOM"` 进行样式隔离,并已经将 `document` 替换为了 `shadowRoot` 对象。如果需要访问页面的 `document`,请访问 `window.document`
:::
#### 演示
::: demo [react] 一个函数式 React Demo
```js
const { useState } = React;
export default () => {
const [message, setMessage] = useState(" 强大");
const handler = () => {
setMessage(`十分${message}`);
};
return (
<div className="box">
<code>Hello Word !</code>
<span id="powerful" onClick={handler}>
{message}
</span>
</div>
);
};
```
```css
.box #powerful {
color: blue;
}
```
:::
:::: details 代码
```` md
::: demo [react] 一个函数式 React Demo
```js
const { useState } = React;
export default () => {
const [message, setMessage] = useState(" 强大");
const handler = () => {
setMessage(`十分${message}`);
};
return (
<div className="box">
<code>Hello Word !</code>
<span id="powerful" onClick={handler}>
{message}
</span>
</div>
);
};
```
```css
.box #powerful {
color: blue;
}
```
:::
````
::::
## 其他支持
更多支持请参考 [主题插件配置](/note/vuepress-theme-plume/plugins-config/#markdownenhance)

View File

@ -0,0 +1,167 @@
---
title: notes配置
createTime: 2022/04/09 02:48:41
author: pengzhanbo
permalink: /note/vuepress-theme-plume/notes-config/
---
`notes` 功能,是为了在本主题满足了 Blog的基本功能后期望能够 以 `note` 或者 `book` 的形式聚合文章而形成的,形式上类似于 `vuepress` 默认主题的功能。同时也减少了配置的复杂度。
## 配置
所有主题内部使用的插件, 均在 `notes` 字段中进行配置。
``` js {3-5}
module.exports = {
themeConfig: {
notes: {
// this
}
}
}
```
## 配置字段
### dir
- 类型: `string`
- 默认值: `'_notes'`
- 详情所有notes存放的目录该目录相对于`sourceDir`
示例
```
├─ {sourceDir}
│ ├─ _notes
│ │ └─ typescript学习笔记
│ └─ README.md
```
### link
- 类型: `string`
- 默认值: `'/note/'`
- 详情: 作为notes内的文章链接的前缀。自定义是请以 `'/'` 开头
### notes
- 类型: `PlumeThemeNotesItem[]`
- 默认值: `[]`
- 详情: note数组配置多个 note
#### `PlumeThemeNotesItem`
``` ts
interface PlumeThemeNotesItem {
/**
* note 标题
*/
text: string
/*
* note 链接,相对于 前面配置的 link。
* 如 /typescript-learn/ 映射到访问链接则为 /note//typescript-learn/
*/
link: string
/*
* note 所在的目录,相对于 前面配置的 dir
* 如 typescript 则实际路径为 {sourceDir}/_notes/typescript
*/
dir: string
/*
* 当前 note 的sidebar配置
*/
sidebar?: PlumeThemeSidebarConfigOptions | 'auto'
}
type PlumeThemeSidebarConfigOptions = (PlumeThemeNotesConfigItem | string)[]
interface PlumeThemeNotesConfigItem {
text: string
link?: string
children: PlumeThemeNotesConfigItem[]
}
```
### notes\[index\].sidebar
这个字段是用于配置当前 note 的 sidebar 左侧导航栏
- 类型: `(PlumeThemeNotesConfigItem | string)[]`
- 详情:
- 如果子元素为字符串时,可以是相对于 dir目录的md文件路径可以省略`.md`后缀,也可以是生成的文章,`frontmatter`中的
`permalink`的链接, 如果为空,则表示当前文件夹下的 `README.md`文件
- 如果子元素是`PlumeThemeNotesConfigItem`, 其中 `text` 表示 sidebar显示的文案
`link` 等价于 上一条 string 的规则。
`children` 可以继续嵌套`(PlumeThemeNotesConfigItem | string)`
## 示例
`_notes` 文件夹下用如下文件结构
```
_notes
└── vuepress-theme-plume
├── README.md
├── note配置.md
├── 主题配置.md
├── 快速开始.md
├── 编写文章.md
├── 页面配置.md
└── 主题插件配置.md
```
则可以进行如下配置:
:::: code-group
::: code-group-item config.ts
``` ts
import { defineUserConfig } from 'vuepress'
import type {PlumeThemeOptions } from '@vuepress-plume/vuepress-theme-plume'
import notes from './notes.ts'
export default defineUserConfig<PlumeThemeOptions>({
themeConfig: {
notes: {
dir: '_notes',
link: '/note/',
notes,
}
}
})
```
:::
::: code-group-item notes.ts
``` ts
export default [
{
text: 'VuePress-theme-plume',
dir: 'vuepress-theme-plume',
link: '/vuepress-theme-plume',
sidebar: [
'',
{
text: '指南',
children: [
'快速开始',
'编写文章',
]
},
{
text: '配置',
children: [
{
text: '主题配置',
link: '主题配置',
children: [
'主题插件配置',
'notes配置',
]
},
'页面配置',
]
},
{
text: '功能',
children: []
}
]
}
]
```
:::
::::
其效果 即为 本文档 左侧 sidebar 展示效果。

View File

@ -0,0 +1,164 @@
---
title: 主题插件配置
createTime: 2022/04/09 02:48:30
author: pengzhanbo
permalink: /note/vuepress-theme-plume/plugins-config/
---
主题内置的使用的插件,扩展了主题的众多功能,你可以在这个 字段中, 实现对内部使用的各个插件的自定义配置。
## 配置
所有主题内部使用的插件, 均在 `themePlugins` 字段中进行配置。
``` js {4-6}
import { themePlume } from '@vuepress-plume/vuepress-theme-plume'
module.exports = {
theme: themePlume({
themePlugins: {
// this
}
})
}
```
## 配置字段
### caniuse
关联插件: [@vuepress-plume/vuepress-plugin-caniuse](https://www.npmjs.com/package/@vuepress-plume/vuepress-plugin-caniuse)
- 类型: `false | CanIUsePluginOptions`
- 默认值: `{ mode: 'embed' }`
- 详情:该插件支持在你的文章中嵌入 [can I use](https://caniuse.com/) 特性支持图表。
设置为 `false` 表示不启动该插件。
- `caniuse.mode`: 图表嵌入模式, `embed`表示嵌入可交互式的图表, `image` 嵌入动态图片。
- 配置示例:
``` js
module.exports = {
theme: themePlume({
themePlugins: {
caniuse: {
mode: 'embed'
},
},
}),
}
```
### externalLinkIcon
关联插件: [@vuepress/plugin-external-link-icon](https://v2.vuepress.vuejs.org/zh/reference/plugin/external-link-icon.html)
- 类型: `false | string`
- 默认值: `''`
- 详情: 该插件会为你 Markdown 内容中的外部链接添加一个图标,即 <ExternalLinkIcon />
一般来说你不需要对它进行配置
### search
网站内容搜索插件
关联插件: [@vuepress/plugin-search](https://v2.vuepress.vuejs.org/zh/reference/plugin/search.html)
详细介绍与配置,请查阅 [官方文档](https://v2.vuepress.vuejs.org/zh/reference/plugin/search.html)
- 默认配置: `''`
### docsearch
使用 [Algolia DocSearch](https://docsearch.algolia.com/) 提供支持的网站内容搜索插件
关联插件:[@vuepress/plugin-docsearch](https://v2.vuepress.vuejs.org/zh/reference/plugin/docsearch.html)
详细介绍与配置,请查阅 [官方文档](https://v2.vuepress.vuejs.org/zh/reference/plugin/docsearch.html)
- 默认配置: `''`
::: info 提示
请勿 同时配置 `search``docsearch` ,两者的功能是类似的,且同时配置仅会使用优先使用 `search`
:::
### prismjs
代码块语法高亮插件
关联插件: [@vuepress/plugin-prismjs](https://v2.vuepress.vuejs.org/zh/reference/plugin/prismjs.html)
详细介绍与配置,请查阅 [官方文档](https://v2.vuepress.vuejs.org/zh/reference/plugin/prismjs.html)
### nprogress
页面切换时展示进度条。
关联插件: [@vuepress/plugin-nprogress](https://v2.vuepress.vuejs.org/zh/reference/plugin/nprogress.html)
详细介绍与配置,请查阅 [官方文档](https://v2.vuepress.vuejs.org/zh/reference/plugin/nprogress.html)
### copyCode
代码拷贝插件
支持在代码块中进行代码复制
关联插件:[vuepress-plugin-copy-code2](https://vuepress-theme-hope.github.io/v2/copy-code/)
详细介绍与配置,请查阅[官方文档](https://vuepress-theme-hope.github.io/v2/copy-code/)
- 默认配置:
``` js
module.exports = {
theme: themePlume({
themePlugins: {
copyCode: {
selector: '.page-content div[class*="language-"] pre',
locales: {
'/': {
copy: '复制成功',
hint: '复制代码',
},
},
},
},
}),
}
```
### markdownEnhance
`Markdown` 功能扩展插件
关联插件:[vuepress-plugin-md-enhance](https://vuepress-theme-hope.github.io/v2/md-enhance/zh/)
扩展支持自定义容器、代码块分组、上下角标、自定义对齐、脚注、标记、任务列表、chart、流程图、代码演示 等功能。
相关介绍及配置,请查阅 [官方文档](https://vuepress-theme-hope.github.io/v2/md-enhance/zh/)
- 默认配置:
``` js
module.exports = {
theme: themePlume({
themePlugins: {
markdownEnhance: {
container: true, // 自定义容器 info note tip warning danger details
codegroup: true, // 代码块分组
align: true, // 自定义对齐
mark: true, // 标记
tasklist: true, // 任务列表
demo: true, // 代码演示
}
}
})
}
```
### comment
评论插件
关联插件: [vuepress-plugin-comment2](https://vuepress-theme-hope.github.io/v2/comment/zh/)
支持使用 `giscus``twikoo``waline` 启用评论功能。
相关介绍及配置,请查阅 [官方文档](https://vuepress-theme-hope.github.io/v2/comment/zh/)
- 默认配置:`''`

View File

@ -0,0 +1,342 @@
---
title: 主题配置
createTime: 2022/04/09 12:18:12
author: pengzhanbo
permalink: /note/vuepress-theme-plume/theme-config/
---
虽然本主题希望尽可能的少写配置,但还是有些配置是不可省略的,而且也是为了保证一定程度的可定制性。
## 配置文件
`Vuepress` 默认的配置文件是`.vuepress/config.ts`,可能你的项目配置如下,
新建`.vuepress/config.ts`文件进行配置:
```
├─ {sourceDir}
│ ├─ .vuepress
│ │ └─ config.js
│ └─ README.md
├─ .gitignore
└─ package.json
```
`VuePress` 支持的配置,请查阅 [官方文档](https://v2.vuepress.vuejs.org/zh/guide/configuration.html)
`Vuepress@v2`中对于主题的配置,引入主题函数,在函数中进行配置
:::: code-group
::: code-group-item ts
``` ts {3,6-8}
// .vuepress/config.ts
import { defineUserConfig } from 'vuepress'
import { themePlume } from '@vuepress-plume/vuepress-theme-plume'
export default defineUserConfig({
theme: themePlume({
// more...
})
})
```
:::
::: code-group-item js
``` js {4-6}
// .vuepress/config.js
import { themePlume } from '@vuepress-plume/vuepress-theme-plume'
module.exports = {
theme: themePlume({
// more...
})
}
```
:::
::::
## 配置
### home
- 类型: `false | NavLink`
- 默认值: `{ text: '首页', link: '/' }`
- 详情:
首页的路径, 它将被用于:
- 导航栏中 logo的链接
- 404页面的 *返回首页* 的链接;
- navbar 中 首页的链接。
### logo
- 类型: `false | string`
- 默认值: `false`
- 详情: 导航栏中的logo。
### logoDark
- 类型 `false | string`
- 默认值: `false`
- 详情: Dark模式下导航栏中的logo。
### darkMode
- 类型: `boolean`
- 默认值: `true`
- 详情: 是否启用 dark模式
### avatar
- 类型: `PlumeThemeAvatar`
- 默认值: `{}`
- 详情:配置站点博主的个人信息
- `avatar.url`: 头像地址,用于右侧博主信息展示
- `avatar.name`: 名称, 用于右侧博主信息展示
- `avatar.description`: 座右铭,个人描述,用于右侧博主信息展示
- 示例:
``` ts
export default {
theme: themePlume({
avatar: {
url: '/avatar.jpg',
name: '张三',
description: '此处无银三百两,隔壁王二不曾偷',
}
})
}
```
### social
- 类型: `false | PlumeThemeSocialOption`
- 默认值: `false`
- 详情: 个人社交信息配置。用于右侧博主信息展示,展示为社交图标。
- `social.email`: 邮箱
- `social.github`: 个人github地址
- `social.QQ`: QQ账号
- `social.weiBo`: 个人微博地址
- `social.zhiHu`: 个人知乎地址
- `social.facebook`: facebook地址
- `social.twitter`: twitter 地址
- `social.linkedin`: 领英 linkedin 地址
- 示例:
``` ts
export default {
theme: themePlume({
social: {
email: 'me@email.com'
github: 'https://github.com/zhangsan',
QQ: '123456789',
}
})
}
```
### article
- 类型: `string`
- 默认值: `/article/`
- 详情: 文章链接前缀
### tag
- 类型: `NavLink`
- 默认值: `{ text: '标签', link: '/tag/' }`
- 详情: 标签页配置,与 navbar 配置
### category
- 类型: `NavLink`
- 默认值: `{ text: '分类', link: '/category/ }`
- 详情: 分类页配置,与 navbar 配置
### archive
- 类型: `NavLink`
- 默认值: `{ text: '归档', link: '/timeline/' }`
- 详情: 归档页配置,与 navbar 配置
### navbar
- 类型: `(NavbarItem | NavbarGroup | string)[]`
- 默认值: `[]`
- 详情: 导航栏配置。
为了配置导航栏元素,你可以将其设置为 导航栏数组 ,其中的每个元素是 `NavbarItem` 对象、 `NavbarGroup` 对象、或者字符串:
- `NavbarItem` 对象应该有一个 text 字段和一个 link 字段,还有一个可选的 `activeMatch` 字段。
- `NavbarGroup` 对象应该有一个 `text` 字段和一个 `children` 字段。 `children` 字段同样是一个 导航栏数组 。
- 字符串应为目标页面文件的路径。它将会被转换为 `NavbarItem` 对象,将页面标题作为 `text` ,将页面路由路径作为 `link`
- 示例1
``` js
module.exports = {
theme: themePlume({
navbar: [
// NavbarItem
{
text: 'Foo',
link: '/foo/',
},
// NavbarGroup
{
text: 'Group',
children: ['/group/foo.md', '/group/bar.md'],
},
// 字符串 - 页面文件路径
'/bar/README.md',
],
}),
}
```
- 示例2
``` js
module.exports = {
theme: themePlume({
navbar: [
// 嵌套 Group - 最大深度为 2
{
text: 'Group',
children: [
{
text: 'SubGroup',
children: ['/group/sub/foo.md', '/group/sub/bar.md'],
},
],
},
// 控制元素何时被激活
{
text: 'Group 2',
children: [
{
text: 'Always active',
link: '/',
// 该元素将一直处于激活状态
activeMatch: '/',
},
{
text: 'Active on /foo/',
link: '/not-foo/',
// 该元素在当前路由路径是 /foo/ 开头时激活
// 支持正则表达式
activeMatch: '^/foo/',
},
],
},
],
}),
}
```
### footer
- 类型: `false | { content: string; copyright: string }`
- 默认值: `false`
- 详情:页脚配置。
### notes
- 类型: `false | PlumeThemeNotesOptions`
- 默认值: `{ link: '/note', dir: 'notes', notes: [] }`
- 详情: 笔记配置, 笔记中的文章默认不会出现在首页文章列表
你可以将配置的notes 配置到 navbar中以便浏览查看
详细配置请查看 [此文档](/note/vuepress-theme-plume/notes-config/)
### themePlugins
- 类型:`PlumeThemePluginOptions`
- 默认值: `{}`
- 详情: 对主题内使用的插件进行自定义配置。
主题使用的插件默认已进行了配置,默认情况下不需要进行修改,如果需要使用到细致的定制化,请查阅
[此文档](/note/vuepress-theme-plume/plugins-config/)
## 完整示例
:::: code-group
::: code-group-item ts
``` ts
import { defineUserConfig } from 'vuepress'
import { themePlume } from '@vuepress-plume/vuepress-theme-plume'
export default defineUserConfig({
lang: 'zh-CN',
locales: {
'/': {
lang: 'zh-CN',
title: 'Theme Plume',
description: 'The Theme for VuePress 2',
},
},
dest: 'docs',
head: [
['link', { rel: 'icon', href: '/g.gif' }],
['meta', { 'http-equiv': 'X-UA-Compatible', content: 'id=edg' }],
],
theme: themePlume({
logo: '/g.gif',
darkMode: true,
avatar: {
name: 'theme plume',
url: '/images/blogger.png',
description: 'good good study, day day up !'
},
social: {
email: 'me@email.com',
github: 'https://github.com/me',
QQ: '123456789',
},
navbar: [{ text: 'Theme-Plume', link: '/note/vuepress-theme-plume' }],
notes: {
dir: 'notes',
link: '/note',
},
footer: {
copyright: 'Copyright © 2022-present pengzhanbo',
content: '',
},
}),
})
```
:::
::: code-group-item js
``` js
import { themePlume } from '@vuepress-plume/vuepress-theme-plume'
module.exports = {
lang: 'zh-CN',
locales: {
'/': {
lang: 'zh-CN',
title: 'Theme Plume',
description: 'The Theme for VuePress 2',
},
},
dest: 'docs',
head: [
['link', { rel: 'icon', href: '/g.gif' }],
['meta', { 'http-equiv': 'X-UA-Compatible', content: 'id=edg' }],
],
theme: themePlume({
logo: '/g.gif',
darkMode: true,
avatar: {
name: 'theme plume',
url: '/images/blogger.jpg',
description: 'good good study, day day up !'
},
social: {
email: 'me@email.com',
github: 'https://github.com/me',
QQ: '123456789',
},
navbar: [{ text: 'Theme-Plume', link: '/note/vuepress-theme-plume' }],
notes: {
dir: 'notes',
link: '/note',
},
footer: {
copyright: 'Copyright © 2022-present pengzhanbo',
content: '',
},
}),
}
```
:::
::::

View File

@ -0,0 +1,78 @@
---
title: 基础功能
createTime: 2022/04/09 06:43:20
author: pengzhanbo
permalink: /note/vuepress-theme-plume/basis-power/
---
## 首页
### 文章列表
- 自动生成 文章列表,并支持文章分页功能。
- 文章列表子项 支持显示
- 标题
- 作者
- 分类
- 标签
- 创建时间
- 文章内容截取
### 右侧博主信息展示
- 头像
- 名称
- 个人简介/座右铭
- 个人社交账号信息
- Email
- github
- 微博
- 知乎
- QQ
- facebook
- twitter
- linkedin
## 分类页
根据 `${sourceDir}` 中的 文章所在目录,自动生成文章分类。
并生成 分类页,可以根据分类查看文章。
## 标签页
支持配置 文章标签
并生成 标签页, 可以根据 标签筛选文章。
## 归档页
根据文章创建时间,生成 文章归档页面。
## 站内搜索
支持站内搜索相关文章。
## 深色模式
支持深色模式
## 主题定制
支持自定义样式。
该功能由 [@vuepress/plugin-palette](https://v2.vuepress.vuejs.org/zh/reference/plugin/palette.html) 提供支持。
请查阅 [官方文档](https://v2.vuepress.vuejs.org/zh/reference/plugin/palette.html)
``` scss
:root {
// 主题颜色
// brand color
--c-brand: #0095d9;
--c-brand-light: #2ca9e1;
}
```
## 文章评论
支持文章评论。

View File

@ -0,0 +1,140 @@
---
title: 快速开始
createTime: 2022/04/08 09:43:20
author: pengzhanbo
permalink: /note/vuepress-theme-plume/quick-start/
---
## 依赖环境
- [Node.js v12+](https://nodejs.org/en/)
- [Yarn v1 classic](https://classic.yarnpkg.com/en/)
::: tip 提示
- 使用 [pnpm](https://pnpm.io/zh/) 时,你需要在 `.npmrc` 文件中设置 `shamefully-hoist=true`
- 使用 [Yarn 2](https://yarnpkg.com/) 时,你需要在 `.yarnrc.yml` 文件中设置 `nodeLinker: 'node-modules'`
:::
## 安装
使用本主题,你需要首先新建一个项目,并安装`vuepress@next`以及本主题
- __步骤1__ 创建一个新文件夹,并进入目录
``` sh
mkdir my-blog
cd my-blog
```
- __步骤2__ 初始化项目
:::: code-group
::: code-group-item yarn
``` sh
git init
yarn init
```
:::
::: code-group-item npm
``` sh
git init
npm init
```
:::
::::
- __步骤3__ 安装相关依赖
安装 `vuepress@next``@vuepress-plume/vuepress-theme-plume`作为本地依赖。
如果你是希望将已有的项目进行升级,请从 `步骤5` 开始
:::: code-group
::: code-group-item yarn
``` sh
yarn add -D vuepress@next @vuepress-plume/vuepress-theme-plume
```
:::
::: code-group-item npm
``` sh
npm i -D vuepress@next @vuepress-plume/vuepress-theme-plume
```
:::
::::
- __步骤4__`package.json`中添加`script`
比如,你希望项目中的`src`目录作为你的文章的写作目录:
``` json
{
"scripts": {
"dev": "vuepress dev src",
"build": "vuepress build src"
}
}
```
- __步骤5__ 将默认的临时目录和缓存目录添加到`.gitignore` 文件中
:::: code-group
::: code-group-item sh
``` sh
echo 'node_modules' >> .gitignore
echo '.temp' >> .gitignore
echo '.cache' >> .gitignore
```
:::
::: code-group-item .gitignore
``` text
node_modules
.temp
.cache
```
::::
- __步骤6__`.vuepress/config.ts` 中配置主题
:::: code-group
::: code-group-item ts
``` ts {3,5-7}
// .vuepress/config.ts
import { defineUserConfig } from 'vuepress'
import { themePlume } from '@vuepress-plume/vuepress-theme-plume'
export default defineUserConfig({
theme: themePlume({
// theme config
})
})
```
:::
::: code-group-item js
``` js {2,4-6}
// .vuepress/config.js
import { themePlume } from '@vuepress-plume/vuepress-theme-plume'
module.exports = {
theme: themePlume({
// theme config
})
}
```
:::
::::
- __步骤7__`src` 目录下新建`README.md`文件
声明首页配置。
``` md
---
home: true
---
```
- __步骤8__ 在本地服务器启动你的文档站点
:::: code-group
::: code-group-item yarn
``` sh
yarn dev
```
:::
::: code-group-item npm
``` sh
npm run dev
```
:::
::::
Vuepress 会在 [http://localhost:8080](http://localhost:8080) 。启动一个热重载的开发服务器。当你修改你的 Markdown 文件时,浏览器中的内容也会自动更新。
现在,你应该已经有了一个简单可用的 VuePress Blog 网站。接下来,了解一下 [编写 Blog 文章](/note/vuepress-theme-plume/write-article/) 和 [主题配置](/note/vuepress-theme-plume/theme-config/) 的相关内容。

View File

@ -0,0 +1,55 @@
---
title: 编写文章
createTime: 2022/04/09 12:13:56
author: pengzhanbo
permalink: /note/vuepress-theme-plume/write-article/
---
::: info 注释
- 以下内容中,以`sourceDir` 表示 项目中用于保存 `Markdown`文件的目录。
`package.json``scripts``vuepress dev src` 声明的`src`目录
:::
## 约定
使用本主题编写文章是一件很轻松的事情,你可以在 `sourceDir`目录中按照你的个人命名喜好新建任意名字的`Markdown`文件,
主题将会自动帮你生成一个文章永久链接,并保存在文章的配置中,以便随时修改。
但对于 `sourceDir` 中的文件夹命名,主题有一套简单的约定。
- 文件夹的名称将作为 `category`__分类__。将会映射到 `navbar`作为分类的子项。
- 允许多级目录,子级目录将作为父目录对应的分类的子项。
- 如果目录名称 在 [主题配置 notes](/note/vuepress-theme-plume/theme-config/#notes) 中声明用于 notes 文章管理,则默认不作为 分类目录。
### 文件夹命名约定
由于文件夹名称将作为分类名称,且不在主题配置中进行排序配置,对于有排序需要的场景,使用以下规则进行命名
``` ts
const dir = /\d+\.[^]+/ // 即 数字 + dot + 分类名称
```
数字将作为 __排序__ 的依据。 如果不带数字,则以默认的规则进行排序。
__example:__
```
.{sourceDir}
- 1.前端
- 1.html
- 2.css
- 3.javascript
- 2.后端
- 运维
```
## 博客首页
`sourceDir` 目录新建`README.md` 文件,并写入以下内容即可。
``` md
---
home: true
---
```
主题会解析该文件,并插入 文章列表,以及相关内容。
## 文章写作
你可以使用 `markdown` 语法开始编写你自己的文章了,关于 markdown 扩展的功能支持,请查看 [这个文档](/note/vuepress-theme-plume/markdown-enhance/)。

View File

@ -0,0 +1,136 @@
---
title: 页面配置
createTime: 2022/04/09 01:24:17
author: pengzhanbo
permalink: /note/vuepress-theme-plume/page-config/
---
## 说明
页面配置是为了能够以更细小的颗粒度控制单个页面的行为。
在本主题中,当你启动本地服务器后,主题会在你新建 `markdown`文件时,自动在文件头部插入基本的配置,你可以随时修改它。
`markdown`中的配置形式,如下所示:
``` md
---
title: 标题
createTime: 2022/04/09 01:24:17
author: You
permalink: /note/vuepress-theme-plume/page-config/
tags:
- vuepress
---
```
配置内容是以 `YAML` 的格式进行书写的。
## 配置字段
### title
- 类型: `string`
- 默认值: `''`
- 详情:
文章标题,启动本地服务器时,如果该字段为空,会根据当前文件名称自动生成。
### createTime
- 类型: `DateString` 格式 `yyyy/MM/dd hh:mm:ss`
- 默认值: `''`
- 详情:
文章创建时间,启动本地服务器时,如果该字段为空,会根据当前文件的创建时间自动生成
### author
- 类型: `string`
- 默认值: `''`
- 详情:
文章作者,启动本地服务器时,如果该字段为空,会根据当前项目`package.json`中的`author`字段生成
### permalink
- 类型: `string`
- 默认值: `''`
- 详情:
文章永久链接,启动本地服务器时,如果该字段为空,会根据默认规则生成。
在本主题中通过 `nanoid` 生成文章唯一链接。
### tags
- 类型: `string[]`
- 默认值: `[]`
- 详情:
文章标签,可配置多个
- 示例:
``` md
---
tags:
- html
- javascript
---
```
### sticky
- 类型: `boolean | number`
- 默认值: `false`
- 详情:
是否置顶当前文章。
当同时配置多篇文章置顶如果值为number则number越大的文章越靠前。
### article
- 类型: `boolean`
- 默认值: `true``notes` 中的文章,默认值为 `false`
- 详情:
是否将文章收录到 首页 文章列表
## 首页配置字段
### home
- 类型: `boolean`
- 默认值: `true`
- 详情:
标记当前 md文件为博客首页仅在 `{sourceDir}/README.md` 中配置即可
### banner
- 类型: `string`
- 默认值: `''`
- 详情
配置首页首屏大图
### mobileBanner
- 类型: `string`
- 默认值:`''`
- 详情
配置首页首屏,在移动端设备中使用的大图
### motto
- 类型: `string`
- 默认值: `''`
- 详情
座右铭,显示在首屏大图上
``` md
---
home: true
banner: /images/big-banner.jpg
motto: 世间的美好总是不期而遇,恬静而自然。
---
```

View File

@ -1,13 +0,0 @@
---
title: 盒模型
createTime: 2022/04/12 11:27:38
author: pengzhanbo
permalink: /note/interview-question/sfnusib9/
---
`CSS盒模型` 问题是 面试中比较常见的基础题型。提问的方式,可能包括以下:
- 请简述 CSS 盒模型
- 什么是 标准模式和 怪异模式

View File

@ -1,56 +0,0 @@
---
title: 面试题
createTime: 2022/04/12 10:16:26
author: pengzhanbo
permalink: /note/interview-question/
---
### 说明
本笔记主要用于整理、记录,从个人角度尝试回答 可能会遇到的、跟其他人讨论过的 面试题目。
但本笔记 所收集的面试题, 主要是在 前端的范畴中,不涉及其他。
如果你准备找工作,想刷刷面试题,可以 以此作为参考,
但请不要作为标准答案,因为这些仅仅是我个人的理解,
并不一定百分百正确。
::: tip
如果这篇笔记对你有帮助,你有遇到不错的面试题,希望可以在本笔记的评论区提交你遇到的面试题与我分享,我不胜感激!
如果你发现本笔记中有哪些错误,欢迎指出,我将虚心受教!
:::
1
1
1
1
11
1
1
1
1
1
1
1
1
1
1

View File

@ -10,7 +10,8 @@ const mode = __CAN_I_USE_INJECT_MODE__
export default defineClientAppEnhance(({ router }) => {
if (__VUEPRESS_SSR__) return
router.afterEach((to) => {
router.afterEach((to, from) => {
if (to.path === from.path) return
if (mode === 'embed') {
setTimeout(() => resolveCanIUse(), 1500)
}

View File

@ -90,8 +90,8 @@ const headers = computed(() => {
&::before {
content: '';
display: inline-block;
width: 12px;
height: 12px;
width: 0.75rem;
height: 0.75rem;
background-color: var(--c-bg-container);
border-radius: 6px;
border: solid 2px var(--c-border-dark);
@ -117,8 +117,8 @@ const headers = computed(() => {
&::before {
content: '';
display: inline-block;
width: 10px;
height: 10px;
width: 0.625rem;
height: 0.625rem;
background-color: var(--c-bg-container);
border-radius: 5px;
border: solid 2px var(--c-border-dark);

View File

@ -146,8 +146,8 @@ const postStat = usePostStat()
.email-icon,
.github-icon,
.weiBo-icon {
width: 24px;
height: 24px;
width: 1.5rem;
height: 1.5rem;
}
}
@ -163,14 +163,14 @@ const postStat = usePostStat()
text-align: center;
color: var(--c-text-quote);
.icon {
width: 32px;
height: 32px;
width: 2rem;
height: 2rem;
color: var(--c-text-lightest);
}
span {
display: inline-block;
width: 100%;
font-size: 20px;
font-size: 1.25rem;
font-weight: 500;
}
}

View File

@ -67,6 +67,8 @@ const avatar = themeLocale.value.avatar || {}
</div>
</template>
<style lang="scss">
@import '../styles/_variables';
.home-big-banner-wrapper {
position: relative;
display: flex;
@ -82,8 +84,8 @@ const avatar = themeLocale.value.avatar || {}
position: absolute;
bottom: 1.25rem;
left: 50%;
width: 48px;
height: 48px;
width: 3rem;
height: 3rem;
color: var(--c-home-arrow-bottom);
animation: home-banner-arrow 1.5s ease 0.3s infinite;
cursor: pointer;
@ -93,8 +95,8 @@ const avatar = themeLocale.value.avatar || {}
margin: auto;
text-align: center;
.blogger-img {
width: 240px;
height: 240px;
width: 15rem;
height: 15rem;
border-radius: 50%;
overflow: hidden;
padding: 1.25rem;
@ -109,7 +111,7 @@ const avatar = themeLocale.value.avatar || {}
h3 {
display: inline-block;
font-size: 64px;
font-size: 4rem;
max-width: var(--content-width);
color: rgba(255, 255, 255, 0.85);
padding: 0 1.25rem;
@ -118,7 +120,7 @@ const avatar = themeLocale.value.avatar || {}
.blogger-motto {
max-width: var(--content-width);
font-size: 32px;
font-size: 2rem;
color: rgba(255, 255, 255, 0.75);
padding: 0 1.25rem;
border-radius: var(--p-around);
@ -126,10 +128,25 @@ const avatar = themeLocale.value.avatar || {}
}
}
@media (max-width: $MQMobile) {
.home-big-banner-wrapper .home-blogger-info {
.blogger-img {
width: 50vw;
height: 50vw;
}
h3 {
font-size: 3rem;
}
.blogger-motto {
font-size: 1.5rem;
}
}
}
@keyframes home-banner-arrow {
0% {
opacity: 0;
transform: translateY(-10px);
transform: translateX(-50%) translateY(-10px);
}
10% {
@ -138,12 +155,12 @@ const avatar = themeLocale.value.avatar || {}
95% {
opacity: 1;
transform: translateY(0);
transform: translateX(-50%) translateY(0);
}
100% {
opacity: 0.25;
transform: translateY(-7px);
transform: translateX(-50%) translateY(-7px);
}
}
</style>

View File

@ -5,11 +5,10 @@ import Sidebar from '@theme-plume/Sidebar.vue'
import { usePageData } from '@vuepress/client'
import { computed } from 'vue'
import type { PlumeThemePageData } from '../../shared'
import { useDarkMode, useThemeLocaleData } from '../composables'
import { useDarkMode } from '../composables'
import Toc from './Toc'
const page = usePageData<PlumeThemePageData>()
const themeLocale = useThemeLocaleData()
const isDarkMode = useDarkMode()
const isNote = computed(() => {
@ -27,7 +26,7 @@ const enabledSidebar = computed(() => {
<div class="page-container" :class="{ 'has-sidebar': enabledSidebar }">
<main class="plume-theme-content">
<Sidebar v-if="enabledSidebar" />
<div class="page-content">
<div class="page-content" :class="{ 'note-content': isNote }">
<h1>{{ page.title }}</h1>
<PostMeta :post="page" type="post" border />
<Content />
@ -68,6 +67,10 @@ const enabledSidebar = computed(() => {
max-width: var(--content-width);
padding: 0 2rem 1rem;
margin: 0 auto;
&.note-content {
max-width: var(--content-note-width);
}
}
img {

View File

@ -35,7 +35,7 @@ const footer = computed(() => {
padding: 1.25rem;
background-color: var(--c-bg-container);
box-shadow: var(--shadow-footer);
font-size: 14px;
font-size: 0.875rem;
text-align: center;
.theme-plume-footer-content {

View File

@ -113,7 +113,7 @@ function handleJump(): void {
justify-content: flex-start;
align-items: center;
text-align: center;
font-size: 14px;
font-size: 0.875rem;
.pagination-container {
flex: 1;
@ -132,8 +132,8 @@ function handleJump(): void {
cursor: pointer;
font-size: inherit;
padding: 0 0.8rem;
height: 34px;
line-height: 34px;
height: 2.125rem;
line-height: 2.125rem;
border: solid 1px transparent;
color: var(--c-text);
box-shadow: var(--shadow-sm);
@ -156,8 +156,8 @@ function handleJump(): void {
&.btn-prev,
&.btn-next {
.icon {
width: 14px;
height: 14px;
width: 0.875rem;
height: 0.875rem;
vertical-align: text-top;
}
}
@ -168,8 +168,8 @@ function handleJump(): void {
font-size: inherit;
padding: 0.5rem;
width: 3.25rem;
height: 34px;
line-height: 34px;
height: 2.125rem;
line-height: 2.125rem;
border: solid 1px transparent;
color: var(--c-text);
box-shadow: var(--shadow-sm);

View File

@ -108,7 +108,7 @@ const togglePage = (currentPage: number): void => {
.post-banner {
position: relative;
height: 300px;
height: 18.75rem;
margin: -1.25rem -1.5rem 1.25rem -1.5rem;
overflow: hidden;
cursor: pointer;
@ -134,7 +134,7 @@ const togglePage = (currentPage: number): void => {
left: 1.5rem;
width: 0;
height: 0;
border: solid 20px;
border: solid 1.25rem;
border-color: transparent transparent var(--c-bg-container) transparent;
z-index: 1;
}

View File

@ -48,7 +48,7 @@ onMounted(() => {
width: 18rem;
height: calc(100vh - var(--navbar-height) - 1.25rem);
border-right: solid 1px var(--c-border);
font-size: 18px;
font-size: 1.125rem;
padding-left: 1.25rem;
overflow-y: auto;
scrollbar-width: thin;
@ -78,7 +78,7 @@ onMounted(() => {
content: '';
position: absolute;
left: -1.25rem;
bottom: -4px;
bottom: -0.25rem;
right: 0;
border-bottom: solid 4px var(--c-border);
}

View File

@ -116,16 +116,16 @@ const sidebarClick = (sidebar: SidebarListComputed): void => {
p.sidebar-items-title {
position: relative;
margin: 0;
height: 40px;
line-height: 40px;
height: 2.5rem;
line-height: 2.5rem;
cursor: pointer;
.arrow-right-icon {
position: absolute;
left: -1.5rem;
top: 8px;
width: 20px;
height: 20px;
width: 1.25rem;
height: 1.25rem;
transform: rotate(0);
transition: transform var(--t-color);
color: var(--c-text-quote);

View File

@ -3,6 +3,10 @@ import { ref } from 'vue'
import type { Ref } from 'vue'
import type { PostIndex } from '../../shared'
const isBoolean = (arg: unknown): boolean => {
return typeof arg === 'boolean'
}
export type PostIndexRef = Ref<PostIndex>
export const postIndex: PostIndexRef = ref(postIndexRaw)
@ -11,7 +15,19 @@ export const usePostAllIndex = (): PostIndexRef => postIndex
// 在首页文章列表的,默认排除掉 note中的文章除非显示声明 article
export const usePostIndex = (): PostIndexRef => {
const postList = postIndex.value.filter((post) => {
const postIndexData = [
...postIndex.value
.filter((post) => post.sticky)
.sort((left, right) => {
const leftSticky = isBoolean(left.sticky) ? 1 : (left.sticky as number)
const rightSticky = isBoolean(right.sticky)
? 1
: (right.sticky as number)
return leftSticky < rightSticky ? 1 : -1
}),
...postIndex.value.filter((post) => !post.sticky),
]
const postList = postIndexData.filter((post) => {
if (post.isNote) {
return post.article === true
} else {

View File

@ -107,9 +107,10 @@ h1 {
h2 {
font-size: 1.65rem;
padding-bottom: 0.3rem;
padding-bottom: 0.5rem;
border-bottom: solid 1px var(--c-border);
transition: border-color var(--t-color);
margin-top: 2.75rem;
}
h3 {

View File

@ -1,4 +1,3 @@
.theme-plume-toc {
border-left: solid 1px var(--c-border);
max-height: calc(100vh - var(--navbar-height) - (1.25rem * 3));
@ -13,7 +12,6 @@
}
}
.theme-plume-toc-list {
list-style: none;
@ -48,7 +46,7 @@
}
.plume-theme-page-toc {
width: 200px;
width: 12.5rem;
margin-left: 1.25rem;
.theme-plume-toc {

View File

@ -86,7 +86,8 @@
--navbar-padding-h: 1.5rem;
--sidebar-width: 20rem;
--sidebar-width-mobile: calc(var(--sidebar-width) * 0.82);
--content-width: 740px;
--content-width: 850px;
--content-note-width: 1000px;
// search box vars
--search-bg-color: transparent;

View File

@ -24,15 +24,11 @@ if (import.meta.hot) {
}
`
const isBoolean = (arg: unknown): boolean => {
return typeof arg === 'boolean'
}
export const preparedPostIndex = (
app: App,
localeOption: PlumeThemeLocaleOptions
): void => {
let postIndex: PostIndex = (app.pages as Page<PlumeThemePageData>[])
const postIndex: PostIndex = (app.pages as Page<PlumeThemePageData>[])
.filter((page) => {
return (
!!page.pathInferred &&
@ -64,18 +60,6 @@ export const preparedPostIndex = (
banner: frontmatter.banner,
} as PostItem
})
postIndex = [
...postIndex
.filter((post) => post.sticky)
.sort((left, right) => {
const leftSticky = isBoolean(left.sticky) ? 1 : (left.sticky as number)
const rightSticky = isBoolean(right.sticky)
? 1
: (right.sticky as number)
return leftSticky < rightSticky ? 1 : -1
}),
...postIndex.filter((post) => !post.sticky),
]
let content = `
export const postIndex = ${JSON.stringify(postIndex, null, 2)}