mirror of
https://github.com/wahyd4/vuepress.git
synced 2026-08-09 05:16:23 +10:00
refactor($theme-default): leverage markdown-it-table-of-contents (#1436)
This commit is contained in:
@@ -16,7 +16,6 @@ import Content from './components/Content.js'
|
||||
import ContentSlotsDistributor from './components/ContentSlotsDistributor'
|
||||
import OutboundLink from './components/OutboundLink.vue'
|
||||
import ClientOnly from './components/ClientOnly'
|
||||
import TOC from './components/TOC.vue'
|
||||
|
||||
// suggest dev server restart on base change
|
||||
if (module.hot) {
|
||||
@@ -47,8 +46,6 @@ Vue.component('ClientOnly', ClientOnly)
|
||||
// core components
|
||||
Vue.component('Layout', getLayoutAsyncComponent('Layout'))
|
||||
Vue.component('NotFound', getLayoutAsyncComponent('NotFound'))
|
||||
// markdown components
|
||||
Vue.component('TOC', TOC)
|
||||
|
||||
// global helper for adding base path to absolute urls
|
||||
Vue.prototype.$withBase = function (path) {
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
<template>
|
||||
<component :is="listType[0]">
|
||||
<li v-for="(item, index) in items" :key="index">
|
||||
<router-link :to="'#' + item.slug" v-text="item.title" />
|
||||
<HeaderList v-if="item.children" :items="item.children" :list-type="innerListType" />
|
||||
</li>
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'HeaderList',
|
||||
props: ['items', 'listType'],
|
||||
computed: {
|
||||
innerListType () {
|
||||
return this.listType.slice(Math.min(this.listType.length - 1, 1))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,57 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<slot name="header" />
|
||||
<HeaderList :items="groupedHeaders" :list-type="listTypes" />
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HeaderList from './HeaderList.vue'
|
||||
export default {
|
||||
props: {
|
||||
listType: {
|
||||
type: [String, Array],
|
||||
default: 'ul'
|
||||
},
|
||||
includeLevel: {
|
||||
type: Array,
|
||||
default: () => [2, 3]
|
||||
}
|
||||
},
|
||||
components: { HeaderList },
|
||||
computed: {
|
||||
listTypes () {
|
||||
return typeof this.listType === 'string' ? [this.listType] : this.listType
|
||||
},
|
||||
groupedHeaders () {
|
||||
return this.groupHeaders(this.$page.headers).list
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
groupHeaders (headers, startLevel = 1) {
|
||||
const list = []
|
||||
let index = 0
|
||||
while (index < headers.length) {
|
||||
const header = headers[index]
|
||||
if (header.level < startLevel) break
|
||||
if (header.level > startLevel) {
|
||||
const result = this.groupHeaders(headers.slice(index), header.level)
|
||||
if (list.length) {
|
||||
list[list.length - 1].children = result.list
|
||||
} else {
|
||||
list.push(...result.list)
|
||||
}
|
||||
index += result.index
|
||||
} else {
|
||||
if (header.level <= this.includeLevel[1] && header.level >= this.includeLevel[0]) {
|
||||
list.push({ ...header })
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
return { list, index }
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -15,7 +15,6 @@ const componentPlugin = require('./lib/component')
|
||||
const hoistScriptStylePlugin = require('./lib/hoist')
|
||||
const convertRouterLinkPlugin = require('./lib/link')
|
||||
const snippetPlugin = require('./lib/snippet')
|
||||
const tocPlugin = require('./lib/tableOfContents')
|
||||
const emojiPlugin = require('markdown-it-emoji')
|
||||
const anchorPlugin = require('markdown-it-anchor')
|
||||
const {
|
||||
@@ -32,7 +31,6 @@ module.exports = (markdown = {}) => {
|
||||
const {
|
||||
externalLinks,
|
||||
anchor,
|
||||
toc,
|
||||
plugins,
|
||||
lineNumbers,
|
||||
beforeInstantiate,
|
||||
@@ -93,10 +91,6 @@ module.exports = (markdown = {}) => {
|
||||
}, anchor)])
|
||||
.end()
|
||||
|
||||
.plugin(PLUGINS.TOC)
|
||||
.use(tocPlugin, [toc])
|
||||
.end()
|
||||
|
||||
if (lineNumbers) {
|
||||
config
|
||||
.plugin(PLUGINS.LINE_NUMBERS)
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
// reference: https://github.com/Oktavilla/markdown-it-table-of-contents
|
||||
|
||||
const defaults = {
|
||||
includeLevel: [2, 3],
|
||||
containerClass: 'table-of-contents',
|
||||
markerPattern: /^\[\[toc\]\]/im,
|
||||
listType: 'ul',
|
||||
containerHeaderHtml: '',
|
||||
containerFooterHtml: ''
|
||||
}
|
||||
|
||||
module.exports = (md, options) => {
|
||||
options = Object.assign({}, defaults, options)
|
||||
const tocRegexp = options.markerPattern
|
||||
|
||||
function toc (state, silent) {
|
||||
var token
|
||||
var match
|
||||
|
||||
// Reject if the token does not start with [
|
||||
if (state.src.charCodeAt(state.pos) !== 0x5B /* [ */) {
|
||||
return false
|
||||
}
|
||||
// Don't run any pairs in validation mode
|
||||
if (silent) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Detect TOC markdown
|
||||
match = tocRegexp.exec(state.src)
|
||||
match = !match ? [] : match.filter(function (m) { return m })
|
||||
if (match.length < 1) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Build content
|
||||
token = state.push('toc_open', 'toc', 1)
|
||||
token.markup = '[[toc]]'
|
||||
token = state.push('toc_body', '', 0)
|
||||
token = state.push('toc_close', 'toc', -1)
|
||||
|
||||
// Update pos so the parser can continue
|
||||
var newline = state.src.indexOf('\n')
|
||||
if (newline !== -1) {
|
||||
state.pos = state.pos + newline
|
||||
} else {
|
||||
state.pos = state.pos + state.posMax + 1
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
md.renderer.rules.toc_open = function () {
|
||||
return vBindEscape`<TOC
|
||||
:class=${options.containerClass}
|
||||
:list-type=${options.listType}
|
||||
:include-level=${options.includeLevel}
|
||||
>`
|
||||
}
|
||||
|
||||
md.renderer.rules.toc_body = function () {
|
||||
return `<template slot="header">${options.containerHeaderHtml}</template>`
|
||||
+ `<template slot="footer">${options.containerFooterHtml}</template>`
|
||||
}
|
||||
|
||||
md.renderer.rules.toc_close = function () {
|
||||
return `</TOC>`
|
||||
}
|
||||
|
||||
// Insert TOC
|
||||
md.inline.ruler.after('emphasis', 'toc', toc)
|
||||
}
|
||||
|
||||
/** escape double quotes in v-bind derivatives */
|
||||
function vBindEscape (strs, ...args) {
|
||||
return strs.reduce((prev, curr, index) => {
|
||||
return prev + curr + (index >= args.length
|
||||
? ''
|
||||
: `"${JSON.stringify(args[index])
|
||||
.replace(/"/g, "'")
|
||||
.replace(/([^\\])(\\\\)*\\'/g, (_, char) => char + '\\u0022')}"`)
|
||||
}, '')
|
||||
}
|
||||
@@ -17,10 +17,19 @@ module.exports = (options, ctx) => ({
|
||||
}
|
||||
},
|
||||
|
||||
extendMarkdown (md) {
|
||||
if (options.toc !== false) {
|
||||
md.use(require('markdown-it-table-of-contents'), {
|
||||
includeLevel: [2, 3],
|
||||
...options.toc
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
plugins: [
|
||||
['@vuepress/active-header-links', options.activeHeaderLinks],
|
||||
'@vuepress/search',
|
||||
'@vuepress/plugin-nprogress',
|
||||
['@vuepress/search'],
|
||||
['@vuepress/nprogress'],
|
||||
['container', {
|
||||
type: 'tip',
|
||||
defaultTitle: {
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"@vuepress/plugin-nprogress": "^1.0.0-alpha.47",
|
||||
"@vuepress/plugin-search": "^1.0.0-alpha.47",
|
||||
"docsearch.js": "^2.5.2",
|
||||
"markdown-it-table-of-contents": "^0.4.3",
|
||||
"stylus": "^0.54.5",
|
||||
"stylus-loader": "^3.0.2",
|
||||
"vuepress-plugin-container": "^2.0.0"
|
||||
|
||||
@@ -215,21 +215,6 @@ Options for [markdown-it-anchor](https://github.com/valeriangalliat/markdown-it-
|
||||
|
||||
The key and value pair will be added to `<a>` tags that point to an external link. The default option will open external links in a new window.
|
||||
|
||||
### markdown.toc
|
||||
|
||||
- Type: `Object`
|
||||
|
||||
This attribute will control the behaviour of `[[TOC]]`. It contains the following options:
|
||||
|
||||
- includeLevel: [number, number], level of headers to be included, defaults to `[2, 3]`.
|
||||
- containerClass: string, the class name for the container, defaults to `table-of-contents`.
|
||||
- markerPattern: RegExp, the regular expression for the marker to be replaced with TOC, defaults to `/^\[\[toc\]\]/im`.
|
||||
- listType: string or Array, labels for all levels of the list, defaults to `"ul"`.
|
||||
- containerHeaderHtml: string, an HTML string for container header, defaults to `""`.
|
||||
- containerFooterHtml: string, an HTML string for container footer, defaults to `""`.
|
||||
|
||||
We also provide a [global component TOC](../guide/using-vue.md#toc) which allows for more free control by passing props directly to `<TOC>`.
|
||||
|
||||
### markdown.plugins
|
||||
|
||||
You can install any markdown-it plugins through `markdown.plugins` option. It is similar with [using VuePress plugins](../plugin/using-a-plugin.html#using-a-plugin). You can either use Babel style or object style. The `markdown-it-` prefix is optional and can omit in the list.
|
||||
|
||||
@@ -101,7 +101,7 @@ For more details, check out the [Front Matter](./frontmatter.md) page.
|
||||
|
||||
A list of all emojis available can be found [here](https://github.com/markdown-it/markdown-it-emoji/blob/master/lib/data/full.json).
|
||||
|
||||
## Table of Contents
|
||||
## Table of Contents <Badge text="default theme"/>
|
||||
|
||||
**Input**
|
||||
|
||||
@@ -109,17 +109,13 @@ A list of all emojis available can be found [here](https://github.com/markdown-i
|
||||
[[toc]]
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```md
|
||||
<TOC/>
|
||||
```
|
||||
|
||||
**Output**
|
||||
|
||||
[[toc]]
|
||||
|
||||
Rendering of TOC can be configured using the [`markdown.toc`](../config/README.md#markdown-toc) option, or as props of [TOC component](./using-vue.md#toc), like `<TOC list-type="ol" :include-level="[2, Infinity]"/>`.
|
||||
Rendering of TOC can be configured using the [`themeConfig.toc`](../theme/default-theme-config.md#table-of-contents) option.
|
||||
|
||||
> You can also use the official plugin [vuepress-plugin-toc](https://vuepress.github.io/plugins/toc/) for an advanced `<TOC/>` component.
|
||||
|
||||
## Custom Containers <Badge text="default theme"/>
|
||||
|
||||
|
||||
@@ -224,28 +224,6 @@ Specify a specific slot for a specific page (.md) for rendering. This will be ve
|
||||
- [Markdown Slot](./markdown-slot.md)
|
||||
- [Writing a theme > Content Outlet](../theme/writing-a-theme.md#content-outlet)
|
||||
|
||||
### TOC <Badge text="1.0.0-alpha.41+"/>
|
||||
|
||||
- **Props**:
|
||||
- `listType` - string or Array, defaults to `"ul"`
|
||||
- `includeLevel` - [number, number], defaults to `[2, 3]`
|
||||
|
||||
- **Slots**: `header`, `footer`
|
||||
|
||||
- **Usage**:
|
||||
|
||||
You can add a custom table of contents by specify some props to this component. `includeLevel` decides which level of headers should be included. `listType` decides the tags of lists. If specified as an array, the component will take the first element as the first-level list type and so on. If there are not enough values provided, the last value will be used for all the remaining list types.
|
||||
|
||||
``` md
|
||||
<TOC :list-type="['ol', 'ul']">
|
||||
<p slot="header"><strong>Custom Table of Contents</strong></p>
|
||||
</TOC>
|
||||
```
|
||||
|
||||
<TOC :list-type="['ol', 'ul']">
|
||||
<p slot="header"><strong>Custom Table of Contents</strong></p>
|
||||
</TOC>
|
||||
|
||||
### Badge <Badge text="beta" type="warn"/> <Badge text="0.10.1+"/> <Badge text="default theme"/>
|
||||
|
||||
- **Props**:
|
||||
|
||||
@@ -304,6 +304,26 @@ sidebar: false
|
||||
---
|
||||
```
|
||||
|
||||
## Table Of Contents
|
||||
|
||||
``` js
|
||||
// .vuepress/config.js
|
||||
module.exports = {
|
||||
themeConfig: {
|
||||
toc: {
|
||||
sidebar: 'auto'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Options for [markdown-it-table-of-contents](https://github.com/Oktavilla/markdown-it-table-of-contents#options). The default options are `{ includeLevel: [2, 3] }`.
|
||||
|
||||
::: tip
|
||||
1. You should always use [`markdown.slugify`](../config/#markdown-slugify) instead of `themeConfig.toc.slugify` if you want to customize header ids.
|
||||
2. Setting `themeConfig.toc` to `false` will disable the `[[toc]]` syntax (in case you want to switch to other plugins, such as [vuepress-plugin-toc](https://vuepress.github.io/plugins/toc/)).
|
||||
:::
|
||||
|
||||
## Search Box
|
||||
|
||||
### Built-in Search
|
||||
|
||||
@@ -206,21 +206,6 @@ VuePress 提供了一种添加额外样式的简便方法。你可以创建一
|
||||
|
||||
这个键值对将会作为特性被增加到是外部链接的 `<a>` 标签上,默认的选项将会在新窗口中打开一个该外部链接。
|
||||
|
||||
### markdown.toc
|
||||
|
||||
- 类型: `Object`
|
||||
|
||||
这个值将会控制 `[[TOC]]` 默认行为。它包含下面的选项:
|
||||
|
||||
- includeLevel: [number, number],决定哪些级别的标题会被显示在目录中,默认值为 `[2, 3]`。
|
||||
- containerClass: string,决定了目录容器的类名,默认值为 `table-of-contents`。
|
||||
- markerPattern: RegExp,决定了标题匹配的正则表达式,默认值为 `/^\[\[toc\]\]/im`。
|
||||
- listType: string 或 Array,决定了各级列表的标签,默认值为 `"ul"`。
|
||||
- containerHeaderHtml: string,在目录开头插入的 HTML 字符串,默认值为 `""`。
|
||||
- containerFooterHtml: string,在目录结尾插入的 HTML 字符串,默认值为 `""`。
|
||||
|
||||
此外,我们还提供了[全局组件 TOC](../guide/using-vue.md#toc),可以通过直接向 `<TOC>` 传递属性实现更加自由的控制。
|
||||
|
||||
### markdown.plugins
|
||||
|
||||
你可以使用 `markdown.plugins` 来安装 markdown-it 插件。它的使用方法与[安装一个 VuePress 插件](../plugin/using-a-plugin.html#using-a-plugin)类似。你可以使用 Babel 语法或对象语法。`markdown-it-` 前缀同样是可以忽略的。
|
||||
|
||||
@@ -99,7 +99,7 @@ lang: en-US
|
||||
|
||||
:tada: :100:
|
||||
|
||||
## 目录
|
||||
## 目录 <Badge text="默认主题"/>
|
||||
|
||||
**输入**
|
||||
|
||||
@@ -107,17 +107,13 @@ lang: en-US
|
||||
[[toc]]
|
||||
```
|
||||
|
||||
或者
|
||||
|
||||
```md
|
||||
<TOC/>
|
||||
```
|
||||
|
||||
**输出**
|
||||
|
||||
[[toc]]
|
||||
|
||||
目录(Table of Contents)的渲染可以通过 [`markdown.toc`](../config/README.md#markdown-toc) 选项来配置,也可以在 [TOC 组件](./using-vue.md#toc)中直接传入,如 `<TOC list-type="ol" :include-level="[2, Infinity]"/>`。
|
||||
目录(Table of Contents)的渲染可以通过 [`themeConfig.toc`](../theme/default-theme-config.md#table-of-contents) 选项来配置。
|
||||
|
||||
> 如果想要使用高级的 `<TOC/>` 组件,你也可以使用官方提供的 [vuepress-plugin-toc](https://vuepress.github.io/plugins/toc/) 插件。
|
||||
|
||||
## 自定义容器 <Badge text="默认主题"/>
|
||||
|
||||
|
||||
@@ -225,28 +225,6 @@ export default {
|
||||
- [Markdown 插槽](./markdown-slot.md)
|
||||
- [开发主题 > 获取渲染内容](../theme/writing-a-theme.md#获取渲染内容)
|
||||
|
||||
### TOC <Badge text="1.0.0-alpha.41+"/>
|
||||
|
||||
- **Props**:
|
||||
- `listType` - string 或 Array, 默认值为 `"ul"`
|
||||
- `includeLevel` - [number, number], 默认值为 `[2, 3]`
|
||||
|
||||
- **Slots**: `header`, `footer`
|
||||
|
||||
- **Usage**:
|
||||
|
||||
你可以通过一些属性来实现一个自定义的目录。`includeLevel` 决定了哪些级别的标题会被显示在目录中。`listType` 决定了所有列表的标签。如果设置为了数组,组件将会使用第一个元素作为第一级列表的标签,以此类推。如果提供的标签不够多,将使用提供的最后一个值作为全部剩下的列表标签。
|
||||
|
||||
``` md
|
||||
<TOC :list-type="['ol', 'ul']">
|
||||
<p slot="header"><strong>自定义目录</strong></p>
|
||||
</TOC>
|
||||
```
|
||||
|
||||
<TOC :list-type="['ol', 'ul']">
|
||||
<p slot="header"><strong>自定义目录</strong></p>
|
||||
</TOC>
|
||||
|
||||
### Badge <Badge text="beta" type="warn"/> <Badge text="0.10.1+"/> <Badge text="默认主题"/>
|
||||
|
||||
- **Props**:
|
||||
|
||||
@@ -299,6 +299,26 @@ sidebar: false
|
||||
---
|
||||
```
|
||||
|
||||
## 目录
|
||||
|
||||
``` js
|
||||
// .vuepress/config.js
|
||||
module.exports = {
|
||||
themeConfig: {
|
||||
toc: {
|
||||
sidebar: 'auto'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
提供给 [markdown-it-table-of-contents](https://github.com/Oktavilla/markdown-it-table-of-contents#options) 的选项。默认选项为 `{ includeLevel: [2, 3] }`。
|
||||
|
||||
::: tip
|
||||
1. 如果你希望自定义标题,你应该使用 [`markdown.slugify`](../config/#markdown-slugify) 而不是 `themeConfig.toc.slugify`。
|
||||
2. 将 `themeConfig.toc` 设为 `false` 将会禁用 `[[toc]]` 的语法(这在当你想要使用诸如 [vuepress-plugin-toc](https://vuepress.github.io/plugins/toc/) 的插件时是有用的)。
|
||||
:::
|
||||
|
||||
## 搜索框
|
||||
|
||||
### 内置搜索
|
||||
|
||||
@@ -6587,6 +6587,11 @@ markdown-it-emoji@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz#9bee0e9a990a963ba96df6980c4fddb05dfb4dcc"
|
||||
|
||||
markdown-it-table-of-contents@^0.4.3:
|
||||
version "0.4.3"
|
||||
resolved "https://registry.yarnpkg.com/markdown-it-table-of-contents/-/markdown-it-table-of-contents-0.4.3.tgz#6453925a76e49b9b3d9569a0d89f1c2168b46982"
|
||||
integrity sha512-x/OdaRzLYxAjmB+jIVlXuE3nX7tZTLDQxm58RkgjTLyQ+I290jYQvPS9cJjVN6SM3U6K6CHKYNgUtPNZmLblYQ==
|
||||
|
||||
markdown-it@^8.4.1:
|
||||
version "8.4.2"
|
||||
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.2.tgz#386f98998dc15a37722aa7722084f4020bdd9b54"
|
||||
|
||||
Reference in New Issue
Block a user