From 0941d4e2f3dece9373cd689507da15578fa76a91 Mon Sep 17 00:00:00 2001 From: Justineo Date: Thu, 26 May 2022 19:16:47 +0800 Subject: [PATCH] feat: add anchor link for all headings --- assets/styles/post.styl | 30 ++++- nuxt.config.js | 1 + one/build/page.js | 19 ++- one/build/rehype-link.js | 10 +- one/build/rehype-scoped.js | 2 +- one/build/remark-anchor.js | 5 +- one/docs/changelog.vue | 4 +- one/docs/demo/style/number.vue | 57 +++++++++ package-lock.json | 228 +++++++++++++++++++++++++++++++++ package.json | 2 + plugins/global.js | 4 + plugins/target.js | 2 + 12 files changed, 347 insertions(+), 17 deletions(-) create mode 100644 one/docs/demo/style/number.vue create mode 100644 plugins/global.js diff --git a/assets/styles/post.styl b/assets/styles/post.styl index 3baefba..96533d4 100644 --- a/assets/styles/post.styl +++ b/assets/styles/post.styl @@ -34,7 +34,20 @@ margin-y($top, $bottom = $top) .one-details margin-bottom 5px -[data-markdown] + .icon-link + position absolute + transition-property transform, opacity + transition-duration 0.2s + transform translate(calc(-1px - 100%), -50%) + opacity 0 + padding 0.1em + +[data-target] + .icon-link + opacity 1 + transform translate(-100%, -50%) + +[data-md] h1 h1& margin-y(0, 1.25em) @@ -49,11 +62,6 @@ margin-y($top, $bottom = $top) margin-y(1.3em, 1.2em) font-size 30px - &::before - content "#" - margin-right 5px - color #ccc - & + h3 margin-top 2em @@ -98,9 +106,17 @@ margin-y($top, $bottom = $top) h5& h6 h6& + position relative + display flex + align-items center color #333 line-height 1 + &:hover + .icon-link + opacity 1 + transform translate(-100%, -50%) + br br& clear both @@ -368,7 +384,7 @@ margin-y($top, $bottom = $top) .post padding 30px - [data-markdown] + [data-md] h1 h1& font-size 24px diff --git a/nuxt.config.js b/nuxt.config.js index c3e7be4..62a565a 100644 --- a/nuxt.config.js +++ b/nuxt.config.js @@ -53,6 +53,7 @@ module.exports = { ], plugins: [ + { src: '~plugins/global.js' }, { src: '~plugins/hm.js', ssr: false }, { src: '~plugins/i18n.js' }, { src: '~plugins/l10n.js' }, diff --git a/one/build/page.js b/one/build/page.js index bb73c8d..8449378 100644 --- a/one/build/page.js +++ b/one/build/page.js @@ -6,6 +6,7 @@ import frontmatter from 'remark-frontmatter' import shortcodes from 'remark-shortcodes' import remarkToRehype from 'remark-rehype' import raw from 'rehype-raw' +import rehypeAutolinkHeadings from '@justfork/rehype-autolink-headings' import html from 'rehype-stringify' import highlight from 'rehype-highlight' import etpl from 'etpl' @@ -45,6 +46,14 @@ const md = remark() .use(toc) .use(remarkToRehype, { allowDangerousHTML: true }) .use(raw) + .use(rehypeAutolinkHeadings, { + content: { + type: 'element', + tagName: 'icon-link', + properties: { class: 'icon-link' } + }, + test: ['h2', 'h3', 'h4', 'h5', 'h6'] + }) .use(rehypePreviewImg) .use(rehypeLink) .use(rehypeScoped) @@ -87,16 +96,20 @@ export function renderDocToPage (file) { .replace(/\{/g, '{') .replace(/\}/g, '}') .replace(/v-pre="true"/g, 'v-pre') - .replace(/data-markdown="true"/g, 'data-markdown'), + .replace(/data-md="true"/g, 'data-md'), demos: demoList.map(name => { return { name, - src: join('@/components/demos', relative(DOCS_DIR, demos[name].filePath)) + src: join( + '@/components/demos', + relative(DOCS_DIR, demos[name].filePath) + ) } }), components: componentList, alert: hasAlert, - boilerplate: demoList.length || componentList.length || hasAlert || style === 'post', + boilerplate: + demoList.length || componentList.length || hasAlert || style === 'post', layout, style, path: file, diff --git a/one/build/rehype-link.js b/one/build/rehype-link.js index a4771d5..e939764 100644 --- a/one/build/rehype-link.js +++ b/one/build/rehype-link.js @@ -10,12 +10,16 @@ export default function attacher () { let [, locale] = localPath.match(RE_LOCALE) || [] visit(tree, 'element', node => { - let { tagName, properties: { href, ...props } } = node - if (tagName !== 'a' || href.match(/^\w+:\/\//)) { + let { + tagName, + properties: { href, ...props } + } = node + if (tagName !== 'a' || href.startsWith('#') || href.match(/^\w+:\/\//)) { return } - let routePath = locale && href.indexOf('/') === 0 ? `/${locale}${href}` : href + let routePath = + locale && href.indexOf('/') === 0 ? `/${locale}${href}` : href node.tagName = 'nuxt-link' node.properties = { ...props, to: routePath } diff --git a/one/build/rehype-scoped.js b/one/build/rehype-scoped.js index 7fce431..010f46f 100644 --- a/one/build/rehype-scoped.js +++ b/one/build/rehype-scoped.js @@ -6,7 +6,7 @@ export default function attacher () { return tree => { visit(tree, 'element', ({ tagName, properties }, _, { type }) => { if (type === 'root' && !RE_DEMO.test(tagName)) { - properties['data-markdown'] = true + properties['data-md'] = true } }) } diff --git a/one/build/remark-anchor.js b/one/build/remark-anchor.js index 4f82f7e..058ea2f 100644 --- a/one/build/remark-anchor.js +++ b/one/build/remark-anchor.js @@ -29,7 +29,10 @@ export default function attacher () { const { type, depth, children, value, position } = node if (type === 'heading') { if (depth === 3) { - const text = children[0] + let text = children[0] + if (text && text.type === 'element' && text.tagName === 'icon-link') { + text = children[1] + } if (text && text.type === 'text' && KNOWN_SCOPES[text.value]) { scope = KNOWN_SCOPES[text.value] return diff --git a/one/docs/changelog.vue b/one/docs/changelog.vue index eb48374..328e215 100644 --- a/one/docs/changelog.vue +++ b/one/docs/changelog.vue @@ -3,7 +3,7 @@ class="content post" :class="{ 'filter-version': compareValid }" > -

