Up-port
This commit is contained in:
@ -24,6 +24,12 @@ Documentation is written as Markdown files in the `content` directory, and is or
|
||||
|
||||
We care about the ease of writing documentation. Docbox comes with batteries included: after you `npm install` the project, you can run `npm start` and its development server, [budo](https://github.com/mattdesl/budo), will serve the website locally and update automatically.
|
||||
|
||||
### Requirements
|
||||
|
||||
* Node v4 or higher
|
||||
* NPM
|
||||
* Git
|
||||
|
||||
To run the site locally:
|
||||
|
||||
1. Clone this repository
|
||||
|
@ -55,7 +55,7 @@ wobbles.list()
|
||||
Creates a new, empty wobble.
|
||||
|
||||
```endpoint
|
||||
POST /wobbles/v1/{username} wobbles:write
|
||||
POST /wobbles/v1/{username}
|
||||
```
|
||||
|
||||
#### Example request
|
||||
@ -114,7 +114,7 @@ Property | Description
|
||||
Returns a single wobble.
|
||||
|
||||
```endpoint
|
||||
GET /wobbles/v1/{username}/{wobble_id} wobbles:read
|
||||
GET /wobbles/v1/{username}/{wobble_id}
|
||||
```
|
||||
|
||||
Retrieve information about an existing wobble.
|
||||
@ -156,7 +156,7 @@ client.readWobble('wobble-id',
|
||||
Updates the properties of a particular wobble.
|
||||
|
||||
```endpoint
|
||||
PATCH /wobbles/v1/{username}/{wobble_id} wobbles:write
|
||||
PATCH /wobbles/v1/{username}/{wobble_id}
|
||||
```
|
||||
|
||||
#### Example request
|
||||
@ -217,7 +217,7 @@ Property | Description
|
||||
Deletes a wobble, including all wibbles it contains.
|
||||
|
||||
```endpoint
|
||||
DELETE /wobbles/v1/{username}/{wobble_id} wobbles:write
|
||||
DELETE /wobbles/v1/{username}/{wobble_id}
|
||||
```
|
||||
|
||||
#### Example request
|
||||
@ -250,7 +250,7 @@ List all the wibbles in a wobble. The response body will be a
|
||||
WobbleCollection.
|
||||
|
||||
```endpoint
|
||||
GET /wobbles/v1/{username}/{wobble_id}/wibbles wobbles:read
|
||||
GET /wobbles/v1/{username}/{wobble_id}/wibbles
|
||||
```
|
||||
|
||||
#### Example request
|
||||
@ -304,7 +304,7 @@ with the given ID in the wobble, it will be replaced. If there isn't
|
||||
a wibble with that ID, a new wibble is created.
|
||||
|
||||
```endpoint
|
||||
PUT /wobbles/v1/{username}/{wobble_id}/wibbles/{wibble_id} wobbles:write
|
||||
PUT /wobbles/v1/{username}/{wobble_id}/wibbles/{wibble_id}
|
||||
```
|
||||
|
||||
#### Example request
|
||||
@ -362,7 +362,7 @@ Property | Description
|
||||
Retrieves a wibble in a wobble.
|
||||
|
||||
```endpoint
|
||||
GET /wobbles/v1/{username}/{wobble_id}/wibbles/{wibble_id} wobbles:read
|
||||
GET /wobbles/v1/{username}/{wobble_id}/wibbles/{wibble_id}
|
||||
```
|
||||
|
||||
#### Example request
|
||||
@ -403,7 +403,7 @@ wibble = wobbles.read_wibble(wobble_id, '2').json()
|
||||
Removes a wibble from a wobble.
|
||||
|
||||
```endpoint
|
||||
DELETE /wobbles/v1/{username}/{wobble_id}/wibbles/{wibble_id} wobbles:write
|
||||
DELETE /wobbles/v1/{username}/{wobble_id}/wibbles/{wibble_id}
|
||||
```
|
||||
|
||||
#### Example request
|
||||
|
16
custom/content.js
Normal file
16
custom/content.js
Normal file
@ -0,0 +1,16 @@
|
||||
var fs = require('fs');
|
||||
|
||||
/**
|
||||
* This file exports the content of your website, as a bunch of concatenated
|
||||
* Markdown files. By doing this explicitly, you can control the order
|
||||
* of content without any level of abstraction.
|
||||
*
|
||||
* Using the brfs module, fs.readFileSync calls in this file are translated
|
||||
* into strings of those files' content before the file is delivered to a
|
||||
* browser: the content is read ahead-of-time and included in bundle.js.
|
||||
*/
|
||||
module.exports =
|
||||
'# Introduction\n' +
|
||||
fs.readFileSync('./content/introduction.md', 'utf8') + '\n' +
|
||||
'# Example\n' +
|
||||
fs.readFileSync('./content/example.md', 'utf8') + '\n';
|
61
custom/index.js
Normal file
61
custom/index.js
Normal file
@ -0,0 +1,61 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Brand names, in order to decreasing length, for different
|
||||
* media queries.
|
||||
*/
|
||||
module.exports.brandNames = {
|
||||
desktop: 'Wobble API Documentation',
|
||||
tablet: 'Wobble API Docs',
|
||||
mobile: 'API Docs'
|
||||
};
|
||||
|
||||
/**
|
||||
* Classes that define the top-left brand box.
|
||||
*/
|
||||
module.exports.brandClasses = 'fill-red';
|
||||
|
||||
|
||||
/**
|
||||
* Text for the link back to the linking website.
|
||||
*/
|
||||
module.exports.backLink = 'Back to wobbles.com';
|
||||
|
||||
/**
|
||||
* Runs after highlighting code samples. You can use this
|
||||
* hook to, for instance, highlight a token and link it
|
||||
* to some canonical part of documentation.
|
||||
*/
|
||||
module.exports.postHighlight = function(html) {
|
||||
return html;
|
||||
};
|
||||
|
||||
/**
|
||||
* Highlight tokens in endpoint URLs, optionally linking to documentation
|
||||
* or adding detail. This is the equivalent of postHighlight but it
|
||||
* operates on endpoint URLs only.
|
||||
*/
|
||||
function highlightTokens(str) {
|
||||
return str.replace(/{[\w_]+}/g,
|
||||
(str) => '<span class="strong">' + str + '</span>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform endpoints given as strings in a highlighted block like
|
||||
*
|
||||
* ```endpoint
|
||||
* GET /foo/bar
|
||||
* ```
|
||||
*
|
||||
* Into HTML nodes that format those endpoints in nice ways.
|
||||
*/
|
||||
module.exports.transformURL = function(value) {
|
||||
let parts = value.split(/\s+/);
|
||||
return {
|
||||
type: 'html',
|
||||
value: `<div class='endpoint dark fill-dark round '>
|
||||
<div class='round-left pad0y pad1x fill-lighten0 code small endpoint-method'>${parts[0]}</div>
|
||||
<div class='pad0 code small endpoint-url'>${highlightTokens(parts[1])}</div>
|
||||
</div>`
|
||||
};
|
||||
};
|
@ -5,11 +5,12 @@ import RoundedToggle from './rounded_toggle';
|
||||
import PureRenderMixin from 'react-pure-render/mixin';
|
||||
import GithubSlugger from 'github-slugger';
|
||||
import debounce from 'lodash.debounce';
|
||||
import { brandNames, brandClasses } from '../../custom';
|
||||
|
||||
let slugger = new GithubSlugger();
|
||||
let slug = title => { slugger.reset(); return slugger.slug(title); };
|
||||
|
||||
let languageOptions = ['curl', 'cli', 'python', 'javascript'];
|
||||
let languageOptions = ['cURL', 'CLI', 'Python', 'JavaScript'];
|
||||
|
||||
let debouncedReplaceState = debounce(hash => {
|
||||
window.history.replaceState('', '', hash);
|
||||
@ -45,7 +46,7 @@ var App = React.createClass({
|
||||
return {
|
||||
mqls: mqls,
|
||||
queries: {},
|
||||
language: 'curl',
|
||||
language: 'cURL',
|
||||
activeSection: active,
|
||||
showNav: false
|
||||
};
|
||||
@ -57,7 +58,7 @@ var App = React.createClass({
|
||||
queries: {
|
||||
desktop: true
|
||||
},
|
||||
language: 'curl',
|
||||
language: 'cURL',
|
||||
activeSection: '',
|
||||
showNav: false
|
||||
};
|
||||
@ -126,11 +127,11 @@ var App = React.createClass({
|
||||
|
||||
{/* Content background */ }
|
||||
{!queries.mobile && <div className={`fixed-top fixed-right ${queries.desktop && 'space-left16'}`}>
|
||||
<div className='fill-dark col6 pin-right'></div>
|
||||
<div className='fill-light col6 pin-right'></div>
|
||||
</div>}
|
||||
|
||||
{/* Desktop nav */ }
|
||||
{queries.desktop && <div className='space-top5 scroll-styled pad1 width16 sidebar fixed-left fill-light'>
|
||||
{queries.desktop && <div className='space-top5 scroll-styled pad1 width16 sidebar fixed-left fill-dark dark'>
|
||||
<Navigation
|
||||
handleClick={this.handleClick}
|
||||
activeSection={activeSection}
|
||||
@ -142,12 +143,15 @@ var App = React.createClass({
|
||||
<Content
|
||||
ast={ast}
|
||||
queries={queries}
|
||||
language={this.state.language}/>
|
||||
language={this.state.language.toLowerCase()}/>
|
||||
</div>
|
||||
|
||||
{/* Language toggle */ }
|
||||
<div className={`fixed-top dark ${queries.desktop && 'space-left16'}`}>
|
||||
<div className={`events fill-dark2 pad1 col6 pin-topright ${queries.mobile && 'space-top5 fixed-topright'}`}>
|
||||
<div className={`fixed-top ${queries.desktop && 'space-left16'}`}>
|
||||
<div className={`events fill-light bottom-shadow pad1 col6 pin-topright ${queries.tablet && 'dark fill-blue'} ${queries.mobile && 'space-top5 fixed-topright'}`}>
|
||||
<div className='space-right1 small quiet inline'>
|
||||
Show examples in:
|
||||
</div>
|
||||
<RoundedToggle
|
||||
options={languageOptions}
|
||||
onChange={this.onChangeLanguage}
|
||||
@ -156,20 +160,20 @@ var App = React.createClass({
|
||||
</div>
|
||||
|
||||
{/* Header */ }
|
||||
<div className={`fill-gray fixed-top ${queries.tablet ? 'pad1y pad2x col6' : 'pad0 width16'}`}>
|
||||
<a href='/' className='active space-top1 space-left1 pin-topleft icon round fill-blue dark pad0 mapbox'></a>
|
||||
<div className={`fill-dark dark bottom-shadow fixed-top ${queries.tablet ? 'pad1y pad2x col6' : 'pad0 width16'}`}>
|
||||
<a href='/' className={`active space-top1 space-left1 pin-topleft icon round dark pad0 ${brandClasses}`}></a>
|
||||
<div className={`strong small pad0 ${queries.mobile && 'space-left3'} ${queries.tablet ? 'space-left2' : 'space-left4 line-height15' }`}>
|
||||
{queries.desktop ? 'API Documentation' :
|
||||
queries.mobile ? 'API Docs' : 'API Docs'}
|
||||
{queries.desktop ? brandNames.desktop :
|
||||
queries.mobile ? brandNames.mobile : brandNames.tablet}
|
||||
</div>
|
||||
{queries.tablet && <div>
|
||||
<button
|
||||
onClick={this.toggleNav}
|
||||
className={`short quiet pin-topright micro button rcon ${showNav ? 'caret-up' : 'caret-down'} space-right1 space-top1`}>
|
||||
{activeSection}
|
||||
className={`short quiet pin-topright button rcon ${showNav ? 'caret-up' : 'caret-down'} space-right1 space-top1`}>
|
||||
<span className='micro'>{activeSection}</span>
|
||||
</button>
|
||||
{showNav && <div
|
||||
className='fixed-left fill-light pin-left col6 pad2 scroll-styled space-top5'>
|
||||
className='fixed-left keyline-top fill-dark pin-left col6 pad2 scroll-styled space-top5'>
|
||||
<Navigation
|
||||
handleClick={this.handleClick}
|
||||
activeSection={activeSection}
|
||||
|
@ -2,45 +2,10 @@ import React from 'react';
|
||||
import Section from './section';
|
||||
import PureRenderMixin from 'react-pure-render/mixin';
|
||||
import GithubSlugger from 'github-slugger';
|
||||
import { transformURL } from '../../custom';
|
||||
let slugger = new GithubSlugger();
|
||||
let slug = title => { slugger.reset(); return slugger.slug(title); };
|
||||
|
||||
function highlightTokens(str) {
|
||||
return str.replace(/{[\w_]+}/g,
|
||||
(str) => '<span class="strong">' + str + '</span>')
|
||||
.replace(
|
||||
/{@2x}/g,
|
||||
`<a title='Retina support: adding @2x to this URL will produce 2x scale images' href='#retina'>{@2x}</a>`);
|
||||
}
|
||||
|
||||
function transformURL(node) {
|
||||
let { value } = node;
|
||||
let parts = value.split(/\s+/);
|
||||
if (parts.length === 3) {
|
||||
return {
|
||||
type: 'html',
|
||||
value: `<div class='endpoint'>
|
||||
<div class='round-left pad0y pad1x fill-lighten0 code micro endpoint-method'>${parts[0]}</div>
|
||||
<div class='fill-darken1 pad0 code micro endpoint-url'>${highlightTokens(parts[1])}</div>
|
||||
<div class='endpoint-token contain fill-lighten0 pad0x round-topright'>
|
||||
<span class='pad0 micro code'>${parts[2]}</span>
|
||||
<a href='#access-tokens' class='center endpoint-scope space-top3 micro pad1x pin-top fill-lighten1 round-bottom'>
|
||||
Token scope
|
||||
</a>
|
||||
</div>
|
||||
</div>`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
type: 'html',
|
||||
value: `<div class='endpoint'>
|
||||
<div class='round-left pad0y pad1x fill-lighten0 code small endpoint-method'>${parts[0]}</div>
|
||||
<div class='fill-darken1 pad0 code small endpoint-url'>${highlightTokens(parts[1])}</div>
|
||||
</div>`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function chunkifyAST(ast, language) {
|
||||
var preview = false;
|
||||
return ast.children.reduce((chunks, node) => {
|
||||
@ -72,7 +37,9 @@ function chunkifyAST(ast, language) {
|
||||
right.push(node);
|
||||
}
|
||||
} else if (node.lang === 'endpoint') {
|
||||
right.push(transformURL(node));
|
||||
right.push(transformURL(node.value));
|
||||
} else if (node.lang === null) {
|
||||
left.push(node);
|
||||
}
|
||||
} else if (node.type === 'heading' && node.depth >= 4) {
|
||||
right.push(node);
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import PureRenderMixin from 'react-pure-render/mixin';
|
||||
import NavigationItem from './navigation_item';
|
||||
import { backLink } from '../../custom';
|
||||
|
||||
function getAllInSectionFromChild(headings, idx) {
|
||||
for (var i = idx; i > 0; i--) {
|
||||
@ -65,7 +66,7 @@ var Navigation = React.createClass({
|
||||
if (child.depth === 1) {
|
||||
return (<div key={i}
|
||||
onClick={this.handleClick}
|
||||
className='small pad0x strong space-top1'>{sectionName}</div>);
|
||||
className='small pad0x quiet space-top1'>{sectionName}</div>);
|
||||
} else if (child.depth === 2) {
|
||||
return (<NavigationItem
|
||||
key={i}
|
||||
@ -87,6 +88,7 @@ var Navigation = React.createClass({
|
||||
}
|
||||
}
|
||||
})}
|
||||
<a href='/' className='space-top2 pad1y dark keyline-top block small quiet'>{backLink}</a>
|
||||
</div>);
|
||||
}
|
||||
});
|
||||
|
@ -17,7 +17,7 @@ var NavigationItem = React.createClass({
|
||||
return (<a
|
||||
href={href}
|
||||
onClick={this.onClick}
|
||||
className={`line-height15 pad0x pad00y block ${active ? 'fill-darken0 quiet active round' : ''}`}>
|
||||
className={`line-height15 pad0x pad00y quiet block ${active ? 'fill-lighten0 round' : ''}`}>
|
||||
{sectionName}
|
||||
</a>);
|
||||
}
|
||||
|
@ -3,18 +3,16 @@ import remark from 'remark';
|
||||
import remarkHTML from 'remark-html';
|
||||
import remarkHighlight from 'remark-highlight.js';
|
||||
import PureRenderMixin from 'react-pure-render/mixin';
|
||||
import { postHighlight } from '../../custom';
|
||||
|
||||
function renderHighlighted(nodes) {
|
||||
return {
|
||||
__html: remark()
|
||||
__html: postHighlight(remark()
|
||||
.use(remarkHTML)
|
||||
.stringify(remark().use(remarkHighlight).run({
|
||||
type: 'root',
|
||||
children: nodes
|
||||
}))
|
||||
.replace(
|
||||
/<span class="hljs-string">"{timestamp}"<\/span>/g,
|
||||
`<span class="hljs-string">"</span><a class='hljs-linked' href='#dates'>{timestamp}</a><span class="hljs-string">"</span>`)
|
||||
})))
|
||||
};
|
||||
}
|
||||
|
||||
@ -28,12 +26,12 @@ var Section = React.createClass({
|
||||
let { left, right, preview } = chunk;
|
||||
return (<div
|
||||
data-title={chunk.title}
|
||||
className={`section pad2y contain clearfix ${preview ? 'preview' : ''}`}>
|
||||
className={`keyline-top section contain clearfix ${preview ? 'preview' : ''}`}>
|
||||
<div
|
||||
className='col6 pad2x prose clip'
|
||||
className='space-bottom8 col6 pad2x prose clip'
|
||||
dangerouslySetInnerHTML={renderHighlighted(left)} />
|
||||
{right.length > 0 && <div
|
||||
className='col6 pad2 prose dark space-top5 clip keyline-top fill-dark'
|
||||
className='space-bottom4 col6 pad2 prose clip fill-light space-top5'
|
||||
dangerouslySetInnerHTML={renderHighlighted(right)} />}
|
||||
</div>);
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
var fs = require('fs');
|
||||
|
||||
module.exports =
|
||||
'# Introduction\n' +
|
||||
fs.readFileSync('./content/introduction.md', 'utf8') + '\n' +
|
||||
'# Example\n' +
|
||||
fs.readFileSync('./content/example.md', 'utf8') + '\n';
|
@ -4,9 +4,11 @@ import ReactDOM from 'react-dom';
|
||||
import App from './components/app';
|
||||
import remark from 'remark';
|
||||
import slug from 'remark-slug';
|
||||
import content from './content';
|
||||
import content from '../custom/content';
|
||||
|
||||
var ast = remark().use(slug).run(remark().parse(content));
|
||||
var ast = remark()
|
||||
.use(slug)
|
||||
.run(remark().parse(content));
|
||||
|
||||
ReactDOM.render(
|
||||
<App ast={ast} content={content} />,
|
||||
|
@ -3,10 +3,12 @@ import ReactDOMServer from 'react-dom/server';
|
||||
import App from './components/app';
|
||||
import remark from 'remark';
|
||||
import slug from 'remark-slug';
|
||||
import content from './content';
|
||||
import content from '../custom/content';
|
||||
import fs from 'fs';
|
||||
|
||||
var ast = remark().use(slug).run(remark().parse(content));
|
||||
var ast = remark()
|
||||
.use(slug)
|
||||
.run(remark().parse(content));
|
||||
|
||||
var template = fs.readFileSync('./index.html', 'utf8');
|
||||
|
||||
|
Reference in New Issue
Block a user