diff --git a/lib/md-loader.js b/lib/md-loader.js index 0a920c4c..f6ea8b4f 100644 --- a/lib/md-loader.js +++ b/lib/md-loader.js @@ -1,6 +1,9 @@ const fm = require('gray-matter'); const remark = require('remark'); const strip = require('strip-markdown'); +const readingTime = require('reading-time'); + +const getReadingTime = mdxContent => readingTime(mdxContent); const getHeadings = mdxContent => { const regex = /\n(#+)(.*)/gm; @@ -32,11 +35,10 @@ module.exports = async function (src) { const callback = this.async(); const { content, data } = fm(src); const headings = getHeadings(content); + const duration = getReadingTime(content).text; const code = `import { MDWrapper } from '@components/layouts/markdown-wrapper'; -import { PageReference } from '@components/custom-blocks/page-reference'; -const shortcodes = {['pagereference']: PageReference}; -export const frontmatter = ${ JSON.stringify({...data, headings}) }; +export const frontmatter = ${JSON.stringify({ duration, ...data, headings })}; const Layout = ({ children, ...props }) => ( {children} ) diff --git a/lib/remark-plugins.js b/lib/remark-plugins.js index f5ce19c8..ba12d39b 100644 --- a/lib/remark-plugins.js +++ b/lib/remark-plugins.js @@ -11,6 +11,7 @@ const slug = require('remark-slug'); const headingID = require('remark-heading-id'); const sectionize = require('remark-sectionize'); const customBlocks = require('remark-custom-blocks'); +const externalLinks = require('remark-external-links'); const remarkPlugins = [ [memoize(include), { resolveFrom: path.join(__dirname, '../src/includes') }], @@ -22,6 +23,7 @@ const remarkPlugins = [ memoize(slug), memoize(headingID), memoize(sectionize), + memoize(externalLinks), [ customBlocks, { diff --git a/next.config.js b/next.config.js index 7078ee06..0692716b 100755 --- a/next.config.js +++ b/next.config.js @@ -4,55 +4,135 @@ const withBundleAnalyzer = require('@next/bundle-analyzer')({ const path = require('path'); const { remarkPlugins } = require('./lib/remark-plugins'); const { rehypePlugins } = require('./lib/rehype-plugins'); +const withFonts = require('next-fonts'); -module.exports = withBundleAnalyzer({ - experimental: { - modern: true, - polyfillsOptimization: true, - jsconfigPaths: true, - }, - pageExtensions: ['js', 'ts', 'tsx', 'md', 'mdx'], - webpack: (config, options) => { - config.module.rules.push({ - test: /.mdx?$/, // load both .md and .mdx files - use: [ - options.defaultLoaders.babel, - { - loader: '@mdx-js/loader', - options: { - remarkPlugins, - rehypePlugins, +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: '/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 }, + { source: '/core/naming/namespaces.html', destination: '', permanent: true }, + { source: '/core/naming/comparison.html', destination: '', permanent: true }, + { source: '/core/naming/tutorial_subdomains.html', destination: '', permanent: true }, + { source: '/core/naming/search.html', destination: '', permanent: true }, + { source: '/core/faq_technical.html', destination: '', permanent: true }, + { source: '/core/naming/pickname.html', destination: '', permanent: true }, + { source: '/core/naming/creationhowto.html', destination: '', permanent: true }, + { source: '/core/naming/resolving.html', destination: '', permanent: true }, + { source: '/core/naming/register.html', destination: '', permanent: true }, + { source: '/core/naming/manage.html', destination: '', permanent: true }, + { source: '/core/naming/subdomains.html', destination: '', permanent: true }, + { source: '/core/naming/forks.html', destination: '', permanent: true }, + { source: '/develop/collections.html', destination: '', permanent: true }, + { source: '/develop/collection-type.html', destination: '', permanent: true }, + { source: '/storage/hub-operation.html', destination: '', permanent: true }, + { source: '/storage/amazon-s3-deploy.html', destination: '', permanent: true }, + { source: '/storage/digital-ocean-deploy.html', destination: '', permanent: true }, + { source: '/storage/hello-hub-choice.html', destination: '', permanent: true }, + { source: '/storage/gaia-admin.html', destination: '', permanent: true }, + { source: '/core/atlas/overview.html', destination: '', permanent: true }, + { source: '/core/atlas/howitworks.html', destination: '', permanent: true }, + { source: '/core/atlas/howtouse.html', destination: '', permanent: true }, + { source: '/org/overview.html', destination: '', permanent: true }, + { source: '/faqs/allFAQS.html', destination: '', permanent: true }, + { source: '/org/token.html', destination: '', permanent: true }, + { source: '/org/whitepaper-blockchain.html', destination: '', permanent: true }, + { source: '/org/wallet-intro.html', destination: '', permanent: true }, + { source: '/org/wallet-install.html', destination: '', permanent: true }, + { source: '/org/wallet-use.html', destination: '', permanent: true }, + { source: '/org/wallet-troubleshoot.html', destination: '', permanent: true }, + { source: '/org/tokenholders.html', destination: '', permanent: true }, + { source: '/core/cmdLineRef.html', destination: '', permanent: true }, + { source: '/core/smart/clarityRef.html', destination: '', permanent: true }, + { source: '/core/smart/rpc-api.html', destination: '', permanent: true }, + { source: '/common/javascript_ref.html', destination: '', permanent: true }, + { source: '/common/android_ref.html', destination: '', permanent: true }, + { source: '/common/ios_ref.html', destination: '', permanent: true }, + { source: '/common/core_ref.html', destination: '', permanent: true }, + { source: '/core/wire-format.html', destination: '', permanent: true }, + { source: '/storage/config-schema.html', destination: '', permanent: true }, + { source: '/org/secureref.html', destination: '', permanent: true }, + { source: '/develop/overview_auth.html', destination: '', permanent: true }, + { source: '/org/terms.html', destination: '', permanent: true }, + ]; +} + +module.exports = withFonts( + withBundleAnalyzer({ + experimental: { + modern: true, + polyfillsOptimization: true, + jsconfigPaths: true, + }, + pageExtensions: ['js', 'ts', 'tsx', 'md', 'mdx'], + webpack: (config, options) => { + config.module.rules.push({ + test: /.mdx?$/, // load both .md and .mdx files + use: [ + options.defaultLoaders.babel, + { + loader: '@mdx-js/loader', + options: { + remarkPlugins, + rehypePlugins, + }, }, - }, - path.join(__dirname, './lib/md-loader'), - ], - }); + path.join(__dirname, './lib/md-loader'), + ], + }); + + config.module.rules.push({ + test: /\.ya?ml$/, + type: 'json', + use: 'yaml-loader', + }); - if (!options.dev) { - const splitChunks = config.optimization && config.optimization.splitChunks; - if (splitChunks) { - const cacheGroups = splitChunks.cacheGroups; - const test = /[\\/]node_modules[\\/](preact|preact-render-to-string|preact-context-provider)[\\/]/; - if (cacheGroups.framework) { - cacheGroups.preact = Object.assign({}, cacheGroups.framework, { - test, - }); - cacheGroups.commons.name = 'framework'; - } else { - cacheGroups.preact = { - name: 'commons', - chunks: 'all', - test, - }; + if (!options.dev) { + const splitChunks = config.optimization && config.optimization.splitChunks; + if (splitChunks) { + const cacheGroups = splitChunks.cacheGroups; + const test = /[\\/]node_modules[\\/](preact|preact-render-to-string|preact-context-provider)[\\/]/; + if (cacheGroups.framework) { + cacheGroups.preact = Object.assign({}, cacheGroups.framework, { + test, + }); + cacheGroups.commons.name = 'framework'; + } else { + cacheGroups.preact = { + name: 'commons', + chunks: 'all', + test, + }; + } } - } - // Install webpack aliases: - const aliases = config.resolve.alias || (config.resolve.alias = {}); - aliases.react = aliases['react-dom'] = 'preact/compat'; - aliases['react-ssr-prepass'] = 'preact-ssr-prepass'; - } + // Install webpack aliases: + const aliases = config.resolve.alias || (config.resolve.alias = {}); + aliases.react = aliases['react-dom'] = 'preact/compat'; + aliases['react-ssr-prepass'] = 'preact-ssr-prepass'; + } - return config; - }, -}); + return config; + }, + }) +); diff --git a/package.json b/package.json index 2436e951..c530e1ff 100755 --- a/package.json +++ b/package.json @@ -22,7 +22,6 @@ "cache-manager-fs-hash": "^0.0.9", "csvtojson": "^2.0.10", "docsearch.js": "^2.6.3", - "eslint": "^7.4.0", "fathom-client": "^3.0.0", "front-matter": "^4.0.2", "fs-extra": "^9.0.1", @@ -33,7 +32,8 @@ "lodash.debounce": "^4.0.8", "mdi-react": "7.3.0", "micro-memoize": "^4.0.9", - "next": "^9.5.1-canary.0", + "next": "^9.5.2-canary.1", + "next-fonts": "^1.4.0", "next-google-fonts": "^1.1.0", "next-mdx-remote": "^0.6.0", "nprogress": "^0.2.0", @@ -44,6 +44,7 @@ "prettier": "^2.0.5", "preval.macro": "^5.0.0", "react-gesture-responder": "^2.1.0", + "reading-time": "^1.2.0", "remark": "^12.0.1", "remark-custom-blocks": "^2.5.0", "remark-emoji": "2.1.0", @@ -68,7 +69,8 @@ "unist-util-is": "^4.0.2", "unist-util-select": "^3.0.1", "unist-util-visit": "^2.0.3", - "use-events": "^1.4.2" + "use-events": "^1.4.2", + "yaml-loader": "^0.6.0" }, "devDependencies": { "@babel/preset-react": "^7.10.4", @@ -101,7 +103,8 @@ }, "resolutions": { "preact": "^10.4.4", - "@blockstack/ui": "2.12.2-beta.0" + "@blockstack/ui": "2.12.2-beta.0", + "eslint": "^7.4.0" }, "prettier": "@blockstack/prettier-config" } diff --git a/public/static/fonts/soehne-mono-web-buch.otf b/public/static/fonts/soehne-mono-web-buch.otf new file mode 100644 index 00000000..45e5646b Binary files /dev/null and b/public/static/fonts/soehne-mono-web-buch.otf differ diff --git a/public/static/fonts/soehne-web-buch.otf b/public/static/fonts/soehne-web-buch.otf new file mode 100644 index 00000000..a0eef113 Binary files /dev/null and b/public/static/fonts/soehne-web-buch.otf differ diff --git a/public/static/fonts/soehne-web-halbfett_1.otf b/public/static/fonts/soehne-web-halbfett_1.otf new file mode 100644 index 00000000..2f6d2323 Binary files /dev/null and b/public/static/fonts/soehne-web-halbfett_1.otf differ diff --git a/public/static/fonts/soehne-web-kraftig_1.otf b/public/static/fonts/soehne-web-kraftig_1.otf new file mode 100644 index 00000000..1837fb02 Binary files /dev/null and b/public/static/fonts/soehne-web-kraftig_1.otf differ diff --git a/src/common/navigation.yaml b/src/common/navigation.yaml new file mode 100644 index 00000000..115a0662 --- /dev/null +++ b/src/common/navigation.yaml @@ -0,0 +1,102 @@ +sections: + - pages: + - path: / + - path: /build-an-app # is an overview page + - path: /smart-contracts + pages: + - path: /overview + - path: /testing-contracts + - path: /principals + - path: /running-testnet-node + sections: + - title: Tutorials + pages: + - path: /hello-world-tutorial + - path: /counter-tutorial + - path: /signing-transactions + - path: /mining # is an overview page + + - title: Technology + pages: + - path: /authentication + pages: + - path: /overview + - path: /profiles + - path: /connect + sections: + - title: Tutorials + pages: + - path: /building-todo-app + - path: /data-storage + pages: + - path: /overview + - path: /storage-guide + - path: /authentication + - path: /storage-write-read + - path: /collections + - path: /collection-type + - path: /data-indexing + pages: + - path: /overview + - path: /integrate + - path: /models + - path: /collaborate + - path: /server-extras + - path: /stacks-blockchain + pages: + - path: /overview + - path: /best-practices + - path: /wire-format + - path: /atlas + pages: + - path: /overview + - path: /how-atlas-works + - path: /usage + sections: + - title: Tutorials + pages: + - path: /install-api + - path: /installing-memcached + - path: /naming-services + pages: + - path: /overview + - path: /architecture + - path: /comparison + - path: /did + - path: /forks + - path: /namespaces + - path: /subdomains + - path: /forks + sections: + - title: Tutorials + pages: + - path: /build-profile-search-index + - path: /choose-name + - path: /create-namespace + - path: /resolve-name + - path: /register-name + - path: /manage-names + - path: /subdomains-tutorial + - path: /storage-hubs # this seems out of date, kill? + pages: + - path: /overview + - path: /hello-hub-choice + - path: /gaia-admin + - path: /config-schema + - path: /digital-ocean-deploy + - path: /amazon-s3-deploy + - title: Ecosystem + pages: + - path: /overview #pbc et al + - path: /stacks-token + - path: /contributing + + - title: References + pages: + - path: /clarity-reference + - path: /blockstack-cli-reference + - path: /stacks-blockchain-reference + - path: /stacks-rpc-api-reference + - path: /faqs + - path: /glossary + - path: /deploy-tips diff --git a/src/common/routes/get-routes.js b/src/common/routes/get-routes.js index 9551ebcc..137ac1fd 100644 --- a/src/common/routes/get-routes.js +++ b/src/common/routes/get-routes.js @@ -10,7 +10,46 @@ const fm = require('front-matter'); const fs = require('fs-extra'); const path = require('path'); -const sections = require('./all-routes.json'); + +const slugify = string => + string + .toLowerCase() + .replace(/\s+/g, '-') // Replace spaces with - + .replace(/[^\w\-]+/g, '') // Remove all non-word chars + .replace(/\-\-+/g, '-') // Replace multiple - with single - + .replace(/^-+/, '') // Trim - from start of text + .replace(/-+$/, ''); // Trim - from end of text + +const YAML = require('yaml'); +const yamlFile = fs.readFileSync(path.resolve(__dirname, '../navigation.yaml'), 'utf8'); +const navigation = YAML.parse(yamlFile); + +const getFlatMap = navigation => { + return navigation.sections.flatMap(section => + section.pages.flatMap(page => { + if (page.pages) { + let sectionPages = []; + if (page.sections) { + sectionPages = page.sections.flatMap(_section => + _section.pages.flatMap(sectionPage => `${page.path}${sectionPage.path}`) + ); + } + const pages = page.pages.flatMap(_page => { + if (_page.pages) { + return _page.pages.flatMap(p => `${page.path}${_page.path}${p.path}`); + } else { + return `${page.path}${_page.path}`; + } + }); + return [...pages, ...sectionPages]; + } else { + return `${section.title ? '/' + slugify(section.title) : ''}${page.path}`; + } + }) + ); +}; + +const allRoutes = getFlatMap(navigation); const getHeadings = mdContent => { const regex = /(#+)(.*)/gm; @@ -20,25 +59,23 @@ const getHeadings = mdContent => { : undefined; }; -const routes = sections.map(section => { - const _routes = section.routes.map(route => { - try { - const fileContent = fs.readFileSync(path.join('./src/pages/', route.path + '.md'), 'utf8'); - const data = fm(fileContent); - const headings = getHeadings(data.body); - return { - ...route, - ...data.attributes, - headings, - }; - } catch (e) { - console.log(e); - } - }); - return { - ...section, - routes: _routes, - }; +const routes = allRoutes.map(route => { + try { + const fileContent = fs.readFileSync( + path.join('./src/pages', (route === '/' ? 'index' : route) + '.md'), + 'utf8' + ); + const data = fm(fileContent); + const headings = getHeadings(data.body); + return { + path: route, + ...data.attributes, + headings, + }; + } catch (e) { + console.error('ROUTES ERROR'); + console.warn(e); + } }); -module.exports = routes || []; +module.exports = routes; diff --git a/src/components/custom-blocks/page-reference.tsx b/src/components/custom-blocks/page-reference.tsx index 95c039da..279ff95e 100644 --- a/src/components/custom-blocks/page-reference.tsx +++ b/src/components/custom-blocks/page-reference.tsx @@ -1,42 +1,113 @@ import React from 'react'; -import { Box, color, Grid, space } from '@blockstack/ui'; -import { onlyText } from '@common/utils'; -import { useAppState } from '@common/hooks/use-app-state'; -import { Text } from '@components/typography'; +import { Box, Flex, BoxProps, color, Grid, space, transition } from '@blockstack/ui'; +import { border, onlyText } from '@common/utils'; +import { useTouchable } from '@common/hooks/use-touchable'; +import { Caption, Text } from '@components/typography'; import Link from 'next/link'; +import routes from '@common/routes'; + +const Image = (props: BoxProps) => ( + +); + +const Title = ({ children, ...props }: BoxProps) => ( + + {children} + +); + +const Description = ({ children, ...props }) => ( + + {children} + +); + +const FloatingLink = ({ href, ...props }: any) => ( + + + +); +const InlineCard = ({ page }) => { + const { hover, active, bind } = useTouchable({ + behavior: 'link', + }); + return ( + + + + + + {page.title || page.headings[0]} + + {page.tags?.length + ? page.tags.map(tag => ( + + {tag} + + )) + : null} + + {page.description} + + + + ); +}; + export const PageReference = ({ children }) => { - const { routes } = useAppState(); const content = onlyText(children).trim(); const [variant, _paths] = content.includes('\n') ? content.split('\n') : ['default', content]; const paths = _paths.includes(', ') ? _paths.split(', ') : [_paths]; - const flatRoutes = routes.flatMap(section => - section.routes.map(route => ({ - section: section.title, - ...route, - })) - ); + if (!routes) return null; - const pages = paths - .map(path => flatRoutes.find(route => route.path === path)) - .filter(page => page); + const pages = paths.map(path => routes?.find(route => route.path === path)).filter(page => page); return ( - {pages.map(page => ( - - - - {page.title || page.headings[0]} + {pages.map(page => + variant === 'inline' ? ( + + ) : ( + + + + {page.title || page.headings[0]} + {page.description} + + - {page.description} - - - - - ))} + ) + )} ); }; diff --git a/src/components/layouts/markdown-wrapper.tsx b/src/components/layouts/markdown-wrapper.tsx index 2fb80aed..3980e7b2 100644 --- a/src/components/layouts/markdown-wrapper.tsx +++ b/src/components/layouts/markdown-wrapper.tsx @@ -1,16 +1,44 @@ import React from 'react'; +import { Box, Stack, space } from '@blockstack/ui'; import { MDContents } from '@components/mdx/md-contents'; +import { H1 } from '@components/mdx'; import Head from 'next/head'; +import { Caption, Text } from '@components/typography'; const getTitle = ({ title, headings }) => title || (headings?.length && headings[0].content); + +const PageTop = props => { + return ( + +

{getTitle(props)}

+ {props.description ? ( + + {props.description}{' '} + + ) : null} + + + {props.experience ? {props.experience} : null} + {props.duration ? {props.duration} : null} + +
+ ); +}; + export const MDWrapper = ({ frontmatter, dynamicHeadings = [], ...props }) => { const { headings, description } = frontmatter; + return ( <> {getTitle(frontmatter)} | Blockstack - {props.children} + } + headings={[...headings, ...dynamicHeadings]} + > + {props.children} + ); }; diff --git a/src/components/mdx/components/heading.tsx b/src/components/mdx/components/heading.tsx index 3a8fff9d..077077dc 100644 --- a/src/components/mdx/components/heading.tsx +++ b/src/components/mdx/components/heading.tsx @@ -57,7 +57,7 @@ const AnchorOffset = ({ id }: BoxProps) => display="block" position="absolute" style={{ userSelect: 'none', pointerEvents: 'none' }} - top={`-${HEADER_HEIGHT + 42}px`} + top={`-64px`} id={id} /> ) : null; diff --git a/src/components/mdx/md-contents.tsx b/src/components/mdx/md-contents.tsx index eac34bd2..a947fa62 100644 --- a/src/components/mdx/md-contents.tsx +++ b/src/components/mdx/md-contents.tsx @@ -12,35 +12,39 @@ import { border } from '@common/utils'; import { useRouter } from 'next/router'; const Search = dynamic(() => import('@components/search')); -export const MDContents: React.FC = React.memo(({ headings, children }) => { - const router = useRouter(); - const isHome = router.pathname === '/'; - return ( - <> - - {children} - - {!isHome ? ( - - - - {headings?.length > 1 ? ( - - ) : null} + +export const MDContents: React.FC = React.memo( + ({ pageTop: PageTop = null, headings, children }) => { + const router = useRouter(); + const isHome = router.pathname === '/'; + return ( + <> + + {PageTop && } + {children} + + {!isHome ? ( + + + + {headings?.length > 1 ? ( + + ) : null} + - - ) : null} - - ); -}); + ) : null} + + ); + } +); diff --git a/src/components/mdx/mdx-components.tsx b/src/components/mdx/mdx-components.tsx index 8f58ff49..382a4178 100644 --- a/src/components/mdx/mdx-components.tsx +++ b/src/components/mdx/mdx-components.tsx @@ -27,7 +27,7 @@ import { Code } from '@components/mdx/components'; import { PageReference } from '@components/custom-blocks/page-reference'; export const MDXComponents = { - h1: H1, + h1: () => null, h2: H2, h3: H3, h4: H4, diff --git a/src/components/mdx/styles.tsx b/src/components/mdx/styles.tsx index 085418aa..5978d026 100644 --- a/src/components/mdx/styles.tsx +++ b/src/components/mdx/styles.tsx @@ -5,6 +5,9 @@ import { getHeadingStyles } from '@components/mdx/typography'; import { border } from '@common/utils'; export const MdxOverrides = createGlobalStyle` +html, body { + font-family: 'Soehne', Inter, sans-serif; +} @counter-style list { pad: "0"; } @@ -95,6 +98,9 @@ export const MdxOverrides = createGlobalStyle` color: ${color('accent')}; } +pre, code{ +font-family: "Soehne Mono", "Fira Code", monospace; +} pre{ display: inline-block; } @@ -108,6 +114,9 @@ p, ul, ol, table { export const styleOverwrites = { section: { + '&:first-child > h2:first-child': { + mt: 0, + }, '& > *:not(pre):not(ul):not(ol):not(img):not([data-reach-accordion]):not(section)': { px: space('extra-loose'), }, diff --git a/src/components/mdx/typography.ts b/src/components/mdx/typography.ts index 043a88e5..06209a4f 100644 --- a/src/components/mdx/typography.ts +++ b/src/components/mdx/typography.ts @@ -2,10 +2,11 @@ export const baseTypeStyles = { letterSpacing: '-0.01em', dispay: 'flex', fontFeatureSettings: `'ss01' on`, + fontFamily: `'Soehne', Inter, sans-serif`, }; const h1 = { - fontWeight: 'bolder', + fontWeight: 600, fontSize: ['38px', '38px', '44px'], lineHeight: '52px', padding: '0.05px 0', @@ -23,7 +24,7 @@ const h1 = { }, }; const h2 = { - fontWeight: 600, + fontWeight: 500, fontSize: '27.5px', lineHeight: '34px', padding: '0.05px 0', @@ -61,6 +62,7 @@ const h3 = { }; const h4 = { + fontWeight: 400, fontSize: '19.25px', lineHeight: '28px', padding: '0.05px 0', @@ -78,15 +80,15 @@ const h4 = { }, }; const h5 = { + fontWeight: 400, fontSize: '16px', lineHeight: '28px', - fontWeight: 'bold', }; const h6 = { + fontWeight: 400, fontSize: '14px', lineHeight: '28px', - fontWeight: 'bold', }; const headings = { diff --git a/src/components/pagination.tsx b/src/components/pagination.tsx index cc5a3b8b..3aa99993 100644 --- a/src/components/pagination.tsx +++ b/src/components/pagination.tsx @@ -15,6 +15,11 @@ const usePaginateRoutes = () => { const getSection = _section => _section.routes.find(getRoute); const findSectionByTitle = item => item.title === section.title; + return { + next: undefined, + prev: undefined, + }; + const section = routes.find(getSection); if (!section) diff --git a/src/components/side-nav.tsx b/src/components/side-nav.tsx index 22e5fc17..cafce20e 100644 --- a/src/components/side-nav.tsx +++ b/src/components/side-nav.tsx @@ -6,6 +6,10 @@ import { useRouter } from 'next/router'; import routes from '@common/routes'; import { useMobileMenuState } from '@common/hooks/use-mobile-menu'; import { SIDEBAR_WIDTH } from '@common/constants'; +// @ts-ignore +import nav from '@common/navigation.yaml'; +import ArrowLeftIcon from 'mdi-react/ArrowLeftIcon'; +import { slugify } from '@common/utils'; const Wrapper: React.FC = ({ width = `${SIDEBAR_WIDTH}px`, @@ -32,117 +36,239 @@ const Wrapper: React.FC = ({ ); }; -const LinkItem: React.FC = React.forwardRef( - ({ isActive, ...rest }, ref) => ( - - ) +const capitalize = s => { + if (typeof s !== 'string') return ''; + return s.charAt(0).toUpperCase() + s.slice(1); +}; + +const convertToTitle = (path: string) => + !path ? null : path === '/' ? 'Home' : capitalize(path.replace('/', '').replace(/-/g, ' ')); + +const PageItem = ({ isActive, ...props }: any) => ( + ); -const Links: React.FC = ({ routes, prefix = '', ...rest }) => { - const router = useRouter(); - const { handleClose } = useMobileMenuState(); - const { pathname } = router; +const SectionTitle: React.FC = props => ( + +); + +const ChildPages = ({ items, handleClick }) => + items.pages.map((page, index) => { + const path = page.pages + ? `${page.path}${page.pages[0].path}` + : items.path + ? '/' + slugify(items.path) + page.path + : page.path; + + const routePath = routes.find(route => route.path.endsWith(path)); - return routes.map((route, linkKey) => { - const isActive = pathname === `/${route.path}`; return ( - - - - {route.title || - (route.headings && route.headings.length && route.headings[0]) || - route.path} - + + + handleClick(page) : undefined} as="a"> + {convertToTitle(page.path)} + ); }); -}; -const SectionTitle: React.FC = ({ - children, - textStyles, - ...rest -}) => ( - - - {children} - - +const ChildSection = ({ sections }) => + sections.map(section => { + return ( + + {section.title} + + + ); + }); + +const BackItem = props => ( + + + + + Back + ); -const Section = ({ section, visible, isLast, isFirst, setVisible, ...rest }: any) => { - const isVisible = section.title === visible?.title; +const NewNav = () => { + const [selected, setSelected] = React.useState({ + type: 'default', + items: nav.sections, + selected: undefined, + }); - return ( - - {section.title ? ( - setVisible(section)} - _hover={{ - cursor: 'pointer', - }} - > - {section.title} - - - - - ) : null} - {isVisible && } - - ); + const handleClick = (page: any) => { + if (page.pages) { + setSelected({ + type: 'page', + items: page, + }); + } else { + setSelected({ + type: 'default', + items: nav.sections, + selected: page.path, + }); + } + }; + + const handleBack = () => + setSelected({ + type: 'default', + items: nav.sections, + }); + + if (selected.type === 'page') { + return ( + + + {convertToTitle(selected.items.path)} + + {selected.items ? : null} + {selected.items?.sections ? ( + ({ + ...section, + path: selected.items.path, + }))} + /> + ) : null} + + + ); + } + + if (selected.type === 'default') { + return selected.items.map((section, i) => { + const itemProps = + i === 0 + ? { + color: color('text-title'), + mb: space('tight'), + fontSize: '16px', + _hover: { + color: color('accent'), + cursor: 'pointer', + }, + } + : {}; + return ( + + {section.title ? ( + + {section.title} + + + + + ) : null} + {section.pages.map(page => { + const path = page.pages + ? `${page.path}${page.pages[0].path}` + : section?.title + ? '/' + slugify(section?.title) + page.path + : page.path; + + return ( + + + handleClick(page)} + > + {convertToTitle(page.path)} + + + + ); + })} + + ); + }); + } }; export const SideNav: React.FC = ({ containerProps, ...rest }) => { - const router = useRouter(); - const { pathname } = router; - const active = routes.find(section => - section.routes.find(route => pathname === `/${route.path}`) - ); - const [visible, setVisible] = React.useState(active); - const handleSectionClick = (section: any) => { - if (section?.title === active?.title) { - setVisible(false); - } else { - setVisible(section); - } + // const router = useRouter(); + // const { pathname } = router; + // const active = routes.find(section => + // section.routes.find(route => pathname === `/${route.path}`) + // ); + // const [visible, setVisible] = React.useState(active); + // const handleSectionClick = (section: any) => { + // if (section?.title === active?.title) { + // setVisible(false); + // } else { + // setVisible(section); + // } + // }; + + const getFlatMap = navigation => { + return navigation.sections.flatMap(section => + section.pages.flatMap(page => { + if (page.pages) { + let sectionPages = []; + if (page.sections) { + sectionPages = page.sections.flatMap(_section => + _section.pages.flatMap(sectionPage => `${page.path}${sectionPage.path}`) + ); + } + const pages = page.pages.flatMap(_page => { + if (_page.pages) { + return _page.pages.flatMap(p => `${page.path}${_page.path}${p.path}`); + } else { + return `${page.path}${_page.path}`; + } + }); + return [...pages, ...sectionPages]; + } else { + return `${section?.title ? '/' + slugify(section.title) : ''}${page.path}`; + } + }) + ); }; + return ( - {routes.map((section, sectionKey, arr) => ( -
- ))} + + {/*{routes.map((section, sectionKey, arr) => (*/} + {/* */} + {/*))}*/} ); }; diff --git a/src/components/typography.tsx b/src/components/typography.tsx index e054dea5..b8a02523 100644 --- a/src/components/typography.tsx +++ b/src/components/typography.tsx @@ -28,7 +28,7 @@ export const SectionTitle: React.FC = props => ( export const Pre = React.forwardRef((props: BoxProps, ref) => ( { const { isHome } = pageProps; return ( <> - diff --git a/src/pages/_document.tsx b/src/pages/_document.tsx index f1924777..43b08079 100755 --- a/src/pages/_document.tsx +++ b/src/pages/_document.tsx @@ -33,6 +33,41 @@ export default class MyDocument extends Document { +