From 89952ec168b4ad1e7457f576a0b42d7bc6dec150 Mon Sep 17 00:00:00 2001 From: cha0s Date: Tue, 5 Mar 2019 23:20:26 -0600 Subject: [PATCH] flow: stuff --- .gitignore | 1 + actions.js | 31 +++++------- frontend/app/api.js | 69 +++++++++++++++++++++++++++ frontend/app/component.js | 45 ++++++++++++++++++ frontend/app/component.scss | 58 +++++++++++++++++++++++ frontend/app/ducks.js | 45 ++++++++++++++++++ frontend/app/editor/component.js | 24 ++++++++++ frontend/app/editor/index.js | 31 ++++++++++++ frontend/app/fixtures.js | 45 ++++++++++++++++++ {styles => frontend/app}/forms.scss | 2 +- frontend/app/index.js | 71 ++++++++++++++++++++-------- frontend/app/index.scss | 58 +++++++++++++++++++++-- {styles => frontend/app}/mixins.scss | 0 frontend/app/tabs/component.js | 20 ++++++++ frontend/app/tabs/component.scss | 4 ++ frontend/app/tabs/index.js | 3 ++ frontend/app/tabs/tab.js | 23 +++++++++ frontend/app/tabs/tab.scss | 21 ++++++++ frontend/app/welcome.js | 28 ----------- frontend/app/welcome.scss | 27 ----------- frontend/app/workspace.js | 45 ++++++++++++++++++ frontend/{root => }/dev-tools.js | 7 +-- frontend/index.js | 15 ++++-- frontend/reducer.js | 7 +++ frontend/root/index.dev.js | 26 ---------- frontend/root/index.js | 6 --- frontend/root/index.prod.js | 19 -------- frontend/root/index.scss | 9 ---- frontend/root/reducer.js | 9 ---- frontend/root/saga.js | 8 ---- frontend/root/store.dev.js | 28 ----------- frontend/root/store.prod.js | 21 -------- frontend/saga.js | 7 +++ frontend/store.dev.js | 33 +++++++++++++ frontend/{root => }/store.js | 0 hooks.js | 23 ++++++++- index.js | 2 +- package.json | 14 ++++-- response.dev.js | 5 -- styles/global.scss | 53 +-------------------- webpack.config.js | 21 ++++++-- 41 files changed, 666 insertions(+), 298 deletions(-) create mode 100644 .gitignore create mode 100644 frontend/app/api.js create mode 100644 frontend/app/component.js create mode 100644 frontend/app/component.scss create mode 100644 frontend/app/ducks.js create mode 100644 frontend/app/editor/component.js create mode 100644 frontend/app/editor/index.js create mode 100644 frontend/app/fixtures.js rename {styles => frontend/app}/forms.scss (98%) rename {styles => frontend/app}/mixins.scss (100%) create mode 100644 frontend/app/tabs/component.js create mode 100644 frontend/app/tabs/component.scss create mode 100644 frontend/app/tabs/index.js create mode 100644 frontend/app/tabs/tab.js create mode 100644 frontend/app/tabs/tab.scss delete mode 100644 frontend/app/welcome.js delete mode 100644 frontend/app/welcome.scss create mode 100644 frontend/app/workspace.js rename frontend/{root => }/dev-tools.js (88%) create mode 100644 frontend/reducer.js delete mode 100644 frontend/root/index.dev.js delete mode 100644 frontend/root/index.js delete mode 100644 frontend/root/index.prod.js delete mode 100644 frontend/root/index.scss delete mode 100644 frontend/root/reducer.js delete mode 100644 frontend/root/saga.js delete mode 100644 frontend/root/store.dev.js delete mode 100644 frontend/root/store.prod.js create mode 100644 frontend/saga.js create mode 100644 frontend/store.dev.js rename frontend/{root => }/store.js (100%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..35deabf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/frontend/old diff --git a/actions.js b/actions.js index 639dca6..bed2b34 100644 --- a/actions.js +++ b/actions.js @@ -1,5 +1,3 @@ -const {invokeHookSerial} = require('@truss/truss'); - const {Responder} = require('./response.dev'); let responder = new Responder(); @@ -7,24 +5,21 @@ responder.start(); module.exports = () => ({ - 'truss/http-get': (action) => { - const {payload: {headers}} = action; - - delete headers.host; - delete headers.connection; - - return responder.respond(action).then(({html, headers: resHeaders}) => { - return invokeHookSerial('truss/web-response', { - status: 200, - headers: {...defaultResponseHeaders(), ...resHeaders}, - html, - }, headers); - }); + '@truss/http-get': async (action) => { + const {html, headers} = await responder.respond(action); + return { + status: 200, + headers: { + ...defaultResponseHeaders(), + ...headers + }, + response: html, + }; }, - 'truss/schema': () => { - return {executors: ['truss/http-get']}; - }, + '@truss/schema': () => ({ + executors: ['@truss/http-get'], + }), }); function defaultResponseHeaders() { diff --git a/frontend/app/api.js b/frontend/app/api.js new file mode 100644 index 0000000..5d129da --- /dev/null +++ b/frontend/app/api.js @@ -0,0 +1,69 @@ +import {RSAA} from 'redux-api-middleware'; + +const PERSEA_FRONTHOST = '10.0.0.93'; + +export function createActionTypes(type, prefix) { + return ['REQUEST', 'SUCCESS', 'FAILURE'].reduce((actions, action) => { + return { + ...actions, + [`${type}_${action}`]: `${prefix}/${type}_${action}`, + }; + }, {}); +} + +export function createCall(uri, types, type) { + const prefix = `http://${PERSEA_FRONTHOST}/api`; + return { + [RSAA]: { + endpoint: `${prefix}${uri}`, + method: 'GET', + headers: { + 'Content-Type': 'application/json' + }, + types: ['REQUEST', 'SUCCESS', 'FAILURE'].map((action) => { + return types[`${type}_${action}`] + }), + fetch: managedFetch, + }, + }; +} + +export class ApiRequestHandler { + + doesFetchEndpoint(input) { + return false; + } + + async fetch(input, init) { + return new Response(null); + } + + static normalizeRequestUrl(input) { + return ('string' === typeof input) ? input : input.url; + } + +} + +const handlers = []; + +export function registerApiRequestHandler(handler) { + handlers.push(handler); +} + +function handlerForInput(input) { + for (const handler of handlers) { + if (handler.doesFetchEndpoint(input)) { + return handler; + } + } +} + +export function managedFetch(input, init) { + const handler = handlerForInput(input); + if (handler) { + return handler.fetch(input, init); + } + else { + return fetch(input, init); + } +} diff --git a/frontend/app/component.js b/frontend/app/component.js new file mode 100644 index 0000000..0437125 --- /dev/null +++ b/frontend/app/component.js @@ -0,0 +1,45 @@ +import React from 'react'; +import {hot} from 'react-hot-loader'; +import {BrowserRouter} from 'react-router-dom'; +import {compose} from 'redux'; +import {connect} from 'react-redux'; + +import contempo from 'contempo'; + +import Editor from './editor/component'; +import {ducks} from './index'; +import {createMapDispatchToProps} from './ducks'; + +import DevTools from '../dev-tools'; + +const decorate = compose( + hot(module), + contempo(require('./component.scss')), + connect( + (state) => ({ + currentWorkspace: state.workspace.current, + }), + createMapDispatchToProps(ducks) + ), +) + +function App({ + currentWorkspace, + workspace, +}) { + return + +
+ + +
+
+
+ +
+
; +}; + +export default decorate(App); diff --git a/frontend/app/component.scss b/frontend/app/component.scss new file mode 100644 index 0000000..2225b15 --- /dev/null +++ b/frontend/app/component.scss @@ -0,0 +1,58 @@ +@import './forms.scss'; + +.app { + background-color: #222; + height: 100%; + width: 100%; +} + +.aside { + font-size: 0.8em; +} + +button { + &:hover { + background-color: #555; + } +} + +button, input, select, option { + + &[disabled] { + filter: grayscale(1); + opacity: 0.5; + + &:hover { + background-color: transparent; + } + } + + &:focus { + outline: none; + box-shadow: inset 0 0 1pt 0.5pt #CCC, 0 0 1pt 0.5pt #CCC + } +} + +hr { + border: none; + border-bottom: 1px solid #333; + margin: 1em 0; +} + +.loading { + align-items: center; + display: flex; + height: 100%; + justify-content: center; + width: 100%; + + svg { + height: 25%; + width: 25%; + } +} + +.editor.avocado-environment { + height: 100%; + width: 100%; +} diff --git a/frontend/app/ducks.js b/frontend/app/ducks.js new file mode 100644 index 0000000..e4465af --- /dev/null +++ b/frontend/app/ducks.js @@ -0,0 +1,45 @@ +import {combineReducers} from 'redux'; +import {all, call} from 'redux-saga/effects'; + +export function createMapDispatchToProps(ducks) { + return (dispatch) => { + const map = {}; + for (const i in ducks) { + map[i] = {}; + for (const j in ducks[i].actions.creators) { + map[i][j] = (...args) => { + return dispatch(ducks[i].actions.creators[j](...args)); + } + } + } + return map; + }; +} + +export function createReducer(ducks) { + const map = {}; + for (const i in ducks) { + map[i] = ducks[i].reducer; + } + return combineReducers(map); +} + +export function createSaga(ducks) { + const sagas = []; + for (const i in ducks) { + if (!ducks[i].saga) { + continue; + } + sagas.push(call(ducks[i].saga)); + } + return function* () { + yield all(sagas); + } +} + +export function compose(ducks) { + return { + reducer: createReducer(ducks), + saga: createSaga(ducks), + } +} diff --git a/frontend/app/editor/component.js b/frontend/app/editor/component.js new file mode 100644 index 0000000..5118ebf --- /dev/null +++ b/frontend/app/editor/component.js @@ -0,0 +1,24 @@ +import React from 'react'; +import {compose} from 'redux'; +import {connect} from 'react-redux'; + +import Tabs from '../tabs/component'; +import Tab from '../tabs/tab'; + +const decorate = compose( + connect( + (state) => ({ + tabs: state.editor.tabs, + }), + ) +); + +function Editor({tabs}) { + return
+ + + +
; +} + +export default decorate(Editor); diff --git a/frontend/app/editor/index.js b/frontend/app/editor/index.js new file mode 100644 index 0000000..8895f63 --- /dev/null +++ b/frontend/app/editor/index.js @@ -0,0 +1,31 @@ +import {combineReducers} from 'redux' + +const types = { + EDITOR_CREATE_TAB: '@@persea/EDITOR_CREATE_TAB', + EDITOR_CLOSE_TAB: '@@persea/EDITOR_CLOSE_TAB', +}; + +const creators = { + createTab: (title, uri) => { + return { + type: types.EDITOR_CREATE_TAB, + payload: { + title, + uri, + }, + }; + }, +}; + +export const actions = {types, creators}; + +export const reducer = combineReducers({ + tabs: (state = [], action) => { + switch (action.type) { + case types.EDITOR_CREATE_TAB: + return [...state, action.payload]; + default: + return state; + } + }, +}); diff --git a/frontend/app/fixtures.js b/frontend/app/fixtures.js new file mode 100644 index 0000000..859e9a8 --- /dev/null +++ b/frontend/app/fixtures.js @@ -0,0 +1,45 @@ +import {ApiRequestHandler, registerApiRequestHandler} from './api'; + +export const data = { + '/api/config.json': { + workspace: '/workspace/test', + }, + '/api/workspace/test': { + name: "Some workspace", + tree: [], + open: [ + { + uri: "" + } + ], + settings: {}, + }, +}; + +function lookupData(url) { + const {pathname} = new URL(url); + return data[pathname]; +} + +class FixtureApiRequestHandler extends ApiRequestHandler { + + doesFetchEndpoint(input) { + const url = ApiRequestHandler.normalizeRequestUrl(input); + return !!lookupData(url); + } + + fetch(input, init) { + const url = ApiRequestHandler.normalizeRequestUrl(input); + const data = lookupData(url); + return new Response( + JSON.stringify(data), { + headers: { + 'Content-Type': 'application/json', + }, + } + ); + } + +} + +registerApiRequestHandler(new FixtureApiRequestHandler()); diff --git a/styles/forms.scss b/frontend/app/forms.scss similarity index 98% rename from styles/forms.scss rename to frontend/app/forms.scss index 70e10fa..8c6aaa1 100644 --- a/styles/forms.scss +++ b/frontend/app/forms.scss @@ -7,7 +7,7 @@ button, input, select { button { border: 1px solid #333; - padding: 0; + padding: 2em; &:hover { background-color: #555; diff --git a/frontend/app/index.js b/frontend/app/index.js index d6b2dcb..d10f732 100644 --- a/frontend/app/index.js +++ b/frontend/app/index.js @@ -1,25 +1,54 @@ -import React from 'react'; +import {put, take} from 'redux-saga/effects'; -import classnames from 'classnames'; -import {Route, Switch} from 'react-router'; +import {compose} from './ducks'; +import * as editor from './editor'; +import * as workspace from './workspace'; -import Welcome from './welcome'; -function App() { +import {createActionTypes, createCall} from './api'; - return
- - - -
; +const types = { + APPLICATION_START: '@@persea/APPLICATION_START', + ...createActionTypes('APPLICATION_CONFIG_LOAD', '@@persea'), +}; + +const creators = { + loadConfig: () => { + return createCall('/config.json', types, 'APPLICATION_CONFIG_LOAD'); + }, + start: () => { + return { + type: types.APPLICATION_START, + payload: null, + }; + }, +}; + +export const actions = {types, creators}; + +export const ducks = { + editor, + workspace, +}; + +const {reducer, saga: ducksSaga} = compose(ducks); + +export {reducer}; + +export function* saga() { + yield ducksSaga; + // Wait for application start. + yield take(types.APPLICATION_START); + // Load fixtures. + require('./fixtures'); + // Read config. + yield put(creators.loadConfig()); + const {payload: config} = yield take(types.APPLICATION_CONFIG_LOAD_SUCCESS); + // Workspace to load? + if (config.workspace) { + yield put(workspace.actions.creators.load(config.workspace)); + } + // Put the dummy tab. + else { + yield put(editor.actions.creators.createTab('Welcome', '/foo/bar')); + } } - -import contempo from 'contempo'; -App = contempo(App, require('./index.scss')); - -import {hot} from 'react-hot-loader'; -App = hot(module)(App); - -export default App; diff --git a/frontend/app/index.scss b/frontend/app/index.scss index 90a5f4e..f3ba059 100644 --- a/frontend/app/index.scss +++ b/frontend/app/index.scss @@ -1,6 +1,58 @@ -.app { - background-color: #444444; - color: #fff; +@import './forms.scss'; + +.app-container { + background-color: #222; + height: 100%; + width: 100%; +} + +.aside { + font-size: 0.8em; +} + +button { + &:hover { + background-color: #555; + } +} + +button, input, select, option { + + &[disabled] { + filter: grayscale(1); + opacity: 0.5; + + &:hover { + background-color: transparent; + } + } + + &:focus { + outline: none; + box-shadow: inset 0 0 1pt 0.5pt #CCC, 0 0 1pt 0.5pt #CCC + } +} + +hr { + border: none; + border-bottom: 1px solid #333; + margin: 1em 0; +} + +.loading { + align-items: center; + display: flex; + height: 100%; + justify-content: center; + width: 100%; + + svg { + height: 25%; + width: 25%; + } +} + +.editor.avocado-environment { height: 100%; width: 100%; } diff --git a/styles/mixins.scss b/frontend/app/mixins.scss similarity index 100% rename from styles/mixins.scss rename to frontend/app/mixins.scss diff --git a/frontend/app/tabs/component.js b/frontend/app/tabs/component.js new file mode 100644 index 0000000..05a2631 --- /dev/null +++ b/frontend/app/tabs/component.js @@ -0,0 +1,20 @@ +import React from 'react'; +import {compose} from 'redux'; + +import contempo from 'contempo'; + +import Tab from './tab'; + +const decorate = compose( + contempo(require('./component.scss')) +); + +function Tabs({ + children, +}) { + return
+ {children} +
+} + +export default decorate(Tabs); diff --git a/frontend/app/tabs/component.scss b/frontend/app/tabs/component.scss new file mode 100644 index 0000000..7fa6a1d --- /dev/null +++ b/frontend/app/tabs/component.scss @@ -0,0 +1,4 @@ +.tabs { + width: 100%; + height: 3em; +} diff --git a/frontend/app/tabs/index.js b/frontend/app/tabs/index.js new file mode 100644 index 0000000..988caa6 --- /dev/null +++ b/frontend/app/tabs/index.js @@ -0,0 +1,3 @@ +// persea:///workspace +// http://api-server.com/workspace +// file:///persea-data-dir/workspace diff --git a/frontend/app/tabs/tab.js b/frontend/app/tabs/tab.js new file mode 100644 index 0000000..85877d1 --- /dev/null +++ b/frontend/app/tabs/tab.js @@ -0,0 +1,23 @@ +import React from 'react'; +import {compose} from 'redux'; + +import contempo from 'contempo'; + +const decorate = compose( + contempo(require('./tab.scss')) +); + +function Tab({ + basename, + icon, + path +}) { + return
+ {icon} + {basename} + {path} + • +
; +} + +export default decorate(Tab); diff --git a/frontend/app/tabs/tab.scss b/frontend/app/tabs/tab.scss new file mode 100644 index 0000000..e5d8b72 --- /dev/null +++ b/frontend/app/tabs/tab.scss @@ -0,0 +1,21 @@ +.tab { + display: flex; + height: 3em; + float: left; + padding: 0.5em; + cursor: pointer; + align-items: center; + + .close { + padding: 0 0.5em; + } + .icon { + padding-right: 0.5em; + } + .path { + padding-left: 0.5em; + color: #777777; + } +} + + diff --git a/frontend/app/welcome.js b/frontend/app/welcome.js deleted file mode 100644 index 215c003..0000000 --- a/frontend/app/welcome.js +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; - -class Welcome extends React.Component { - - render() { - return
-
-

- 💕 - Welcome back to Persea - 💕 -

- {this.thingsToDo()} -
-
; - } - - thingsToDo() { - const things =

You have nothing to do!

; - return
{things}
; - } - -} - -import contempo from 'contempo'; -Welcome = contempo(Welcome, require('./welcome.scss')); - -export default Welcome; diff --git a/frontend/app/welcome.scss b/frontend/app/welcome.scss deleted file mode 100644 index 17925e4..0000000 --- a/frontend/app/welcome.scss +++ /dev/null @@ -1,27 +0,0 @@ - -.welcome { - display: flex; - align-items: center; - justify-content: center; - height: 100%; -} - -h2 { - display: block; - font-size: 1.5em; - margin-bottom: 1.5em; - - span { - color: red; - } -} - -.content { - background-color: #333; - padding: 6em; - text-align: center; -} - -.things-to-do div { - margin-bottom: 1em; -} diff --git a/frontend/app/workspace.js b/frontend/app/workspace.js new file mode 100644 index 0000000..434e24a --- /dev/null +++ b/frontend/app/workspace.js @@ -0,0 +1,45 @@ +import {combineReducers} from 'redux' + +import {createActionTypes, createCall} from './api'; + +const types = { + ...createActionTypes('WORKSPACE_LOAD', '@@persea'), +}; + +const creators = { + load: (uri) => { + return createCall(uri, types, 'WORKSPACE_LOAD'); + }, +}; + +export const actions = {types, creators}; + +export const reducer = combineReducers({ + current: (state = null, action) => { + switch (action.type) { + case types.WORKSPACE_LOAD_SUCCESS: + return action.payload; + default: + return state; + } + }, +}); + +class Duck { + + constructor(namespace) { + + } + + types() { + return {}; + } + + creators() { + return {}; + } + + *saga() { + } + +} diff --git a/frontend/root/dev-tools.js b/frontend/dev-tools.js similarity index 88% rename from frontend/root/dev-tools.js rename to frontend/dev-tools.js index 13d404b..9db5dcc 100644 --- a/frontend/root/dev-tools.js +++ b/frontend/dev-tools.js @@ -7,18 +7,15 @@ import DockMonitor from 'redux-devtools-dock-monitor'; import FilterMonitor from 'redux-devtools-filter-actions'; const DevTools = createDevTools( - - - - ); diff --git a/frontend/index.js b/frontend/index.js index cb9b7ca..d160cf9 100644 --- a/frontend/index.js +++ b/frontend/index.js @@ -1,10 +1,19 @@ import React from 'react'; import ReactDOM from 'react-dom'; +import {Provider} from 'react-redux'; -import Root from './root'; -import createRootStore from './root/store'; +import App from './app/component'; +import {create as createStore} from './store'; + +const store = createStore(); + +// Application start. +import {actions} from './app'; +store.dispatch(actions.creators.start()); ReactDOM.render( - , + + + , document.querySelector('.root') ); diff --git a/frontend/reducer.js b/frontend/reducer.js new file mode 100644 index 0000000..846a2a0 --- /dev/null +++ b/frontend/reducer.js @@ -0,0 +1,7 @@ +import {combineReducers} from 'redux' + +import {reducer} from './app'; + +export default function createRootReducer() { + return reducer; +} diff --git a/frontend/root/index.dev.js b/frontend/root/index.dev.js deleted file mode 100644 index 591db2e..0000000 --- a/frontend/root/index.dev.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import {Provider} from 'react-redux'; -import {BrowserRouter} from 'react-router-dom'; - -import DevTools from './dev-tools'; - -import App from '../app'; - -function Root ({store}) { - - return - - - - -
- -
-
-
; -}; - -import contempo from 'contempo'; -Root = contempo(Root, require('./index.scss')); - -export default Root; diff --git a/frontend/root/index.js b/frontend/root/index.js deleted file mode 100644 index f669d43..0000000 --- a/frontend/root/index.js +++ /dev/null @@ -1,6 +0,0 @@ -if ('production' === process.env.NODE_ENV) { - module.exports = require('./index.prod'); -} -else { - module.exports = require('./index.dev'); -} diff --git a/frontend/root/index.prod.js b/frontend/root/index.prod.js deleted file mode 100644 index 9dda690..0000000 --- a/frontend/root/index.prod.js +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; -import {Provider} from 'react-redux'; -import {BrowserRouter} from 'react-router-dom'; - -import App from '../app'; - -function Root ({store}) { - - return - - - - ; -}; - -import contempo from 'contempo'; -Root = contempo(Root, require('./index.scss')); - -export default Root; diff --git a/frontend/root/index.scss b/frontend/root/index.scss deleted file mode 100644 index 839a45a..0000000 --- a/frontend/root/index.scss +++ /dev/null @@ -1,9 +0,0 @@ -@media (max-width: 1023px) { - .testing { - margin: 0; - } -} - -.dev-tools { - opacity: 0.9; -} diff --git a/frontend/root/reducer.js b/frontend/root/reducer.js deleted file mode 100644 index 8e5d6de..0000000 --- a/frontend/root/reducer.js +++ /dev/null @@ -1,9 +0,0 @@ -import {combineReducers} from 'redux'; -import {reducer as formReducer} from 'redux-form/immutable'; - -export default function createRootReducer() { - - return combineReducers({ - form: formReducer, - }); -} diff --git a/frontend/root/saga.js b/frontend/root/saga.js deleted file mode 100644 index 10168d5..0000000 --- a/frontend/root/saga.js +++ /dev/null @@ -1,8 +0,0 @@ -import {all, call} from 'redux-saga/effects' - -export default function createRootSaga() { - return function*() { - return yield all([ - ].map(call)); - }; -} diff --git a/frontend/root/store.dev.js b/frontend/root/store.dev.js deleted file mode 100644 index ec2be0a..0000000 --- a/frontend/root/store.dev.js +++ /dev/null @@ -1,28 +0,0 @@ -import createSagaMiddleware from 'redux-saga'; -import {compose, createStore, applyMiddleware} from 'redux'; - -import DevTools from './dev-tools'; - -import createRootReducer from './reducer'; -import createRootSaga from './saga'; - -export default function createRootStore() { - - const sagaMiddleware = createSagaMiddleware(); - - const store = createStore( - createRootReducer(), - compose( - applyMiddleware(sagaMiddleware), - DevTools.instrument() - ) - ); - - module.hot.accept('./reducer', () => { - store.replaceReducer(require('./reducer').default()); - }); - - sagaMiddleware.run(createRootSaga()); - - return store; -} diff --git a/frontend/root/store.prod.js b/frontend/root/store.prod.js deleted file mode 100644 index 3981ee7..0000000 --- a/frontend/root/store.prod.js +++ /dev/null @@ -1,21 +0,0 @@ -import createSagaMiddleware from 'redux-saga'; -import {compose, createStore, applyMiddleware} from 'redux'; - -import createRootReducer from './reducer'; -import createRootSaga from './saga'; - -export default function createRootStore() { - - const sagaMiddleware = createSagaMiddleware() - - const store = createStore( - createRootReducer(), - compose( - applyMiddleware(sagaMiddleware) - ) - ); - - sagaMiddleware.run(createRootSaga()); - - return store -} diff --git a/frontend/saga.js b/frontend/saga.js new file mode 100644 index 0000000..2f61999 --- /dev/null +++ b/frontend/saga.js @@ -0,0 +1,7 @@ +import {all} from 'redux-saga/effects'; + +import {saga} from './app'; + +export default function createRootSaga() { + return saga; +} diff --git a/frontend/store.dev.js b/frontend/store.dev.js new file mode 100644 index 0000000..288a4da --- /dev/null +++ b/frontend/store.dev.js @@ -0,0 +1,33 @@ +import {compose, createStore, applyMiddleware} from 'redux'; +import {apiMiddleware} from 'redux-api-middleware'; +import createSagaMiddleware from 'redux-saga'; + +import DevTools from './dev-tools'; + +import {reducer, saga} from './app'; + +export function create() { + const sagaMiddleware = createSagaMiddleware({ + onError: (error, options) => { + console.error(error); + if (options && options.sagaStack) { + console.error(`(above error originates from: ${options.sagaStack})`); + } + } + }); + const middleware = applyMiddleware(apiMiddleware, sagaMiddleware); + const enhancer = compose(middleware, DevTools.instrument()); + const store = createStore(reducer, enhancer); + let sagaTask = sagaMiddleware.run(saga); + if (module.hot) { + module.hot.accept('./app', () => { + const {reducer: newReducer, saga: newSaga} = require('./app'); + store.replaceReducer(newReducer); + sagaTask.cancel(); + sagaTask.done.then(() => { + sagaTask = sagaMiddleware.run(newSaga); + }); + }); + } + return store; +} diff --git a/frontend/root/store.js b/frontend/store.js similarity index 100% rename from frontend/root/store.js rename to frontend/store.js diff --git a/hooks.js b/hooks.js index 17f95fe..4a98b3e 100644 --- a/hooks.js +++ b/hooks.js @@ -1 +1,22 @@ -module.exports = () => ({}); +module.exports = () => ({ + ormCollections: () => { + return [ + { + identity: 'project', + datastore: 'default', + primaryKey: 'id', + attributes: { + id: { + type: 'number', + autoMigrations: { + autoIncrement: true, + }, + }, + name: { + type: 'string', + }, + } + }, + ]; + }, +}); diff --git a/index.js b/index.js index 85f1318..31acfe2 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,4 @@ -import {createDispatcher} from '@truss/truss'; +const {createDispatcher} = require('@truss/comm'); const dispatcher = createDispatcher(); dispatcher.lookupActions(require('./actions')); diff --git a/package.json b/package.json index 46510ac..ca6ba53 100644 --- a/package.json +++ b/package.json @@ -4,14 +4,17 @@ "description": "", "main": "index.js", "scripts": { - "build": "node -e '' -r '@truss/truss/task/build'", + "build": "node -e '' -r '@truss/webpack/task/build'", "default": "yarn run dev", - "dev": "node -e '' -r '@truss/truss/task/scaffold'" + "dev": "node -e '' -r '@truss/webpack/task/scaffold'" }, "author": "cha0s", "license": "MIT", "dependencies": { - "@truss/truss": "1.x", + "@persea/behavior": "1.x", + "@truss/comm": "1.x", + "@truss/webpack": "1.x", + "babel-plugin-redux-saga": "1.0.2", "classnames": "^2.2.6", "contempo": "1.x", "debug": "3.1.0", @@ -23,7 +26,9 @@ "react-redux": "^5.0.7", "react-router": "^4.3.1", "react-router-dom": "^4.3.1", + "react-split-pane": "^0.1.84", "redux": "^4.0.0", + "redux-api-middleware": "3.0.1", "redux-devtools": "^3.4.1", "redux-devtools-dock-monitor": "^1.1.3", "redux-devtools-filter-actions": "^1.2.2", @@ -31,6 +36,7 @@ "redux-form": "^7.4.2", "redux-saga": "^0.16.0", "webpack-dev-middleware": "3.1.3", - "webpack-hot-middleware": "2.22.3" + "webpack-hot-middleware": "2.22.3", + "yallist": "^3.0.2" } } diff --git a/response.dev.js b/response.dev.js index 9ace1e8..dc0643c 100644 --- a/response.dev.js +++ b/response.dev.js @@ -71,11 +71,6 @@ exports.Responder = class Responder { } respond({payload: {headers, url}}) { - headers = {...headers}; - - delete headers.host; - delete headers.connection; - // forward to internal HTTP return new Promise((resolve, reject) => { diff --git a/styles/global.scss b/styles/global.scss index a96633f..7c98574 100644 --- a/styles/global.scss +++ b/styles/global.scss @@ -1,55 +1,4 @@ -html, body, .app, .root { +html, body, .root { width: 100%; height: 100%; } - -.aside { - font-size: 0.8em; -} - -button { - &:hover { - background-color: #555; - } -} - -button, input, select, option { - - &[disabled] { - filter: grayscale(1); - opacity: 0.5; - - &:hover { - background-color: transparent; - } - } - - &:focus { - outline: none; - box-shadow: inset 0 0 1pt 0.5pt #CCC, 0 0 1pt 0.5pt #CCC - } -} - -hr { - border: none; - border-bottom: 1px solid #333; - margin: 1em 0; -} - -.loading { - align-items: center; - display: flex; - height: 100%; - justify-content: center; - width: 100%; - - svg { - height: 25%; - width: 25%; - } -} - -.editor.avocado-environment { - height: 100%; - width: 100%; -} diff --git a/webpack.config.js b/webpack.config.js index ab2243a..1e5abc3 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -37,16 +37,25 @@ module.exports.webpackConfig = function() { style: [ path.join(cssPrefix, styleDirectory, 'reset.css'), path.join(scssPrefix, styleDirectory, 'global.scss'), - path.join(scssPrefix, styleDirectory, 'forms.scss'), ], }, - optimization: {}, + optimization: { + splitChunks: { + cacheGroups: { + commons: { + test: /(node_modules\/(?!contempo|@avocado|@truss))/, + name: 'vendor', + chunks: 'all', + } + } + } + }, module: { rules: [ { test: /\.js$/, exclude: [ - /(node_modules\/(?!contempo))/, + /(node_modules\/(?!contempo|@avocado|@truss))/, ], use: { loader: 'babel-loader', @@ -55,7 +64,13 @@ module.exports.webpackConfig = function() { OUTPUT_PATH, ], plugins: [ + 'babel-plugin-redux-saga', + ['@babel/plugin-proposal-decorators', { + legacy: true, + }], + '@babel/plugin-proposal-class-properties', '@babel/plugin-proposal-object-rest-spread', + '@babel/plugin-syntax-dynamic-import', 'react-hot-loader/babel', ], presets: [