Wired up /edit route re-using Reader components.
This commit is contained in:
parent
13b472cd2b
commit
7e2ec994f7
1
TODO.txt
1
TODO.txt
|
@ -20,6 +20,7 @@
|
|||
|
||||
- Error Handling
|
||||
- Unit Testing
|
||||
- Remove Flask-Webpack
|
||||
- Admin Access Restrictions (OAuth?)
|
||||
- Admin Page
|
||||
- Search Functionality
|
||||
|
|
|
@ -3,16 +3,20 @@ from flask_webpack import Webpack
|
|||
from werkzeug.serving import run_simple
|
||||
|
||||
from blueprints.reader import reader
|
||||
from blueprints.editor import editor
|
||||
from blueprints.api import api
|
||||
|
||||
# Initialize application
|
||||
application = Flask(__name__)
|
||||
|
||||
WEBPACK_MANIFEST_PATH = './static/manifest.json'
|
||||
|
||||
params = {
|
||||
'DEBUG': True,
|
||||
'WEBPACK_MANIFEST_PATH': './static/js/manifest.json'
|
||||
'WEBPACK_MANIFEST_PATH': WEBPACK_MANIFEST_PATH
|
||||
}
|
||||
|
||||
|
||||
application.config.update(params)
|
||||
|
||||
webpack = Webpack()
|
||||
|
@ -20,6 +24,7 @@ webpack.init_app(application)
|
|||
|
||||
# Register blueprints
|
||||
application.register_blueprint(reader)
|
||||
application.register_blueprint(editor, url_prefix='/edit')
|
||||
application.register_blueprint(api, url_prefix='/api')
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
from flask import Blueprint, render_template, abort
|
||||
from jinja2 import TemplateNotFound
|
||||
|
||||
editor = Blueprint('editor', __name__)
|
||||
|
||||
@editor.route('/')
|
||||
def show_reader():
|
||||
return render_template('editor.html')
|
|
@ -34,6 +34,7 @@
|
|||
"sass-loader": "^6.0.6",
|
||||
"style-loader": "^0.19.0",
|
||||
"sync-exec": "^0.6.2",
|
||||
"webpack": "^3.8.1"
|
||||
"webpack": "^3.8.1",
|
||||
"webpack-bundle-size-analyzer": "^2.7.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import React from 'react'
|
||||
import Navbar from '../components/navbar'
|
||||
import Sidebar from '../components/sidebar'
|
||||
import Content from '../components/content'
|
||||
|
||||
const EditorContainer = () =>
|
||||
<div>
|
||||
<Navbar />
|
||||
<div id='joyce_editor' className='container-fluid'>
|
||||
<div className="row">
|
||||
{console.log('Hey you')}
|
||||
<Sidebar />
|
||||
<Content />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
export default EditorContainer
|
|
@ -1,26 +1,20 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { createStore, applyMiddleware } from 'redux'
|
||||
import { Provider } from 'react-redux'
|
||||
import 'bootstrap'
|
||||
|
||||
const Editor = props =>
|
||||
<div className='col-sm-4'>
|
||||
import reduceEditor from './reducers/editor'
|
||||
import joyceAPIService from './middleware'
|
||||
import EditorContainer from './containers/editorContainer'
|
||||
|
||||
</div>
|
||||
let store = createStore(reduceEditor, applyMiddleware(joyceAPIService))
|
||||
|
||||
|
||||
const EditSidebar = props =>
|
||||
<EditChapterList chapters={props.chapters}/>
|
||||
|
||||
const EditChapterList = props =>
|
||||
{this.props.chapters.map(chapter =>
|
||||
<div>
|
||||
<EditChapterButton chapter={chapter} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
const EditChapterButton = props =>
|
||||
<a className=''>{props.chapter.name}</a>
|
||||
|
||||
const EditChapter = props =>
|
||||
<div className='text_wrapper'>
|
||||
{props.currentChapter.text}
|
||||
</div>
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<EditorContainer />
|
||||
</Provider>,
|
||||
document.getElementById('wrapper')
|
||||
)
|
||||
store.dispatch({type: 'GET_CHAPTER_DATA'})
|
||||
store.dispatch({type: 'GET_TEXT_DATA', id: 1})
|
|
@ -1,6 +1,6 @@
|
|||
import axios from 'axios'
|
||||
|
||||
let apiRoute = 'api/chapters/'
|
||||
let apiRoute = '/api/chapters/'
|
||||
|
||||
const joyceAPIService = state => next => action => {
|
||||
next(action)
|
||||
|
|
|
@ -4,11 +4,11 @@ import { createStore, applyMiddleware } from 'redux'
|
|||
import { Provider } from 'react-redux'
|
||||
import 'bootstrap'
|
||||
|
||||
import readerApp from './reducers'
|
||||
import reduceReader from './reducers/reader'
|
||||
import joyceAPIService from './middleware'
|
||||
import { ReaderContainer } from './containers/readerContainer'
|
||||
|
||||
let store = createStore(readerApp, applyMiddleware(joyceAPIService))
|
||||
let store = createStore(reduceReader, applyMiddleware(joyceAPIService))
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
|
|
|
@ -28,10 +28,10 @@ const currentChapter = (state={}, action) => {
|
|||
}
|
||||
}
|
||||
|
||||
const readerApp = combineReducers({
|
||||
const reduceEditor = combineReducers({
|
||||
chapters,
|
||||
currentChapter,
|
||||
highlightActive
|
||||
})
|
||||
|
||||
export default readerApp
|
||||
export default reduceEditor
|
|
@ -0,0 +1,37 @@
|
|||
import { combineReducers } from 'redux'
|
||||
import objectAssign from 'object-assign' // Object.assign() polyfill for older browsers
|
||||
|
||||
const chapters = (state=[], action) => {
|
||||
switch(action.type) {
|
||||
case 'GET_CHAPTER_DATA_RECEIVED':
|
||||
return action.data
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
const highlightActive = (state=false, action) => {
|
||||
switch(action.type) {
|
||||
case 'TOGGLE_HIGHLIGHT':
|
||||
return !state
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
const currentChapter = (state={}, action) => {
|
||||
switch(action.type) {
|
||||
case 'GET_TEXT_DATA_RECEIVED':
|
||||
return action.data
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
const reduceReader = combineReducers({
|
||||
chapters,
|
||||
currentChapter,
|
||||
highlightActive
|
||||
})
|
||||
|
||||
export default reduceReader
|
|
@ -0,0 +1,121 @@
|
|||
@import "custom";
|
||||
@import "node_modules/bootstrap/scss/bootstrap";
|
||||
|
||||
$bg_gradient1: #ede9de;
|
||||
$bg_gradient2: #e0dbb5;
|
||||
|
||||
$nav_gradient1: #152e3a;
|
||||
$nav_gradient2: #181b21;
|
||||
|
||||
$border_color: rgba(120,120,120,0.7);
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
html body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
background-color: rgba(211,211,211,1);
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
background: -webkit-linear-gradient(-15deg, $bg_gradient1, $bg_gradient2); /* For Safari 5.1 to 6.0 */
|
||||
background: -o-linear-gradient(-15deg, $bg_gradient1, $bg_gradient2); /* For Opera 11.1 to 12.0 */
|
||||
background: -moz-linear-gradient(-15deg, $bg_gradient1, $bg_gradient2); /* For Firefox 3.6 to 15 */
|
||||
background: linear-gradient(-15deg, $bg_gradient1, $bg_gradient2); /* Standard syntax */
|
||||
}
|
||||
|
||||
nav.navbar {
|
||||
background-color: rgba(10,10,10,1);
|
||||
background: -webkit-linear-gradient(0, $nav_gradient1, $nav_gradient2); /* For Safari 5.1 to 6.0 */
|
||||
background: -o-linear-gradient(0, $nav_gradient1, $nav_gradient2); /* For Opera 11.1 to 12.0 */
|
||||
background: -moz-linear-gradient(0, $nav_gradient1, $nav_gradient2); /* For Firefox 3.6 to 15 */
|
||||
background: linear-gradient(0, $nav_gradient1, $nav_gradient2); /* Standard syntax */
|
||||
box-shadow: 0px 4px 4px 1px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
a.navbar-brand {
|
||||
margin-left: 2%;
|
||||
font-size: 1.8em;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
nav a:hover {
|
||||
color: #b7b7b7;
|
||||
}
|
||||
|
||||
#wrapper {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#wrapper > div {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#joyce_reader {
|
||||
overflow: hidden;
|
||||
width: 95%;
|
||||
height: 100%;
|
||||
background-color: rgba(256,256,256,0.5);
|
||||
border-left: 1px solid $border_color;
|
||||
border-right: 1px solid $border_color;
|
||||
}
|
||||
|
||||
#joyce_reader > div {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
background-color: rgba(250,250,250,.8);
|
||||
margin: -2.5% 2% 1.5% 2%;
|
||||
padding: 1%;
|
||||
border: 1px solid $border_color;
|
||||
border-radius: 0 0 5px 5px;
|
||||
box-shadow: 2px 5px 10px 1px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
#content_window {
|
||||
height: 44em;
|
||||
background-color: rgba(250,250,250,.8);
|
||||
margin: 0 2% 1.5% 2%;
|
||||
padding: 2% 2%;
|
||||
border: 1px solid $border_color;
|
||||
border-radius: 5px;
|
||||
box-shadow: 2px 5px 10px 1px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
#page {
|
||||
height: 100%;
|
||||
background-color: rgba(256,256,256,.8);
|
||||
box-shadow: 2px 5px 10px 1px rgba(0, 0, 0, 0.3);
|
||||
padding: 3% 8%;
|
||||
border: 1px solid $border_color;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
#page {
|
||||
|
||||
h2 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h3 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#highlight_button > button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sidebar_spacer {
|
||||
margin: 3% 0;
|
||||
border: 1px solid $border_color;
|
||||
}
|
||||
|
||||
.chapter_button > button {
|
||||
width: 100%;
|
||||
margin: 1% 0 1% 0;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<!doctype html>
|
||||
<head>
|
||||
<title>Joyce Editor</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!-- <link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}"> -->
|
||||
<link rel="manifest" href="/static/manifest.json">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Reader Layout -->
|
||||
<div id="wrapper">
|
||||
</div>
|
||||
<!-- Scripts -->
|
||||
<script src="{{asset_url_for('editor.js')}}"></script>
|
||||
</body>
|
|
@ -3,7 +3,7 @@
|
|||
<title>Joyce</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!-- <link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}"> -->
|
||||
<link rel="manifest" href="static/js/manifest.json">
|
||||
<link rel="manifest" href="static/manifest.json">
|
||||
<link rel="icon" type="image/png" href="static/image/icon.png">
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -16,12 +16,16 @@ module.exports = {
|
|||
rootAssetPath + 'reader',
|
||||
rootAssetPath + 'stylesheets/' + 'reader.scss'
|
||||
],
|
||||
editor: [
|
||||
rootAssetPath + 'editor',
|
||||
rootAssetPath + 'stylesheets/' + 'editor.scss'
|
||||
]
|
||||
// style: [
|
||||
// ]
|
||||
},
|
||||
output: {
|
||||
publicPath: "static/js/",
|
||||
filename: 'reader.[chunkhash].js',
|
||||
publicPath: "/static/js/",
|
||||
filename: '[name].[chunkhash].js',
|
||||
path: path.resolve(__dirname, 'static/js/')
|
||||
},
|
||||
watch: true,
|
||||
|
@ -62,7 +66,7 @@ module.exports = {
|
|||
plugins: [
|
||||
// TODO: Dev / Prod Config
|
||||
// new webpack.optimize.UglifyJsPlugin(),
|
||||
new ManifestRevisionPlugin(path.join('static/js', 'manifest.json'), {
|
||||
new ManifestRevisionPlugin(path.join('static/', 'manifest.json'), {
|
||||
rootAssetPath: rootAssetPath
|
||||
}),
|
||||
new webpack.ProvidePlugin({
|
||||
|
|
Loading…
Reference in New Issue