From 45a027b6cbf683c44d725dc2f399fe174ef6c704 Mon Sep 17 00:00:00 2001 From: Justineo Date: Mon, 25 Oct 2021 20:19:04 +0800 Subject: [PATCH] feat: add post toc --- components/OneMenu.vue | 4 +-- components/OneToc.vue | 27 ++++++++++++++++++ one/build/page.js | 13 ++++++--- one/build/remark-anchor.js | 1 + one/build/remark-extract-toc.js | 49 +++++++++++++++++++++++++++++++++ one/docs/en-US/index.md | 3 ++ one/docs/index.md | 3 ++ one/templates/page.etpl | 24 ++++++++++------ package-lock.json | 45 ++++++++++++++++++++++++++++-- package.json | 2 ++ 10 files changed, 154 insertions(+), 17 deletions(-) create mode 100644 components/OneToc.vue create mode 100644 one/build/remark-extract-toc.js diff --git a/components/OneMenu.vue b/components/OneMenu.vue index 20db671..c56e002 100644 --- a/components/OneMenu.vue +++ b/components/OneMenu.vue @@ -1,5 +1,5 @@ - + + + diff --git a/one/build/page.js b/one/build/page.js index 142a0e9..c4f3398 100644 --- a/one/build/page.js +++ b/one/build/page.js @@ -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) diff --git a/one/build/remark-anchor.js b/one/build/remark-anchor.js index 9acd23f..5d8931e 100644 --- a/one/build/remark-anchor.js +++ b/one/build/remark-anchor.js @@ -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') { diff --git a/one/build/remark-extract-toc.js b/one/build/remark-extract-toc.js new file mode 100644 index 0000000..029c392 --- /dev/null +++ b/one/build/remark-extract-toc.js @@ -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 + } + } +} diff --git a/one/docs/en-US/index.md b/one/docs/en-US/index.md index 622318d..4e3f989 100644 --- a/one/docs/en-US/index.md +++ b/one/docs/en-US/index.md @@ -1,3 +1,6 @@ +--- +toc: false +--- # VEUI :::oss-badges diff --git a/one/docs/index.md b/one/docs/index.md index d3335ed..77ba9ec 100644 --- a/one/docs/index.md +++ b/one/docs/index.md @@ -1,3 +1,6 @@ +--- +toc: false +--- # VEUI :::oss-badges diff --git a/one/templates/page.etpl b/one/templates/page.etpl index de77ecd..43b24b6 100644 --- a/one/templates/page.etpl +++ b/one/templates/page.etpl @@ -1,5 +1,6 @@