Skip to content

Commit c7bb9cf

Browse files
committed
new site
1 parent 75c7276 commit c7bb9cf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+2318
-1944
lines changed

.babelrc

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"presets": ["next/babel"],
3+
"plugins": ["babel-plugin-macros"]
4+
}

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
.DS_Store
21
node_modules
32
.next
3+
.DS_Store
4+
yarn-error.log

.nextra/directories.js

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import preval from 'preval.macro'
2+
3+
const excludes = ['/_app.js', '/_document.js', '/_error.js']
4+
5+
const items = preval`
6+
const { resolve, join } = require('path')
7+
const { readdirSync, readFileSync } = require('fs')
8+
const title = require('title')
9+
10+
const extension = /(\.mdx?)$/
11+
12+
function getFiles(dir, route) {
13+
const files = readdirSync(dir, { withFileTypes: true })
14+
15+
// contains orders and titles
16+
let meta = null
17+
let fnames = null
18+
19+
// go through the directory
20+
const items = files
21+
.map(f => {
22+
const filePath = resolve(dir, f.name)
23+
const fileRoute = join(route, f.name.replace(extension, '').replace(/^index$/, ''))
24+
25+
if (f.isDirectory()) {
26+
const children = getFiles(filePath, fileRoute)
27+
if (!children.length) return null
28+
return { name: f.name, children, route: fileRoute }
29+
} else if (f.name === 'meta.json') {
30+
meta = JSON.parse(readFileSync(filePath))
31+
fnames = Object.keys(meta)
32+
return null
33+
} else if (extension.test(f.name)) {
34+
return { name: f.name.replace(extension, ''), route: fileRoute }
35+
}
36+
})
37+
.map(item => {
38+
if (!item) return
39+
if (meta) {
40+
if (!meta[item.name]) return
41+
return { ...item, title: meta[item.name] }
42+
} else {
43+
return { ...item, title: title(item.name) }
44+
}
45+
return item
46+
})
47+
.filter(Boolean)
48+
.sort((a, b) => {
49+
if (meta) {
50+
return fnames.indexOf(a.name) - fnames.indexOf(b.name)
51+
}
52+
// by default, we put directories first
53+
if (!!a.children !== !!b.children) {
54+
return !!a.children ? -1 : 1
55+
}
56+
// sort by file name
57+
return a.name < b.name ? -1 : 1
58+
})
59+
60+
return items
61+
}
62+
module.exports = getFiles(join(process.cwd(), 'pages'), '/')
63+
`
64+
65+
export default () => items.filter(item => !excludes.includes(item.name))

