Template for docs pages

Summary:
- Dynamic loading of documentation pages
- code highlighting for markdown files
- editing playground from sidebar

Reviewed By: emilsjolander

Differential Revision: D6964951

fbshipit-source-id: 1c7f36afa8d23215471d5b9a9c01bd2241c2008e
This commit is contained in:
Daniel Büchele
2018-02-12 10:25:02 -08:00
committed by Facebook Github Bot
parent e43bb9da19
commit 951a429ac5
20 changed files with 321 additions and 149 deletions

View File

@@ -1,4 +1,15 @@
.DocsSidebar {
height: 100%;
width: 350px;
padding: 20px;
border-right: 1px solid #dddfe2;
}
.DocsSidebar h3 {
margin-bottom: 0;
}
.DocsSidebar h4 {
margin-top: 10px;
margin-bottom: 5px;
}

View File

@@ -14,6 +14,13 @@ h2 {
font-weight: 500;
}
.gatsby-highlight pre[class*="language-"] {
background: none;
padding: 0;
font-size: 14px;
margin-bottom: 15px;
}
.Page {
display: flex;
flex-direction: column;
@@ -25,3 +32,7 @@ h2 {
flex-direction: column;
flex-grow: 1;
}
.PageContent.withSpacing {
padding-top: 35px;
}

View File

@@ -14,11 +14,13 @@ import React from 'react';
import Toolbar from './Toolbar';
import Footer from './Footer';
import './Page.css';
require('prismjs/themes/prism.css');
type Props = {|
children: any,
title?: string,
className?: string,
withSpacing?: boolean,
|};
export default (props: Props) => (
@@ -32,7 +34,9 @@ export default (props: Props) => (
<title>Yoga Layout{props.title ? ` | ${props.title}` : ''}</title>
</Head> */}
<Toolbar />
<div className="PageContent">{props.children}</div>
<div className={`PageContent ${props.withSpacing ? 'withSpacing' : ''}`}>
{props.children}
</div>
<Footer />
</div>
);

View File

@@ -0,0 +1,35 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @flow
* @format
*/
import React, {Component} from 'react';
import YogaEnumSelect from './YogaEnumSelect';
import YogaPositionEditor from './YogaPositionEditor';
import {Input} from 'antd';
type Props<T, S> = {
property: string,
disabled?: boolean,
value: string | number,
onChange: (value: number) => void,
};
export default (props: Props<T, S>) => {
if (YogaEnumSelect.availableProperties.indexOf(props.property) > -1) {
return <YogaEnumSelect {...props} />;
} else if (
YogaPositionEditor.availableProperties.indexOf(props.property) > -1
) {
return <YogaPositionEditor {...props} />;
} else {
return <Input type="text" {...props} />;
}
};

View File

@@ -11,12 +11,11 @@
*/
import React, {Component} from 'react';
import {Row, Col, Button, Tabs, Input} from 'antd';
import YogaEnumSelect from './YogaEnumSelect';
import {Row, Col, Button, Tabs} from 'antd';
import EditValue from './EditValue';
import type {LayoutRecordT} from './LayoutRecord';
import type {Yoga$Direction} from 'yoga-layout';
import InfoText from './InfoText';
import YogaPositionEditor from './YogaPositionEditor';
import './Editor.css';
const TabPane = Tabs.TabPane;
@@ -64,8 +63,8 @@ export default class Editor extends Component<Props> {
direction
</InfoText>
</h2>
<YogaEnumSelect
property="DIRECTION"
<EditValue
property="direction"
value={this.props.direction}
onChange={e => this.props.onChangeSetting('direction', e)}
/>
@@ -73,9 +72,9 @@ export default class Editor extends Component<Props> {
Flex direction
<InfoText>Defining the direction of the main-axis</InfoText>
</h2>
<YogaEnumSelect
<EditValue
disabled={disabled}
property="FLEX_DIRECTION"
property="flexDirection"
value={node ? node.flexDirection : ''}
onChange={e => this.props.onChangeLayout('flexDirection', e)}
/>
@@ -89,7 +88,7 @@ export default class Editor extends Component<Props> {
up, relative to it's siblings
</InfoText>
</h2>
<Input
<EditValue
type="text"
disabled={disabled || selectedNodeIsRoot}
value={node ? node.flexGrow : ''}
@@ -106,7 +105,7 @@ export default class Editor extends Component<Props> {
anymore.
</InfoText>
</h2>
<Input
<EditValue
type="text"
disabled={disabled || selectedNodeIsRoot}
value={node ? node.flexShrink : ''}
@@ -123,9 +122,9 @@ export default class Editor extends Component<Props> {
Wrapping behaviour when child nodes don't fit into a single line
</InfoText>
</h2>
<YogaEnumSelect
<EditValue
disabled={disabled}
property="WRAP"
property="flexWrap"
value={node ? node.flexWrap : ''}
onChange={e => this.props.onChangeLayout('flexWrap', e)}
/>
@@ -135,9 +134,9 @@ export default class Editor extends Component<Props> {
Justify content
<InfoText>Aligns child nodes along the main-axis</InfoText>
</h2>
<YogaEnumSelect
<EditValue
disabled={disabled}
property="JUSTIFY"
property="justifyContent"
value={node ? node.justifyContent : ''}
onChange={e => this.props.onChangeLayout('justifyContent', e)}
/>
@@ -146,9 +145,9 @@ export default class Editor extends Component<Props> {
Align items
<InfoText>Aligns child nodes along the cross-axis</InfoText>
</h2>
<YogaEnumSelect
<EditValue
disabled={disabled}
property="ALIGN"
property="alignItems"
value={node ? node.alignItems : ''}
onChange={e => this.props.onChangeLayout('alignItems', e)}
/>
@@ -159,9 +158,9 @@ export default class Editor extends Component<Props> {
Specifies alignment on the cross-axis for the node itself
</InfoText>
</h2>
<YogaEnumSelect
<EditValue
disabled={disabled || selectedNodeIsRoot}
property="ALIGN"
property="alignSelf"
value={node ? node.alignSelf : ''}
onChange={e => this.props.onChangeLayout('alignSelf', e)}
/>
@@ -172,9 +171,9 @@ export default class Editor extends Component<Props> {
Alignment of lines along the cross-axis when wrapping
</InfoText>
</h2>
<YogaEnumSelect
<EditValue
disabled={disabled}
property="ALIGN"
property="alignContent"
value={node ? node.alignContent : ''}
onChange={e => this.props.onChangeLayout('alignContent', e)}
/>
@@ -186,7 +185,7 @@ export default class Editor extends Component<Props> {
</h2>
<Row gutter={15}>
<Col span={12}>
<Input
<EditValue
type="text"
placeholder="width"
disabled={disabled}
@@ -197,7 +196,7 @@ export default class Editor extends Component<Props> {
/>
</Col>
<Col span={12}>
<Input
<EditValue
type="text"
placeholder="height"
disabled={disabled}
@@ -216,7 +215,7 @@ export default class Editor extends Component<Props> {
displaying videos
</InfoText>
</h2>
<Input
<EditValue
type="text"
placeholder="Aspect ratio"
disabled={disabled}
@@ -228,7 +227,7 @@ export default class Editor extends Component<Props> {
<h2>Box model</h2>
{['padding', 'border', 'margin'].map(property => (
<YogaPositionEditor
<EditValue
property={property}
key={property}
value={node ? node[property] : undefined}
@@ -244,13 +243,13 @@ export default class Editor extends Component<Props> {
</InfoText>
</h2>
<YogaEnumSelect
<EditValue
disabled={disabled}
property="POSITION_TYPE"
property="positionType"
value={node ? node.positionType : ''}
onChange={e => this.props.onChangeLayout('positionType', e)}
/>
<YogaPositionEditor
<EditValue
property="position"
value={node ? node.position : undefined}
onChange={value => this.props.onChangeLayout('position', value)}

View File

@@ -1,4 +1,4 @@
.YogaEnumSelect.ant-radio-group {
.YogaEnumSelect {
display: flex;
}
@@ -7,3 +7,8 @@
flex-basis: 0;
text-align: center;
}
.YogaEnumSelect .ant-btn {
flex-grow: 1;
flex-basis: 0;
}

View File

@@ -17,18 +17,32 @@ import './YogaEnumSelect.css';
const RadioButton = Radio.Button;
const RadioGroup = Radio.Group;
const PROPERTY_LOOKUP = {
flexDirection: 'FLEX_DIRECTION',
direction: 'DIRECTION',
justifyContent: 'JUSTIFY',
alignSelf: 'ALIGN',
alignContent: 'ALIGN',
alignItems: 'ALIGN',
positionType: 'POSITION_TYPE',
flexWrap: 'WRAP',
};
type Props = {
property: string,
property: $Keys<typeof PROPERTY_LOOKUP>,
disabled?: boolean,
value: string | number,
onChange: (value: number) => void,
};
export default class YogaEnumSelect extends Component<Props> {
static availableProperties = Object.keys(PROPERTY_LOOKUP);
values: Array<{key: string, value: number}>;
constructor({property}: Props) {
super();
property = PROPERTY_LOOKUP[property];
// $FlowFixMe
this.values = Object.keys(yoga)
.map(key => ({key, value: yoga[key]}))
@@ -42,29 +56,32 @@ export default class YogaEnumSelect extends Component<Props> {
};
render() {
const {property, ...props} = this.props;
let {property, ...props} = this.props;
property = PROPERTY_LOOKUP[property];
const selected = this.values.find(
({key, value}) => value === this.props.value,
);
const replacer = new RegExp(`^${property}_`);
return this.values.length > 3 ? (
<Dropdown
disabled={props.disabled}
overlay={
<Menu onClick={this.handleMenuClick}>
{this.values.map(({key, value}) => (
<Menu.Item key={key} value={value}>
{key.replace(replacer, '')}
</Menu.Item>
))}
</Menu>
}>
<Button>
{selected ? selected.key.replace(replacer, '') : 'undefiend'}{' '}
<Icon type="down" />
</Button>
</Dropdown>
<div className="YogaEnumSelect">
<Dropdown
disabled={props.disabled}
overlay={
<Menu onClick={this.handleMenuClick}>
{this.values.map(({key, value}) => (
<Menu.Item key={key} value={value}>
{key.replace(replacer, '')}
</Menu.Item>
))}
</Menu>
}>
<Button>
{selected ? selected.key.replace(replacer, '') : ''}
<Icon type="down" />
</Button>
</Dropdown>
</div>
) : (
<RadioGroup
{...props}

View File

@@ -18,11 +18,13 @@ import './YogaPositionEditor.css';
type Props = {
value: PositionRecordT,
property: string,
property: 'position' | 'margin' | 'padding' | 'border',
onChange: (value: PositionRecordT) => void,
};
export default class YogaPositionEditor extends Component<Props> {
static availableProperties = ['position', 'margin', 'padding', 'border'];
static defaultProps = {
value: PositionRecord(),
};

View File

@@ -34,6 +34,7 @@ type Props = {
showGuides: boolean,
className?: string,
height?: string | number,
persist?: boolean,
renderSidebar?: (layoutDefinition: LayoutRecordT, onChange: Function) => any,
};
@@ -53,7 +54,7 @@ export default class Playground extends Component<Props, State> {
static defaultProps = {
layoutDefinition: LayoutRecord({
width: 800,
width: 700,
height: 400,
justifyContent: yoga.JUSTIFY_SPACE_BETWEEN,
alignItems: yoga.ALIGN_FLEX_START,
@@ -65,14 +66,15 @@ export default class Playground extends Component<Props, State> {
bottom: '10',
}),
margin: PositionRecord({
left: '20',
top: '70',
left: '30',
top: '30',
}),
}),
direction: yoga.DIRECTION_LTR,
maxDepth: 3,
showCode: false,
showGuides: true,
persist: false,
};
state = {
@@ -144,8 +146,9 @@ export default class Playground extends Component<Props, State> {
const {selectedNodePath, layoutDefinition} = this.state;
if (selectedNodePath) {
const index = selectedNodePath.pop();
const path = getPath(selectedNodePath).concat('children');
const updatedChildren = layoutDefinition.getIn(path).delete(index);
const updatedChildren = layoutDefinition
.getIn(getPath(selectedNodePath))
.delete(index);
this.modifyAtPath(path, updatedChildren);
this.setState({selectedNodePath: null});
}
@@ -154,8 +157,9 @@ export default class Playground extends Component<Props, State> {
onAdd = () => {
const {selectedNodePath, layoutDefinition} = this.state;
if (selectedNodePath) {
const path = getPath(selectedNodePath).concat('children');
const updatedChildren = layoutDefinition.getIn(path).push(LayoutRecord());
const updatedChildren = layoutDefinition
.getIn(getPath(selectedNodePath))
.push(LayoutRecord());
this.modifyAtPath(
path,
updatedChildren,
@@ -177,9 +181,11 @@ export default class Playground extends Component<Props, State> {
selectedNodePath,
});
window.location.hash = btoa(
JSON.stringify(this.removeUnchangedProperties(layoutDefinition)),
);
if (this.props.persist) {
window.location.hash = btoa(
JSON.stringify(this.removeUnchangedProperties(layoutDefinition)),
);
}
}
removeUnchangedProperties = (node: LayoutRecordT): Object => {
@@ -306,7 +312,7 @@ export default class Playground extends Component<Props, State> {
<div className={`PlaygroundContainer ${this.props.className || ''}`}>
<div>
{this.props.renderSidebar(
this.state.layoutDefinition,
layoutDefinition.getIn(getPath(selectedNodePath)),
this.onChangeLayout,
)}
</div>