From f9bde996b772906e2862a9a4342ee82fe5071ae9 Mon Sep 17 00:00:00 2001 From: Fergus Bentley Date: Tue, 19 Sep 2023 23:40:35 +0100 Subject: [PATCH] feat: :technologist: Add dynamic tutorial lists (#9) --- docs/tutorials/{index.md => index.mdx} | 11 ++++-- docusaurus.config.js | 4 +- src/components/TutorialsList.js | 16 ++++++++ src/plugins/dynamic-tutorials-list/index.js | 43 +++++++++++++++++++++ 4 files changed, 69 insertions(+), 5 deletions(-) rename docs/tutorials/{index.md => index.mdx} (72%) create mode 100644 src/components/TutorialsList.js create mode 100644 src/plugins/dynamic-tutorials-list/index.js diff --git a/docs/tutorials/index.md b/docs/tutorials/index.mdx similarity index 72% rename from docs/tutorials/index.md rename to docs/tutorials/index.mdx index 4e60518..966a872 100644 --- a/docs/tutorials/index.md +++ b/docs/tutorials/index.mdx @@ -1,3 +1,5 @@ +import TutorialsList from "@site/src/components/TutorialsList" + # Tutorials Welcome to the tutorials section of the documentation. Here you will find a collection of tutorials that will help you get started with the API. @@ -8,17 +10,18 @@ The currently available tutorials are: Beginner tutorials are designed to help you get started programming using the API as a learning environment. They are intended for people who have done little to no programming and are completely new to APIs. -- [Getting Started](./beginner/getting-started.md) + ## Basic Basic tutorials are designed to help you get started with the API. They are intended for people who have done some programming and are new to the API. -- [Discover D&D Races with Shell Scripting](./basic/discover-dnd-races-with-shell-scripting.mdx) + + ## Advanced Advanced tutorials are designed to help you build more complex applications with the API. They are intended for developers who are comfortable with programming and want to build more advanced applications. -- [Monster Search with Javascript](./advanced/monster-search-with-javascript.mdx) -- [Terminal Spellbook with Python](./advanced/terminal-spellbook-with-python.mdx) + + diff --git a/docusaurus.config.js b/docusaurus.config.js index 2851aae..7e3fa71 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -37,7 +37,9 @@ const config = { }), ], ], - + plugins: [ + "./src/plugins/dynamic-tutorials-list" + ], themeConfig: /** @type {import('docusaurus-preset-openapi').ThemeConfig} */ ({ diff --git a/src/components/TutorialsList.js b/src/components/TutorialsList.js new file mode 100644 index 0000000..ba45ac2 --- /dev/null +++ b/src/components/TutorialsList.js @@ -0,0 +1,16 @@ +import React from 'react' +import { usePluginData } from '@docusaurus/useGlobalData' + +export default function TutorialsList({ category }) { + const { categories } = usePluginData('dynamic-tutorials-list'); + + return ( + + ) +} \ No newline at end of file diff --git a/src/plugins/dynamic-tutorials-list/index.js b/src/plugins/dynamic-tutorials-list/index.js new file mode 100644 index 0000000..1837346 --- /dev/null +++ b/src/plugins/dynamic-tutorials-list/index.js @@ -0,0 +1,43 @@ +const path = require('path') +const fs = require('fs') + +function makeTitle(name) { + return name.split(/\W+/) + .map(word => word.length > 3 ? word.charAt(0).toUpperCase() + word.substring(1) : word) + .join(" ") +} + +function readCategories(dir) { + return Object.fromEntries( + fs.readdirSync(dir, { withFileTypes: true }) + .filter(dirent => dirent.isDirectory()) + .map(dirent => [dirent.name, readCategory(dirent)]) + ); +} + +function readCategory(dirent) { + const dir = path.join(dirent.path, dirent.name); + + return fs.readdirSync(dir) + .filter(file => /\.mdx?/.test(file)) + .map(file => { + const name = file.substring(0, file.lastIndexOf('.')); + const filePath = path.join(dir, file); + const contents = fs.readFileSync(filePath).toString(); + const title = contents.match(/\#[^\r\n]+/)?.[0]?.substring(1)?.trim() + ?? makeTitle(name); + const href = `/docs/docs/tutorials/${dirent.name}/${name}` + return { name, title, href }; + }) +} + +module.exports = async function dynamicTutorialsPlugin({ siteDir }) { + return { + name: 'dynamic-tutorials-list', + async contentLoaded({ actions }) { + const tutorialsDir = path.join(siteDir, '/docs/tutorials'); + const categories = readCategories(tutorialsDir); + actions.setGlobalData({ categories }); + } + } +} \ No newline at end of file