diff --git a/lib/md-loader.js b/lib/mdx-loader.js similarity index 52% rename from lib/md-loader.js rename to lib/mdx-loader.js index f6ea8b4f..21e6ccf9 100644 --- a/lib/md-loader.js +++ b/lib/mdx-loader.js @@ -1,8 +1,15 @@ +const { getOptions } = require('loader-utils'); +const mdx = require('@mdx-js/mdx'); const fm = require('gray-matter'); const remark = require('remark'); const strip = require('strip-markdown'); const readingTime = require('reading-time'); +const DEFAULT_RENDERER = ` +import React from 'react' +import { mdx } from '@mdx-js/react' +`; + const getReadingTime = mdxContent => readingTime(mdxContent); const getHeadings = mdxContent => { @@ -27,24 +34,37 @@ const getHeadings = mdxContent => { return headings; }; -// makes mdx in next.js suck less by injecting necessary exports so that -// the docs are still readable on github -// (Shamelessly stolen from Expo.io docs) -// @see https://github.com/expo/expo/blob/master/docs/common/md-loader.js -module.exports = async function (src) { +const layoutPropsString = `const layoutProps = {`; +const newLayoutPropsString = frontmatter => `const layoutProps = { + frontmatter: ${frontmatter},\n`; + +const withFrontmatter = (code, frontmatter) => + code.replace(layoutPropsString, newLayoutPropsString(frontmatter)); + +const loader = async function (src) { const callback = this.async(); + const options = Object.assign({}, getOptions(this), { + filepath: this.resourcePath, + }); + const { content, data } = fm(src); const headings = getHeadings(content); const duration = getReadingTime(content).text; - const code = - `import { MDWrapper } from '@components/layouts/markdown-wrapper'; -export const frontmatter = ${JSON.stringify({ duration, ...data, headings })}; -const Layout = ({ children, ...props }) => ( - {children} -) -export default Layout; + const frontmatter = JSON.stringify({ duration, ...data, headings }); -` + content; + let result; + + try { + result = await mdx(content, options); + } catch (err) { + return callback(err); + } + + const { renderer = DEFAULT_RENDERER } = options; + + const code = withFrontmatter(`${renderer}\n${result}`, frontmatter); return callback(null, code); }; + +module.exports = loader; diff --git a/next.config.js b/next.config.js index d28183c7..f0740641 100755 --- a/next.config.js +++ b/next.config.js @@ -8,26 +8,94 @@ const withFonts = require('next-fonts'); async function redirects() { return [ - { source: '/browser/todo-list.html', destination: '', permanent: true }, - { source: '/develop/connect/get-started.html', destination: '', permanent: true }, - { source: '/develop/connect/overview.html', destination: '', permanent: true }, - { source: '/develop/profiles.html', destination: '', permanent: true }, - { source: '/storage/overview.html', destination: '', permanent: true }, - { source: '/develop/storage.html', destination: '', permanent: true }, - { source: '/storage/authentication.html', destination: '', permanent: true }, - { source: '/storage/write-to-read.html', destination: '', permanent: true }, - { source: '/develop/radiks-intro.html', destination: '', permanent: true }, - { source: '/develop/radiks-setup.html', destination: '', permanent: true }, - { source: '/develop/radiks-models.html', destination: '', permanent: true }, - { source: '/develop/radiks-collaborate.html', destination: '', permanent: true }, - { source: '/develop/radiks-server-extras.html', destination: '', permanent: true }, - { source: '/core/smart/overview.html', destination: '', permanent: true }, - { source: '/core/smart/tutorial.html', destination: '', permanent: true }, - { source: '/core/smart/tutorial-counter.html', destination: '', permanent: true }, - { source: '/core/smart/tutorial-test.html', destination: '', permanent: true }, - { source: '/develop/connect/use-with-clarity.html', destination: '', permanent: true }, - { source: '/core/smart/principals.html', destination: '', permanent: true }, - { source: '/core/smart/testnet-node.html', destination: '', permanent: true }, + { + source: '/browser/todo-list.html', + destination: '/authentication/building-todo-app', + permanent: true, + }, + { + source: '/develop/connect/get-started.html', + destination: '/authentication/connect', + permanent: true, + }, + { + source: '/develop/connect/overview.html', + destination: '/authentication/connect', + permanent: true, + }, + { source: '/develop/profiles.html', destination: '/authentication/profiles', permanent: true }, + { source: '/storage/overview.html', destination: '/data-storage/overview', permanent: true }, + { source: '/develop/storage.html', destination: '/data-storage/overview', permanent: true }, + { + source: '/storage/authentication.html', + destination: '/data-storage/authentication', + permanent: true, + }, + { + source: '/storage/write-to-read.html', + destination: '/data-storage/storage-write-read', + permanent: true, + }, + { + source: '/develop/radiks-intro.html', + destination: '/data-indexing/overview', + permanent: true, + }, + { + source: '/develop/radiks-setup.html', + destination: '/data-indexing/integrate', + permanent: true, + }, + { + source: '/develop/radiks-models.html', + destination: '/data-indexing/models', + permanent: true, + }, + { + source: '/develop/radiks-collaborate.html', + destination: '/data-indexing/collaborate', + permanent: true, + }, + { + source: '/develop/radiks-server-extras.html', + destination: '/data-indexing/server-extras', + permanent: true, + }, + { + source: '/core/smart/overview.html', + destination: '/smart-contracts/overview', + permanent: true, + }, + { + source: '/core/smart/tutorial.html', + destination: '/smart-contracts/hello-world-tutorial', + permanent: true, + }, + { + source: '/core/smart/tutorial-counter.html', + destination: '/smart-contracts/counter-tutorial', + permanent: true, + }, + { + source: '/core/smart/tutorial-test.html', + destination: '/smart-contracts/testing-contracts', + permanent: true, + }, + { + source: '/develop/connect/use-with-clarity.html', + destination: '/smart-contracts/signing-transactions', + permanent: true, + }, + { + source: '/core/smart/principals.html', + destination: '/smart-contracts/principals', + permanent: true, + }, + { + source: '/core/smart/testnet-node.html', + destination: '/smart-contracts/running-a-testnet-node', + permanent: true, + }, { source: '/core/smart/cli-wallet-quickstart.html', destination: '', permanent: true }, { source: '/core/naming/introduction.html', destination: '', permanent: true }, { source: '/core/naming/architecture.html', destination: '', permanent: true }, @@ -92,13 +160,12 @@ module.exports = withFonts( use: [ options.defaultLoaders.babel, { - loader: '@mdx-js/loader', + loader: './lib/mdx-loader', options: { remarkPlugins, rehypePlugins, }, }, - path.join(__dirname, './lib/md-loader'), ], }); diff --git a/package.json b/package.json index 908a4db3..cdd728de 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "lodash.debounce": "^4.0.8", "mdi-react": "7.3.0", "micro-memoize": "^4.0.9", - "next": "^9.5.2-canary.5", + "next": "^9.5.2-canary.6", "next-fonts": "^1.4.0", "next-google-fonts": "^1.1.0", "next-mdx-remote": "^0.6.0", diff --git a/src/common/utils/index.ts b/src/common/utils/index.ts index 0980d039..0efb65f3 100644 --- a/src/common/utils/index.ts +++ b/src/common/utils/index.ts @@ -68,7 +68,8 @@ const getTitleFromHeading = (headings?: any[]) => : headings[0].content : undefined; -export const getTitle = ({ title, headings }): string => title || getTitleFromHeading(headings); +export const getTitle = ({ title, headings }: { title?: string; headings?: any[] }): string => + title || getTitleFromHeading(headings); export const transition = (timing = '0.2s', properties = 'all') => `${properties} ${timing} cubic-bezier(0.23, 1, 0.32, 1)`; diff --git a/src/components/clarity-ref.tsx b/src/components/clarity-ref.tsx index 6f184fe9..ef54522b 100644 --- a/src/components/clarity-ref.tsx +++ b/src/components/clarity-ref.tsx @@ -8,7 +8,7 @@ export const ClarityKeywordReference = ({ content, headings }) => { return ( <> - {hydrate(content, MDXComponents)} + {hydrate(content, { ...MDXComponents, wrapper: undefined })} ); }; @@ -20,6 +20,6 @@ export const ClarityFunctionReference = ({ content, headings }) => ( label="Contents" headings={headings} /> - {hydrate(content, MDXComponents)} + {hydrate(content, { ...MDXComponents, wrapper: undefined })} ); diff --git a/src/components/cli-reference.tsx b/src/components/cli-reference.tsx index 60b4ebc2..eebe856b 100644 --- a/src/components/cli-reference.tsx +++ b/src/components/cli-reference.tsx @@ -3,7 +3,7 @@ import { cliReferenceData } from '@common/../_data/cliRef'; import { MDXComponents } from '@components/mdx/mdx-components'; import { Grid, Box, color } from '@blockstack/ui'; import { border } from '@common/utils'; -import { hydrate } from '@common/data/hydrate-mdx'; +import hydrate from 'next-mdx-remote/hydrate'; const styles = { maxWidth: '100%', @@ -23,6 +23,7 @@ const ReferenceEntry = ({ entry, usage }) => ( {hydrate(usage, { ...MDXComponents, + wrapper: undefined, p: (props: any) => ( { - {hydrate(faq.answer, MDXComponents)} + {hydrate(faq.answer, { ...MDXComponents, wrapper: undefined })} ); diff --git a/src/components/glossary.tsx b/src/components/glossary.tsx index c6a15ad5..c99ebc40 100644 --- a/src/components/glossary.tsx +++ b/src/components/glossary.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Box, space } from '@blockstack/ui'; -import { hydrate } from '@common/data/hydrate-mdx'; +import hydrate from 'next-mdx-remote/hydrate'; import { MDXComponents } from '@components/mdx/mdx-components'; import { slugify } from '@common/utils'; import { css } from '@styled-system/css'; @@ -37,7 +37,7 @@ export const Glossary = ({ data }) => { }, })} > - {hydrate(entry.definition, MDXComponents)} + {hydrate(entry.definition, { ...MDXComponents, wrapper: undefined })} ))} diff --git a/src/components/layouts/markdown-wrapper.tsx b/src/components/layouts/markdown-wrapper.tsx index ae48e710..c1510898 100644 --- a/src/components/layouts/markdown-wrapper.tsx +++ b/src/components/layouts/markdown-wrapper.tsx @@ -13,7 +13,7 @@ const Search = dynamic(() => import('@components/search')); const PageTop = props => { const router = useRouter(); - const isHome = router.pathname === '/'; + const isHome = router?.pathname === '/'; return ( { ); }; -export const MDWrapper = ({ frontmatter, dynamicHeadings = [], ...props }) => { - const { headings, description } = frontmatter; - - return ( - <> - - {getTitle(frontmatter)} | Blockstack - - - } - headings={[...headings, ...dynamicHeadings]} - > - {props.children} - - - ); +const defaultFrontmatter = { + headings: [], + description: + 'Blockstack is an open-source and developer-friendly network for building decentralized apps and smart contracts.', }; +export const MDWrapper: React.FC = React.memo( + ({ frontmatter = defaultFrontmatter, dynamicHeadings = [], ...props }) => { + const { headings, description } = frontmatter; + + return ( + <> + + {getTitle(frontmatter)} | Blockstack + + + } + headings={[...headings, ...dynamicHeadings]} + > + {props.children} + + + ); + } +); + export default MDWrapper; diff --git a/src/components/mdx/md-contents.tsx b/src/components/mdx/md-contents.tsx index 31ce6dd2..09b9e8e5 100644 --- a/src/components/mdx/md-contents.tsx +++ b/src/components/mdx/md-contents.tsx @@ -13,44 +13,35 @@ import dynamic from 'next/dynamic'; const Search = dynamic(() => import('@components/search')); -export const MDContents: React.FC = React.memo( - ({ pageTop: PageTop = null, headings, children }) => { - const router = useRouter(); - const isHome = router.pathname === '/'; +export const MDContents: React.FC = ({ pageTop: PageTop = null, headings, children }) => { + const router = useRouter(); + const isHome = router?.pathname === '/'; - const TOCShowing = !isHome && headings?.length > 1; - return ( - <> - 1; + return ( + <> + + {PageTop && } + {children} + + {!isHome ? ( + - {PageTop && } - {children} - - {!isHome ? ( - - - - {TOCShowing ? ( - - ) : null} - + + + {TOCShowing ? null : null} - ) : null} - - ); - } -); + + ) : null} + + ); +}; diff --git a/src/components/mdx/mdx-components.tsx b/src/components/mdx/mdx-components.tsx index 382a4178..bd14fbd4 100644 --- a/src/components/mdx/mdx-components.tsx +++ b/src/components/mdx/mdx-components.tsx @@ -1,4 +1,4 @@ -import React, { Children } from 'react'; +import React from 'react'; import { Pre, THead, @@ -6,7 +6,6 @@ import { TData, Table, InlineCode, - H1, H2, H3, H4, @@ -25,6 +24,7 @@ import { import { Img } from '@components/mdx/image'; import { Code } from '@components/mdx/components'; import { PageReference } from '@components/custom-blocks/page-reference'; +import { MDWrapper } from '@components/layouts/markdown-wrapper'; export const MDXComponents = { h1: () => null, @@ -51,4 +51,5 @@ export const MDXComponents = { sup: Sup, section: Section, pagereference: PageReference, + wrapper: MDWrapper, }; diff --git a/src/components/mdx/styles.tsx b/src/components/mdx/styles.tsx index d652ba00..708a1995 100644 --- a/src/components/mdx/styles.tsx +++ b/src/components/mdx/styles.tsx @@ -9,6 +9,10 @@ export const MdxOverrides = createGlobalStyle` * { font-feature-settings: 'ss01' on; } +section{ + content-visibility: auto; + contain-intrinsic-size: 1000px; +} html, body { font-family: 'Soehne', Inter, sans-serif; } diff --git a/yarn.lock b/yarn.lock index 97a88dc3..27d64f13 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1526,10 +1526,10 @@ resolved "https://registry.yarnpkg.com/@next/mdx/-/mdx-9.5.1.tgz#c7e2fd457810b34e8ce598f57075b799ca48751b" integrity sha512-jmNKqEMWkCPQWWeoq6CiOShngGv99Cs+rQSLlU7BZMVCZzbcTVEkAsUqR4WfLA97K2ihjtNidY5jwbKFu4h83Q== -"@next/react-dev-overlay@9.5.2-canary.5": - version "9.5.2-canary.5" - resolved "https://registry.yarnpkg.com/@next/react-dev-overlay/-/react-dev-overlay-9.5.2-canary.5.tgz#b04f84a4df8d4a49239b8264b5156487c2a6f393" - integrity sha512-YaO0gIHC6/VrrbN/2FeN96pCcrsJAVGmxa1TUHEq2djzzv2NCh0MXnGzqWfbeQGYshjLzHNksDpfZgdHujncqg== +"@next/react-dev-overlay@9.5.2-canary.6": + version "9.5.2-canary.6" + resolved "https://registry.yarnpkg.com/@next/react-dev-overlay/-/react-dev-overlay-9.5.2-canary.6.tgz#a1c057fc3d64abe6f2aa4caa50639cb1e3d83e5e" + integrity sha512-j7OL0bWMSTJO4YlMgiyRJ3MPphfeVtlQzZSeZJAGDuTDt3TSdMNo05HElgsYgZR9g2NVGIJkOqxZaz5+P/fggg== dependencies: "@babel/code-frame" "7.8.3" ally.js "1.4.1" @@ -1542,10 +1542,10 @@ stacktrace-parser "0.1.10" strip-ansi "6.0.0" -"@next/react-refresh-utils@9.5.2-canary.5": - version "9.5.2-canary.5" - resolved "https://registry.yarnpkg.com/@next/react-refresh-utils/-/react-refresh-utils-9.5.2-canary.5.tgz#314c04d281018157eda010c351548cbf3cc8ca48" - integrity sha512-mYT+8yMHlLQ5jSwibwKOCnsMY2qnlZ/caNI5qwTRH+ugKdyTNyFONm9d54KT9umdXei3azlkWJc0CI/Ceuo8mw== +"@next/react-refresh-utils@9.5.2-canary.6": + version "9.5.2-canary.6" + resolved "https://registry.yarnpkg.com/@next/react-refresh-utils/-/react-refresh-utils-9.5.2-canary.6.tgz#0e7ef8f4759af55add1115da1b8a3ed085f61df7" + integrity sha512-5Y4u7tHb8VIv0tAWqBj020lucp3VvfUYn8aI5hbu3bgvHvuWbffJ8MOlIQeLIMD9qzjeNz+far+Q6SDvFHH1aQ== "@popperjs/core@^2.4.0": version "2.4.4" @@ -6324,10 +6324,10 @@ next-transpile-modules@^4.0.2: micromatch "^4.0.2" slash "^3.0.0" -next@^9.5.2-canary.5: - version "9.5.2-canary.5" - resolved "https://registry.yarnpkg.com/next/-/next-9.5.2-canary.5.tgz#3743800daa0271fd97d4f037ba9ef74688f3b849" - integrity sha512-a5XTn8T5D88seubihcclRnf0ZKD0lz2cvYVH+aSi9pbUSyzKrG0yHNi1dauXXtba+CUFxvLn8BTWjmFXPy0W+g== +next@^9.5.2-canary.6: + version "9.5.2-canary.6" + resolved "https://registry.yarnpkg.com/next/-/next-9.5.2-canary.6.tgz#0ea1194028cd49427eb761d19e654f01a94cf138" + integrity sha512-fCCQrQs42x6N//Nb88ZT2gsI7awIdtqu4nVHw/lLhahQGyHefb/8yDol0b2Zpud9siyj1FwfIMpVxRSOnZCsjg== dependencies: "@ampproject/toolbox-optimizer" "2.5.14" "@babel/code-frame" "7.8.3" @@ -6348,8 +6348,8 @@ next@^9.5.2-canary.5: "@babel/preset-typescript" "7.9.0" "@babel/runtime" "7.9.6" "@babel/types" "7.9.6" - "@next/react-dev-overlay" "9.5.2-canary.5" - "@next/react-refresh-utils" "9.5.2-canary.5" + "@next/react-dev-overlay" "9.5.2-canary.6" + "@next/react-refresh-utils" "9.5.2-canary.6" ast-types "0.13.2" babel-plugin-syntax-jsx "6.18.0" babel-plugin-transform-define "2.0.0"