mirror of
https://github.com/nature-of-code/noc-book-2
synced 2024-11-17 07:49:05 +01:00
simplified gatsby sourcing
This commit is contained in:
parent
1db5100551
commit
66e28644cc
14 changed files with 377 additions and 2740 deletions
|
@ -5,12 +5,13 @@ module.exports = {
|
|||
},
|
||||
plugins: [
|
||||
{
|
||||
resolve: `gatsby-plugin-mdx`,
|
||||
resolve: `gatsby-source-filesystem`,
|
||||
options: {
|
||||
extensions: [`.mdx`],
|
||||
gatsbyRemarkPlugins: ['gatsby-remark-prismjs'],
|
||||
name: `pages`,
|
||||
path: `${__dirname}/content/`,
|
||||
},
|
||||
},
|
||||
`gatsby-transformer-json`,
|
||||
`gatsby-plugin-postcss`,
|
||||
],
|
||||
};
|
||||
|
|
|
@ -1,42 +1,2 @@
|
|||
const path = require('path');
|
||||
|
||||
exports.sourceNodes = require('./gatsby/source-nodes.js');
|
||||
|
||||
exports.createPages = async ({ graphql, actions, reporter }) => {
|
||||
const { createPage } = actions;
|
||||
|
||||
const result = await graphql(`
|
||||
query {
|
||||
allMdx {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
parent {
|
||||
... on SourceRemark {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
if (result.errors) {
|
||||
reporter.panicOnBuild('🚨 ERROR: Loading "createPages" query');
|
||||
}
|
||||
|
||||
// Create blog post pages.
|
||||
const posts = result.data.allMdx.edges;
|
||||
|
||||
// you'll call `createPage` for each result
|
||||
posts.forEach(({ node }) => {
|
||||
createPage({
|
||||
path: `/${node.parent.title}/`,
|
||||
component: path.resolve(`./src/layouts/PostLayout.js`),
|
||||
context: {
|
||||
id: node.id,
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
exports.onCreateNode = require('./gatsby/on-create-node.js');
|
||||
exports.createPages = require('./gatsby/create-pages.js');
|
||||
|
|
35
gatsby/create-pages.js
Normal file
35
gatsby/create-pages.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
const path = require('path');
|
||||
|
||||
module.exports = async ({ graphql, actions, reporter }) => {
|
||||
const { createPage } = actions;
|
||||
|
||||
const result = await graphql(`
|
||||
query {
|
||||
allChaptersJson {
|
||||
edges {
|
||||
node {
|
||||
slug
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
if (result.errors) {
|
||||
reporter.panicOnBuild('🚨 ERROR: Loading "createPages" query');
|
||||
}
|
||||
|
||||
// Create a page for each chapter
|
||||
const pages = result.data.allChaptersJson.edges;
|
||||
|
||||
pages.forEach(({ node }) => {
|
||||
createPage({
|
||||
path: `/${node.slug}/`,
|
||||
component: path.resolve(`./src/layouts/ChapterLayout.js`),
|
||||
context: {
|
||||
id: node.id,
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
|
@ -1,46 +0,0 @@
|
|||
import { parseFragment } from 'parse5';
|
||||
import { fromParse5 } from 'hast-util-from-parse5';
|
||||
import { toMdast } from 'hast-util-to-mdast';
|
||||
import { toMarkdown } from 'mdast-util-to-markdown';
|
||||
import { toString } from 'hast-util-to-string';
|
||||
import { toHtml } from 'hast-util-to-html';
|
||||
import { mdxToMarkdown } from 'mdast-util-mdx';
|
||||
import { mathToMarkdown } from 'mdast-util-math';
|
||||
|
||||
export const convert = (html) => {
|
||||
const parse5 = parseFragment(html);
|
||||
const hast = fromParse5(parse5);
|
||||
|
||||
const mdast = toMdast(hast, {
|
||||
handlers: {
|
||||
table(h, node) {
|
||||
return h(node, 'html', toHtml(node, { space: 'table' }));
|
||||
},
|
||||
div(h, node) {
|
||||
if (node.properties['example-path']) {
|
||||
return h(node, 'mdxJsxFlowElement', {
|
||||
name: 'Example',
|
||||
attributes: [
|
||||
{
|
||||
type: 'mdxJsxAttribute',
|
||||
name: 'path',
|
||||
value: node.properties['example-path'],
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
},
|
||||
equation(h, node) {
|
||||
if (node.properties.dataType === 'inline') {
|
||||
return h(node, 'inlineMath', toString(node));
|
||||
}
|
||||
return h(node, 'math', toString(node));
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return toMarkdown(mdast, {
|
||||
listItemIndent: 'one',
|
||||
extensions: [mathToMarkdown(), mdxToMarkdown()],
|
||||
});
|
||||
};
|
15
gatsby/on-create-node.js
Normal file
15
gatsby/on-create-node.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
module.exports = async ({ node, actions, loadNodeContent }) => {
|
||||
const { createNodeField } = actions;
|
||||
|
||||
if (node.internal.mediaType !== `text/html`) {
|
||||
return;
|
||||
}
|
||||
|
||||
// load the html source to every HTML file node
|
||||
const content = await loadNodeContent(node);
|
||||
createNodeField({
|
||||
node,
|
||||
name: 'html',
|
||||
value: content,
|
||||
});
|
||||
};
|
|
@ -1,34 +0,0 @@
|
|||
const fs = require('fs/promises');
|
||||
const path = require('path');
|
||||
|
||||
const CONTENT_DIR = 'content/';
|
||||
|
||||
module.exports = async ({ actions, createNodeId, createContentDigest }) => {
|
||||
const { createNode } = actions;
|
||||
|
||||
const { convert } = await import('./lib/convert-file.mjs');
|
||||
|
||||
const fileNames = await fs.readdir(CONTENT_DIR);
|
||||
|
||||
await Promise.all(fileNames.map(importFile));
|
||||
|
||||
async function importFile(fileName, index) {
|
||||
const html = String(await fs.readFile(path.resolve(CONTENT_DIR, fileName)));
|
||||
const content = convert(html);
|
||||
|
||||
const node = {
|
||||
id: createNodeId(`source-remark-${fileName}`),
|
||||
parent: null,
|
||||
children: [],
|
||||
title: fileName.split('.html')[0],
|
||||
internal: {
|
||||
type: `SourceRemark`,
|
||||
mediaType: 'text/markdown',
|
||||
content: String(content),
|
||||
contentDigest: createContentDigest(content),
|
||||
},
|
||||
};
|
||||
|
||||
createNode(node);
|
||||
}
|
||||
};
|
2794
package-lock.json
generated
2794
package-lock.json
generated
File diff suppressed because it is too large
Load diff
17
package.json
17
package.json
|
@ -23,35 +23,28 @@
|
|||
},
|
||||
"homepage": "https://github.com/nature-of-code/noc-notion#readme",
|
||||
"dependencies": {
|
||||
"@mdx-js/mdx": "^1.6.22",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"@notionhq/client": "^2.0.0",
|
||||
"@tailwindcss/typography": "^0.5.4",
|
||||
"autoprefixer": "^10.4.7",
|
||||
"dotenv": "^16.0.0",
|
||||
"gatsby": "^4.19.1",
|
||||
"gatsby-plugin-mdx": "^3.19.0",
|
||||
"gatsby-plugin-postcss": "^5.19.0",
|
||||
"gatsby-remark-prismjs": "^6.19.0",
|
||||
"hast-util-from-parse5": "^7.1.0",
|
||||
"gatsby-source-filesystem": "^4.19.0",
|
||||
"gatsby-transformer-json": "^4.19.0",
|
||||
"hast-util-to-html": "^8.0.3",
|
||||
"hast-util-to-mdast": "^8.3.1",
|
||||
"hast-util-to-string": "^2.0.0",
|
||||
"hastscript": "^7.0.2",
|
||||
"lodash-es": "^4.17.21",
|
||||
"magicbook": "^0.1.20",
|
||||
"magicbook-codesplit": "^0.1.6",
|
||||
"magicbook-katex": "0.0.7",
|
||||
"mdast-util-math": "^2.0.1",
|
||||
"mdast-util-mdx": "^2.0.0",
|
||||
"mdast-util-to-markdown": "^1.3.0",
|
||||
"parse5": "^7.0.0",
|
||||
"postcss": "^8.4.14",
|
||||
"prismjs": "^1.28.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"rehype-format": "^4.0.1",
|
||||
"rehype-parse": "^8.0.4",
|
||||
"rehype-react": "^7.1.1",
|
||||
"tailwindcss": "^3.1.6",
|
||||
"unified": "^10.1.2",
|
||||
"unist-util-visit": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {}
|
||||
|
|
|
@ -36,17 +36,18 @@ async function main() {
|
|||
}
|
||||
|
||||
async function importDatabase(pages) {
|
||||
const db = {
|
||||
pages: pages.map((page) => {
|
||||
const chapters = pages.map((page) => {
|
||||
return {
|
||||
title: page.properties['Title'],
|
||||
src: `./${page.properties['File Name']}.html`,
|
||||
slug: page.properties['Slug'],
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
await fs.writeFile(`${DESTINATION_FOLDER}/db.json`, JSON.stringify(db));
|
||||
await fs.writeFile(
|
||||
`${DESTINATION_FOLDER}/chapters.json`,
|
||||
JSON.stringify(chapters),
|
||||
);
|
||||
}
|
||||
|
||||
async function importPage({ id, properties }) {
|
||||
|
|
|
@ -77,13 +77,7 @@ function transform(block) {
|
|||
{
|
||||
dataCodeLanguage: block.code.language,
|
||||
},
|
||||
[
|
||||
h(
|
||||
'code',
|
||||
{ class: `language-${block.code.language}` },
|
||||
block.code.rich_text.map(transformText),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
// List
|
||||
|
|
20
src/hooks/useRehypeProcessor.js
Normal file
20
src/hooks/useRehypeProcessor.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { createElement, Fragment, useEffect, useState } from 'react';
|
||||
import { unified } from 'unified';
|
||||
import rehypeParse from 'rehype-parse';
|
||||
import rehypeReact from 'rehype-react';
|
||||
|
||||
export function useRehypeProcessor(text) {
|
||||
const [Content, setContent] = useState(Fragment);
|
||||
|
||||
useEffect(() => {
|
||||
unified()
|
||||
.use(rehypeParse, { fragment: true })
|
||||
.use(rehypeReact, { createElement, Fragment })
|
||||
.process(text)
|
||||
.then((file) => {
|
||||
setContent(file.result);
|
||||
});
|
||||
}, [text]);
|
||||
|
||||
return Content;
|
||||
}
|
30
src/layouts/ChapterLayout.js
Normal file
30
src/layouts/ChapterLayout.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
import React from 'react';
|
||||
import { graphql } from 'gatsby';
|
||||
|
||||
import { useRehypeProcessor } from '../hooks/useRehypeProcessor';
|
||||
|
||||
export default function ChapterLayout({ data }) {
|
||||
const { chaptersJson } = data;
|
||||
const body = useRehypeProcessor(chaptersJson.src.fields.html);
|
||||
|
||||
return (
|
||||
<div className="px-4">
|
||||
<div className="my-8 mx-auto w-[640px] prose">{body}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const query = graphql`
|
||||
query ChapterById($id: String!) {
|
||||
chaptersJson(id: { eq: $id }) {
|
||||
id
|
||||
slug
|
||||
title
|
||||
src {
|
||||
fields {
|
||||
html
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
|
@ -1,27 +0,0 @@
|
|||
import React from 'react';
|
||||
import { graphql } from 'gatsby';
|
||||
import { MDXRenderer } from 'gatsby-plugin-mdx';
|
||||
import { MDXProvider } from '@mdx-js/react';
|
||||
|
||||
import Example from '../components/Example';
|
||||
|
||||
export default function PostLayout({ data }) {
|
||||
const { body } = data.mdx;
|
||||
return (
|
||||
<div className="px-4">
|
||||
<MDXProvider components={{ Example }}>
|
||||
<div className="my-8 mx-auto w-[640px] prose">
|
||||
<MDXRenderer>{body}</MDXRenderer>
|
||||
</div>
|
||||
</MDXProvider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const query = graphql`
|
||||
query PostBySlug($id: String!) {
|
||||
mdx(id: { eq: $id }) {
|
||||
body
|
||||
}
|
||||
}
|
||||
`;
|
|
@ -7,12 +7,10 @@ export default function IndexPage({ data }) {
|
|||
<div className="my-8 mx-auto w-[640px] prose">
|
||||
<h1>Nature of Code</h1>
|
||||
<ul>
|
||||
{data.allMdx.edges.map(({ node }) => {
|
||||
{data.allChaptersJson.edges.map(({ node }) => {
|
||||
return (
|
||||
<li key={node.parent.title}>
|
||||
<Link
|
||||
to={`${node.parent.title}/`}
|
||||
>{`${node.parent.title}/`}</Link>
|
||||
<li key={node.id}>
|
||||
<Link to={`/${node.slug}`}>{node.title}</Link>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
|
@ -23,16 +21,13 @@ export default function IndexPage({ data }) {
|
|||
}
|
||||
|
||||
export const query = graphql`
|
||||
query QueryPages {
|
||||
allMdx {
|
||||
query QueryChapters {
|
||||
allChaptersJson {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
parent {
|
||||
... on SourceRemark {
|
||||
title
|
||||
}
|
||||
}
|
||||
slug
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue