diff --git a/package.json b/package.json index ad051f0bb..0af9d0251 100644 --- a/package.json +++ b/package.json @@ -90,6 +90,7 @@ "react-redux": "^4.4.0", "react-router": "^2.0.0", "react-router-redux": "^4.0.4", + "rebass": "^0.2.6", "redux": "^3.3.1", "redux-logger": "^2.6.1", "redux-persist": "3.0.3", diff --git a/src/Actions/index.js b/src/Actions/index.js deleted file mode 100644 index 0373d54ac..000000000 --- a/src/Actions/index.js +++ /dev/null @@ -1,43 +0,0 @@ -import keyMirror from 'fbjs/lib/keyMirror'; - -/* - * Action types - */ - -export const UPDATE_TEXT = 'UPDATE_TEXT'; -export const TOGGLE_EDITORS = 'TOGGLE_EDITORS'; -export const ADD_REVISION = 'ADD_REVISION'; -export const REPLACE_TEXT= 'REPLACE_TEXT'; - -export const SLACK_AUTH_PENDING = 'SLACK_AUTH_PENDING'; -export const SLACK_AUTH_SUCCESS = 'SLACK_AUTH_SUCCESS'; -export const SLACK_AUTH_FAILURE = 'SLACK_AUTH_FAILURE'; - -/* - * Other Constants - */ - -export const ActiveEditors = keyMirror({ - MARKDOWN: null, - TEXT: null, -}); - -/* - * Action creators - */ - -export function updateText(text, editor) { - return { type: UPDATE_TEXT, text, editor }; -} - -export function toggleEditors(toggledEditor) { - return { type: TOGGLE_EDITORS, toggledEditor }; -} - -export function addRevision(createdAt) { - return { type: ADD_REVISION, createdAt }; -} - -export function replaceText(originalText, replacedText) { - return { type: REPLACE_TEXT, originalText, replacedText }; -} \ No newline at end of file diff --git a/src/Components/Header/Header.js b/src/Components/Header/Header.js deleted file mode 100644 index 88f33ce9b..000000000 --- a/src/Components/Header/Header.js +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react'; - -import styles from './Header.scss'; -import classNames from 'classnames/bind'; -const cx = classNames.bind(styles); - -const Header = ({ - toggleEditors, - }) => { - return ( -
-
Beautiful Atlas
-
-
- Aa -
-
-
- ); -}; - -Header.propTypes = { - activeEditors: React.PropTypes.array.isRequired, - toggleEditors: React.PropTypes.func.isRequired, -}; - -export default Header; diff --git a/src/Components/Header/Header.scss b/src/Components/Header/Header.scss deleted file mode 100644 index e2c6971ad..000000000 --- a/src/Components/Header/Header.scss +++ /dev/null @@ -1,61 +0,0 @@ -.header { - display: flex; - width: 100%; - height: 42px; - position: fixed; - z-index: 9999; - - justify-content: space-between; - - background-color: #111; - color: #fff; - - i { - color: #fff; - font-family: serif; - } - - .headerItem { - width: 150px; - padding: 12px 22px; - - font-size: 15px; - font-weight: 300; - font-family: "Atlas Grotesk", "Helvetica Neue", sans-serif; - text-align: center; - - &:first-child { - text-align: left; - } - - &:last-child { - text-align: right; - } - } - - .editorToggle div { - margin-right: 12px; - cursor: pointer; - opacity: 0.4; - color: #fff; - - &.active { - opacity: 1; - } - - &:first-child { - margin-top: 2px; - margin-right: 15px; - } - - &:last-child { - margin-top: -2px; - } - } - - .textIcon { - font-family: Times, serif; - font-size: 20px; - - } -} \ No newline at end of file diff --git a/src/Components/Header/index.js b/src/Components/Header/index.js deleted file mode 100644 index 24421ce68..000000000 --- a/src/Components/Header/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import Header from './Header'; -export default Header; diff --git a/src/Components/MarkdownEditor/MarkdownEditor.js b/src/Components/MarkdownEditor/MarkdownEditor.js index 98f34e2db..3b7fbb0a4 100644 --- a/src/Components/MarkdownEditor/MarkdownEditor.js +++ b/src/Components/MarkdownEditor/MarkdownEditor.js @@ -93,7 +93,7 @@ class MarkdownAtlas extends React.Component { mode: 'gfm', matchBrackets: true, lineWrapping: true, - viewportMargin: Infinity, + // viewportMargin: Infinity, theme: 'atlas', extraKeys: { Enter: 'newlineAndIndentContinueMarkdownList', @@ -106,22 +106,20 @@ class MarkdownAtlas extends React.Component { // - Emojify // - return ( -
- - - -
+ + + ); } } diff --git a/src/Components/MarkdownEditor/MarkdownEditor.scss b/src/Components/MarkdownEditor/MarkdownEditor.scss index a51254f66..5c57851a3 100644 --- a/src/Components/MarkdownEditor/MarkdownEditor.scss +++ b/src/Components/MarkdownEditor/MarkdownEditor.scss @@ -1,4 +1,7 @@ .container { + display: flex; + flex: 1; + font-weight: 400; font-size: 1em; line-height: 1.5em; @@ -9,5 +12,14 @@ } @media all and (max-width: 2000px) and (min-width: 960px) { - .container {font-size: 1.1em} + .container { + margin-top: 48px; + font-size: 1.1em; + } +} + +@media all and (max-width: 960px) { + .container { + font-size: 0.9em; + } } \ No newline at end of file diff --git a/src/Components/TextEditor/TextEditor.js b/src/Components/TextEditor/TextEditor.js deleted file mode 100644 index 96b80d44b..000000000 --- a/src/Components/TextEditor/TextEditor.js +++ /dev/null @@ -1,52 +0,0 @@ -import React from 'react'; -import Editor from 'react-medium-editor'; -import marked from 'marked'; - -require('medium-editor/dist/css/medium-editor.css'); -require('medium-editor/dist/css/themes/default.css'); -import styles from './TextEditor.scss'; - -class TextEditor extends React.Component { - static propTypes = { - text: React.PropTypes.string, - onChange: React.PropTypes.func, - } - - onChange = (newText) => { - if (newText !== this.props.text) { - this.props.onChange(newText); - } - } - - render = () => { - return ( -
-
- -
- ); - } -} - -export default TextEditor; diff --git a/src/Components/TextEditor/TextEditor.scss b/src/Components/TextEditor/TextEditor.scss deleted file mode 100644 index 920b7bfed..000000000 --- a/src/Components/TextEditor/TextEditor.scss +++ /dev/null @@ -1,19 +0,0 @@ -.container { - font-weight: 400; - font-size: 1em; - line-height: 1.5em; - - margin: 0 auto; - padding: 2em 3em; - max-width: 50em; -} - -.editor { - outline: none; - - font-family: 'Atlas Grotesk', 'Helvetica Neue', sans-serif; -} - -@media all and (max-width: 2000px) and (min-width: 960px) { - .container {font-size: 1.1em} -} \ No newline at end of file diff --git a/src/Components/TextEditor/index.js b/src/Components/TextEditor/index.js deleted file mode 100644 index 0a79673b9..000000000 --- a/src/Components/TextEditor/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import TextEditor from './TextEditor'; -export default TextEditor; diff --git a/src/Reducers/index.js b/src/Reducers/index.js index f8336382a..0354bc2b6 100644 --- a/src/Reducers/index.js +++ b/src/Reducers/index.js @@ -1,118 +1,13 @@ -import _xor from 'lodash/xor'; -import _last from 'lodash/last'; import { combineReducers } from 'redux'; -import { - UPDATE_TEXT, - TOGGLE_EDITORS, - TOGGLE_HISTORY_SIDEBAR, - ADD_REVISION, - REPLACE_TEXT, - ActiveEditors -} from '../actions'; - -const activeEditors = (state = [ActiveEditors.MARKDOWN, ActiveEditors.TEXT], action) => { - switch (action.type) { - case TOGGLE_EDITORS: { - // TODO: A rewrite would be nice - const newState = _xor(state, [action.toggledEditor]); - if (newState.length > 0) { - return newState; - } else { - return _xor([ActiveEditors.MARKDOWN, ActiveEditors.TEXT], [action.toggledEditor]); - } - } - default: - return state; - } -}; - -const historySidebar = (state = { visible: false }, action) => { - switch (action.type) { - case TOGGLE_HISTORY_SIDEBAR: { - return { - ...state, - visible: !state.visible, - }; - } - default: - return state; - } -}; - -const defaultTest = `# Welcome to Beautiful Atlas - -This is just a small preview here's what you can do: - -- Write markdown or rich text, you choose -- Dont' worry about saving -- One document for now -- More to come -` - -const textDefaultState = { - text: defaultTest, - revisions: [], - unsavedChanges: false, -}; - -const text = (state = textDefaultState, action) => { - const lastRevision = _last(state.revisions); - - switch (action.type) { - case UPDATE_TEXT: { - let unsavedChanges = false; - if (lastRevision && lastRevision.text !== state.text) { - unsavedChanges = true; - } - return { - ...state, - unsavedChanges, - text: action.text, - }; - } - case ADD_REVISION: { - // Create new revision if it differs from the previous one - if (!lastRevision || lastRevision.text !== state.text) { - const lastId = lastRevision ? lastRevision.id : 0; - return { - ...state, - revisions: [ - ...state.revisions, - { - id: lastId + 1, - text: state.text, - created_at: action.createdAt, - }, - ], - unsavedChanges: false, - }; - } else { - return state; - } - } - case REPLACE_TEXT: { - const newText = state.text.replace(action.originalText, action.replacedText); - - return { - ...state, - text: newText, - }; - } - default: - return state; - } -}; - -import team from './team'; -import user from './user'; import atlases from './atlases'; +import team from './team'; +import editor from './editor'; +import user from './user'; export default combineReducers({ - activeEditors, - historySidebar, - text, - user, - team, atlases, + team, + editor, + user, }); diff --git a/src/actions/EditorActions.js b/src/actions/EditorActions.js index 1418dbce8..2f5726e35 100644 --- a/src/actions/EditorActions.js +++ b/src/actions/EditorActions.js @@ -1,5 +1,9 @@ import makeActionCreator from '../utils/actions'; -export const TOGGLE_PREVIEW = 'TOGGLE_PREVIEW'; +// export const TOGGLE_PREVIEW = 'TOGGLE_PREVIEW'; +export const UPDATE_TEXT = 'UPDATE_TEXT'; +export const REPLACE_TEXT = 'REPLACE_TEXT'; -const togglePreview = makeActionCreator(TOGGLE_PREVIEW); +// export const togglePreview = makeActionCreator(TOGGLE_PREVIEW); +export const updateText = makeActionCreator(UPDATE_TEXT, 'text'); +export const replaceText = makeActionCreator(REPLACE_TEXT, 'originalText', 'replacedText'); diff --git a/src/assets/styles/codemirror.css b/src/assets/styles/codemirror.css new file mode 100644 index 000000000..42e5868bd --- /dev/null +++ b/src/assets/styles/codemirror.css @@ -0,0 +1,340 @@ +:global { + /* BASICS */ + + .CodeMirror { + /* Set height, width, borders, and global font properties here */ + font-family: monospace; + height: 300px; + color: black; + } + + /* PADDING */ + + .CodeMirror-lines { + padding: 4px 0; /* Vertical padding around content */ + } + .CodeMirror pre { + padding: 0 4px; /* Horizontal padding of content */ + } + + .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + background-color: white; /* The little square between H and V scrollbars */ + } + + /* GUTTER */ + + .CodeMirror-gutters { + border-right: 1px solid #ddd; + background-color: #f7f7f7; + white-space: nowrap; + } + .CodeMirror-linenumbers {} + .CodeMirror-linenumber { + padding: 0 3px 0 5px; + min-width: 20px; + text-align: right; + color: #999; + white-space: nowrap; + } + + .CodeMirror-guttermarker { color: black; } + .CodeMirror-guttermarker-subtle { color: #999; } + + /* CURSOR */ + + .CodeMirror-cursor { + border-left: 1px solid black; + border-right: none; + width: 0; + } + /* Shown when moving in bi-directional text */ + .CodeMirror div.CodeMirror-secondarycursor { + border-left: 1px solid silver; + } + .cm-fat-cursor .CodeMirror-cursor { + width: auto; + border: 0; + background: #7e7; + } + .cm-fat-cursor div.CodeMirror-cursors { + z-index: 1; + } + + .cm-animate-fat-cursor { + width: auto; + border: 0; + -webkit-animation: blink 1.06s steps(1) infinite; + -moz-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; + background-color: #7e7; + } + @-moz-keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} + } + @-webkit-keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} + } + @keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} + } + + /* Can style cursor different in overwrite (non-insert) mode */ + .CodeMirror-overwrite .CodeMirror-cursor {} + + .cm-tab { display: inline-block; text-decoration: inherit; } + + .CodeMirror-ruler { + border-left: 1px solid #ccc; + position: absolute; + } + + /* DEFAULT THEME */ + + .cm-s-default .cm-header {color: blue;} + .cm-s-default .cm-quote {color: #090;} + .cm-negative {color: #d44;} + .cm-positive {color: #292;} + .cm-header, .cm-strong {font-weight: bold;} + .cm-em {font-style: italic;} + .cm-link {text-decoration: underline;} + .cm-strikethrough {text-decoration: line-through;} + + .cm-s-default .cm-keyword {color: #708;} + .cm-s-default .cm-atom {color: #219;} + .cm-s-default .cm-number {color: #164;} + .cm-s-default .cm-def {color: #00f;} + .cm-s-default .cm-variable, + .cm-s-default .cm-punctuation, + .cm-s-default .cm-property, + .cm-s-default .cm-operator {} + .cm-s-default .cm-variable-2 {color: #05a;} + .cm-s-default .cm-variable-3 {color: #085;} + .cm-s-default .cm-comment {color: #a50;} + .cm-s-default .cm-string {color: #a11;} + .cm-s-default .cm-string-2 {color: #f50;} + .cm-s-default .cm-meta {color: #555;} + .cm-s-default .cm-qualifier {color: #555;} + .cm-s-default .cm-builtin {color: #30a;} + .cm-s-default .cm-bracket {color: #997;} + .cm-s-default .cm-tag {color: #170;} + .cm-s-default .cm-attribute {color: #00c;} + .cm-s-default .cm-hr {color: #999;} + .cm-s-default .cm-link {color: #00c;} + + .cm-s-default .cm-error {color: #f00;} + .cm-invalidchar {color: #f00;} + + .CodeMirror-composing { border-bottom: 2px solid; } + + /* Default styles for common addons */ + + div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} + div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} + .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } + .CodeMirror-activeline-background {background: #e8f2ff;} + + /* STOP */ + + /* The rest of this file contains styles related to the mechanics of + the editor. You probably shouldn't touch them. */ + + .CodeMirror { + position: relative; + overflow: hidden; + background: white; + } + + .CodeMirror-scroll { + overflow: scroll !important; /* Things will break if this is overridden */ + /* 30px is the magic margin used to hide the element's real scrollbars */ + /* See overflow: hidden in .CodeMirror */ + margin-bottom: -30px; margin-right: -30px; + padding-bottom: 30px; + height: 100%; + outline: none; /* Prevent dragging from highlighting the element */ + position: relative; + } + .CodeMirror-sizer { + position: relative; + border-right: 30px solid transparent; + } + + /* The fake, visible scrollbars. Used to force redraw during scrolling + before actual scrolling happens, thus preventing shaking and + flickering artifacts. */ + .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + position: absolute; + z-index: 6; + display: none; + } + .CodeMirror-vscrollbar { + right: 0; top: 0; + overflow-x: hidden; + overflow-y: scroll; + } + .CodeMirror-hscrollbar { + bottom: 0; left: 0; + overflow-y: hidden; + overflow-x: scroll; + } + .CodeMirror-scrollbar-filler { + right: 0; bottom: 0; + } + .CodeMirror-gutter-filler { + left: 0; bottom: 0; + } + + .CodeMirror-gutters { + position: absolute; left: 0; top: 0; + min-height: 100%; + z-index: 3; + } + .CodeMirror-gutter { + white-space: normal; + height: 100%; + display: inline-block; + vertical-align: top; + margin-bottom: -30px; + /* Hack to make IE7 behave */ + *zoom:1; + *display:inline; + } + .CodeMirror-gutter-wrapper { + position: absolute; + z-index: 4; + background: none !important; + border: none !important; + } + .CodeMirror-gutter-background { + position: absolute; + top: 0; bottom: 0; + z-index: 4; + } + .CodeMirror-gutter-elt { + position: absolute; + cursor: default; + z-index: 4; + } + .CodeMirror-gutter-wrapper { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + } + + .CodeMirror-lines { + cursor: text; + min-height: 1px; /* prevents collapsing before first draw */ + } + .CodeMirror pre { + /* Reset some styles that the rest of the page might have set */ + -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; + border-width: 0; + background: transparent; + font-family: inherit; + font-size: inherit; + margin: 0; + white-space: pre; + word-wrap: normal; + line-height: inherit; + color: inherit; + z-index: 2; + position: relative; + overflow: visible; + -webkit-tap-highlight-color: transparent; + -webkit-font-variant-ligatures: none; + font-variant-ligatures: none; + } + .CodeMirror-wrap pre { + word-wrap: break-word; + white-space: pre-wrap; + word-break: normal; + } + + .CodeMirror-linebackground { + position: absolute; + left: 0; right: 0; top: 0; bottom: 0; + z-index: 0; + } + + .CodeMirror-linewidget { + position: relative; + z-index: 2; + overflow: auto; + } + + .CodeMirror-widget {} + + .CodeMirror-code { + outline: none; + } + + /* Force content-box sizing for the elements where we expect it */ + .CodeMirror-scroll, + .CodeMirror-sizer, + .CodeMirror-gutter, + .CodeMirror-gutters, + .CodeMirror-linenumber { + -moz-box-sizing: content-box; + box-sizing: content-box; + } + + .CodeMirror-measure { + position: absolute; + width: 100%; + height: 0; + overflow: hidden; + visibility: hidden; + } + + .CodeMirror-cursor { position: absolute; } + .CodeMirror-measure pre { position: static; } + + div.CodeMirror-cursors { + visibility: hidden; + position: relative; + z-index: 3; + } + div.CodeMirror-dragcursors { + visibility: visible; + } + + .CodeMirror-focused div.CodeMirror-cursors { + visibility: visible; + } + + .CodeMirror-selected { background: #d9d9d9; } + .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } + .CodeMirror-crosshair { cursor: crosshair; } + .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; } + .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; } + + .cm-searching { + background: #ffa; + background: rgba(255, 255, 0, .4); + } + + /* IE7 hack to prevent it from returning funny offsetTops on the spans */ + .CodeMirror span { *vertical-align: text-bottom; } + + /* Used to force a border model for a node */ + .cm-force-border { padding-right: .1px; } + + @media print { + /* Hide the cursor when printing */ + .CodeMirror div.CodeMirror-cursors { + visibility: hidden; + } + } + + /* See issue #2901 */ + .cm-tab-wrap-hack:after { content: ''; } + + /* Help users use markselection to safely style text background */ + span.CodeMirror-selectedtext { background: none; } +} \ No newline at end of file diff --git a/src/components/Editor/Editor.js b/src/components/Editor/Editor.js deleted file mode 100644 index 8fbafa541..000000000 --- a/src/components/Editor/Editor.js +++ /dev/null @@ -1,60 +0,0 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; - -import MarkdownEditor from '../../components/MarkdownEditor'; - -import { - updateText, - replaceText, -} from '../../actions'; - -import constants from '../../constants'; - -import styles from './Editor.scss'; - -class Editor extends Component { - static propTypes = { - editMarkdown: React.PropTypes.func.isRequired, - text: React.PropTypes.string, - replaceText: React.PropTypes.func.isRequired, - showHistorySidebar: React.PropTypes.bool.isRequired, - } - - render() { - return ( -
-
- -
-
- ); - } -} - -const mapStateToProps = (state) => { - return { - text: state.text.text, - editor: state.editor, - showHistorySidebar: state.historySidebar.visible, - revisions: state.text.revisions, - }; -}; - -const mapDispatchToProps = (dispatch) => { - return { - editMarkdown: (text) => { - dispatch(updateText(text, 'markdown')); - }, - }; -}; - -Editor = connect( - mapStateToProps, - mapDispatchToProps, -)(Editor); - -export default Editor; diff --git a/src/components/Editor/Editor.scss b/src/components/Editor/Editor.scss deleted file mode 100644 index 6d832691c..000000000 --- a/src/components/Editor/Editor.scss +++ /dev/null @@ -1,16 +0,0 @@ -.container { - display: flex; - padding-top: 48px; -} - -.panel { - width: 50%; -} - -.fullscreen { - width: 100%; -} - -.markdown { - background-color: #ffffff; -} diff --git a/src/components/Flex.js b/src/components/Flex.js index 54bb1d6cd..3d6053c6a 100644 --- a/src/components/Flex.js +++ b/src/components/Flex.js @@ -24,7 +24,7 @@ Flex.defaultProps = { }; Flex.propTypes = { - children: React.PropTypes.arrayOf(React.PropTypes.node).isRequired, + children: React.PropTypes.node.isRequired, direction: React.PropTypes.string, justify: React.PropTypes.string, align: React.PropTypes.string, diff --git a/src/components/Layout/Layout.js b/src/components/Layout/Layout.js index 4984ad5b1..6200781a3 100644 --- a/src/components/Layout/Layout.js +++ b/src/components/Layout/Layout.js @@ -1,4 +1,5 @@ import React from 'react'; +import _truncate from 'lodash/truncate'; import { connect } from 'react-redux'; import Link from 'react-router/lib/Link'; @@ -9,8 +10,8 @@ import styles from './Layout.scss'; class Layout extends React.Component { static propTypes = { - actions: React.PropTypes.arrayOf(React.PropTypes.node), - title: React.PropTypes.node, + actions: React.PropTypes.node, + title: React.PropTypes.string, } render() { @@ -21,7 +22,11 @@ class Layout extends React.Component { { this.props.teamName } - { this.props.title } + { this.props.title ? ( + { _truncate(this.props.title, 60) } + ) : ( + Untitled document + )} diff --git a/src/components/Layout/Layout.scss b/src/components/Layout/Layout.scss index c19bf7034..c7ff6aa49 100644 --- a/src/components/Layout/Layout.scss +++ b/src/components/Layout/Layout.scss @@ -41,3 +41,7 @@ text-decoration: none; margin-right: 15px; } + +.untitled { + color: #ccc; +} \ No newline at end of file diff --git a/src/index.js b/src/index.js index c2b0bbd8e..feedcd4ef 100644 --- a/src/index.js +++ b/src/index.js @@ -20,7 +20,7 @@ import 'utils/base-styles.scss'; import 'fonts/atlas/atlas.css'; import Home from 'scenes/Home'; -// import App from 'scenes/App'; +import Editor from 'scenes/Editor'; import Dashboard from 'scenes/Dashboard'; import Atlas from 'scenes/Atlas'; import SlackAuth from 'scenes/SlackAuth'; @@ -50,6 +50,7 @@ persistStore(store, { + diff --git a/src/reducers/EditorReducer.js b/src/reducers/EditorReducer.js deleted file mode 100644 index a610c8b7f..000000000 --- a/src/reducers/EditorReducer.js +++ /dev/null @@ -1,62 +0,0 @@ -const defaultTest = `# Welcome to Beautiful Atlas - -This is just a small preview here's what you can do: - -- Write markdown or rich text, you choose -- Dont' worry about saving -- One document for now -- More to come -` - -const state = { - previousTest: null, - text: null, - unsavedChanges: false, -}; - -const text = (state = state, action) => { - - switch (action.type) { - case UPDATE_TEXT: { - let unsavedChanges = false; - if (lastRevision && lastRevision.text !== state.text) { - unsavedChanges = true; - } - return { - ...state, - unsavedChanges, - text: action.text, - }; - } - case ADD_REVISION: { - // Create new revision if it differs from the previous one - if (!lastRevision || lastRevision.text !== state.text) { - const lastId = lastRevision ? lastRevision.id : 0; - return { - ...state, - revisions: [ - ...state.revisions, - { - id: lastId + 1, - text: state.text, - created_at: action.createdAt, - }, - ], - unsavedChanges: false, - }; - } else { - return state; - } - } - case REPLACE_TEXT: { - const newText = state.text.replace(action.originalText, action.replacedText); - - return { - ...state, - text: newText, - }; - } - default: - return state; - } -}; \ No newline at end of file diff --git a/src/reducers/editor.js b/src/reducers/editor.js new file mode 100644 index 000000000..dd1ae2dc5 --- /dev/null +++ b/src/reducers/editor.js @@ -0,0 +1,54 @@ +import { + UPDATE_TEXT, + REPLACE_TEXT, +} from 'actions/EditorActions'; + +const initialState = { + originalText: null, + text: null, + title: null, + unsavedChanges: false, +}; + +const parseHeader = (text) => { + const firstLine = text.split(/\r?\n/)[0]; + const match = firstLine.match(/^#+ +(.*)$/); + + if (match) { + return match[1]; + } +} + +const editor = (state = initialState, action) => { + switch (action.type) { + case UPDATE_TEXT: { + const title = parseHeader(action.text); + + console.log(title); + + let unsavedChanges = false; + if (state.originalText !== action.text) { + unsavedChanges = true; + } + return { + ...state, + unsavedChanges, + text: action.text, + title: title || state.title, + }; + } + case REPLACE_TEXT: { + const newText = state.text.replace(action.originalText, action.replacedText); + + return { + ...state, + unsavedChanges: true, + text: newText, + }; + } + default: + return state; + } +}; + +export default editor; diff --git a/src/scenes/App/App.js b/src/scenes/App/App.js deleted file mode 100644 index 369793fc3..000000000 --- a/src/scenes/App/App.js +++ /dev/null @@ -1,57 +0,0 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; - -import styles from './App.scss'; - -import { - toggleEditors, - addRevision, - } from '../../actions'; - -import Header from '../../components/Header'; -import Editor from '../../components/Editor'; - -class App extends Component { - static propTypes = { - children: React.PropTypes.element, - addRevision: React.PropTypes.func.isRequired, - unsavedChanges: React.PropTypes.bool.isRequired, - } - - render() { - return ( -
-
-
- -
-
- ); - } -} - -const mapStateToProps = (state) => { - return { - activeEditors: state.activeEditors, - unsavedChanges: state.text.unsavedChanges, - }; -}; - -const mapDispatchToProps = (dispatch) => { - return { - addRevision: () => { - dispatch(addRevision()); - }, - }; -}; - -App = connect( - mapStateToProps, - mapDispatchToProps, -)(App); - -export default App; diff --git a/src/scenes/App/index.js b/src/scenes/App/index.js deleted file mode 100644 index 54374b9b6..000000000 --- a/src/scenes/App/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import App from './App'; -export default App; diff --git a/src/scenes/Atlas/Atlas.js b/src/scenes/Atlas/Atlas.js index ce6a3e48d..ee620a1fe 100644 --- a/src/scenes/Atlas/Atlas.js +++ b/src/scenes/Atlas/Atlas.js @@ -47,7 +47,7 @@ class Atlas extends React.Component { return ( New document + New document )} title={ data.name } > diff --git a/src/scenes/Editor/Editor.js b/src/scenes/Editor/Editor.js new file mode 100644 index 000000000..acfcadd2e --- /dev/null +++ b/src/scenes/Editor/Editor.js @@ -0,0 +1,70 @@ +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; + +import { + updateText, + replaceText, +} from 'actions/EditorActions'; + +import styles from './Editor.scss'; +import 'assets/styles/codemirror.css'; + +import Layout from 'components/Layout'; +import Flex from 'components/Flex'; +import MarkdownEditor from 'components/MarkdownEditor'; + +import SaveAction from './components/SaveAction'; +import MoreAction from './components/MoreAction'; + +class Editor extends Component { + static propTypes = { + updateText: React.PropTypes.func.isRequired, + replaceText: React.PropTypes.func.isRequired, + text: React.PropTypes.string, + title: React.PropTypes.string, + } + + render() { + return ( + + + +
+ )} + title={ this.props.title } + > + + + + + ); + } +} + +const mapStateToProps = (state) => { + return { + text: state.editor.text, + title: state.editor.title, + }; +}; + +const mapDispatchToProps = (dispatch) => { + return bindActionCreators({ + updateText, + replaceText, + }, dispatch) +}; + +Editor = connect( + mapStateToProps, + mapDispatchToProps, +)(Editor); + +export default Editor; diff --git a/src/scenes/App/App.scss b/src/scenes/Editor/Editor.scss similarity index 100% rename from src/scenes/App/App.scss rename to src/scenes/Editor/Editor.scss diff --git a/src/scenes/Editor/components/MoreAction.js b/src/scenes/Editor/components/MoreAction.js new file mode 100644 index 000000000..0e3a1ad01 --- /dev/null +++ b/src/scenes/Editor/components/MoreAction.js @@ -0,0 +1,12 @@ +import React from 'react'; +import { Arrow } from 'rebass'; + +const MoreAction = (props) => { + return ( +
+ +
+ ); +}; + +export default MoreAction; \ No newline at end of file diff --git a/src/scenes/Editor/components/SaveAction.js b/src/scenes/Editor/components/SaveAction.js new file mode 100644 index 000000000..59e0dc695 --- /dev/null +++ b/src/scenes/Editor/components/SaveAction.js @@ -0,0 +1,12 @@ +import React from 'react'; +import { Arrow } from 'rebass'; + +const SaveAction = (props) => { + return ( +
+ Save +
+ ); +}; + +export default SaveAction; \ No newline at end of file diff --git a/src/components/Editor/index.js b/src/scenes/Editor/index.js similarity index 100% rename from src/components/Editor/index.js rename to src/scenes/Editor/index.js