mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-11 08:07:26 +02:00
chore: better examples
This commit is contained in:
parent
d3e12c9455
commit
be3d259ac8
18 changed files with 619 additions and 174 deletions
|
@ -50,7 +50,7 @@ module.exports = async function start(siteDir, cliOptions = {}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const port = await getPort(cliOptions.port);
|
const port = await getPort(cliOptions.port);
|
||||||
const hotPort = await getPort(port + 1);
|
const hotPort = await getPort(5555);
|
||||||
const {baseUrl} = props;
|
const {baseUrl} = props;
|
||||||
|
|
||||||
// create compiler from generated webpack config
|
// create compiler from generated webpack config
|
||||||
|
|
|
@ -3,5 +3,6 @@ import {renderRoutes} from 'react-router-config';
|
||||||
import routes from '@generated/routes'; // eslint-disable-line
|
import routes from '@generated/routes'; // eslint-disable-line
|
||||||
import docsData from '@generated/docsData'; // eslint-disable-line
|
import docsData from '@generated/docsData'; // eslint-disable-line
|
||||||
import pagesData from '@generated/pagesData'; // eslint-disable-line
|
import pagesData from '@generated/pagesData'; // eslint-disable-line
|
||||||
|
import config from '@site/siteConfig.js'; //eslint-disable-line
|
||||||
|
|
||||||
export default () => renderRoutes(routes, {docsData, pagesData});
|
export default () => renderRoutes(routes, {docsData, pagesData, config});
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import Layout from '@theme/Layout';
|
|
||||||
|
|
||||||
export default class Docs extends React.Component {
|
|
||||||
render() {
|
|
||||||
return <Layout>{this.props.children}</Layout>;
|
|
||||||
}
|
|
||||||
}
|
|
38
lib/theme/Docs/index.js
Normal file
38
lib/theme/Docs/index.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
import React from 'react';
|
||||||
|
import Helmet from 'react-helmet';
|
||||||
|
import styles from './styles.css';
|
||||||
|
import Layout from '@theme/Layout'; // eslint-disable-line
|
||||||
|
|
||||||
|
export default class Docs extends React.Component {
|
||||||
|
render() {
|
||||||
|
const {location, docsData, config} = this.props;
|
||||||
|
const currentDoc = docsData.find(data => data.path === location.pathname);
|
||||||
|
|
||||||
|
const highlight = Object.assign(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
version: '9.12.0',
|
||||||
|
theme: 'default'
|
||||||
|
},
|
||||||
|
config.highlight
|
||||||
|
);
|
||||||
|
|
||||||
|
// Use user-provided themeUrl if it exists, else construct one from version and theme.
|
||||||
|
const highlightThemeURL = highlight.themeUrl
|
||||||
|
? highlight.themeUrl
|
||||||
|
: `//cdnjs.cloudflare.com/ajax/libs/highlight.js/${
|
||||||
|
highlight.version
|
||||||
|
}/styles/${highlight.theme}.min.css`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout {...this.props}>
|
||||||
|
<Helmet>
|
||||||
|
<title>{currentDoc.title || 'Document'}</title>
|
||||||
|
<link rel="stylesheet" href={highlightThemeURL} />
|
||||||
|
</Helmet>
|
||||||
|
<div className={styles.mainContainer}>{this.props.children}</div>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import style from './layout.css';
|
|
||||||
|
|
||||||
export default class Layout extends React.Component {
|
|
||||||
render() {
|
|
||||||
const {children} = this.props;
|
|
||||||
return <div className={style.mainContainer}>{children}</div>;
|
|
||||||
}
|
|
||||||
}
|
|
27
lib/theme/Layout/index.js
Normal file
27
lib/theme/Layout/index.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import React from 'react';
|
||||||
|
import {Link} from 'react-router-dom';
|
||||||
|
import styles from './styles.css';
|
||||||
|
|
||||||
|
/* eslint-disable react/prefer-stateless-function */
|
||||||
|
export default class Layout extends React.Component {
|
||||||
|
render() {
|
||||||
|
console.log(this.props);
|
||||||
|
const {children, pagesData, docsData, location} = this.props;
|
||||||
|
const routeLinks = [...pagesData, ...docsData].map(
|
||||||
|
data =>
|
||||||
|
data.path !== location.pathname && (
|
||||||
|
<li key={data.path}>
|
||||||
|
<Link to={data.path}>{data.path}</Link>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{children}
|
||||||
|
<div className={styles.footer}>
|
||||||
|
<ul className={styles.routeLinks}>{routeLinks}</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
38
lib/theme/Layout/styles.css
Normal file
38
lib/theme/Layout/styles.css
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
.footer {
|
||||||
|
color: #777;
|
||||||
|
padding: 10px 15px;
|
||||||
|
height: 20px;
|
||||||
|
text-align: center;
|
||||||
|
border-top: 1px solid #e6e6e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.routeLinks {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.routeLinks li {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.routeLinks li a {
|
||||||
|
color: inherit;
|
||||||
|
margin: 3px;
|
||||||
|
padding: 3px 7px;
|
||||||
|
text-decoration: none;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.routeLinks li a.selected,
|
||||||
|
.routeLinks li a:hover {
|
||||||
|
border-color: rgba(175, 47, 47, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.routeLinks li a.selected {
|
||||||
|
border-color: rgba(175, 47, 47, 0.2);
|
||||||
|
}
|
36
website/components/Tictactoe/board.js
Normal file
36
website/components/Tictactoe/board.js
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import React from 'react';
|
||||||
|
import Square from './square';
|
||||||
|
import styles from './styles.css';
|
||||||
|
|
||||||
|
export default class Board extends React.Component {
|
||||||
|
renderSquare(i) {
|
||||||
|
return (
|
||||||
|
<Square
|
||||||
|
value={this.props.squares[i]}
|
||||||
|
onClick={() => this.props.onClick(i)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className={styles.boardRow}>
|
||||||
|
{this.renderSquare(0)}
|
||||||
|
{this.renderSquare(1)}
|
||||||
|
{this.renderSquare(2)}
|
||||||
|
</div>
|
||||||
|
<div className={styles.boardRow}>
|
||||||
|
{this.renderSquare(3)}
|
||||||
|
{this.renderSquare(4)}
|
||||||
|
{this.renderSquare(5)}
|
||||||
|
</div>
|
||||||
|
<div className={styles.boardRow}>
|
||||||
|
{this.renderSquare(6)}
|
||||||
|
{this.renderSquare(7)}
|
||||||
|
{this.renderSquare(8)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
106
website/components/Tictactoe/index.js
Normal file
106
website/components/Tictactoe/index.js
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
import React from 'react';
|
||||||
|
import Helmet from 'react-helmet';
|
||||||
|
import Layout from '@theme/Layout';
|
||||||
|
import Board from './board';
|
||||||
|
import styles from './styles.css';
|
||||||
|
|
||||||
|
class Game extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
history: [
|
||||||
|
{
|
||||||
|
squares: Array(9).fill(null)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
stepNumber: 0,
|
||||||
|
xIsNext: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateWinner(squares) {
|
||||||
|
const lines = [
|
||||||
|
[0, 1, 2],
|
||||||
|
[3, 4, 5],
|
||||||
|
[6, 7, 8],
|
||||||
|
[0, 3, 6],
|
||||||
|
[1, 4, 7],
|
||||||
|
[2, 5, 8],
|
||||||
|
[0, 4, 8],
|
||||||
|
[2, 4, 6]
|
||||||
|
];
|
||||||
|
for (let i = 0; i < lines.length; i++) {
|
||||||
|
const [a, b, c] = lines[i];
|
||||||
|
if (
|
||||||
|
squares[a] &&
|
||||||
|
squares[a] === squares[b] &&
|
||||||
|
squares[a] === squares[c]
|
||||||
|
) {
|
||||||
|
return squares[a];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClick(i) {
|
||||||
|
const history = this.state.history.slice(0, this.state.stepNumber + 1);
|
||||||
|
const current = history[history.length - 1];
|
||||||
|
const squares = current.squares.slice();
|
||||||
|
if (this.calculateWinner(squares) || squares[i]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
squares[i] = this.state.xIsNext ? 'X' : 'O';
|
||||||
|
this.setState({
|
||||||
|
history: history.concat([
|
||||||
|
{
|
||||||
|
squares: squares
|
||||||
|
}
|
||||||
|
]),
|
||||||
|
stepNumber: history.length,
|
||||||
|
xIsNext: !this.state.xIsNext
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
jumpTo(step) {
|
||||||
|
this.setState({
|
||||||
|
stepNumber: step,
|
||||||
|
xIsNext: step % 2 === 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const history = this.state.history;
|
||||||
|
const current = history[this.state.stepNumber];
|
||||||
|
const winner = this.calculateWinner(current.squares);
|
||||||
|
|
||||||
|
const moves = history.map((step, move) => {
|
||||||
|
const desc = move ? 'Go to move #' + move : 'Go to game start';
|
||||||
|
return (
|
||||||
|
<li key={move}>
|
||||||
|
<button onClick={() => this.jumpTo(move)}>{desc}</button>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
let status;
|
||||||
|
if (winner) {
|
||||||
|
status = 'Winner: ' + winner;
|
||||||
|
} else {
|
||||||
|
status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.game}>
|
||||||
|
<div className={styles.gameBoard}>
|
||||||
|
<Board squares={current.squares} onClick={i => this.handleClick(i)} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.gameInfo}>
|
||||||
|
<div>{status}</div>
|
||||||
|
<ol>{moves}</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Game;
|
10
website/components/Tictactoe/square.js
Normal file
10
website/components/Tictactoe/square.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import React from 'react';
|
||||||
|
import styles from './styles.css';
|
||||||
|
|
||||||
|
export default props => {
|
||||||
|
return (
|
||||||
|
<button className={styles.square} onClick={props.onClick}>
|
||||||
|
{props.value}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
|
@ -30,6 +30,9 @@
|
||||||
.game {
|
.game {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gameInfo {
|
.gameInfo {
|
94
website/components/Todo/TodoItem.js
Normal file
94
website/components/Todo/TodoItem.js
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
const ESCAPE_KEY = 27;
|
||||||
|
const ENTER_KEY = 13;
|
||||||
|
|
||||||
|
export default class TodoItem extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
editText: props.todo.title
|
||||||
|
};
|
||||||
|
this.handleEdit = this.handleEdit.bind(this);
|
||||||
|
this.handleSubmit = this.handleSubmit.bind(this);
|
||||||
|
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
|
return (
|
||||||
|
nextProps.todo !== this.props.todo ||
|
||||||
|
nextProps.editing !== this.props.editing ||
|
||||||
|
nextState.editText !== this.state.editText
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
if (!prevProps.editing && this.props.editing) {
|
||||||
|
const node = ReactDOM.findDOMNode(this.refs.editField);
|
||||||
|
node.focus();
|
||||||
|
node.setSelectionRange(node.value.length, node.value.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSubmit() {
|
||||||
|
const val = this.state.editText.trim();
|
||||||
|
if (val) {
|
||||||
|
this.props.onSave(val);
|
||||||
|
this.setState({editText: val});
|
||||||
|
} else {
|
||||||
|
this.props.onDestroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleEdit() {
|
||||||
|
this.props.onEdit();
|
||||||
|
this.setState({editText: this.props.todo.title});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeyDown(event) {
|
||||||
|
if (event.which === ESCAPE_KEY) {
|
||||||
|
this.setState({editText: this.props.todo.title});
|
||||||
|
this.props.onCancel(event);
|
||||||
|
} else if (event.which === ENTER_KEY) {
|
||||||
|
this.handleSubmit(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChange(event) {
|
||||||
|
if (this.props.editing) {
|
||||||
|
this.setState({editText: event.target.value});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
className={classNames({
|
||||||
|
completed: this.props.todo.completed,
|
||||||
|
editing: this.props.editing
|
||||||
|
})}>
|
||||||
|
<div className="view">
|
||||||
|
<input
|
||||||
|
className="toggle"
|
||||||
|
type="checkbox"
|
||||||
|
checked={this.props.todo.completed}
|
||||||
|
onChange={this.props.onToggle}
|
||||||
|
/>
|
||||||
|
<label onDoubleClick={this.handleEdit}>{this.props.todo.title}</label>
|
||||||
|
<button className="destroy" onClick={this.props.onDestroy} />
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
ref="editField"
|
||||||
|
className="edit"
|
||||||
|
value={this.state.editText}
|
||||||
|
onBlur={this.handleSubmit}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
onKeyDown={this.handleKeyDown}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
29
website/components/Todo/TodoList.js
Normal file
29
website/components/Todo/TodoList.js
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import React from 'react';
|
||||||
|
import TodoItem from './TodoItem';
|
||||||
|
|
||||||
|
export default function TodoList(props) {
|
||||||
|
const todoItems = props.todos.map(todo => (
|
||||||
|
<TodoItem
|
||||||
|
key={todo.id}
|
||||||
|
todo={todo}
|
||||||
|
onToggle={() => {
|
||||||
|
props.onToggle(todo);
|
||||||
|
}}
|
||||||
|
onDestroy={() => {
|
||||||
|
props.onDestroy(todo);
|
||||||
|
}}
|
||||||
|
onEdit={() => {
|
||||||
|
props.onEdit(todo);
|
||||||
|
}}
|
||||||
|
editing={props.editing(todo)}
|
||||||
|
onSave={text => {
|
||||||
|
props.onSave(todo, text);
|
||||||
|
}}
|
||||||
|
onCancel={() => {
|
||||||
|
props.onCancel();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
|
return <div>{todoItems}</div>;
|
||||||
|
}
|
209
website/components/Todo/index.js
Normal file
209
website/components/Todo/index.js
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
import React from 'react';
|
||||||
|
import Helmet from 'react-helmet';
|
||||||
|
import TodoList from './TodoList';
|
||||||
|
|
||||||
|
const ENTER_KEY = 13;
|
||||||
|
|
||||||
|
function uuid() {
|
||||||
|
function s4() {
|
||||||
|
return Math.floor((1 + Math.random()) * 0x10000)
|
||||||
|
.toString(16)
|
||||||
|
.substring(1);
|
||||||
|
}
|
||||||
|
return `${s4()}${s4()}-${s4()}-${s4()}-${s4()}-${s4()}${s4()}${s4()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const todos = [
|
||||||
|
{
|
||||||
|
id: 'ed0bcc48-bbbe-5f06-c7c9-2ccb0456ceba',
|
||||||
|
title: 'Build this Todo App.',
|
||||||
|
completed: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '42582304-3c6e-311e-7f88-7e3791caf88c',
|
||||||
|
title: '?????',
|
||||||
|
completed: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '1cf63885-5f75-8deb-19dc-9b6765deae6c',
|
||||||
|
title: '1,000 stars on GitHub.',
|
||||||
|
completed: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '63a871b2-0b6f-4427-9c35-304bc680a4b7',
|
||||||
|
title: 'Write a popular medium post.',
|
||||||
|
completed: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '63a871b2-0b6f-4422-9c35-304bc680a4b7',
|
||||||
|
title: 'Earn money through open source work.',
|
||||||
|
completed: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '036af7f9-1181-fb8f-258f-3f06034c020f',
|
||||||
|
title: 'Write a blog post.',
|
||||||
|
completed: false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
class TodoApp extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
editing: null,
|
||||||
|
newTodo: '',
|
||||||
|
todos: todos
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChange(event) {
|
||||||
|
this.setState({newTodo: event.target.value});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleNewTodoKeyDown(event) {
|
||||||
|
if (event.keyCode !== ENTER_KEY) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const val = this.state.newTodo.trim();
|
||||||
|
|
||||||
|
if (val) {
|
||||||
|
this.setState({
|
||||||
|
todos: this.state.todos.concat({
|
||||||
|
id: uuid(),
|
||||||
|
title: val,
|
||||||
|
completed: false
|
||||||
|
}),
|
||||||
|
newTodo: ''
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleAll(event) {
|
||||||
|
const {checked} = event.target;
|
||||||
|
this.setState({
|
||||||
|
todos: this.state.todos.map(todo =>
|
||||||
|
Object.assign({}, todo, {completed: checked})
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle(todoToToggle) {
|
||||||
|
this.setState({
|
||||||
|
todos: this.state.todos.map(todo => {
|
||||||
|
if (todo === todoToToggle) {
|
||||||
|
return Object.assign({}, todo, {
|
||||||
|
completed: !todo.completed
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return todo;
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy(passedTodo) {
|
||||||
|
this.setState({
|
||||||
|
todos: this.state.todos.filter(todo => todo !== passedTodo)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
edit(todo) {
|
||||||
|
this.setState({editing: todo.id});
|
||||||
|
}
|
||||||
|
|
||||||
|
save(todoToSave, text) {
|
||||||
|
this.setState({
|
||||||
|
todos: this.state.todos.map(todo => {
|
||||||
|
if (todo === todoToSave) {
|
||||||
|
return Object.assign({}, todo, {
|
||||||
|
title: text
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return todo;
|
||||||
|
}),
|
||||||
|
editing: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel() {
|
||||||
|
this.setState({editing: null});
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCompleted() {
|
||||||
|
this.setState({
|
||||||
|
todos: this.state.todos.filter(todo => !todo.completed)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let main;
|
||||||
|
const {todos} = this.state;
|
||||||
|
|
||||||
|
const activeTodoCount = todos.reduce(
|
||||||
|
(accum, todo) => (todo.completed ? accum : accum + 1),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
if (todos.length) {
|
||||||
|
main = (
|
||||||
|
<section className="main">
|
||||||
|
<input
|
||||||
|
className="toggle-all"
|
||||||
|
type="checkbox"
|
||||||
|
onChange={this.toggleAll}
|
||||||
|
checked={activeTodoCount === 0}
|
||||||
|
/>
|
||||||
|
<ul className="todo-list">
|
||||||
|
<TodoList
|
||||||
|
todos={todos}
|
||||||
|
onToggle={todo => {
|
||||||
|
this.toggle(todo);
|
||||||
|
}}
|
||||||
|
onDestroy={todo => {
|
||||||
|
this.destroy(todo);
|
||||||
|
}}
|
||||||
|
onEdit={todo => {
|
||||||
|
this.edit(todo);
|
||||||
|
}}
|
||||||
|
editing={todo => this.state.editing === todo.id}
|
||||||
|
onSave={(todo, text) => {
|
||||||
|
this.save(todo, text);
|
||||||
|
}}
|
||||||
|
onCancel={() => this.cancel()}
|
||||||
|
/>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="todoapp">
|
||||||
|
<Helmet>
|
||||||
|
<title>Todo App</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/css/todo.css" />
|
||||||
|
</Helmet>
|
||||||
|
<header className="header">
|
||||||
|
<h1>todos</h1>
|
||||||
|
<input
|
||||||
|
className="new-todo"
|
||||||
|
placeholder="What needs to be done?"
|
||||||
|
value={this.state.newTodo}
|
||||||
|
onKeyDown={event => {
|
||||||
|
this.handleNewTodoKeyDown(event);
|
||||||
|
}}
|
||||||
|
onChange={event => {
|
||||||
|
this.handleChange(event);
|
||||||
|
}}
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
|
</header>
|
||||||
|
{main}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TodoApp;
|
|
@ -1,21 +1,17 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Helmet from 'react-helmet';
|
import Helmet from 'react-helmet';
|
||||||
import {Link} from 'react-router-dom';
|
import Layout from '@theme/Layout';
|
||||||
|
import Todo from '@site/components/Todo';
|
||||||
|
|
||||||
export default class Home extends React.Component {
|
export default class Home extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
const {pagesData, docsData} = this.props;
|
|
||||||
const routeLinks = [...pagesData, ...docsData].map(data => (
|
|
||||||
<li key={data.path}>
|
|
||||||
<Link to={data.path}>{data.path}</Link>
|
|
||||||
</li>
|
|
||||||
));
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<Layout {...this.props}>
|
||||||
<Helmet title="Homepage" />
|
<Helmet>
|
||||||
<h2> Available Urls </h2>
|
<title>Homepage</title>
|
||||||
<ul>{routeLinks}</ul>
|
</Helmet>
|
||||||
</div>
|
<Todo />
|
||||||
|
</Layout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,142 +1,17 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Helmet from 'react-helmet';
|
import Helmet from 'react-helmet';
|
||||||
import style from './tictactoe.css';
|
import Layout from '@theme/Layout';
|
||||||
|
import Tictactoe from '@site/components/Tictactoe';
|
||||||
function Square(props) {
|
|
||||||
return (
|
|
||||||
<button className={style.square} onClick={props.onClick}>
|
|
||||||
{props.value}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function calculateWinner(squares) {
|
|
||||||
const lines = [
|
|
||||||
[0, 1, 2],
|
|
||||||
[3, 4, 5],
|
|
||||||
[6, 7, 8],
|
|
||||||
[0, 3, 6],
|
|
||||||
[1, 4, 7],
|
|
||||||
[2, 5, 8],
|
|
||||||
[0, 4, 8],
|
|
||||||
[2, 4, 6]
|
|
||||||
];
|
|
||||||
for (let i = 0; i < lines.length; i++) {
|
|
||||||
const [a, b, c] = lines[i];
|
|
||||||
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
|
|
||||||
return squares[a];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Board extends React.Component {
|
|
||||||
renderSquare(i) {
|
|
||||||
return (
|
|
||||||
<Square
|
|
||||||
value={this.props.squares[i]}
|
|
||||||
onClick={() => this.props.onClick(i)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
export default class Home extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<Layout {...this.props}>
|
||||||
<div className={style.boardRow}>
|
<Helmet>
|
||||||
{this.renderSquare(0)}
|
<title>Tic Tac Toe</title>
|
||||||
{this.renderSquare(1)}
|
</Helmet>
|
||||||
{this.renderSquare(2)}
|
<Tictactoe />
|
||||||
</div>
|
</Layout>
|
||||||
<div className={style.boardRow}>
|
|
||||||
{this.renderSquare(3)}
|
|
||||||
{this.renderSquare(4)}
|
|
||||||
{this.renderSquare(5)}
|
|
||||||
</div>
|
|
||||||
<div className={style.boardRow}>
|
|
||||||
{this.renderSquare(6)}
|
|
||||||
{this.renderSquare(7)}
|
|
||||||
{this.renderSquare(8)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Game extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
history: [
|
|
||||||
{
|
|
||||||
squares: Array(9).fill(null)
|
|
||||||
}
|
|
||||||
],
|
|
||||||
stepNumber: 0,
|
|
||||||
xIsNext: true
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
handleClick(i) {
|
|
||||||
const history = this.state.history.slice(0, this.state.stepNumber + 1);
|
|
||||||
const current = history[history.length - 1];
|
|
||||||
const squares = current.squares.slice();
|
|
||||||
if (calculateWinner(squares) || squares[i]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
squares[i] = this.state.xIsNext ? 'X' : 'O';
|
|
||||||
this.setState({
|
|
||||||
history: history.concat([
|
|
||||||
{
|
|
||||||
squares: squares
|
|
||||||
}
|
|
||||||
]),
|
|
||||||
stepNumber: history.length,
|
|
||||||
xIsNext: !this.state.xIsNext
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
jumpTo(step) {
|
|
||||||
this.setState({
|
|
||||||
stepNumber: step,
|
|
||||||
xIsNext: step % 2 === 0
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const history = this.state.history;
|
|
||||||
const current = history[this.state.stepNumber];
|
|
||||||
const winner = calculateWinner(current.squares);
|
|
||||||
|
|
||||||
const moves = history.map((step, move) => {
|
|
||||||
const desc = move ? 'Go to move #' + move : 'Go to game start';
|
|
||||||
return (
|
|
||||||
<li key={move}>
|
|
||||||
<button onClick={() => this.jumpTo(move)}>{desc}</button>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
let status;
|
|
||||||
if (winner) {
|
|
||||||
status = 'Winner: ' + winner;
|
|
||||||
} else {
|
|
||||||
status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={style.game}>
|
|
||||||
<Helmet title="Tic Tac Toe" />
|
|
||||||
<div className={style.gameBoard}>
|
|
||||||
<Board squares={current.squares} onClick={i => this.handleClick(i)} />
|
|
||||||
</div>
|
|
||||||
<div className={style.gameInfo}>
|
|
||||||
<div>{status}</div>
|
|
||||||
<ol>{moves}</ol>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Game;
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue