From 49520d6e627e49a1f9f1b8cfa9b323450307fcc6 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 24 Aug 2016 17:56:44 +0200 Subject: Adding React.js, Redux, revamping dashboard --- app/assets/javascripts/application.js | 4 ++- app/assets/javascripts/channels/timeline.js | 13 ------- app/assets/javascripts/components.js | 9 +++++ app/assets/javascripts/components/.gitkeep | 0 .../javascripts/components/actions/statuses.jsx | 18 ++++++++++ .../javascripts/components/components/column.jsx | 19 ++++++++++ .../components/components/column_header.jsx | 15 ++++++++ .../components/components/columns_area.jsx | 15 ++++++++ .../javascripts/components/components/frontend.jsx | 16 +++++++++ .../javascripts/components/components/nav_bar.jsx | 8 +++++ .../javascripts/components/components/status.jsx | 19 ++++++++++ .../components/components/status_list.jsx | 22 ++++++++++++ .../javascripts/components/containers/root.jsx | 40 ++++++++++++++++++++++ .../containers/status_list_container.jsx | 10 ++++++ .../javascripts/components/reducers/index.jsx | 6 ++++ .../javascripts/components/reducers/statuses.jsx | 17 +++++++++ .../components/store/configureStore.jsx | 6 ++++ 17 files changed, 223 insertions(+), 14 deletions(-) delete mode 100644 app/assets/javascripts/channels/timeline.js create mode 100644 app/assets/javascripts/components.js create mode 100644 app/assets/javascripts/components/.gitkeep create mode 100644 app/assets/javascripts/components/actions/statuses.jsx create mode 100644 app/assets/javascripts/components/components/column.jsx create mode 100644 app/assets/javascripts/components/components/column_header.jsx create mode 100644 app/assets/javascripts/components/components/columns_area.jsx create mode 100644 app/assets/javascripts/components/components/frontend.jsx create mode 100644 app/assets/javascripts/components/components/nav_bar.jsx create mode 100644 app/assets/javascripts/components/components/status.jsx create mode 100644 app/assets/javascripts/components/components/status_list.jsx create mode 100644 app/assets/javascripts/components/containers/root.jsx create mode 100644 app/assets/javascripts/components/containers/status_list_container.jsx create mode 100644 app/assets/javascripts/components/reducers/index.jsx create mode 100644 app/assets/javascripts/components/reducers/statuses.jsx create mode 100644 app/assets/javascripts/components/store/configureStore.jsx (limited to 'app/assets/javascripts') diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 646c5aba4..b9d77b07f 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -12,4 +12,6 @@ // //= require jquery //= require jquery_ujs -//= require_tree . +//= require components +//= require cable +//= require mastodon-logo diff --git a/app/assets/javascripts/channels/timeline.js b/app/assets/javascripts/channels/timeline.js deleted file mode 100644 index ca7c50d12..000000000 --- a/app/assets/javascripts/channels/timeline.js +++ /dev/null @@ -1,13 +0,0 @@ -App.timeline = App.cable.subscriptions.create("TimelineChannel", { - connected: function() { - console.log('Connected'); - }, - - disconnected: function() { - console.log('Disconnected'); - }, - - received: function(data) { - console.log(JSON.parse(data.message)); - } -}); diff --git a/app/assets/javascripts/components.js b/app/assets/javascripts/components.js new file mode 100644 index 000000000..d4d9b97e4 --- /dev/null +++ b/app/assets/javascripts/components.js @@ -0,0 +1,9 @@ +//= require_self +//= require react_ujs + +window.React = require('react'); +window.ReactDOM = require('react-dom'); + +//= require_tree ./components + +window.Root = require('./components/containers/root'); diff --git a/app/assets/javascripts/components/.gitkeep b/app/assets/javascripts/components/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/app/assets/javascripts/components/actions/statuses.jsx b/app/assets/javascripts/components/actions/statuses.jsx new file mode 100644 index 000000000..21821b8ba --- /dev/null +++ b/app/assets/javascripts/components/actions/statuses.jsx @@ -0,0 +1,18 @@ +export const SET_TIMELINE = 'SET_TIMELINE'; +export const ADD_STATUS = 'ADD_STATUS'; + +export function setTimeline(timeline, statuses) { + return { + type: SET_TIMELINE, + timeline: timeline, + statuses: statuses + }; +} + +export function addStatus(timeline, status) { + return { + type: ADD_STATUS, + timeline: timeline, + status: status + }; +} diff --git a/app/assets/javascripts/components/components/column.jsx b/app/assets/javascripts/components/components/column.jsx new file mode 100644 index 000000000..c585b6b0b --- /dev/null +++ b/app/assets/javascripts/components/components/column.jsx @@ -0,0 +1,19 @@ +import StatusListContainer from '../containers/status_list_container'; +import ColumnHeader from './column_header'; + +const Column = React.createClass({ + propTypes: { + type: React.PropTypes.string + }, + + render: function() { + return ( +
+ + +
+ ); + } +}); + +export default Column; diff --git a/app/assets/javascripts/components/components/column_header.jsx b/app/assets/javascripts/components/components/column_header.jsx new file mode 100644 index 000000000..e2f7d7c1c --- /dev/null +++ b/app/assets/javascripts/components/components/column_header.jsx @@ -0,0 +1,15 @@ +const ColumnHeader = React.createClass({ + propTypes: { + type: React.PropTypes.string + }, + + render: function() { + return ( +
+ {this.props.type} +
+ ); + } +}); + +export default ColumnHeader; diff --git a/app/assets/javascripts/components/components/columns_area.jsx b/app/assets/javascripts/components/components/columns_area.jsx new file mode 100644 index 000000000..1c46f722d --- /dev/null +++ b/app/assets/javascripts/components/components/columns_area.jsx @@ -0,0 +1,15 @@ +import Column from './column'; + +const ColumnsArea = React.createClass({ + + render: function() { + return ( +
+ + +
+ ); + } +}); + +export default ColumnsArea; diff --git a/app/assets/javascripts/components/components/frontend.jsx b/app/assets/javascripts/components/components/frontend.jsx new file mode 100644 index 000000000..6f9c46fa9 --- /dev/null +++ b/app/assets/javascripts/components/components/frontend.jsx @@ -0,0 +1,16 @@ +import NavBar from './nav_bar'; +import ColumnsArea from './columns_area'; + +const Frontend = React.createClass({ + + render: function() { + return ( +
+ + +
+ ); + } +}); + +export default Frontend; diff --git a/app/assets/javascripts/components/components/nav_bar.jsx b/app/assets/javascripts/components/components/nav_bar.jsx new file mode 100644 index 000000000..1ece3cc34 --- /dev/null +++ b/app/assets/javascripts/components/components/nav_bar.jsx @@ -0,0 +1,8 @@ +const NavBar = React.createClass({ + + render: function() { + return
; + } +}); + +export default NavBar; diff --git a/app/assets/javascripts/components/components/status.jsx b/app/assets/javascripts/components/components/status.jsx new file mode 100644 index 000000000..9bbb02077 --- /dev/null +++ b/app/assets/javascripts/components/components/status.jsx @@ -0,0 +1,19 @@ +import ImmutablePropTypes from 'react-immutable-proptypes'; + +const Status = React.createClass({ + propTypes: { + status: ImmutablePropTypes.map.isRequired + }, + + render: function() { + console.log(this.props.status.toJS()); + + return ( +
+ {this.props.status.getIn(['account', 'username'])}: {this.props.status.get('content')} +
+ ); + } +}); + +export default Status; diff --git a/app/assets/javascripts/components/components/status_list.jsx b/app/assets/javascripts/components/components/status_list.jsx new file mode 100644 index 000000000..c986c773b --- /dev/null +++ b/app/assets/javascripts/components/components/status_list.jsx @@ -0,0 +1,22 @@ +import Status from './status'; +import ImmutablePropTypes from 'react-immutable-proptypes'; + +const StatusList = React.createClass({ + propTypes: { + statuses: ImmutablePropTypes.list.isRequired + }, + + render: function() { + return ( +
+
+ {this.props.statuses.map((status) => { + return ; + })} +
+
+ ); + } +}); + +export default StatusList; diff --git a/app/assets/javascripts/components/containers/root.jsx b/app/assets/javascripts/components/containers/root.jsx new file mode 100644 index 000000000..7da984d89 --- /dev/null +++ b/app/assets/javascripts/components/containers/root.jsx @@ -0,0 +1,40 @@ +import { Provider } from 'react-redux'; +import configureStore from '../store/configureStore'; +import Frontend from '../components/frontend'; +import { setTimeline, addStatus } from '../actions/statuses'; + +const store = configureStore(); + +const Root = React.createClass({ + + componentWillMount() { + for (var timelineType in this.props.timelines) { + if (this.props.timelines.hasOwnProperty(timelineType)) { + store.dispatch(setTimeline(timelineType, JSON.parse(this.props.timelines[timelineType]))); + } + } + + if (typeof App !== 'undefined') { + App.timeline = App.cable.subscriptions.create("TimelineChannel", { + connected: function() {}, + + disconnected: function() {}, + + received: function(data) { + return store.dispatch(addStatus(data.timeline, JSON.parse(data.message))); + } + }); + } + }, + + render() { + return ( + + + + ); + } + +}); + +export default Root; diff --git a/app/assets/javascripts/components/containers/status_list_container.jsx b/app/assets/javascripts/components/containers/status_list_container.jsx new file mode 100644 index 000000000..c2e55db66 --- /dev/null +++ b/app/assets/javascripts/components/containers/status_list_container.jsx @@ -0,0 +1,10 @@ +import { connect } from 'react-redux'; +import StatusList from '../components/status_list'; + +const mapStateToProps = function (state, props) { + return { + statuses: state.getIn(['statuses', props.type]) + }; +}; + +export default connect(mapStateToProps)(StatusList); diff --git a/app/assets/javascripts/components/reducers/index.jsx b/app/assets/javascripts/components/reducers/index.jsx new file mode 100644 index 000000000..c7e858f38 --- /dev/null +++ b/app/assets/javascripts/components/reducers/index.jsx @@ -0,0 +1,6 @@ +import { combineReducers } from 'redux-immutable'; +import statuses from './statuses'; + +export default combineReducers({ + statuses +}); diff --git a/app/assets/javascripts/components/reducers/statuses.jsx b/app/assets/javascripts/components/reducers/statuses.jsx new file mode 100644 index 000000000..d69d66328 --- /dev/null +++ b/app/assets/javascripts/components/reducers/statuses.jsx @@ -0,0 +1,17 @@ +import { SET_TIMELINE, ADD_STATUS } from '../actions/statuses'; +import Immutable from 'immutable'; + +const initialState = Immutable.Map(); + +export default function statuses(state = initialState, action) { + switch(action.type) { + case SET_TIMELINE: + return state.set(action.timeline, Immutable.fromJS(action.statuses)); + case ADD_STATUS: + return state.update(action.timeline, function (list) { + list.unshift(Immutable.fromJS(action.status)); + }); + default: + return state; + } +} diff --git a/app/assets/javascripts/components/store/configureStore.jsx b/app/assets/javascripts/components/store/configureStore.jsx new file mode 100644 index 000000000..bb5d664d0 --- /dev/null +++ b/app/assets/javascripts/components/store/configureStore.jsx @@ -0,0 +1,6 @@ +import { createStore } from 'redux'; +import appReducer from '../reducers'; + +export default function configureStore(initialState) { + return createStore(appReducer, initialState); +} -- cgit