.nextra/layout.js

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import React, { useState, useEffect, useContext, createContext } from 'react'
2+
import { useRouter } from 'next/router'
3+
import Head from 'next/head'
4+
import Link from 'next/link'
5+
import slugify from '@sindresorhus/slugify'
6+
7+
import getDirectories from './directories'
8+
import Theme from './theme'
9+
10+
import GitHubIcon from '../components/github-icon'
11+
import config from '../nextra.config'
12+
13+
const directories = getDirectories()
14+
const TreeState = new Map()
15+
const titleType = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']
16+
const MenuContext = createContext(false)
17+
18+
function Folder ({ item, anchors }) {
19+
const route = useRouter().route + '/'
20+
const active = route.startsWith(item.route + '/')
21+
const open = TreeState[item.route] || active
22+
const [_, render] = useState(false)
23+
24+
useEffect(() => {
25+
if (active) {
26+
TreeState[item.route] = true
27+
}
28+
}, [active])
29+
30+
return <li className={open ? 'active' : ''}>
31+
<button onClick={() => {
32+
if (active) return
33+
TreeState[item.route] = !open
34+
render(x => !x)
35+
}}>{item.title}</button>
36+
<div style={{
37+
display: open ? '' : 'none'
38+
}}><Menu dir={item.children} base={item.route} anchors={anchors} /></div>
39+
</li>
40+
}
41+
42+
function File ({ item, anchors }) {
43+
const { setMenu } = useContext(MenuContext)
44+
const route = useRouter().route + '/'
45+
const active = route.startsWith(item.route + '/')
46+
47+
let title = item.title
48+
// if (item.title.startsWith('> ')) {
49+
// title = title.substr(2)
50+
if (anchors?.length) {
51+
if (active) {
52+
return <li className={active ? 'active' : ''}>
53+
<Link href={item.route}><a>{title}</a></Link>
54+
<ul>{anchors.map(anchor => {
55+
const slug = slugify(anchor || '')
56+
return <a href={'#' + slug} key={`a-${slug}`} onClick={() => setMenu(false)}>
57+
<span className="flex"><span className="mr-2 opacity-25">#</span><span className="inline-block">{anchor}</span></span>
58+
</a>
59+
})}</ul>
60+
</li>
61+
}
62+
}
63+
64+
return <li className={active ? 'active' : ''}>
65+
<Link href={item.route}><a onClick={() => setMenu(false)}>{title}</a></Link>
66+
</li>
67+
}
68+
69+
function Menu ({ dir, anchors }) {
70+
return <ul>{dir.map(item => {
71+
if (item.children) {
72+
return <Folder key={item.name} item={item} anchors={anchors} />
73+
}
74+
return <File key={item.name} item={item} anchors={anchors} />
75+
})}</ul>
76+
}
77+
78+
function Sidebar ({ show, anchors }) {
79+
return <aside className={`h-screen bg-white flex-shrink-0 w-full md:w-64 md:border-r md:block fixed md:sticky z-10 ${show ? '' : 'hidden'}`} style={{
80+
top: '4rem',
81+
height: 'calc(100vh - 4rem)'
82+
}}>
83+
<div className="sidebar w-full p-4 pb-40 md:pb-16 h-full overflow-y-auto">
84+
<Menu dir={directories} anchors={anchors} />
85+
</div>
86+
</aside>
87+
}
88+
89+
export default ({ children }) => {
90+
const [menu, setMenu] = useState(false)
91+
92+
const titles = React.Children.toArray(children).filter(child => titleType.includes(child.props.mdxType))
93+
const title = titles.find(child => child.props.mdxType === 'h1')?.props.children || 'Untitled'
94+
const anchors = titles.filter(child => child.props.mdxType === 'h2').map(child => child.props.children)
95+
96+
useEffect(() => {
97+
if (menu) {
98+
document.body.classList.add('overflow-hidden')
99+
} else {
100+
document.body.classList.remove('overflow-hidden')
101+
}
102+
}, [menu])
103+
104+
return <>
105+
<Head>
106+
<title>{title}{config.titleSuffix || ''}</title>
107+
{config.head}
108+
</Head>
109+
<div className="main-container flex flex-col">
110+
<nav className="flex items-center bg-white z-20 fixed top-0 left-0 right-0 h-16 border-b px-6">
111+
<div className="w-full flex items-center">
112+
<Link href="/"><a className="no-underline text-current inline-flex items-center hover:opacity-75">
113+
{config.logo}
114+
</a></Link>
115+
</div>
116+
{config.github ? <a className="text-current p-2 -mr-2" href={config.github} target="_blank"><GitHubIcon height={28}/></a> : null}
117+
<button className="block md:hidden p-2 -mr-2 ml-2" onClick={() => setMenu(!menu)}>
118+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
119+
</button>
120+
</nav>
121+
<main className="flex flex-1 h-full">
122+
<MenuContext.Provider value={{ setMenu }}>
123+
<Sidebar show={menu} anchors={anchors}/>
124+
</MenuContext.Provider>
125+
<content className="relative pt-20 pb-16 px-6 md:px-8 w-full max-w-full overflow-x-hidden">
126+
<div className="max-w-screen-md">
127+
<Theme>{children}</Theme>
128+
</div>
129+
</content>
130+
</main>
131+
</div>
132+
</>
133+
}

.nextra/nextra-loader.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module.exports = function(source, map) {
2+
this.cacheable()
3+
const prefix = `import NextraLayout from '.nextra/layout'\n\n`
4+
const suffix = `\n\nexport default NextraLayout`
5+
source = prefix + source + suffix
6+
this.callback(null, source, map)
7+
}