+

升级日志

+
+
+ + {{ value }} + + + Tabular numbers + +
+ +
+ + + + + diff --git a/package-lock.json b/package-lock.json index e477172..1784470 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "devDependencies": { "@docsearch/css": "^3.0.0-alpha.39", "@docsearch/js": "^3.0.0-alpha.39", + "@justfork/rehype-autolink-headings": "^5.1.1", "@justfork/vue-monaco": "^0.3.1", "@stackblitz/sdk": "^1.5.2", "@vue/runtime-dom": "^3.2.31", @@ -58,6 +59,7 @@ "raw-loader": "^4.0.2", "recursive-readdir": "^2.2.2", "recursive-readdir-sync": "^1.0.6", + "rehype-autolink-headings": "^5.1.0", "rehype-highlight": "^4.1.0", "rehype-raw": "^2.0.0", "rehype-stringify": "^3.0.0", @@ -1975,6 +1977,62 @@ "integrity": "sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw==", "dev": true }, + "node_modules/@justfork/rehype-autolink-headings": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@justfork/rehype-autolink-headings/-/rehype-autolink-headings-5.1.1.tgz", + "integrity": "sha512-6KuaNZDcTQ5xjxbxzmzJ/9PN1HfdA0m1qC3IxKM+rQWWzTlKJwnErRSgRqsF+eZV5dpy/JaBst0OTa3xTMXejA==", + "dev": true, + "dependencies": { + "extend": "^3.0.0", + "hast-util-has-property": "^1.0.0", + "hast-util-heading-rank": "^1.0.0", + "hast-util-is-element": "^1.1.0", + "unist-util-visit": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@justfork/rehype-autolink-headings/node_modules/unist-util-is": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@justfork/rehype-autolink-headings/node_modules/unist-util-visit": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", + "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@justfork/rehype-autolink-headings/node_modules/unist-util-visit-parents": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/@justfork/vue-monaco": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/@justfork/vue-monaco/-/vue-monaco-0.3.1.tgz", @@ -10744,6 +10802,26 @@ "vfile-location": "^2.0.0" } }, + "node_modules/hast-util-has-property": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-1.0.4.tgz", + "integrity": "sha512-ghHup2voGfgFoHMGnaLHOjbYFACKrRh9KFttdCzMCbFoBMJXiNi2+XTrPP8+q6cDJM/RSqlCfVWrjp1H201rZg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-heading-rank": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-1.0.1.tgz", + "integrity": "sha512-P6Hq7RCky9syMevlrN90QWpqWDXCxwIVOfQR2rK6P4GpY4bqjKEuCzoWSRORZ7vz+VgRpLnXimh+mkwvVFjbyQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-is-element": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-1.1.0.tgz", @@ -18014,6 +18092,61 @@ "jsesc": "bin/jsesc" } }, + "node_modules/rehype-autolink-headings": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/rehype-autolink-headings/-/rehype-autolink-headings-5.1.0.tgz", + "integrity": "sha512-ujU4/ALnWLJQubobQaMdC0h9nkzi7HlW9SOuCxZOkkJqhc/TrQ1cigIjMFQ2Tfc/es0KiFopKvwCUGw7Gw+mFw==", + "dev": true, + "dependencies": { + "extend": "^3.0.0", + "hast-util-has-property": "^1.0.0", + "hast-util-heading-rank": "^1.0.0", + "unist-util-visit": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-autolink-headings/node_modules/unist-util-is": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-autolink-headings/node_modules/unist-util-visit": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", + "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-autolink-headings/node_modules/unist-util-visit-parents": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/rehype-highlight": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/rehype-highlight/-/rehype-highlight-4.1.0.tgz", @@ -25239,6 +25372,48 @@ "integrity": "sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw==", "dev": true }, + "@justfork/rehype-autolink-headings": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@justfork/rehype-autolink-headings/-/rehype-autolink-headings-5.1.1.tgz", + "integrity": "sha512-6KuaNZDcTQ5xjxbxzmzJ/9PN1HfdA0m1qC3IxKM+rQWWzTlKJwnErRSgRqsF+eZV5dpy/JaBst0OTa3xTMXejA==", + "dev": true, + "requires": { + "extend": "^3.0.0", + "hast-util-has-property": "^1.0.0", + "hast-util-heading-rank": "^1.0.0", + "hast-util-is-element": "^1.1.0", + "unist-util-visit": "^2.0.0" + }, + "dependencies": { + "unist-util-is": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "dev": true + }, + "unist-util-visit": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", + "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + } + }, + "unist-util-visit-parents": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + } + } + } + }, "@justfork/vue-monaco": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/@justfork/vue-monaco/-/vue-monaco-0.3.1.tgz", @@ -32281,6 +32456,18 @@ "vfile-location": "^2.0.0" } }, + "hast-util-has-property": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-1.0.4.tgz", + "integrity": "sha512-ghHup2voGfgFoHMGnaLHOjbYFACKrRh9KFttdCzMCbFoBMJXiNi2+XTrPP8+q6cDJM/RSqlCfVWrjp1H201rZg==", + "dev": true + }, + "hast-util-heading-rank": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-1.0.1.tgz", + "integrity": "sha512-P6Hq7RCky9syMevlrN90QWpqWDXCxwIVOfQR2rK6P4GpY4bqjKEuCzoWSRORZ7vz+VgRpLnXimh+mkwvVFjbyQ==", + "dev": true + }, "hast-util-is-element": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-1.1.0.tgz", @@ -38001,6 +38188,47 @@ } } }, + "rehype-autolink-headings": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/rehype-autolink-headings/-/rehype-autolink-headings-5.1.0.tgz", + "integrity": "sha512-ujU4/ALnWLJQubobQaMdC0h9nkzi7HlW9SOuCxZOkkJqhc/TrQ1cigIjMFQ2Tfc/es0KiFopKvwCUGw7Gw+mFw==", + "dev": true, + "requires": { + "extend": "^3.0.0", + "hast-util-has-property": "^1.0.0", + "hast-util-heading-rank": "^1.0.0", + "unist-util-visit": "^2.0.0" + }, + "dependencies": { + "unist-util-is": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "dev": true + }, + "unist-util-visit": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", + "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + } + }, + "unist-util-visit-parents": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + } + } + } + }, "rehype-highlight": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/rehype-highlight/-/rehype-highlight-4.1.0.tgz", diff --git a/package.json b/package.json index 41892e6..6072f98 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "devDependencies": { "@docsearch/css": "^3.0.0-alpha.39", "@docsearch/js": "^3.0.0-alpha.39", + "@justfork/rehype-autolink-headings": "^5.1.1", "@justfork/vue-monaco": "^0.3.1", "@stackblitz/sdk": "^1.5.2", "@vue/runtime-dom": "^3.2.31", @@ -67,6 +68,7 @@ "raw-loader": "^4.0.2", "recursive-readdir": "^2.2.2", "recursive-readdir-sync": "^1.0.6", + "rehype-autolink-headings": "^5.1.0", "rehype-highlight": "^4.1.0", "rehype-raw": "^2.0.0", "rehype-stringify": "^3.0.0", diff --git a/plugins/global.js b/plugins/global.js new file mode 100644 index 0000000..39ab379 --- /dev/null +++ b/plugins/global.js @@ -0,0 +1,4 @@ +import Vue from 'vue' +import { IconLinkAlt } from 'dls-icons-vue' + +Vue.component('icon-link', IconLinkAlt) diff --git a/plugins/target.js b/plugins/target.js index 7d75090..6be3cbf 100644 --- a/plugins/target.js +++ b/plugins/target.js @@ -29,6 +29,8 @@ export default ({ app }) => { target = anchor.closest('tr') } else if (app.router.currentRoute.name === 'changelog' && anchor.tagName === 'H2') { target = anchor.closest('.version-item') + } else if (['H1', 'H2', 'H3', 'H4', 'H5', 'H6'].includes(anchor.tagName)) { + target = anchor } if (target) {