diff --git a/package-lock.json b/package-lock.json index 062641f..8aa51bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,6 +39,7 @@ "lodash-es": "^4.17.21", "lowlight": "^3.1.0", "mdast-util-find-and-replace": "^3.0.1", + "mdast-util-to-string": "^4.0.0", "node-html-parser": "^6.1.13", "purgecss-webpack-plugin": "^6.0.0", "rehype-highlight": "^7.0.0", diff --git a/package.json b/package.json index 21d4069..d1bb95b 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "lodash-es": "^4.17.21", "lowlight": "^3.1.0", "mdast-util-find-and-replace": "^3.0.1", + "mdast-util-to-string": "^4.0.0", "node-html-parser": "^6.1.13", "purgecss-webpack-plugin": "^6.0.0", "rehype-highlight": "^7.0.0", diff --git a/src/views/develop/guides/index.md b/src/views/develop/guides/index.md index 7372e56..51891aa 100644 --- a/src/views/develop/guides/index.md +++ b/src/views/develop/guides/index.md @@ -28,4 +28,5 @@ playback. low-level media APIs like `libndl-media`, it provides low-latency game streaming from a PC. It also uses SDL2 for rendering and input handling. -Next: [Environment Setup](/develop/guides/env-setup) \ No newline at end of file +* Next + * [Environment Setup](/develop/guides/env-setup) \ No newline at end of file diff --git a/webpack/markdown-loader.js b/webpack/markdown-loader.js index 41bf311..33282ab 100644 --- a/webpack/markdown-loader.js +++ b/webpack/markdown-loader.js @@ -6,6 +6,7 @@ import remarkGemoji from 'remark-gemoji'; import remarkRehype from 'remark-rehype'; import remarkTabbedCodeBlock from "./remark/tabbed-code-block.js"; import remarkImageClass from "./remark/image-class.js"; +import remarkPagination from "./remark/pagination.js"; import rehypeRaw from 'rehype-raw'; import rehypeSlug from 'rehype-slug'; @@ -124,11 +125,12 @@ function alertRestyle() { const parser = remark() .use(remarkGfm) .use([remarkAlert, alertRestyle]) - .use(remarkSectionize) .use(remarkBootstrapIcon) .use(remarkGemoji) .use(remarkTabbedCodeBlock) .use(remarkImageClass, {class: 'img-fluid rounded-3'}) + .use(remarkPagination) + .use(remarkSectionize) .use(remarkRehype, {allowDangerousHtml: true}) .use(rehypeRaw) .use(rehypeSlug) diff --git a/webpack/remark/pagination.js b/webpack/remark/pagination.js new file mode 100644 index 0000000..7f3dd2f --- /dev/null +++ b/webpack/remark/pagination.js @@ -0,0 +1,64 @@ +import {toString as mdToString} from 'mdast-util-to-string'; +import {groupBy, mapValues} from "lodash-es"; +import {visit} from "unist-util-visit"; + +import {html} from '../htm-rehype.js'; +import {toHtml} from "hast-util-to-html"; + +/** + * @param node {MarkdownNode} + * @returns {MarkdownLink[]} + */ +function extractLinks(node) { + const result = []; + if (node) visit(node, 'link', (link) => { + result.push(link); + }); + return result; +} + +/** + * @return {Processor} + */ +export default function () { + return (tree) => { + /** @type {MarkdownList} */ + const lastChild = tree.children[tree.children.length - 1]; + if (lastChild?.type !== 'list') { + return; + } + /** @type {Record} */ + const entries = mapValues(groupBy(lastChild.children, i => mdToString(i.children[0])), + l => l.flatMap(i => extractLinks(i.children[1]))); + const prev = entries['Previous']; + const next = entries['Next']; + if (!prev && !next) { + return; + } + tree.children[tree.children.length - 1] = { + type: 'html', + value: toHtml(html` +
+
+ ${prev && html` +
+ Previous + ${prev.map(link => html` + ${mdToString(link)} + `)} +
`} +
+
+ ${next && html` +
+ Next + ${next.map(link => html` + ${mdToString(link)} + `)} +
`} +
+
+ `) + } + } +} \ No newline at end of file diff --git a/webpack/types.js b/webpack/types.js index 91d7032..c692afa 100644 --- a/webpack/types.js +++ b/webpack/types.js @@ -7,6 +7,8 @@ /** @typedef {import('mdast').Root} MarkdownRoot */ /** @typedef {import('mdast').Node} MarkdownNode */ +/** @typedef {import('mdast').List} MarkdownList */ +/** @typedef {import('mdast').MarkdownLink} MarkdownLink */ /** @typedef {import('mdast').Image} MarkdownImage */ /** @typedef {import('mdast').Code} Code */