0
0
Fork 0

Responsively changing layout to single-column + nav on smaller screens

This commit is contained in:
Eugen Rochko 2016-10-12 13:17:17 +02:00
parent e2ff39bf5d
commit 45776b55b0
13 changed files with 220 additions and 100 deletions

View file

@ -15,12 +15,15 @@ import {
hashHistory,
IndexRoute
} from 'react-router';
import UI from '../features/ui';
import Account from '../features/account';
import Status from '../features/status';
import GettingStarted from '../features/getting_started';
import PublicTimeline from '../features/public_timeline';
import UI from '../features/ui';
import AccountTimeline from '../features/account_timeline';
import HomeTimeline from '../features/home_timeline';
import MentionsTimeline from '../features/mentions_timeline';
import Compose from '../features/compose';
const store = configureStore();
@ -77,6 +80,9 @@ const Mastodon = React.createClass({
<Router history={hashHistory}>
<Route path='/' component={UI}>
<IndexRoute component={GettingStarted} />
<Route path='/statuses/new' component={Compose} />
<Route path='/statuses/home' component={HomeTimeline} />
<Route path='/statuses/mentions' component={MentionsTimeline} />
<Route path='/statuses/all' component={PublicTimeline} />
<Route path='/statuses/:statusId' component={Status} />
<Route path='/accounts/:accountId' component={Account}>

View file

@ -0,0 +1,28 @@
import Drawer from '../ui/components/drawer';
import ComposeFormContainer from '../ui/containers/compose_form_container';
import FollowFormContainer from '../ui/containers/follow_form_container';
import UploadFormContainer from '../ui/containers/upload_form_container';
import NavigationContainer from '../ui/containers/navigation_container';
import PureRenderMixin from 'react-addons-pure-render-mixin';
const Compose = React.createClass({
mixins: [PureRenderMixin],
render () {
return (
<Drawer>
<div style={{ flex: '1 1 auto' }}>
<NavigationContainer />
<ComposeFormContainer />
<UploadFormContainer />
</div>
<FollowFormContainer />
</Drawer>
);
}
});
export default Compose;

View file

@ -0,0 +1,19 @@
import PureRenderMixin from 'react-addons-pure-render-mixin';
import StatusListContainer from '../ui/containers/status_list_container';
import Column from '../ui/components/column';
const HomeTimeline = React.createClass({
mixins: [PureRenderMixin],
render () {
return (
<Column icon='home' heading='Home'>
<StatusListContainer type='home' />
</Column>
);
},
});
export default HomeTimeline;

View file

@ -0,0 +1,19 @@
import PureRenderMixin from 'react-addons-pure-render-mixin';
import StatusListContainer from '../ui/containers/status_list_container';
import Column from '../ui/components/column';
const MentionsTimeline = React.createClass({
mixins: [PureRenderMixin],
render () {
return (
<Column icon='at' heading='Mentions'>
<StatusListContainer type='mentions' />
</Column>
);
},
});
export default MentionsTimeline;

View file

@ -1,43 +1,14 @@
import { connect } from 'react-redux';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import ImmutablePropTypes from 'react-immutable-proptypes';
import StatusList from '../../components/status_list';
import StatusListContainer from '../ui/containers/status_list_container';
import Column from '../ui/components/column';
import Immutable from 'immutable';
import { makeGetTimeline } from '../../selectors';
import {
updateTimeline,
refreshTimeline,
expandTimeline
updateTimeline
} from '../../actions/timelines';
import { deleteStatus } from '../../actions/statuses';
import { replyCompose } from '../../actions/compose';
import {
favourite,
reblog,
unreblog,
unfavourite
} from '../../actions/interactions';
const makeMapStateToProps = () => {
const getTimeline = makeGetTimeline();
const mapStateToProps = (state) => ({
statuses: getTimeline(state, 'public'),
me: state.getIn(['timelines', 'me'])
});
return mapStateToProps;
};
const PublicTimeline = React.createClass({
propTypes: {
statuses: ImmutablePropTypes.list.isRequired,
me: React.PropTypes.number.isRequired,
dispatch: React.PropTypes.func.isRequired
},
mixins: [PureRenderMixin],
componentWillMount () {
@ -62,44 +33,14 @@ const PublicTimeline = React.createClass({
}
},
handleReply (status) {
this.props.dispatch(replyCompose(status));
},
handleReblog (status) {
if (status.get('reblogged')) {
this.props.dispatch(unreblog(status));
} else {
this.props.dispatch(reblog(status));
}
},
handleFavourite (status) {
if (status.get('favourited')) {
this.props.dispatch(unfavourite(status));
} else {
this.props.dispatch(favourite(status));
}
},
handleDelete (status) {
this.props.dispatch(deleteStatus(status.get('id')));
},
handleScrollToBottom () {
this.props.dispatch(expandTimeline('public'));
},
render () {
const { statuses, me } = this.props;
return (
<Column icon='globe' heading='Public'>
<StatusList statuses={statuses} me={me} onScrollToBottom={this.handleScrollToBottom} onReply={this.handleReply} onReblog={this.handleReblog} onFavourite={this.handleFavourite} onDelete={this.handleDelete} />
<StatusListContainer type='public' />
</Column>
);
},
});
export default connect(makeMapStateToProps)(PublicTimeline);
export default connect()(PublicTimeline);

View file

@ -29,6 +29,15 @@ const scrollTop = (node) => {
};
};
const style = {
height: '100%',
boxSizing: 'border-box',
flex: '0 0 auto',
background: '#282c37',
display: 'flex',
flexDirection: 'column'
};
const Column = React.createClass({
propTypes: {
@ -56,10 +65,8 @@ const Column = React.createClass({
header = <ColumnHeader icon={this.props.icon} type={this.props.heading} onClick={this.handleHeaderClick} />;
}
const style = { width: '330px', flex: '0 0 auto', background: '#282c37', margin: '10px', marginRight: '0', marginBottom: '0', display: 'flex', flexDirection: 'column' };
return (
<div style={style} onWheel={this.handleWheel}>
<div className='column' style={style} onWheel={this.handleWheel}>
{header}
{this.props.children}
</div>

View file

@ -1,12 +1,20 @@
import PureRenderMixin from 'react-addons-pure-render-mixin';
const style = {
display: 'flex',
flex: '1 1 auto',
flexDirection: 'row',
justifyContent: 'flex-start',
overflowX: 'auto'
};
const ColumnsArea = React.createClass({
mixins: [PureRenderMixin],
render () {
return (
<div style={{ display: 'flex', flexDirection: 'row', flex: '1', justifyContent: 'flex-start', marginRight: '10px', marginBottom: '10px', overflowX: 'auto' }}>
<div className='columns-area' style={style}>
{this.props.children}
</div>
);

View file

@ -1,12 +1,22 @@
import PureRenderMixin from 'react-addons-pure-render-mixin';
const style = {
height: '100%',
flex: '0 0 auto',
boxSizing: 'border-box',
background: '#454b5e',
padding: '0',
display: 'flex',
flexDirection: 'column'
};
const Drawer = React.createClass({
mixins: [PureRenderMixin],
render () {
return (
<div style={{ width: '280px', flex: '0 0 auto', boxSizing: 'border-box', background: '#454b5e', margin: '10px', marginRight: '0', padding: '0', display: 'flex', flexDirection: 'column' }}>
<div className='drawer' style={style}>
{this.props.children}
</div>
);

View file

@ -0,0 +1,38 @@
import { Link } from 'react-router';
const outerStyle = {
background: '#373b4a',
margin: '10px',
flex: '0 0 auto',
marginBottom: '0',
display: 'flex'
};
const tabStyle = {
display: 'block',
flex: '1 1 auto',
padding: '10px',
color: '#fff',
textDecoration: 'none',
fontSize: '12px',
fontWeight: '500',
borderBottom: '2px solid #373b4a'
};
const tabActiveStyle = {
borderBottom: '2px solid #2b90d9',
color: '#2b90d9'
};
const TabsBar = () => {
return (
<div style={outerStyle}>
<Link style={tabStyle} activeStyle={tabActiveStyle} to='/statuses/new'><i className='fa fa-fw fa-pencil' /> Compose</Link>
<Link style={tabStyle} activeStyle={tabActiveStyle} to='/statuses/home'><i className='fa fa-fw fa-home' /> Home</Link>
<Link style={tabStyle} activeStyle={tabActiveStyle} to='/statuses/mentions'><i className='fa fa-fw fa-at' /> Mentions</Link>
<Link style={tabStyle} activeStyle={tabActiveStyle} to='/statuses/all'><i className='fa fa-fw fa-globe' /> Public</Link>
</div>
);
};
export default TabsBar;

View file

@ -1,47 +1,38 @@
import ColumnsArea from './components/columns_area';
import Column from './components/column';
import Drawer from './components/drawer';
import ComposeFormContainer from './containers/compose_form_container';
import FollowFormContainer from './containers/follow_form_container';
import UploadFormContainer from './containers/upload_form_container';
import StatusListContainer from './containers/status_list_container';
import NotificationsContainer from './containers/notifications_container';
import NavigationContainer from './containers/navigation_container';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import LoadingBarContainer from './containers/loading_bar_container';
import HomeTimeline from '../home_timeline';
import MentionsTimeline from '../mentions_timeline';
import Compose from '../compose';
import MediaQuery from 'react-responsive';
import TabsBar from './components/tabs_bar';
const UI = React.createClass({
propTypes: {
router: React.PropTypes.object
},
mixins: [PureRenderMixin],
render () {
const layoutBreakpoint = 1024;
return (
<div style={{ flex: '0 0 auto', display: 'flex', width: '100%', height: '100%', background: '#1a1c23' }}>
<Drawer>
<div style={{ flex: '1 1 auto' }}>
<NavigationContainer />
<ComposeFormContainer />
<UploadFormContainer />
</div>
<FollowFormContainer />
</Drawer>
<ColumnsArea>
<Column icon='home' heading='Home'>
<StatusListContainer type='home' />
</Column>
<Column icon='at' heading='Mentions'>
<StatusListContainer type='mentions' />
</Column>
<div style={{ flex: '0 0 auto', display: 'flex', flexDirection: 'column', width: '100%', height: '100%', background: '#1a1c23' }}>
<MediaQuery maxWidth={layoutBreakpoint}>
<TabsBar />
</MediaQuery>
<MediaQuery maxWidth={layoutBreakpoint} component={ColumnsArea}>
{this.props.children}
</ColumnsArea>
</MediaQuery>
<MediaQuery minWidth={layoutBreakpoint}>
<ColumnsArea>
<Compose />
<HomeTimeline />
<MentionsTimeline />
{this.props.children}
</ColumnsArea>
</MediaQuery>
<NotificationsContainer />
<LoadingBarContainer style={{ backgroundColor: '#2b90d9', left: '0', top: '0' }} />

View file

@ -227,3 +227,31 @@
margin-bottom: 20px;
}
}
.columns-area {
margin: 10px;
margin-left: 0;
}
.column {
width: 330px;
}
.drawer {
width: 280px;
}
.column, .drawer {
margin-left: 10px;
}
@media screen and (max-width: 1024px) {
.column, .drawer {
width: 100%;
margin: 0;
}
.columns-area {
margin: 10px;
}
}