React Base SPA (study)
Single Page Application
React, Bootstrap4
Bootstrap4のデフォルトの色使いが強すぎて使い方が難しい。
by Masaki Moriwaki
HTML
<link rel="stylesheet" href="https://cdn.rawgit.com/twbs/bootstrap/v4-dev/dist/css/bootstrap.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.2/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.2/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.33/browser.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-router/1.0.0-rc3/ReactRouter.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/5.0.1/markdown-it.js"></script>
<script src="https://facebook.github.io/react/js/jsfiddle-integration-babel.js"></script>
<div id="application"></div>
CSS
html {
overflow: hidden;
}
body {
position: fixed;
width: 100%;
height: 100%;
}
.application {
display: flex;
flex-direction: column;
overflow: hidden;
height: 100vh;
}
.viewport {
flex-grow: 1;
display: flex;
flex-direction: row;
overflow: hidden;
max-height: 100vh;
}
.sidenav {
flex: 0 0 10rem;
display: flex;
flex-direction: column;
border-right: #ccc 1px solid;
padding: 1rem 1rem 1rem 0;
}
main {
display: flex;
flex-grow: 1;
}
.editor {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.editor textarea {
resize: none;
}
.editor header {
flex: 0 1 auto;
border-bottom: #ccc 1px solid;
padding: 0.5rem;
}
.editor header input {
border: none;
}
.editor header h2 {
margin: 0;
}
.editor section {
flex: 1 1 auto;
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
}
.editor section .markdown {
flex: 1 1 50%;
border: none;
overflow: auto;
padding: 0.5rem;
}
.editor section .preview {
flex: 1 1 50%;
border-left: #ccc 1px solid;
overflow: auto;
padding: 0.5rem;
}
.editor footer {
flex: 0 1 auto;
display: flex;
flex-direction: row;
border-top: #ccc 1px solid;
}
.editor footer .markdown {
flex: 1 1 50%;
border: none;
overflow: auto;
padding: 0.5rem;
}
.editor footer .preview {
flex: 1 1 50%;
border-left: #ccc 1px solid;
overflow: auto;
padding: 0.5rem;
}
.list {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.list header {
border-bottom: #ccc 1px solid;
padding: 0.5rem;
}
.list header h2 {
margin: 0;
}
.list section {
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
}
.list section nav {
flex: 1 1 25%;
border-right: #ccc 1px solid;
overflow: auto;
padding: 0;
}
.list section nav ul li {
border-bottom: #ccc 1px solid;
padding:...
JavaScript 1.7
const Router = window.ReactRouter.Router;
const Route = window.ReactRouter.Route;
const Link = window.ReactRouter.Link;
const md = window.markdownit();
class Message extends React.Component {
constructor(props) {
super(props);
this.state = {hidden: false};
}
close() {
this.setState({hidden: true});
}
render() {
const level = {
success: 'bg-success',
info: 'bg-info',
warning: 'bg-warning',
danger: 'bg-danger'
};
return (
<div ref="message" className={level[this.props.level]} hidden={this.state.hidden}>
{this.props.text}
<button onClick={this.close.bind(this)} type="button" className="close">
<span>×</span>
</button>
</div>
)
}
};
class Notifications extends React.Component {
render() {
return (
<aside>
{this.props.messages.map((message, i) => {
return <Message key={i} {...message} />;
})}
</aside>
);
}
};
class Navigation extends React.Component {
render() {
return (
<nav className="sidenav">
<ul className="nav nav-pills nav-stacked">
<li className="nav-item"><Link to="/editor" className="nav-link" activeClassName="active">新規投稿</Link></li>
<li className="nav-item"><Link to="/list" className="nav-link" activeClassName="active">投稿一覧</Link></li>
</ul>
</nav>
);
}
};
class Editor extends React.Component {
updatePreview() {
const html = md.render(this.refs.markdown.value);
this.refs.preview.innerHTML = html;
}
save() {
const post = {
title: this.refs.title.value,
markdown: this.refs.markdown.value
};
datastore.push(post);
}
render() {
return (
<div className="editor">
<header>
<h2>
<button onClick={this.save.bind(this)} type="button" className="btn btn-primary pull-right">
保存
</button>
<input type="text" placeholder="タイトル"...