Skip to content
Snippets Groups Projects
Commit 49520d6e authored by Eugen Rochko's avatar Eugen Rochko
Browse files

Adding React.js, Redux, revamping dashboard

parent 68c93f8b
No related branches found
No related tags found
No related merge requests found
Showing
with 243 additions and 14 deletions
......@@ -20,3 +20,4 @@ public/system
public/assets
.env
.env.*
node_modules/
......@@ -38,6 +38,9 @@ gem 'rack-attack'
gem 'sidekiq'
gem 'sinatra', require: nil, github: 'sinatra'
gem 'react-rails'
gem 'browserify-rails'
group :development, :test do
gem 'rspec-rails'
gem 'pry-rails'
......
......@@ -53,6 +53,10 @@ GEM
addressable (2.4.0)
arel (7.1.1)
ast (2.3.0)
babel-source (5.8.35)
babel-transpiler (0.7.0)
babel-source (>= 4.0, < 6)
execjs (~> 2.0)
bcrypt (3.1.11)
better_errors (2.1.1)
coderay (>= 1.0.0)
......@@ -60,6 +64,9 @@ GEM
rack (>= 0.9.0)
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
browserify-rails (3.1.0)
railties (>= 4.0.0, < 5.1)
sprockets (>= 3.5.2)
builder (3.2.2)
bullet (5.3.0)
activesupport (>= 3.0.0)
......@@ -245,6 +252,13 @@ GEM
rake (11.2.2)
rdoc (4.2.2)
json (~> 1.4)
react-rails (1.8.2)
babel-transpiler (>= 0.7.0)
coffee-script-source (~> 1.8)
connection_pool
execjs
railties (>= 3.2)
tilt
redis (3.3.1)
ref (2.0.0)
responders (2.3.0)
......@@ -348,6 +362,7 @@ DEPENDENCIES
addressable
better_errors
binding_of_caller
browserify-rails
bullet
coffee-rails (~> 4.1.0)
devise
......@@ -380,6 +395,7 @@ DEPENDENCIES
rails (= 5.0.0.1)
rails_12factor
rails_autolink
react-rails
redis (~> 3.2)
rspec-rails
rspec-sidekiq
......
......@@ -12,4 +12,6 @@
//
//= require jquery
//= require jquery_ujs
//= require_tree .
//= require components
//= require cable
//= require mastodon-logo
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));
}
});
//= require_self
//= require react_ujs
window.React = require('react');
window.ReactDOM = require('react-dom');
//= require_tree ./components
window.Root = require('./components/containers/root');
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
};
}
import StatusListContainer from '../containers/status_list_container';
import ColumnHeader from './column_header';
const Column = React.createClass({
propTypes: {
type: React.PropTypes.string
},
render: function() {
return (
<div style={{ width: '350px', flex: '0 0 auto', background: '#282c37', margin: '10px', marginRight: '0', display: 'flex', flexDirection: 'column' }}>
<ColumnHeader type={this.props.type} />
<StatusListContainer type={this.props.type} />
</div>
);
}
});
export default Column;
const ColumnHeader = React.createClass({
propTypes: {
type: React.PropTypes.string
},
render: function() {
return (
<div style={{ padding: '15px', fontSize: '16px', background: '#2f3441', flex: '0 0 auto' }}>
{this.props.type}
</div>
);
}
});
export default ColumnHeader;
import Column from './column';
const ColumnsArea = React.createClass({
render: function() {
return (
<div style={{ display: 'flex', flexDirection: 'row', flex: '1' }}>
<Column type='home' />
<Column type='mentions' />
</div>
);
}
});
export default ColumnsArea;
import NavBar from './nav_bar';
import ColumnsArea from './columns_area';
const Frontend = React.createClass({
render: function() {
return (
<div style={{ flex: '0 0 auto', display: 'flex', width: '100%', height: '100%', background: '#1a1c23' }}>
<NavBar />
<ColumnsArea />
</div>
);
}
});
export default Frontend;
const NavBar = React.createClass({
render: function() {
return <div style={{ background: '#2f3441', width: '60px', margin: '10px', marginRight: '0' }} />;
}
});
export default NavBar;
import ImmutablePropTypes from 'react-immutable-proptypes';
const Status = React.createClass({
propTypes: {
status: ImmutablePropTypes.map.isRequired
},
render: function() {
console.log(this.props.status.toJS());
return (
<div style={{ height: '100px' }}>
{this.props.status.getIn(['account', 'username'])}: {this.props.status.get('content')}
</div>
);
}
});
export default Status;
import Status from './status';
import ImmutablePropTypes from 'react-immutable-proptypes';
const StatusList = React.createClass({
propTypes: {
statuses: ImmutablePropTypes.list.isRequired
},
render: function() {
return (
<div style={{ overflowY: 'scroll', flex: '1 1 auto' }}>
<div>
{this.props.statuses.map((status) => {
return <Status key={status.get('id')} status={status} />;
})}
</div>
</div>
);
}
});
export default StatusList;
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 (
<Provider store={store}>
<Frontend />
</Provider>
);
}
});
export default Root;
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);
import { combineReducers } from 'redux-immutable';
import statuses from './statuses';
export default combineReducers({
statuses
});
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;
}
}
import { createStore } from 'redux';
import appReducer from '../reducers';
export default function configureStore(initialState) {
return createStore(appReducer, initialState);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment