1
1
mirror of https://github.com/c8r/x0.git synced 2024-07-14 16:50:34 +03:00

Merge pull request #76 from c8r/next-docs

Update docs
This commit is contained in:
Brent Jackson 2018-06-26 09:56:23 -04:00 committed by GitHub
commit 016f1b9928
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 958 additions and 17 deletions

3
cli.js
View File

@ -41,7 +41,8 @@ const cli = meow(`
-d --out-dir Output directory (default dist)
-s --static Output static HTML without JS bundle
-t --template Path to custom HTML template
--basename Basename for URL paths
--title Page title
`, {
flags: {
// dev

19
docs/JSX.md Normal file
View File

@ -0,0 +1,19 @@
---
---
# Using JSX
x0 supports Compositor JSX format, which allows writing files as pure JSX without any JavaScript syntax.
```jsx
---
title: JSX Example
---
import { Box, Heading } from 'rebass'
<Box p={3} bg='tomato'>
<Heading>
Hello
</Heading>
</Box>
```

20
docs/MDX.md Normal file
View File

@ -0,0 +1,20 @@
# Using MDX
x0 also supports [MDX][mdx] format out of the box.
MDX allows you to mix markdown syntax with JSX to render React components.
```mdx
---
title: MDX Example
---
import { Box } from 'rebass'
# Hello
<Box p={3} bg='tomato'>
Beep
</Box>
```
[mdx]: https://github.com/mdx-js/mdx

View File

@ -8,9 +8,47 @@ import {
Box,
Container,
} from 'rebass'
import sortBy from 'lodash.sortby'
import LandingLayout from './_layout'
import theme from './_theme'
import X0 from './_logo'
const navOrder = [
'index',
'getting-started',
'markdown',
'react',
'MDX',
'JSX',
'routing',
'custom-app',
'components',
'ScopeProvider',
'SidebarLayout',
'LivePreview',
'LiveEditor',
'cli-options',
'exporting',
'examples',
]
const pageNames = {
index: 'Home',
'cli-options': 'CLI Options'
}
const sortRoutes = routes => [
...sortBy([...routes], a => {
const i = navOrder.indexOf(a.name)
return i < 0 ? Infinity : i
})
].map(route => {
if (!pageNames[route.name]) return route
return {
...route,
name: pageNames[route.name]
}
})
export default class App extends React.Component {
static defaultProps = {
@ -29,10 +67,16 @@ export default class App extends React.Component {
? LandingLayout
: SidebarLayout
const nav = sortRoutes(routes)
return (
<ScopeProvider scope={scope}>
<RebassProvider theme={theme}>
<Layout {...this.props} />
<Layout
{...this.props}
routes={nav}
logo={<X0 size={24} color='magenta' />}
/>
</RebassProvider>
</ScopeProvider>
)

27
docs/_logo-rect.js Normal file
View File

@ -0,0 +1,27 @@
import React from 'react'
import X0 from './_logo'
export default ({
size = 1024
}) =>
<svg
xmlns='http://www.w3.org/2000/svg'
viewBox='0 0 24 12'
width={size}
height={size / 2}
fill='none'
stroke='currentcolor'
>
<rect
width={24}
height={12}
stroke='none'
fill='black'
/>
<g transform='translate(8, 2)'>
<X0
size={8}
color='white'
/>
</g>
</svg>

29
docs/_logo.js Normal file
View File

@ -0,0 +1,29 @@
import React from 'react'
export default ({
size = 128,
color = 'currentcolor'
}) =>
<svg
xmlns='http://www.w3.org/2000/svg'
viewBox='-12 -12 24 24'
width={size}
height={size}
fill='none'
stroke={color}
>
<circle
strokeWidth={2}
opacity={4/4}
r={11}
/>
<circle
strokeWidth={1/4}
r={11.75}
opacity={0/4}
/>
<g opacity={4/4} strokeWidth={2}>
<path d='M-5 -5 L5 5' />
<path d='M-5 5 L5 -5' />
</g>
</svg>

39
docs/cli-options.md Normal file
View File

@ -0,0 +1,39 @@
---
name: CLI Options
---
# CLI Options
```
--webpack Path to webpack config file
--match String to match routes against using minimatch
```
The following options are used for the development server.
```
-o --open Open dev server in default browser
-p --port Port for dev server
--analyze Runs with webpack-bundle-analyzer plugin
```
The following options are used for static export.
```
-d --out-dir Output directory (default dist)
-s --static Output static HTML without JS bundle
-t --template Path to custom HTML template
--basename Basename for URL paths
--title Page title
```
## package.json
CLI options can also be specified in a `package.json` field named `x0`.
```json
"x0": {
"title": "Hello",
"basename": "/my-site"
}
```

View File

@ -0,0 +1,17 @@
# LiveEditor
The LiveEditor component can be used in React components outside of markdown code fences.
When used within a [ScopeProvider](ScopeProvider) component, there's no need to pass a custom `scope` object.
```jsx
import React from 'react'
import { LiveEditor } from '@compositor/x0/components'
const code = `<Button>Hello</Button>`
export default props =>
<LiveEditor
code={code}
/>
```

View File

@ -0,0 +1,17 @@
# LivePreview
The LivePreview component can be used in React components outside of markdown code fences.
When used within a [ScopeProvider](ScopeProvider) component, there's no need to pass a custom `scope` object.
```jsx
import React from 'react'
import { LivePreview } from '@compositor/x0/components'
const code = `<Button>Hello</Button>`
export default props =>
<LivePreview
code={code}
/>
```

View File

@ -0,0 +1,17 @@
# ScopeProvider
The ScopeProvider component allows you to customize the components that are used to render markdown elements
and to provide components in scope for rendering code fences as live previews.
It's best to use this component in a [Custom App](/custom-app) component.
```jsx
import React from 'react'
import ScopeProvider from '@compositor/x0/components'
import * as scope from '../src'
export default props =>
<ScopeProvider scope={scope}>
{props.children}
</ScopeProvider>
```

View File

@ -0,0 +1,134 @@
# SidebarLayout
The SidebarLayout component can be used to quickly create a documentation site with navigation.
This site uses the SidebarLayout component for navigation and pagination in the documentation section.
To use the component, import it in a [custom App](/custom-app).
```jsx
import React from 'react'
import { SidebarLayout } from '@compositor/x0/components'
export default props =>
<SidebarLayout {...props} />
```
## Customizing navigation
The `props.routes` array can be altered to customize the order, names, and other aspects of the navigation.
### Sorting the routes
By default the `routes` array is in alphabetical order, with index pages occuring first.
To sort the array for display in navigation, pass a new `routes` prop to the SidebarLayout component.
```jsx
import React from 'react'
import { SidebarLayout } from '@compositor/x0/components'
import sortBy from 'lodash.sortby'
const navOrder = [
'index',
'getting-started',
'api'
]
export default props => {
const sortedRoutes = sortBy(props.routes, route => {
const i = navOrder.indexOf(route.name)
return i
})
return (
<SidebarLayout
{...props}
routes={sortedRoutes}
/>
)
}
```
### Customizing Route Names
By default the layout will format the filename by capitalizing each word and removing hyphens.
To customize the name of the routes for navigation, pass a new `routes` prop to the SidebarLayout component.
```jsx
import React from 'react'
import { SidebarLayout } from '@compositor/x0/components'
import sortBy from 'lodash.sortby'
const routeNames = {
index: 'Home',
api: 'API'
}
export default props => {
const renamedRoutes = props.routes.map(route => {
if (!routeNames[route.name]) return route
return {
...route,
name: routeNames[route.name]
}
})
return (
<SidebarLayout
{...props}
routes={renamedRoutes}
/>
)
}
```
## Full Width Pages
The SidebarLayout component will center the contents of the page by default.
To make a page span the full width of the main column, set the `fullWidth` option in default props or front-matter.
```md
---
fullWidth: true
---
# Full-width markdown page
```
```jsx
import React from 'react'
export default class extends React.Component {
static defaultProps = {
fullWidth: true
}
render () {
return (
<h1>Full-width component</h1>
)
}
}
```
## Page-Specific Layouts
Custom layouts can be specified as front-matter or default props, then handled in a custom App component to control the layout for specific pages.
```jsx
// example with custom layouts
import React from 'react'
import { SidebarLayout } from '@compositor/x0/components'
import HomeLayout from './_home-layout.js'
export default props => {
const { route } = this.props
const { layout } = route.props
const Layout = layout === 'home' ? HomeLayout : SidebarLayout
return <Layout {...this.props} />
}
```

9
docs/components/index.md Normal file
View File

@ -0,0 +1,9 @@
# Built-in Components
x0 includes several built-in components to make creating a custom site quicker.
- [ScopeProvider](ScopeProvider)
- [SidebarLayout](SidebarLayout)
- [LivePreview](LivePreview)
- [LiveEditor](LiveEditor)

126
docs/custom-app.md Normal file
View File

@ -0,0 +1,126 @@
# Custom App Component
Use a custom App component to completely customize the layout, add context providers, use global state, or set a custom scope.
## Layouts
Create a file named `_app.js` to provider a custom App component to x0.
This file can be used for custom layouts, including headers, footers, and navigation.
```jsx
// _app.js
import React from 'react'
import { Link } from 'react-router-dom'
import {
Container,
Toolbar,
NavLink
} from 'rebass'
export default class extends React.Component {
render () {
const { children } = this.props
return (
<React.Fragment>
<Toolbar>
<NavLink is={Link} to='/'>
Home
</NavLink>
</Toolbar>
<Container>
{children}
</Container>
</React.Fragment>
)
}
}
```
## Providers
Context providers, such as styled-component's `ThemeProvider` can be included in a custom app.
```jsx
import React from 'react'
import { ThemeProvider } from 'styled-components'
import theme from '../src/theme'
export default props =>
<ThemeProvider theme={theme}>
<React.Fragment>
{props.children}
</React.Fragment>
</ThemeProvider>
```
## Scope
Use the x0 `ScopeProvider` to customize the components used when rendering markdown elements in `.md` or `.mdx` files.
The `ScopeProvider` also provides scope to [live code examples](markdown/#code-fences) in code fences.
```jsx
import React from 'react'
import { ScopeProvider } from '@compositor/x0/components'
import * as scope from '../src'
export default props =>
<ScopeProvider scope={scope}>
{props.children}
</ScopeProvider>
```
## App State
Global application state can also be provided in a custom App.
Use `props.Component` instead of `props.children` to pass props to the rendered route.
```jsx
import React from 'react'
export default class extends React.Component {
state = {
count: 0
}
update = fn => this.setState(fn)
render () {
const { Component } = this.props
return (
<Component
{...this.state}
update={this.update}
/>
)
}
}
```
## Props
Custom Apps receive the following props, which can expose greater control over the rendering.
- `children`: rendered content of the page
- `Component`: a component to pass props to the current route and render content
- `routes`: an array of route objects for the entire site can be used for rendering navigation
- `route`: the current route object
- The [React Router][react-router] state is also passed to the App
### Route Object
Routes include the following properties:
- `key`: the filepath from webpack's `require.context`
- `name`: the basename of the file
- `path`: path used for routing
- `extname`: file extension
- `dirname`: file directory
- `exact`: (boolean) added to index pages for React Router
- `module`: the JS module for the file
- `Component`: the default export from the file
- `props`: default props or front-matter specified in the file
[react-router]: https://github.com/ReactTraining/react-router

5
docs/examples.md Normal file
View File

@ -0,0 +1,5 @@
---
ignore: true
---
# Examples

49
docs/exporting.md Normal file
View File

@ -0,0 +1,49 @@
# Exporting
x0 sites can be exported as static sites using the `x0 build` command.
```sh
x0 build docs
```
## Options
Options for static export can be passed as flags or specified in a `package.json` field named `x0`.
```
-d --out-dir Output directory (default dist)
-s --static Output static HTML without JS bundle
-t --template Path to custom HTML template
--basename Basename for URL paths
--title Page title
```
## Custom HTML Templates
A custom HTML template function can be used for greater control over the HTML output.
```js
module.exports = ({
html = '',
css = '',
scripts,
title = 'x0',
meta = [],
links = [],
}) =>
`<!DOCTYPE html>
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<title>${title}</title>
${css}
</head>
<div id=root>${html}</div>
${scripts}
`
```
See the [default template][template] for an example.
[template]: https://github.com/c8r/x0/blob/master/lib/template.js

92
docs/getting-started.md Normal file
View File

@ -0,0 +1,92 @@
---
---
# Getting Started
Install x0 either globally or as a dev dependency in your project.
```sh
npm install --global @compositor/x0
```
```sh
npm install --save-dev @compositor/x0
```
Create a directory for your documentation or other site.
```sh
mkdir docs
```
Start the development server.
```sh
x0 docs
```
*Note: if you installed x0 as a dev dependency, add the command above to a run script in your `package.json`*
Create an `index.md` file in the `docs/` directory.
```md
# Hello World
```
Open your browser to <http://localhost:8080> to see the file you just created.
To create another route, add another file to the `docs/` directory,
for example `getting-started.md`
````md
# Getting Started
```sh
npm install @compositor/x0
```
````
The `getting-started.md` file should now be available at <http://localhost:8080/getting-started>.
Add a link to the *Getting Started* page from `index.md`.
```md
# Hello World
- [Getting Started](getting-started)
```
## Using React components
In addition to markdown, x0 can render any React component as a page.
Create a `demo.js` file.
```jsx
// demo.js
import React from 'react'
export default class extends React.Component {
render () {
return (
<h1>Demo</h1>
)
}
}
```
## Using MDX
x0 also supports [MDX][mdx] format, which allows you to mix JSX with markdown syntax.
```md
import { Box } from 'rebass'
# Hello MDX
<Box p={3} bg='tomato'>
This will render as a React component
</Box>
```
[mdx]: https://github.com/mdx-js/mdx

View File

@ -20,8 +20,20 @@ const Video = styled.video([], {
borderRadius: '16px',
})
const features = [
'Zero-config',
'No plugins',
'Components over configuration',
'Use markdown, MDX, or React components',
'Automatic file-system based routing',
'Completely customizable',
'Static-site generator',
'Isolated development environment',
]
export default class extends React.Component {
static defaultProps = {
name: 'Home',
layout: 'landing'
}
@ -29,15 +41,7 @@ export default class extends React.Component {
return (
<React.Fragment>
<Container py={5}>
<Heading
is='h1'
mb={4}
lineHeight={1.125}
fontWeight='bold'
fontSize={[ 4, 5, 6 ]}>
x0: Zero-config React development environment & static site generator
</Heading>
<Box mb={4}>
<Box mb={3}>
<Video
autoPlay
loop
@ -47,6 +51,15 @@ export default class extends React.Component {
src='hello-x0.mp4'
/>
</Box>
<Heading
is='h1'
mb={4}
lineHeight={1.125}
fontWeight='bold'
fontSize={[ 4, 5, 6 ]}>
x0:
Document & develop React components without breaking a sweat
</Heading>
<Pre>npm i -g @compositor/x0</Pre>
<Flex py={4}>
<Button
@ -58,16 +71,25 @@ export default class extends React.Component {
GitHub
</Button>
<Box mx={1} />
{/*
<Button
is={Link}
px={4}
py={3}
bg='black'
to='/docs'>
to='/getting-started'>
Documentation
</Button>
*/}
</Flex>
</Container>
<Container py={5}>
<Flex flexWrap='wrap' mx={-3}>
{features.map(feat => (
<Box key={feat} width={[ 1, 1, 1/2 ]} p={3}>
<Text fontWeight='bold'>
{feat}
</Text>
</Box>
))}
</Flex>
</Container>
</React.Fragment>

107
docs/markdown.md Normal file
View File

@ -0,0 +1,107 @@
---
title: 'x0: Using Markdown'
---
# Using Markdown
Using standard markdown syntax for documentation means that your docs will be easy to edit
and render in many different markdown renderers, such as on [GitHub.com](https://github.com).
In addition to the standard markdown syntax, x0 supports front matter and special fenced code blocks
that can render as live examples or previews of React components.
## Links
Standard markdown links work out of the box.
Under the hood, x0 converts relative links to React Router [`Link`][rr-link] components,
and absolute URLs are standard `<a>` tags.
```md
- [Link to another page](about)
- [Link to another site](http://example.com)
```
## Images
Images in the same directory can be included with relative URLs,
but we recommend using a CDN and absolute URLs for any images.
```md
![Hubble telescope image of a nebula](https://images.unsplash.com/photo-1462331940025-496dfbfc7564?w=2048&q=20)
```
Note: When using relative URLs, be sure to copy image assets to the dist folder when exporting a site with the `x0 build` command.
## Code Fences
To include a code snippet use a code fence.
````md
```sh
npm install @compositor/x0
```
````
### Live Editor
x0 includes support for special code fence language attributes for rendering live examples of React components.
Use the `.jsx` (note the `.` prefix) to render a live preview with an editable code editor.
````md
```.jsx
<Button>Hello</Button>
```
````
The above code will render as the following (note this is only visible on the [documentation site][site]).
Try editing the JSX code below the preview.
```.jsx
<Button>Hello</Button>
```
Using code fences means that your example code will render in any standard markdown renderer, including GitHub.
**Important Note**: To include custom components in scope for the live preview code fences,
you must use the `ScopeProvider` in a [custom App component](custom-app).
### Live Preview
To render a component preview without the code editor below, use the `!jsx` (note the `!` prefix) language attibute.
````md
```!jsx
<Button>Hello</Button>
```
````
The above code will render the following:
```!jsx
<Button>Hello</Button>
```
## Front Matter
All `.md`, `.mdx`, and `.jsx` files in x0 support the use of [front-matter][fm] for setting default props and page-level metadata.
```md
---
title: Getting Started
---
```
### Options
Use the following front-matter options for controlling aspects of how a page renders.
- `ignore`: when set to true, x0 will not add the file as a route
#### HTML Template Options
Front matter will be passed to the [HTML template](customizing) to allow control over the page title, metatags and more.
[rr-link]: https://reacttraining.com/react-router/web/api/Link
[site]: https://compositor.io/x0/markdown
[fm]: https://github.com/jonschlinkert/gray-matter

110
docs/react.md Normal file
View File

@ -0,0 +1,110 @@
# Using React Components
In addition to markdown, x0 is optimized for rendering React components as pages.
This makes it work great as a highly customizable documentation generator,
or as a quick and minimal isolated development environment.
To use a React component as a page, ensure the component is the `default` export.
```jsx
import React from 'react'
export default class extends React.Component {
render () {
return <h1>Hello</h1>
}
}
```
## Default Props
Default props on components work in a similar manner to front-matter,
allowing you to supply page-level metadata to the [HTML template](customizing).
```jsx
import React from 'react'
export default class extends React.Component {
static defaultProps = {
title: 'Hello'
}
render () {
return <h1>Hello</h1>
}
}
```
## Fetching Data
Use the async `getInitialProps` static method to fetch data for the component.
```jsx
import React from 'react'
import fetch from 'isomorphic-fetch'
const endpoint = 'http://example.com/api'
export default class extends React.Component {
static getInitialProps = async () => {
const data = await fetch(endpoint)
return {
data
}
}
render () {
const { data } = this.props
return <pre>{JSON.stringify(data, null, 2)}</pre>
}
}
```
## Local State
Just like any React component, a page can use React state.
```jsx
import React from 'react'
export default class extends React.Component {
state = {
count: 0
}
increment = () => this.setState(state => ({ count: state.count + 1 }))
render () {
return (
<div>
<samp>{count}</samp>
<button
onClick={e => {
this.increment()
}}>
+
</button>
</div>
)
}
}
```
## Links
Import React Router's `Link` component to create links to other pages.
```jsx
import React from 'react'
import { Link } from 'react-router-dom'
export default props =>
<div>
<Link to='/getting-started'>Getting Started</Link>
<Link to='/api'>API</Link>
</div>
```

57
docs/routing.md Normal file
View File

@ -0,0 +1,57 @@
# Routing
x0 automatically creates routes based on files in the root directory.
Any `.js`, `.md`, `.mdx`, or `.jsx` file will create a route based on the file name.
*Note that `.jsx` files are JSX format and **not** standard JavaScript*
Files that begin with an underscore (e.g. `_layout.js`) will be ignored.
To create a page with a React component, it must be the `default` export of a module.
```jsx
import React from 'react'
export default class extends React.Component {
render () {
return (
<h1>Hello</h1>
)
}
}
```
## Index routes
Files with the `index` basename (e.g. `index.js` or `index.md`) will be used as an index page for the directory it's located in. Adding an `index.md` file at the root of the directory will make the page available at the `/` pathname in the URL.
## Nested routes
Adding files to subdirectories will create nested routes.
For example, adding a file at `api/core.md` will create a route at `/api/core` and a file at `api/index.md` will create a route for `/api/`.
## Links
x0 uses [React Router][react-router] under the hood.
In markdown, links will automatically use React Router's `<Link />` component for relative links.
To add links in a React component, import the `Link` component from `react-router-dom`
```jsx
import React from 'react'
import { Link } from 'react-router-dom'
export default props =>
<div>
<Link to='/api'>API</Link>
</div>
```
## 404 page
A custom 404 page can be added with a file named `404.md`, `404.js`, `404.mdx`, or `404.jsx`.
By default, x0 will show a link list of available routes for URLs that aren't valid routes.
When exporting with `x0 build` the 404 page will be written to `404.html`, which works with GitHub pages.
[react-router]: https://github.com/ReactTraining/react-router

View File

@ -7,7 +7,7 @@
"x0": "cli.js"
},
"scripts": {
"start": "./cli.js docs -p 8989",
"start": "./cli.js docs",
"build": "./cli.js build docs",
"test": "nyc ava --timeout=60s",
"test:components": "nyc ava test/components.js",

View File

@ -267,7 +267,7 @@ export default class Layout extends React.Component {
? React.Fragment
: MaxWidth
const index = routes.findIndex(r => r === route)
const index = routes.findIndex(r => r.path === route.path)
const pagination = {
previous: routes[index - 1],
next: routes[index + 1]

View File

@ -98,7 +98,7 @@ export const getRoutes = async (components = initialComponents) => {
const RouterState = withRouter(({ render, ...props }) => {
const { pathname } = props.location
const route = props.routes.find(r => r.path === pathname || r.href === pathname)
const route = props.routes.find(r => r.path === pathname || r.href === pathname) || { props: {} }
return render({ ...props, route })
})