Modified reader entry point to use react-router with redux
This commit is contained in:
parent
a6cf429335
commit
a5043b3ea1
5
TODO.txt
5
TODO.txt
|
@ -24,10 +24,7 @@
|
|||
+ Make Remove Highlight Work with Contextual Disabling +
|
||||
|
||||
|
||||
TODAY:
|
||||
- Implement React-Router
|
||||
|
||||
|
||||
NEXT: Bring everything under single entry point w/ React Router
|
||||
|
||||
SHORT LIST:
|
||||
- Make Annotate Mode Ignore Keyboard Input
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
from flask import Blueprint, render_template, abort
|
||||
from flask import Blueprint, render_template, abort, redirect
|
||||
from jinja2 import TemplateNotFound
|
||||
|
||||
reader = Blueprint('reader', __name__)
|
||||
|
||||
@reader.route('/')
|
||||
def show_reader():
|
||||
return render_template('reader.html')
|
||||
@reader.route('/', defaults={'path': ''})
|
||||
def redirect_root(path):
|
||||
return redirect('/1')
|
||||
@reader.route('/<path:path>')
|
||||
def show_reader(path):
|
||||
return render_template('reader.html')
|
16
package.json
16
package.json
|
@ -11,16 +11,20 @@
|
|||
"author": "Alex Hunt",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"react": "^16.0.0",
|
||||
"react-dom": "^16.0.0",
|
||||
"react-redux": "^5.0.6",
|
||||
"redux": "^3.7.2",
|
||||
"bootstrap": "^4.1.0",
|
||||
"draft-js": "^0.10.4",
|
||||
"draft-js-export-html": "^1.2.0",
|
||||
"draft-js-import-html": "^1.2.1",
|
||||
"bootstrap": "^4.1.0",
|
||||
"font-awesome": "^4.7.0",
|
||||
"history": "^4.7.2",
|
||||
"popper.js": "^1.12.6",
|
||||
"font-awesome": "^4.7.0"
|
||||
"react": "^16.0.0",
|
||||
"react-dom": "^16.0.0",
|
||||
"react-redux": "^5.0.6",
|
||||
"react-router": "^4.2.0",
|
||||
"react-router-dom": "^4.2.2",
|
||||
"react-router-redux": "^5.0.0-alpha.9",
|
||||
"redux": "^3.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.26.0",
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import React from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
import romanize from '../mixins/romanize'
|
||||
|
||||
export const ReaderEditButton = ({onClick}) =>
|
||||
|
@ -19,9 +21,9 @@ export const ReaderAnnotateButton = ({onClick}) =>
|
|||
|
||||
export const ChapterButton = ({chapter, currentChapter, onClick}) =>
|
||||
<div className ='chapter_button text-center'>
|
||||
<button onClick={()=>onClick(chapter.id)} className={currentChapter.id === chapter.id ? 'btn btn-dark btn-lg' : 'btn btn-outline-dark btn-lg inactive_button'}>
|
||||
<Link to={'/'+ chapter.number} className={currentChapter.id === chapter.id ? 'btn btn-dark btn-lg active_button' : 'btn btn-outline-dark btn-lg inactive_button'}>
|
||||
{romanize(chapter.number)}. {chapter.title}
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
export const NoteButton = ({note, currentNote, onClick}) =>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { Route } from 'react-router'
|
||||
|
||||
import Navbar from '../components/navbar'
|
||||
import Content from '../components/content'
|
||||
|
@ -13,20 +14,22 @@ const JoyceReaderPage = ({currentDocument, loadingToggle, annotationNote}) =>
|
|||
<div>
|
||||
<Navbar />
|
||||
<div id='joyce_reader' className='container-fluid'>
|
||||
<div className="row">
|
||||
<JoyceReaderSidebarContainer />
|
||||
<Content>
|
||||
{loadingToggle === true &&
|
||||
<LoadingSpinner size={4} />
|
||||
}
|
||||
{(Object.keys(currentDocument).length > 0 && loadingToggle === false) &&
|
||||
<JoyceReaderContentContainer />
|
||||
}
|
||||
{(Object.keys(currentDocument).length === 0 && loadingToggle === false) &&
|
||||
<ReaderWelcome />
|
||||
}
|
||||
</Content>
|
||||
</div>
|
||||
<Route path='/'>
|
||||
<div className="row">
|
||||
<JoyceReaderSidebarContainer />
|
||||
<Content>
|
||||
{loadingToggle === true &&
|
||||
<LoadingSpinner size={4} />
|
||||
}
|
||||
{(Object.keys(currentDocument).length > 0 && loadingToggle === false) &&
|
||||
<JoyceReaderContentContainer />
|
||||
}
|
||||
{(Object.keys(currentDocument).length === 0 && loadingToggle === false) &&
|
||||
<ReaderWelcome />
|
||||
}
|
||||
</Content>
|
||||
</div>
|
||||
</Route>
|
||||
</div>
|
||||
<AnnotationModal annotationNote={annotationNote} />
|
||||
</div>
|
||||
|
|
|
@ -28,8 +28,9 @@ store.dispatch(getDocumentList({
|
|||
state: 'currentDocType'
|
||||
}))
|
||||
|
||||
// Hacky way to fetch first chapter after async call above has completed.
|
||||
// TODO: Add number lookup to API?
|
||||
// TODO: Remove when
|
||||
// API can handle number lookups
|
||||
// Routing can handle / => /1
|
||||
setTimeout(
|
||||
() => {
|
||||
const firstDocument = getFirstDocument(store, docType)
|
||||
|
|
|
@ -49,6 +49,21 @@ const convertToPlainText = contentState => {
|
|||
)
|
||||
}
|
||||
|
||||
const selectChapterIDByNumber = (store, number) => {
|
||||
for (const chapter of store.getState().chapters) {
|
||||
if (number === chapter.number) {
|
||||
return chapter.id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const parseNumberFromPath = path => {
|
||||
const match = /^\/([0-9]*)/.exec(path)
|
||||
const number = Number(match[1])
|
||||
console.log('Hey!', number)
|
||||
return number
|
||||
}
|
||||
|
||||
// API Middleware
|
||||
export const joyceAPI = store => next => action => {
|
||||
next(action)
|
||||
|
@ -60,6 +75,12 @@ export const joyceAPI = store => next => action => {
|
|||
store.dispatch(getDocumentList(response))
|
||||
)
|
||||
}
|
||||
if (action.status === 'success' && action.state === 'initialPageLoad') {
|
||||
HTTPGetDocumentList(action.docType, action.state).then(response => {
|
||||
const pathName = store.getState().routerReducer.location.pathname
|
||||
store.dispatch(setCurrentDocument(selectChapterIDByNumber(store, parseNumberFromPath(pathName)), action.docType))
|
||||
})
|
||||
}
|
||||
break
|
||||
case 'GET_DOCUMENT_TEXT':
|
||||
if (action.status === 'request') {
|
||||
|
@ -144,7 +165,15 @@ export const joyceAPI = store => next => action => {
|
|||
store.dispatch(getSearchResults(response))
|
||||
)
|
||||
}
|
||||
break
|
||||
break
|
||||
case '@@router/LOCATION_CHANGE':
|
||||
if (/^\/[0-9]*/.test(action.payload.pathname)) {
|
||||
for (const chapter of store.getState().chapters) {
|
||||
if (action.payload.pathname === '/' + chapter.number) {
|
||||
store.dispatch(setCurrentDocument(chapter.id, 'chapters'))
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
|
|
@ -1,42 +1,42 @@
|
|||
// node_modules
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { createStore, applyMiddleware } from 'redux'
|
||||
import { Provider } from 'react-redux'
|
||||
import 'bootstrap'
|
||||
import { ConnectedRouter, routerReducer, routerMiddleware, push } from 'react-router-redux'
|
||||
import createHistory from 'history/createBrowserHistory'
|
||||
// import 'bootstrap'
|
||||
|
||||
// src packages
|
||||
import reduceReader from './reducers/reduceReader'
|
||||
import { getDocumentList } from './actions/apiActions'
|
||||
import { setCurrentDocument, setDocType } from './actions/userActions'
|
||||
import { logger, joyceAPI } from './middleware/'
|
||||
import { getFirstDocument } from './mixins/firstDocument'
|
||||
import JoyceReaderPageContainer from './containers/joyceReaderPageContainer'
|
||||
import JoyceEditorPageContainer from './containers/joyceEditorPageContainer'
|
||||
|
||||
// TODO: Pass routing from Flask?
|
||||
|
||||
let docType = 'chapters'
|
||||
let store = createStore(reduceReader, applyMiddleware(logger, joyceAPI))
|
||||
const history = createHistory()
|
||||
const router = routerMiddleware(history)
|
||||
|
||||
const docType = 'chapters'
|
||||
const store = createStore(reduceReader, applyMiddleware(logger, joyceAPI, router))
|
||||
store.dispatch(setDocType(docType))
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<JoyceReaderPageContainer />
|
||||
<ConnectedRouter history={history}>
|
||||
<div>
|
||||
<JoyceReaderPageContainer />
|
||||
</div>
|
||||
</ConnectedRouter>
|
||||
</Provider>,
|
||||
document.getElementById('wrapper')
|
||||
)
|
||||
|
||||
store.dispatch(getDocumentList({
|
||||
docType: docType,
|
||||
state: 'currentDocType'
|
||||
}))
|
||||
|
||||
// Hacky way to fetch first chapter after async call above has completed.
|
||||
// TODO: Add number lookup to API?
|
||||
setTimeout(
|
||||
() => {
|
||||
const firstDocument = getFirstDocument(store, docType)
|
||||
if (firstDocument) {
|
||||
store.dispatch(setCurrentDocument(firstDocument.id, docType))
|
||||
}
|
||||
},
|
||||
1000
|
||||
)
|
||||
state: 'initialPageLoad'
|
||||
}))
|
|
@ -8,6 +8,8 @@ import annotationNote from './annotationNote'
|
|||
import highlightToggle from './highlightToggle'
|
||||
import loadingToggle from './loadingToggle'
|
||||
import docType from './docType'
|
||||
import { routerReducer } from 'react-router-redux'
|
||||
|
||||
|
||||
const reduceReader = combineReducers({
|
||||
chapters,
|
||||
|
@ -17,7 +19,8 @@ const reduceReader = combineReducers({
|
|||
docType,
|
||||
currentDocument,
|
||||
highlightToggle,
|
||||
loadingToggle
|
||||
loadingToggle,
|
||||
routerReducer
|
||||
})
|
||||
|
||||
export default reduceReader
|
|
@ -20,24 +20,26 @@
|
|||
border: 1px solid $border_color;
|
||||
}
|
||||
|
||||
.chapter_button > button {
|
||||
.chapter_button > a {
|
||||
width: 100%;
|
||||
margin: 0.25% 0;
|
||||
padding: 0.2rem 1rem;
|
||||
font-size: 1rem;
|
||||
box-shadow: 2px 5px 10px 1px rgba(0, 0, 0, 0.3);
|
||||
|
||||
// &:not(.active_button) {
|
||||
// background-color: rgba(250, 250, 250, 0.8);
|
||||
// }
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: rgba(250, 250, 250, 0.8);
|
||||
}
|
||||
|
||||
.chapter_button > button.inactive_button:not(:hover) {
|
||||
background-color: rgba(250, 250, 250, 0.8);
|
||||
.chapter_button > a.inactive_button:not(:hover) {
|
||||
background-color: rgba(250, 250, 250, 1);
|
||||
}
|
||||
|
||||
.note_button > button.inactive_button:not(:hover) {
|
||||
.note_button > a.inactive_button:not(:hover) {
|
||||
background-color: rgba(250, 250, 250, 0.8);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue