This commit is contained in:
Jori Lallo
2016-03-10 22:54:47 -08:00
parent f6456a3817
commit 7225c01924
11 changed files with 121 additions and 39 deletions

View File

@@ -57,7 +57,7 @@
"react-redux": "^4.4.0", "react-redux": "^4.4.0",
"react-router": "^2.0.0", "react-router": "^2.0.0",
"redux": "^3.3.1", "redux": "^3.3.1",
"redux-storage": "^3.0.0", "redux-storage": "^4.0.0",
"redux-storage-engine-localstorage": "^1.0.0", "redux-storage-engine-localstorage": "^1.0.0",
"sass-loader": "^3.1.2", "sass-loader": "^3.1.2",
"style-loader": "^0.13.0", "style-loader": "^0.13.0",

View File

@@ -1,5 +1,7 @@
import React from 'react'; import React from 'react';
import MarkdownIcon from '../../Components/Icons/Markdown';
import styles from './Header.scss'; import styles from './Header.scss';
import classNames from 'classnames/bind'; import classNames from 'classnames/bind';
const cx = classNames.bind(styles); const cx = classNames.bind(styles);
@@ -7,23 +9,26 @@ const cx = classNames.bind(styles);
const Header = ({ const Header = ({
activeEditors, activeEditors,
toggleEditors, toggleEditors,
addRevision,
}) => { }) => {
return ( return (
<div className={ styles.header }> <div className={ styles.header }>
<div className={ styles.headerItem }><i>Beautiful</i> Atlas</div> <div className={ styles.headerItem }><i>Beautiful</i> Atlas</div>
<div className={ cx('headerItem', 'editorToggle') }> <div
<span className={ cx('headerItem', 'editorToggle') }
style={{ display: 'flex', justifyContent: 'flex-end', alignItems: 'center' }}
>
<div
onClick={toggleEditors.bind(this, 'MARKDOWN')} onClick={toggleEditors.bind(this, 'MARKDOWN')}
className={ activeEditors.includes('MARKDOWN') ? styles.active : '' } className={ activeEditors.includes('MARKDOWN') ? styles.active : '' }
>Markdown</span> >
<span <MarkdownIcon style={{ width: '32px', height: '20px', color: '#fff' }} />
</div>
<div
onClick={toggleEditors.bind(this, 'TEXT')} onClick={toggleEditors.bind(this, 'TEXT')}
className={ activeEditors.includes('TEXT') ? styles.active : '' } className={ activeEditors.includes('TEXT') ? styles.active : '' }
>Text</span> >
</div> <span className={ styles.textIcon }>Aa</span>
<div className={ cx('headerItem', 'sidebar') }> </div>
<span onClick={addRevision.bind(this, (new Date()).toISOString())}>Save</span>
</div> </div>
</div> </div>
); );
@@ -32,7 +37,6 @@ const Header = ({
Header.propTypes = { Header.propTypes = {
activeEditors: React.PropTypes.array.isRequired, activeEditors: React.PropTypes.array.isRequired,
toggleEditors: React.PropTypes.func.isRequired, toggleEditors: React.PropTypes.func.isRequired,
addRevision: React.PropTypes.func.isRequired,
}; };
export default Header; export default Header;

View File

@@ -2,6 +2,9 @@
display: flex; display: flex;
width: 100%; width: 100%;
height: 42px; height: 42px;
position: fixed;
z-index: 9999;
justify-content: space-between; justify-content: space-between;
background-color: #111; background-color: #111;
@@ -29,26 +32,29 @@
} }
} }
.editorToggle { .editorToggle div {
span { margin-right: 12px;
margin-right: 12px; cursor: pointer;
cursor: pointer; opacity: 0.4;
color: #fff;
&:last-child { &.active {
margin-right: 0; opacity: 1;
} }
&:first-child {
margin-top: 2px;
margin-right: 15px;
}
&:last-child {
margin-top: -2px;
} }
} }
.sidebar { .textIcon {
span { font-family: Times, serif;
margin-right: 12px; font-size: 20px;
cursor: pointer;
}
}
.active {
text-decoration: underline;
text-decoration-color: #fff;
} }
} }

View File

@@ -0,0 +1,31 @@
import React from 'react';
export default ({ style = {}, className }) => {
return (
<span className={className}>
<svg
xmlns="http://www.w3.org/2000/svg"
width={ style.width || 208 }
height={ style.height || 128 }
viewBox="0 0 208 128"
color={ style.color }
>
<rect
width="198"
height="118"
x="5"
y="5"
ry="10"
stroke="currentColor"
strokeWidth="10"
fill="none"
fillOpacity="0"
/>
<path
d="M30 98v-68h20l20 25 20-25h20v68h-20v-39l-20 25-20-25v39zM155 98l-30-33h20v-35h20v35h20z"
fill="currentColor"
/>
</svg>
</span>
);
};

View File

@@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import Codemirror from 'react-codemirror'; import Codemirror from 'react-codemirror';
import 'codemirror/mode/gfm/gfm'; import 'codemirror/mode/gfm/gfm';
import 'codemirror/mode/javascript/javascript';
import 'codemirror/addon/edit/continuelist'; import 'codemirror/addon/edit/continuelist';
import styles from './MarkdownEditor.scss'; import styles from './MarkdownEditor.scss';

View File

@@ -1,4 +1,13 @@
.container { .container {
width: 70%; font-weight: 400;
margin: 48px auto; font-size: 1em;
line-height: 1.5em;
margin: 0 auto;
padding: 2em 3em;
max-width: 50em;
}
@media all and (max-width: 2000px) and (min-width: 960px) {
.container {font-size: 1.1em}
} }

View File

@@ -11,10 +11,11 @@
@import url(https://fonts.googleapis.com/css?family=Cousine:400,700,700italic,400italic); @import url(https://fonts.googleapis.com/css?family=Cousine:400,700,700italic,400italic);
.cm-s-atlas.CodeMirror { .cm-s-atlas.CodeMirror {
background: #fcfcfc; background: #ffffff;
color: #202020; color: #202020;
font-family: 'Cousine', 'Monaco', monospace; font-family: 'Cousine', 'Monaco', monospace;
font-weight: 300; font-weight: 300;
height: auto;
} }
.cm-s-atlas div.CodeMirror-selected { .cm-s-atlas div.CodeMirror-selected {
background: #90CAF9; background: #90CAF9;

View File

@@ -1,5 +1,17 @@
.container {
font-weight: 400;
font-size: 1em;
line-height: 1.5em;
margin: 0 auto;
padding: 2em 3em;
max-width: 50em;
}
.editor { .editor {
outline: none; outline: none;
margin: 0 0 20px 0; }
padding: 0 0 20px 0;
@media all and (max-width: 2000px) and (min-width: 960px) {
.container {font-size: 1.1em}
} }

View File

@@ -12,11 +12,12 @@ import {
const activeEditors = (state = [ActiveEditors.MARKDOWN, ActiveEditors.TEXT], action) => { const activeEditors = (state = [ActiveEditors.MARKDOWN, ActiveEditors.TEXT], action) => {
switch (action.type) { switch (action.type) {
case TOGGLE_EDITORS: { case TOGGLE_EDITORS: {
// TODO: A rewrite would be nice
const newState = _.xor(state, [action.toggledEditor]); const newState = _.xor(state, [action.toggledEditor]);
if (newState.length > 0) { if (newState.length > 0) {
return newState; return newState;
} else { } else {
return [action.toggledEditor]; return _.xor([ActiveEditors.MARKDOWN, ActiveEditors.TEXT], [action.toggledEditor]);
} }
} }
default: default:
@@ -37,15 +38,28 @@ const historySidebar = (state = { visible: false }, action) => {
} }
}; };
const text = (state = { text: '', revisions: [] }, action) => { const textDefaultState = {
text: '',
revisions: [],
unsavedChanges: false,
};
const text = (state = textDefaultState, action) => {
const lastRevision = _.last(state.revisions);
switch (action.type) { switch (action.type) {
case UPDATE_TEXT: case UPDATE_TEXT: {
let unsavedChanges = false;
if (lastRevision && lastRevision.text !== state.text) {
unsavedChanges = true;
}
return { return {
...state, ...state,
unsavedChanges,
text: action.text, text: action.text,
}; };
}
case ADD_REVISION: { case ADD_REVISION: {
const lastRevision = _.last(state.revisions);
// Create new revision if it differs from the previous one // Create new revision if it differs from the previous one
if (!lastRevision || lastRevision.text !== state.text) { if (!lastRevision || lastRevision.text !== state.text) {
const lastId = lastRevision ? lastRevision.id : 0; const lastId = lastRevision ? lastRevision.id : 0;
@@ -59,6 +73,7 @@ const text = (state = { text: '', revisions: [] }, action) => {
created_at: action.createdAt, created_at: action.createdAt,
}, },
], ],
unsavedChanges: false,
}; };
} else { } else {
return state; return state;

View File

@@ -19,6 +19,7 @@ class App extends Component {
activeEditors: React.PropTypes.array.isRequired, activeEditors: React.PropTypes.array.isRequired,
toggleEditors: React.PropTypes.func.isRequired, toggleEditors: React.PropTypes.func.isRequired,
addRevision: React.PropTypes.func.isRequired, addRevision: React.PropTypes.func.isRequired,
unsavedChanges: React.PropTypes.bool.isRequired,
} }
state = { state = {
@@ -47,6 +48,7 @@ class App extends Component {
activeEditors={this.props.activeEditors} activeEditors={this.props.activeEditors}
toggleEditors={this.props.toggleEditors} toggleEditors={this.props.toggleEditors}
addRevision={this.props.addRevision} addRevision={this.props.addRevision}
unsavedChanges={this.props.unsavedChanges}
/> />
<div className={ styles.content }> <div className={ styles.content }>
{ this.props.children } { this.props.children }
@@ -59,7 +61,7 @@ class App extends Component {
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
return { return {
activeEditors: state.activeEditors, activeEditors: state.activeEditors,
showHistorySidebar: state.historySidebar.visible, unsavedChanges: state.text.unsavedChanges,
}; };
}; };

View File

@@ -1,5 +1,6 @@
.container { .container {
display: flex; display: flex;
padding-top: 48px;
} }
.panel { .panel {
@@ -11,5 +12,5 @@
} }
.markdown { .markdown {
background-color: #fbfbfb; background-color: #ffffff;
} }