about summary refs log tree commit diff
path: root/app/assets
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2016-10-12 13:17:17 +0200
committerEugen Rochko <eugen@zeonfederated.com>2016-10-12 13:17:17 +0200
commit45776b55b0d97d6a6b8b202d3076f19f1d055573 (patch)
tree3cae814a3dfbfbc3b2bac45bf149e18845170922 /app/assets
parente2ff39bf5db8cecd2bbe348dc2c3cf431a6d36ec (diff)
Responsively changing layout to single-column + nav on smaller screens
Diffstat (limited to 'app/assets')
-rw-r--r--app/assets/javascripts/components/containers/mastodon.jsx8
-rw-r--r--app/assets/javascripts/components/features/compose/index.jsx28
-rw-r--r--app/assets/javascripts/components/features/home_timeline/index.jsx19
-rw-r--r--app/assets/javascripts/components/features/mentions_timeline/index.jsx19
-rw-r--r--app/assets/javascripts/components/features/public_timeline/index.jsx67
-rw-r--r--app/assets/javascripts/components/features/ui/components/column.jsx13
-rw-r--r--app/assets/javascripts/components/features/ui/components/columns_area.jsx10
-rw-r--r--app/assets/javascripts/components/features/ui/components/drawer.jsx12
-rw-r--r--app/assets/javascripts/components/features/ui/components/tabs_bar.jsx38
-rw-r--r--app/assets/javascripts/components/features/ui/index.jsx53
-rw-r--r--app/assets/stylesheets/components.scss28
11 files changed, 195 insertions, 100 deletions
diff --git a/app/assets/javascripts/components/containers/mastodon.jsx b/app/assets/javascripts/components/containers/mastodon.jsx
index 90fb46908..1327dba3e 100644
--- a/app/assets/javascripts/components/containers/mastodon.jsx
+++ b/app/assets/javascripts/components/containers/mastodon.jsx
@@ -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}>
diff --git a/app/assets/javascripts/components/features/compose/index.jsx b/app/assets/javascripts/components/features/compose/index.jsx
new file mode 100644
index 000000000..4be938158
--- /dev/null
+++ b/app/assets/javascripts/components/features/compose/index.jsx
@@ -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;
diff --git a/app/assets/javascripts/components/features/home_timeline/index.jsx b/app/assets/javascripts/components/features/home_timeline/index.jsx
new file mode 100644
index 000000000..1f4b25450
--- /dev/null
+++ b/app/assets/javascripts/components/features/home_timeline/index.jsx
@@ -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;
diff --git a/app/assets/javascripts/components/features/mentions_timeline/index.jsx b/app/assets/javascripts/components/features/mentions_timeline/index.jsx
new file mode 100644
index 000000000..d9d0963d0
--- /dev/null
+++ b/app/assets/javascripts/components/features/mentions_timeline/index.jsx
@@ -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;
diff --git a/app/assets/javascripts/components/features/public_timeline/index.jsx b/app/assets/javascripts/components/features/public_timeline/index.jsx
index 450725af6..7d3739214 100644
--- a/app/assets/javascripts/components/features/public_timeline/index.jsx
+++ b/app/assets/javascripts/components/features/public_timeline/index.jsx
@@ -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);
diff --git a/app/assets/javascripts/components/features/ui/components/column.jsx b/app/assets/javascripts/components/features/ui/components/column.jsx
index bb9331267..be4fa8908 100644
--- a/app/assets/javascripts/components/features/ui/components/column.jsx
+++ b/app/assets/javascripts/components/features/ui/components/column.jsx
@@ -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>
diff --git a/app/assets/javascripts/components/features/ui/components/columns_area.jsx b/app/assets/javascripts/components/features/ui/components/columns_area.jsx
index 94433539b..3f88b1ea3 100644
--- a/app/assets/javascripts/components/features/ui/components/columns_area.jsx
+++ b/app/assets/javascripts/components/features/ui/components/columns_area.jsx
@@ -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>
     );
diff --git a/app/assets/javascripts/components/features/ui/components/drawer.jsx b/app/assets/javascripts/components/features/ui/components/drawer.jsx
index dfba11ad2..1fbb9333e 100644
--- a/app/assets/javascripts/components/features/ui/components/drawer.jsx
+++ b/app/assets/javascripts/components/features/ui/components/drawer.jsx
@@ -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>
     );
diff --git a/app/assets/javascripts/components/features/ui/components/tabs_bar.jsx b/app/assets/javascripts/components/features/ui/components/tabs_bar.jsx
new file mode 100644
index 000000000..f5d985996
--- /dev/null
+++ b/app/assets/javascripts/components/features/ui/components/tabs_bar.jsx
@@ -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;
diff --git a/app/assets/javascripts/components/features/ui/index.jsx b/app/assets/javascripts/components/features/ui/index.jsx
index 0bc235b53..fab32a31e 100644
--- a/app/assets/javascripts/components/features/ui/index.jsx
+++ b/app/assets/javascripts/components/features/ui/index.jsx
@@ -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' }} />
diff --git a/app/assets/stylesheets/components.scss b/app/assets/stylesheets/components.scss
index 78419988d..ef39a87ed 100644
--- a/app/assets/stylesheets/components.scss
+++ b/app/assets/stylesheets/components.scss
@@ -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;
+  }
+}