.nextra/nextra.js

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
const path = require('path')
2+
3+
module.exports = (pluginOptions = {
4+
extension: /\.mdx?$/
5+
}) => (nextConfig = {
6+
pageExtensions: ['js', 'jsx', 'md', 'mdx']
7+
}) => {
8+
const extension = pluginOptions.extension || /\.mdx$/
9+
10+
return Object.assign({}, nextConfig, {
11+
webpack(config, options) {
12+
config.module.rules.push({
13+
test: extension,
14+
use: [
15+
options.defaultLoaders.babel,
16+
{
17+
loader: '@mdx-js/loader',
18+
options: pluginOptions.options
19+
},
20+
{
21+
loader: path.resolve('.nextra', 'nextra-loader.js')
22+
}
23+
]
24+
})
25+
26+
if (typeof nextConfig.webpack === 'function') {
27+
return nextConfig.webpack(config, options)
28+
}
29+
30+
return config
31+
}
32+
})
33+
}

.nextra/styles.css

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
@tailwind base;
2+
3+
@font-face {
4+
font-family: 'Inter';
5+
font-weight: 100 900;
6+
font-display: block;
7+
src: url('https://assets.vercel.com/raw/upload/v1587415301/fonts/2/inter-var-latin.woff2')
8+
format('woff2');
9+
}
10+
11+
html {
12+
@apply font-display subpixel-antialiased;
13+
font-size: 16px;
14+
font-feature-settings: 'rlig', 'calt' 1;
15+
scroll-behavior: smooth;
16+
}
17+
18+
h1 {
19+
@apply text-4xl font-bold tracking-tight;
20+
}
21+
h2 {
22+
@apply text-3xl font-semibold tracking-tight mt-10;
23+
@apply border-b;
24+
}
25+
h3 {
26+
@apply text-2xl font-semibold tracking-tight mt-8;
27+
}
28+
h4 {
29+
@apply text-xl font-semibold;
30+
}
31+
h5 {
32+
@apply text-lg font-semibold;
33+
}
34+
h6 {
35+
@apply text-base font-semibold;
36+
}
37+
a {
38+
@apply text-blue-600 underline;
39+
}
40+
p {
41+
@apply mt-6 leading-7;
42+
}
43+
hr {
44+
@apply my-8;
45+
}
46+
code {
47+
@apply p-1 text-sm text-gray-800 bg-gray-200 rounded;
48+
}
49+
pre {
50+
@apply p-4 bg-gray-200 rounded-lg mt-6 mb-4 overflow-x-auto scrolling-touch;
51+
}
52+
pre code {
53+
@apply p-0 text-black bg-transparent rounded-none;
54+
}
55+
56+
@tailwind components;
57+
@tailwind utilities;
58+
59+
.main-container {
60+
min-height: 100vh;
61+
}
62+
63+
.sidebar {
64+
@apply select-none;
65+
}
66+
.sidebar ul ul {
67+
@apply ml-5;
68+
}
69+
.sidebar a:focus, .sidebar button:focus, .sidebar button:active {
70+
@apply outline-none shadow-outline;
71+
}
72+
.sidebar li.active > a {
73+
@apply font-semibold text-black bg-gray-200;
74+
}
75+
.sidebar button, .sidebar a {
76+
@apply block w-full text-left text-base text-black no-underline text-gray-600 mt-1 p-2 rounded select-none;
77+
-webkit-tap-highlight-color: transparent;
78+
-webkit-touch-callout: none;
79+
}
80+
.sidebar a:hover, .sidebar button:hover {
81+
@apply text-gray-900 bg-gray-100;
82+
}
83+
84+
content ul {
85+
@apply list-disc ml-6 mt-6;
86+
}
87+
content li {
88+
@apply mt-2;
89+
}
90+
.subheading-anchor {
91+
margin-top: -84px;
92+
display: inline-block;
93+
position: absolute;
94+
width: 1px;
95+
}

0 commit comments

Comments
 (0)