feat: add post toc

This commit is contained in:
Justineo 2021-10-25 20:19:04 +08:00
parent 0aeafc6129
commit 45a027b6cb
No known key found for this signature in database
GPG Key ID: B73F0979CF18A0EA
10 changed files with 154 additions and 17 deletions

View File

@ -1,5 +1,5 @@
<template>
<aside
<nav
v-outside="collapseMenu"
class="one-nav"
:class="{ expanded }"
@ -52,7 +52,7 @@
{{ label }}<small>{{ sub }}</small>
</template>
</veui-menu>
</aside>
</nav>
</template>
<script>

27
components/OneToc.vue Normal file
View File

@ -0,0 +1,27 @@
<template>
<nav class="one-toc">
<veui-anchor
:items="items"
sticky
/>
</nav>
</template>
<script>
import { Anchor } from 'veui'
export default {
name: 'one-toc',
components: {
'veui-anchor': Anchor
},
props: {
items: Array
}
}
</script>
<style lang="stylus" scoped>
.one-toc
float right
</style>

View File

@ -9,12 +9,14 @@ import raw from 'rehype-raw'
import html from 'rehype-stringify'
import highlight from 'rehype-highlight'
import etpl from 'etpl'
import stringifyObject from 'stringify-object'
import { readFileSync, writeFileSync, replaceExtSync } from './util'
import demo from './remark-demo'
import ref from './remark-ref'
import anchor from './remark-anchor'
import details from './remark-details'
import custom from './remark-custom'
import toc from './remark-extract-toc'
import extractFrontmatter from './remark-extract-frontmatter'
import rehypePreviewImg from './rehype-preview-img'
import rehypeLink from './rehype-link'
@ -40,6 +42,7 @@ const md = remark()
.use(demo)
.use(extractFrontmatter)
.use(slug)
.use(toc)
.use(remarkToRehype, { allowDangerousHTML: true })
.use(raw)
.use(rehypePreviewImg)
@ -67,14 +70,15 @@ export function renderDocToPage (file) {
components = {},
meta = {},
deps = {},
hasAlert = false
hasAlert = false,
toc
} = data
Object.keys(deps || {}).forEach(dep => {
add({ [dep]: { [src]: true } })
})
let { layout, style = 'post' } = meta
let { layout, style = 'post', toc: showToc } = meta
let componentList = Object.keys(components)
let demoList = Object.keys(demos)
let result = renderPage({
@ -87,7 +91,7 @@ export function renderDocToPage (file) {
demos: demoList.map(name => {
return {
name,
src: join('@/components/demos', relative(DOCS_DIR, demos[name].path))
src: join('@/components/demos', relative(DOCS_DIR, demos[name].filePath))
}
}),
components: componentList,
@ -95,7 +99,8 @@ export function renderDocToPage (file) {
boilerplate: demoList.length || componentList.length || hasAlert || style === 'post',
layout,
style,
path: file
path: file,
toc: showToc !== false ? stringifyObject(toc[0].children) : null
})
writeFileSync(dest, result)

View File

@ -20,6 +20,7 @@ const KNOWN_SCOPES = Object.entries(KNOWN_SCOPES_CONFIG).reduce(
export default function attacher () {
return tree => {
let scope = null
visit(tree, (node, index, parent) => {
const { type, depth, children, value, position } = node
if (type === 'heading') {

View File

@ -0,0 +1,49 @@
import toString from 'mdast-util-to-string'
import visit from 'unist-util-visit'
export default function attacher () {
return transformer
function transformer (tree, vfile) {
const headings = []
visit(tree, 'heading', onHeading)
vfile.data.toc = createTree(headings)
function onHeading (node) {
const heading = {
depth: node.depth,
label: toString(node)
}
if (node.data !== undefined && node.data.id != null) {
heading.value = `#${node.data.id}`
}
headings.push(heading)
}
function createTree (headings) {
const root = { depth: 0 }
const parents = []
let previous = root
headings.forEach((heading) => {
if (heading.depth > previous.depth) {
if (previous.children === undefined) {
previous.children = []
}
parents.push(previous)
} else if (heading.depth < previous.depth) {
while (parents[parents.length - 1].depth >= heading.depth) {
parents.pop()
}
}
parents[parents.length - 1].children.push(heading)
previous = heading
})
return root.children
}
}
}

View File

@ -1,3 +1,6 @@
---
toc: false
---
# VEUI
:::oss-badges

View File

@ -1,3 +1,6 @@
---
toc: false
---
# VEUI
:::oss-badges

View File

@ -1,5 +1,6 @@
<template>
<article class="content ${style}">
<article ref="article" class="content ${style}"><!-- if: ${toc} -->
<one-toc :items="toc"/><!-- /if -->
${content | raw}
<section class="meta">
<one-edit-link path="${path}"/>
@ -11,18 +12,25 @@ import { htmlAttrs } from '~/common/i18n'<!-- for: ${components} as ${component}
import ${component} from '~/components/${component}'<!-- /for --><!-- for: ${demos} as ${demo}, ${index} -->
import Demo${index} from '${demo.src}'<!-- /for --><!-- if: ${demos.length} -->
import OneDemo from '~/components/OneDemo'<!-- /if --><!-- if: ${path} -->
import OneEditLink from '~/components/OneEditLink'<!-- /if --><!-- if: ${alert} -->
import OneEditLink from '~/components/OneEditLink'<!-- /if --><!-- if: ${toc} -->
import OneToc from '~/components/OneToc'<!-- /if --><!-- if: ${alert} -->
import { VeuiAlert } from 'veui'<!-- /if -->
export default {
components: {
<!-- for: ${components} as ${component}, ${index} -->${component}<!-- if: (${index} < ${component.length} - 1) && ${demos.length} -->,
<!-- /if--><!-- /for --><!-- for: ${demos} as ${demo}, ${index} -->'${demo.name}': Demo${index},
<!-- /for --><!-- if: ${demos.length} -->OneDemo<!-- /if --><!-- if: (${components.length} || ${demos.length}) && ${alert} -->,<!-- /if --><!-- if: ${alert} -->
VeuiAlert<!-- /if --><!-- if: (${components.length} || ${demos.length}) || ${alert} && ${path} -->,<!-- /if --><!-- if: ${path} -->
OneEditLink<!-- /if -->
<!-- for: ${components} as ${component}, ${index} -->${component},
<!-- /for --><!-- for: ${demos} as ${demo}, ${index} -->'${demo.name}': Demo${index},
<!-- /for --><!-- if: ${demos.length} -->OneDemo,<!-- /if --><!-- if: ${alert} -->
VeuiAlert,<!-- /if --><!-- if: ${toc} -->
OneToc,<!-- /if --><!-- if: ${path} -->
OneEditLink,<!-- /if -->
},
mixins: [htmlAttrs]
mixins: [htmlAttrs]<!-- if: ${toc} -->,
data () {
return {
toc: ${toc | raw}
}
}<!-- /if -->
}
</script><!-- else -->
<script>

45
package-lock.json generated
View File

@ -10141,6 +10141,12 @@
"has-symbols": "^1.0.1"
}
},
"get-own-enumerable-property-symbols": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz",
"integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==",
"dev": true
},
"get-port-please": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/get-port-please/-/get-port-please-2.2.0.tgz",
@ -12398,9 +12404,9 @@
}
},
"mdast-util-to-string": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz",
"integrity": "sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz",
"integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==",
"dev": true
},
"mdn-data": {
@ -16307,6 +16313,14 @@
"github-slugger": "^1.0.0",
"mdast-util-to-string": "^1.0.0",
"unist-util-visit": "^1.0.0"
},
"dependencies": {
"mdast-util-to-string": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz",
"integrity": "sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==",
"dev": true
}
}
},
"remark-stringify": {
@ -17487,6 +17501,31 @@
"is-hexadecimal": "^1.0.0"
}
},
"stringify-object": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz",
"integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==",
"dev": true,
"requires": {
"get-own-enumerable-property-symbols": "^3.0.0",
"is-obj": "^1.0.1",
"is-regexp": "^1.0.0"
},
"dependencies": {
"is-obj": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
"dev": true
},
"is-regexp": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz",
"integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=",
"dev": true
}
}
},
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",

View File

@ -50,6 +50,7 @@
"less-plugin-est": "^3.0.0",
"lodash": "^4.17.21",
"lowlight": "^1.9.2",
"mdast-util-to-string": "^2.0.0",
"mkdirp": "^0.5.5",
"moment": "^2.22.2",
"nuxt": "^2.15.7",
@ -70,6 +71,7 @@
"remark-shortcodes": "^0.1.5",
"remark-slug": "^4.2.3",
"short-circuit-loader": "0.0.1-alpha.2",
"stringify-object": "^3.3.0",
"stylelint": "^13.6.1",
"stylelint-plugin-stylus": "^0.9.0",
"stylus": "^0.54.5",