diff --git a/docusaurus.config.js b/docusaurus.config.js index a9e8478ff..5ed22002b 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -3,6 +3,7 @@ import { themes as prismThemes } from "prism-react-renderer"; const remarkMath = require("remark-math"); const rehypeKatex = require("rehype-katex"); +const readingTimePlugin = require("./plugins/remark-reading-time"); const path = require("path"); @@ -56,7 +57,7 @@ const config = { }, editUrl: "https://github.com/codeharborhub/codeharborhub.github.io/edit/main/", - remarkPlugins: [remarkMath], + remarkPlugins: [readingTimePlugin, remarkMath], rehypePlugins: [rehypeKatex], }, pages: { diff --git a/plugins/remark-reading-time.js b/plugins/remark-reading-time.js new file mode 100644 index 000000000..084522a76 --- /dev/null +++ b/plugins/remark-reading-time.js @@ -0,0 +1,46 @@ +/** + * Remark plugin to calculate and inject reading time into frontmatter + * Estimates reading time based on word count (average 200 words per minute) + * Code blocks are weighted at 0.5x since code is read differently than prose + */ + +const { visit } = require('unist-util-visit'); + +module.exports = function readingTimePlugin() { + return (tree, vfile) => { + let wordCount = 0; + let codeWordCount = 0; + + // Count words in text nodes + visit(tree, 'text', (node) => { + wordCount += node.value + .split(/\s+/) + .filter((word) => word.length > 0).length; + }); + + // Count words in code blocks (weighted at 0.5x) + visit(tree, 'code', (node) => { + codeWordCount += node.value + .split(/\s+/) + .filter((word) => word.length > 0).length; + }); + + visit(tree, 'inlineCode', (node) => { + codeWordCount += node.value + .split(/\s+/) + .filter((word) => word.length > 0).length; + }); + + // Calculate total words with code weighted at 0.5x + const totalWords = wordCount + codeWordCount * 0.5; + + // Estimate reading time (200 words per minute, minimum 1 minute) + const readingTime = Math.max(1, Math.round(totalWords / 200)); + + // Inject into frontmatter + if (!vfile.data.frontMatter) { + vfile.data.frontMatter = {}; + } + vfile.data.frontMatter.readingTime = readingTime; + }; +};