diff --git a/website/_redirects b/website/_redirects
new file mode 100644
index 000000000..0f79d7d79
--- /dev/null
+++ b/website/_redirects
@@ -0,0 +1,2 @@
+/ https://tsdx.io 301!
+/* https://tsdx.io 301!
\ No newline at end of file
diff --git a/website2/.babelrc b/website2/.babelrc
new file mode 100644
index 000000000..357e43654
--- /dev/null
+++ b/website2/.babelrc
@@ -0,0 +1,4 @@
+{
+ "presets": ["next/babel"],
+ "plugins": ["babel-plugin-macros", "./.nextra/babel-plugin-nextjs-mdx-patch"]
+}
\ No newline at end of file
diff --git a/website2/.gitignore b/website2/.gitignore
new file mode 100644
index 000000000..c3ee72b81
--- /dev/null
+++ b/website2/.gitignore
@@ -0,0 +1,4 @@
+node_modules
+.next
+.DS_Store
+yarn-error.log
\ No newline at end of file
diff --git a/website2/.nextra/arrow-right.js b/website2/.nextra/arrow-right.js
new file mode 100644
index 000000000..50c8163f8
--- /dev/null
+++ b/website2/.nextra/arrow-right.js
@@ -0,0 +1,19 @@
+export default ({ width = 24, height = 24, ...props }) => {
+ return (
+
+ )
+}
diff --git a/website2/.nextra/babel-plugin-nextjs-mdx-patch.js b/website2/.nextra/babel-plugin-nextjs-mdx-patch.js
new file mode 100644
index 000000000..c7bfec273
--- /dev/null
+++ b/website2/.nextra/babel-plugin-nextjs-mdx-patch.js
@@ -0,0 +1,34 @@
+/**
+ * Currently it's not possible to export data fetching functions from MDX pages
+ * because MDX includes them in `layoutProps`, and Next.js removes them at some
+ * point, causing a `ReferenceError`.
+ *
+ * https://github.com/mdx-js/mdx/issues/742#issuecomment-612652071
+ *
+ * This plugin can be removed once MDX removes `layoutProps`, at least that
+ * seems to be the current plan.
+ */
+
+// https://nextjs.org/docs/basic-features/data-fetching
+const DATA_FETCH_FNS = ['getStaticPaths', 'getStaticProps', 'getServerProps']
+
+module.exports = () => {
+ return {
+ visitor: {
+ ObjectProperty(path) {
+ if (
+ DATA_FETCH_FNS.includes(path.node.value.name) &&
+ path.findParent(
+ (path) =>
+ path.isVariableDeclarator() &&
+ path.node.id.name === 'layoutProps',
+ )
+ ) {
+ path.remove()
+ }
+ },
+ },
+ }
+}
+
+// https://github.com/vercel/next.js/issues/12053#issuecomment-622939046
diff --git a/website2/.nextra/config.js b/website2/.nextra/config.js
new file mode 100644
index 000000000..0b055a4c5
--- /dev/null
+++ b/website2/.nextra/config.js
@@ -0,0 +1,11 @@
+import userConfig from '../nextra.config';
+
+const defaultConfig = {
+ nextLinks: true,
+ prevLinks: true,
+ search: true,
+};
+
+export default () => {
+ return { ...defaultConfig, ...userConfig };
+};
diff --git a/website2/.nextra/directories.js b/website2/.nextra/directories.js
new file mode 100644
index 000000000..4d3bf8740
--- /dev/null
+++ b/website2/.nextra/directories.js
@@ -0,0 +1,96 @@
+import preval from 'preval.macro'
+import title from 'title'
+
+const excludes = ['/_app.js', '/_document.js', '/_error.js']
+
+// watch all meta files
+const meta = {}
+function importAll(r) {
+ return r.keys().forEach(key => {
+ meta[key.slice(1)] = r(key)
+ })
+}
+importAll(require.context('../pages/', true, /meta\.json$/))
+
+// use macro to load the file list
+const items = preval`
+ const { readdirSync, readFileSync } = require('fs')
+ const { resolve, join } = require('path')
+ const extension = /\.(mdx?|jsx?)$/
+
+ function getFiles(dir, route) {
+ const files = readdirSync(dir, { withFileTypes: true })
+
+ // go through the directory
+ const items = files
+ .map(f => {
+ const filePath = resolve(dir, f.name)
+ const fileRoute = join(route, f.name.replace(extension, '').replace(/^index$/, ''))
+
+ if (f.isDirectory()) {
+ const children = getFiles(filePath, fileRoute)
+ if (!children.length) return null
+ return { name: f.name, children, route: fileRoute }
+ } else if (f.name === 'meta.json') {
+ return null
+ } else if (extension.test(f.name)) {
+ return { name: f.name.replace(extension, ''), route: fileRoute }
+ }
+ })
+ .map(item => {
+ if (!item) return
+ return { ...item, metaPath: join(route, 'meta.json') }
+ })
+ .filter(Boolean)
+
+ return items
+ }
+ module.exports = getFiles(join(process.cwd(), 'pages'), '/')
+`
+
+const attachPageConfig = function (items) {
+ let folderMeta = null
+ let fnames = null
+
+ return items
+ .filter(item => !excludes.includes(item.name))
+ .map(item => {
+ const { metaPath, ...rest } = item
+ folderMeta = meta[metaPath]
+ if (folderMeta) {
+ fnames = Object.keys(folderMeta)
+ }
+
+ const pageConfig = folderMeta?.[item.name]
+
+ if (rest.children) rest.children = attachPageConfig(rest.children)
+
+ if (pageConfig) {
+ if (typeof pageConfig === 'string') {
+ return { ...rest, title: pageConfig }
+ }
+ return { ...rest, ...pageConfig }
+ } else {
+ if (folderMeta) {
+ return null
+ }
+ return { ...rest, title: title(item.name) }
+ }
+ })
+ .filter(Boolean)
+ .sort((a, b) => {
+ if (folderMeta) {
+ return fnames.indexOf(a.name) - fnames.indexOf(b.name)
+ }
+ // by default, we put directories first
+ if (!!a.children !== !!b.children) {
+ return !!a.children ? -1 : 1
+ }
+ // sort by file name
+ return a.name < b.name ? -1 : 1
+ })
+}
+
+export default () => {
+ return attachPageConfig(items)
+}
diff --git a/website2/.nextra/docsearch.js b/website2/.nextra/docsearch.js
new file mode 100644
index 000000000..8dd6f4757
--- /dev/null
+++ b/website2/.nextra/docsearch.js
@@ -0,0 +1,44 @@
+import { useRef, useEffect } from 'react'
+
+export default function () {
+ const input = useRef(null)
+
+ useEffect(() => {
+ const inputs = ['input', 'select', 'button', 'textarea']
+
+ const down = (e) => {
+ if (
+ document.activeElement &&
+ inputs.indexOf(document.activeElement.tagName.toLowerCase() !== -1)
+ ) {
+ if (e.key === '/') {
+ e.preventDefault()
+ input.current?.focus()
+ }
+ }
+ }
+
+ window.addEventListener('keydown', down)
+ return () => window.removeEventListener('keydown', down)
+ }, [])
+
+ useEffect(() => {
+ if (window.docsearch) {
+ window.docsearch({
+ apiKey: '247dd86c8ddbbbe6d7a2d4adf4f3a68a',
+ indexName: 'vercel_swr',
+ inputSelector: 'input#algolia-doc-search'
+ })
+ }
+ }, [])
+
+ return
+ {renderList && (
+
setShow(false)} />
+ )}
+
+
{
+ setSearch(e.target.value);
+ setShow(true);
+ }}
+ className="appearance-none pl-8 border rounded-md py-2 pr-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline w-full"
+ type="search"
+ placeholder='Search ("/" to focus)'
+ onKeyDown={handleKeyDown}
+ onFocus={() => setShow(true)}
+ ref={input}
+ aria-label="Search documentation"
+ />
+ {renderList && (
+
+ {results.map((res, i) => {
+ return (
+ - setActive(i)}
+ />
+ );
+ })}
+
+ )}
+
+ );
+};
+
+export default Search;
diff --git a/website2/.nextra/ssg.js b/website2/.nextra/ssg.js
new file mode 100644
index 000000000..2e4fb8f9a
--- /dev/null
+++ b/website2/.nextra/ssg.js
@@ -0,0 +1,6 @@
+import { createContext, useContext } from 'react'
+
+const SSGContext = createContext({})
+
+export default SSGContext
+export const useSSG = () => useContext(SSGContext)
diff --git a/website2/.nextra/styles.css b/website2/.nextra/styles.css
new file mode 100644
index 000000000..50350ac2a
--- /dev/null
+++ b/website2/.nextra/styles.css
@@ -0,0 +1,211 @@
+@tailwind base;
+
+html {
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',
+ 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
+ sans-serif;
+}
+@supports (font-variation-settings: normal) {
+ html {
+ font-family: 'Inter var', -apple-system, BlinkMacSystemFont, 'Segoe UI',
+ 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',
+ 'Helvetica Neue', sans-serif;
+ }
+}
+
+html {
+ @apply subpixel-antialiased;
+ font-size: 16px;
+ font-feature-settings: 'rlig' 1, 'calt' 1, 'ss01' 1;
+}
+body {
+ @apply bg-white;
+}
+
+h1 {
+ @apply text-4xl font-bold tracking-tight;
+}
+h2 {
+ @apply text-3xl font-semibold tracking-tight mt-10;
+ @apply border-b;
+}
+h3 {
+ @apply text-2xl font-semibold tracking-tight mt-8;
+}
+h4 {
+ @apply text-xl font-semibold tracking-tight mt-8;
+}
+h5 {
+ @apply text-lg font-semibold tracking-tight mt-8;
+}
+h6 {
+ @apply text-base font-semibold tracking-tight mt-8;
+}
+a {
+ @apply text-blue-600 underline;
+}
+p {
+ @apply mt-6 leading-7;
+}
+hr {
+ @apply my-8;
+}
+code {
+ @apply p-1 text-sm text-gray-800 bg-gray-500 bg-opacity-25 rounded;
+}
+pre {
+ @apply p-4 bg-gray-200 rounded-lg mt-6 mb-4 overflow-x-auto scrolling-touch;
+}
+pre code {
+ @apply p-0 text-black bg-transparent rounded-none;
+}
+a code {
+ @apply text-current no-underline;
+}
+figure {
+ @apply mb-8 relative;
+}
+video {
+ @apply absolute top-0 left-0;
+ cursor: pointer;
+}
+figure figcaption {
+ @apply text-sm text-gray-600;
+}
+@media (min-width: 768px) {
+ figure {
+ /* allow figures to overflow, but not exceeding the viewport width */
+ @apply -mr-56;
+ max-width: calc(100vw - 20rem);
+ }
+}
+
+table {
+ @apply my-8 w-full text-gray-700 text-sm;
+}
+
+table > thead > tr {
+ @apply border-b border-t rounded-t-lg;
+}
+
+table > thead > tr > th {
+ @apply px-3 py-2 text-left text-sm font-bold bg-gray-200 text-gray-700;
+}
+
+table > tbody > tr {
+ @apply border-b;
+}
+
+table > tbody > tr > td {
+ @apply p-3;
+}
+
+table > tbody > tr > td:not(:first-child) > code {
+ @apply text-xs;
+}
+
+table > tbody > tr > td > a > code,
+table > tbody > tr > td > code {
+ @apply text-sm;
+}
+table > tbody > tr > td > a {
+ @apply text-blue-600 font-semibold transition-colors duration-150 ease-out;
+}
+table > tbody > tr > td > a:hover {
+ @apply text-blue-800 transition-colors duration-150 ease-out;
+}
+@tailwind components;
+@tailwind utilities;
+
+.main-container {
+ min-height: 100vh;
+}
+
+.sidebar {
+ @apply select-none;
+}
+.sidebar ul ul {
+ @apply ml-5;
+}
+.sidebar a:focus-visible,
+.sidebar button:focus-visible {
+ @apply shadow-outline;
+}
+.sidebar li.active > a {
+ @apply font-semibold text-black bg-gray-200;
+}
+.sidebar button,
+.sidebar a {
+ @apply block w-full text-left text-base text-black no-underline text-gray-600 mt-1 p-2 rounded select-none outline-none;
+ -webkit-tap-highlight-color: transparent;
+ -webkit-touch-callout: none;
+}
+.sidebar a:hover,
+.sidebar button:hover {
+ @apply text-gray-900 bg-gray-100;
+}
+
+.sidebar .active-route > button {
+ @apply text-black font-medium;
+}
+
+.sidebar .active-route > button:hover {
+ @apply text-current bg-transparent cursor-default;
+}
+
+content ul {
+ @apply list-disc ml-6 mt-6;
+}
+content li {
+ @apply mt-2;
+}
+.subheading-anchor {
+ margin-top: -84px;
+ display: inline-block;
+ position: absolute;
+ width: 1px;
+}
+
+.subheading-anchor + a:hover .anchor-icon,
+.subheading-anchor + a:focus .anchor-icon {
+ opacity: 1;
+}
+.anchor-icon {
+ opacity: 0;
+ @apply ml-2 text-gray-500;
+}
+
+h2 a {
+ @apply no-underline;
+}
+input[type='search']::-webkit-search-decoration,
+input[type='search']::-webkit-search-cancel-button,
+input[type='search']::-webkit-search-results-button,
+input[type='search']::-webkit-search-results-decoration {
+ -webkit-appearance: none;
+}
+
+.search-overlay {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+}
+
+.algolia-autocomplete .algolia-docsearch-suggestion--category-header span {
+ display: inline-block;
+}
+.algolia-autocomplete .ds-dropdown-menu {
+ width: 500px;
+ min-width: 300px;
+ max-width: calc(100vw - 50px);
+}
+
+[data-reach-skip-link] {
+ @apply sr-only;
+}
+
+[data-reach-skip-link]:focus {
+ @apply not-sr-only fixed ml-6 top-0 bg-white text-lg px-6 py-2 mt-2 outline-none shadow-outline z-50;
+}
diff --git a/website2/.nextra/theme.js b/website2/.nextra/theme.js
new file mode 100644
index 000000000..e27834972
--- /dev/null
+++ b/website2/.nextra/theme.js
@@ -0,0 +1,194 @@
+import { MDXProvider } from '@mdx-js/react';
+import * as ReactDOM from 'react-dom/server';
+import Link from 'next/link';
+import Highlight, { defaultProps } from 'prism-react-renderer';
+import stripHtml from 'string-strip-html';
+import slugify from '@sindresorhus/slugify';
+
+const THEME = {
+ plain: {
+ color: '#000',
+ backgroundColor: 'transparent',
+ },
+ styles: [
+ {
+ types: ['keyword'],
+ style: {
+ color: '#ff0078',
+ fontWeight: 'bold',
+ },
+ },
+ {
+ types: ['comment'],
+ style: {
+ color: '#999',
+ fontStyle: 'italic',
+ },
+ },
+ {
+ types: ['string', 'url', 'attr-value'],
+ style: {
+ color: '#028265',
+ },
+ },
+ {
+ types: ['builtin', 'char', 'constant', 'language-javascript'],
+ style: {
+ color: '#000',
+ },
+ },
+ {
+ types: ['attr-name'],
+ style: {
+ color: '#d9931e',
+ fontStyle: 'normal',
+ },
+ },
+ {
+ types: ['punctuation', 'operator'],
+ style: {
+ color: '#333',
+ },
+ },
+ {
+ types: ['number', 'function', 'tag'],
+ style: {
+ color: '#0076ff',
+ },
+ },
+ {
+ types: ['boolean', 'regex'],
+ style: {
+ color: '#d9931e',
+ },
+ },
+ ],
+};
+
+// Anchor links
+
+const HeaderLink = ({ tag: Tag, children, ...props }) => {
+ const slug = slugify(ReactDOM.renderToString(children) || '');
+ return (
+
+
+
+ {children}
+
+ #
+
+
+
+ );
+};
+
+const H2 = ({ children, ...props }) => {
+ return (
+
+ {children}
+
+ );
+};
+
+const H3 = ({ children, ...props }) => {
+ return (
+
+ {children}
+
+ );
+};
+
+const H4 = ({ children, ...props }) => {
+ return (
+
+ {children}
+
+ );
+};
+
+const H5 = ({ children, ...props }) => {
+ return (
+
+ {children}
+
+ );
+};
+
+const H6 = ({ children, ...props }) => {
+ return (
+
+ {children}
+
+ );
+};
+
+const A = ({ children, ...props }) => {
+ const isExternal = props.href?.startsWith('https://');
+ if (isExternal) {
+ return (
+
+ {children}
+
+ );
+ }
+ return (
+
+
{children}
+
+ );
+};
+
+const Code = ({ children, className, highlight, ...props }) => {
+ if (!className) return
{children}
;
+
+ const highlightedLines = highlight ? highlight.split(',').map(Number) : [];
+
+ // https://mdxjs.com/guides/syntax-highlighting#all-together
+ const language = className.replace(/language-/, '');
+ return (
+
+ {({ className, style, tokens, getLineProps, getTokenProps }) => (
+
+ {tokens.map((line, i) => (
+
+ {line.map((token, key) => (
+
+ ))}
+
+ ))}
+
+ )}
+
+ );
+};
+
+const components = {
+ h2: H2,
+ h3: H3,
+ h4: H4,
+ h5: H5,
+ h6: H6,
+ a: A,
+ code: Code,
+};
+
+export default ({ children }) => {
+ return
{children};
+};
diff --git a/website2/components/features.js b/website2/components/features.js
new file mode 100644
index 000000000..ab4e18687
--- /dev/null
+++ b/website2/components/features.js
@@ -0,0 +1,819 @@
+import React from 'react';
+import styles from './features.module.css';
+
+const Feature = ({ text, icon }) => (
+
+ {icon}
+
{text}
+
+);
+
+export default () => (
+
+
+ Zero-config CLI for TypeScript package development
+
+
+
CJS, ESM, UMD>}
+ icon={
+
+ }
+ />
+ Treeshaking>}
+ icon={
+
+ }
+ />
+
+ Live Playground
+ >
+ }
+ icon={
+
+ }
+ />
+
+
+
+
+ }
+ />
+
+
+
+
+ }
+ />
+
+
+
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ />
+
+
+
+
+
+
+ }
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ />
+
+
+
+
+
+
+ }
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ />
+
+
+);
diff --git a/website2/components/features.module.css b/website2/components/features.module.css
new file mode 100644
index 000000000..cba1aec08
--- /dev/null
+++ b/website2/components/features.module.css
@@ -0,0 +1,27 @@
+.features {
+ display: flex;
+ flex-wrap: wrap;
+ margin: 2.5rem -0.5rem 2rem;
+}
+
+.feature {
+ flex: 0 0 33%;
+ align-items: center;
+ display: inline-flex;
+ padding: 0 0.5rem 1.5rem;
+ margin: 0 auto;
+}
+.feature h4 {
+ margin: 0 0 0 0.5rem;
+ font-weight: 700;
+ font-size: 0.95rem;
+ white-space: nowrap;
+}
+@media (max-width: 860px) {
+ .feature {
+ padding-left: 0;
+ }
+ .feature h4 {
+ font-size: 0.75rem;
+ }
+}
diff --git a/website2/components/logo.js b/website2/components/logo.js
new file mode 100644
index 000000000..98be9e794
--- /dev/null
+++ b/website2/components/logo.js
@@ -0,0 +1,28 @@
+import React from 'react';
+
+export const Logo = ({ height }) => (
+
+);
diff --git a/website2/components/video.js b/website2/components/video.js
new file mode 100644
index 000000000..5fcbfe91d
--- /dev/null
+++ b/website2/components/video.js
@@ -0,0 +1,52 @@
+import { useRef, useCallback, useEffect } from 'react'
+import { useInView } from 'react-intersection-observer'
+import 'intersection-observer'
+
+export default ({ src, caption, ratio }) => {
+ const [inViewRef, inView] = useInView({
+ threshold: 1,
+ })
+ const videoRef = useRef()
+
+ const setRefs = useCallback(
+ (node) => {
+ // Ref's from useRef needs to have the node assigned to `current`
+ videoRef.current = node
+ // Callback refs, like the one from `useInView`, is a function that takes the node as an argument
+ inViewRef(node)
+
+ if (node) {
+ node.addEventListener('click', function () {
+ if (this.paused) {
+ this.play()
+ } else {
+ this.pause()
+ }
+ })
+ }
+ },
+ [inViewRef]
+ )
+
+ useEffect(() => {
+ if (!videoRef || !videoRef.current) {
+ return
+ }
+
+ if (inView) {
+ videoRef.current.play()
+ } else {
+ videoRef.current.pause()
+ }
+ }, [inView])
+
+ return (
+
+ )
+}
diff --git a/website2/jsconfig.json b/website2/jsconfig.json
new file mode 100644
index 000000000..b639b0f8f
--- /dev/null
+++ b/website2/jsconfig.json
@@ -0,0 +1,5 @@
+{
+ "compilerOptions": {
+ "baseUrl": "."
+ }
+}
\ No newline at end of file
diff --git a/website2/next.config.js b/website2/next.config.js
new file mode 100644
index 000000000..c09e915a8
--- /dev/null
+++ b/website2/next.config.js
@@ -0,0 +1,2 @@
+const withNextra = require('./.nextra/nextra')();
+module.exports = withNextra();
diff --git a/website2/nextra.config.js b/website2/nextra.config.js
new file mode 100644
index 000000000..a0f69edca
--- /dev/null
+++ b/website2/nextra.config.js
@@ -0,0 +1,90 @@
+import { Logo } from 'components/logo';
+
+export default {
+ github: 'https://github.com/formium/tsdx',
+ titleSuffix: ' – TSDX',
+ logo: (
+ <>
+
+
TSDX
+ >
+ ),
+ head: () => (
+ <>
+ {/* Favicons, meta */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/*
*/}
+ >
+ ),
+ footer: ({ filepath }) => (
+ <>
+
+ >
+ ),
+};
diff --git a/website2/package.json b/website2/package.json
new file mode 100644
index 000000000..17281bc0e
--- /dev/null
+++ b/website2/package.json
@@ -0,0 +1,37 @@
+{
+ "name": "tsdx-site",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "dev": "next",
+ "start": "next",
+ "build": "next build"
+ },
+ "author": "Jared Palmer",
+ "license": "MIT",
+ "dependencies": {
+ "@reach/skip-nav": "^0.10.5",
+ "@sindresorhus/slugify": "^1.0.0",
+ "classnames": "^2.2.6",
+ "focus-visible": "^5.1.0",
+ "intersection-observer": "^0.10.0",
+ "markdown-to-jsx": "^6.11.4",
+ "match-sorter": "^4.1.0",
+ "next": "^9.4.4",
+ "next-google-fonts": "^1.1.0",
+ "prism-react-renderer": "^1.1.1",
+ "react": "^16.13.1",
+ "react-dom": "^16.13.1",
+ "react-intersection-observer": "^8.26.2",
+ "string-strip-html": "^4.5.0"
+ },
+ "devDependencies": {
+ "@mdx-js/loader": "^1.6.5",
+ "babel-plugin-macros": "^2.8.0",
+ "postcss-preset-env": "^6.7.0",
+ "preval.macro": "^5.0.0",
+ "tailwindcss": "^1.4.6",
+ "title": "^3.4.2"
+ }
+}
diff --git a/website2/pages/_app.js b/website2/pages/_app.js
new file mode 100644
index 000000000..391b3ab1a
--- /dev/null
+++ b/website2/pages/_app.js
@@ -0,0 +1,14 @@
+import '.nextra/styles.css'
+import GoogleFonts from 'next-google-fonts'
+
+export default function Nextra({ Component, pageProps }) {
+ return (
+ <>
+
+
+ >
+ )
+}
diff --git a/website2/pages/_document.js b/website2/pages/_document.js
new file mode 100644
index 000000000..19e669faa
--- /dev/null
+++ b/website2/pages/_document.js
@@ -0,0 +1,25 @@
+import React from 'react'
+import Document, { Html, Head, Main, NextScript } from 'next/document'
+import { SkipNavLink } from '@reach/skip-nav'
+
+class MyDocument extends Document {
+ render() {
+ return (
+
+
+