闭社主体 forked from https://github.com/tootsuite/mastodon
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
3.8 KiB

  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import ImmutablePropTypes from 'react-immutable-proptypes';
  4. import ImmutablePureComponent from 'react-immutable-pure-component';
  5. import ReactSwipeableViews from 'react-swipeable-views';
  6. import { links, getIndex, getLink } from './tabs_bar';
  7. import BundleContainer from '../containers/bundle_container';
  8. import ColumnLoading from './column_loading';
  9. import BundleColumnError from './bundle_column_error';
  10. import { Compose, Notifications, HomeTimeline, CommunityTimeline, PublicTimeline, HashtagTimeline, FavouritedStatuses } from '../../ui/util/async-components';
  11. const componentMap = {
  12. 'COMPOSE': Compose,
  13. 'HOME': HomeTimeline,
  14. 'NOTIFICATIONS': Notifications,
  15. 'PUBLIC': PublicTimeline,
  16. 'COMMUNITY': CommunityTimeline,
  17. 'HASHTAG': HashtagTimeline,
  18. 'FAVOURITES': FavouritedStatuses,
  19. };
  20. export default class ColumnsArea extends ImmutablePureComponent {
  21. static contextTypes = {
  22. router: PropTypes.object.isRequired,
  23. };
  24. static propTypes = {
  25. columns: ImmutablePropTypes.list.isRequired,
  26. singleColumn: PropTypes.bool,
  27. children: PropTypes.node,
  28. };
  29. state = {
  30. shouldAnimate: false,
  31. }
  32. componentWillReceiveProps() {
  33. this.setState({ shouldAnimate: false });
  34. }
  35. componentDidMount() {
  36. this.lastIndex = getIndex(this.context.router.history.location.pathname);
  37. this.setState({ shouldAnimate: true });
  38. }
  39. componentDidUpdate() {
  40. this.lastIndex = getIndex(this.context.router.history.location.pathname);
  41. this.setState({ shouldAnimate: true });
  42. }
  43. handleSwipe = (index) => {
  44. this.pendingIndex = index;
  45. }
  46. handleAnimationEnd = () => {
  47. if (typeof this.pendingIndex === 'number') {
  48. this.context.router.history.push(getLink(this.pendingIndex));
  49. this.pendingIndex = null;
  50. }
  51. }
  52. renderView = (link, index) => {
  53. const columnIndex = getIndex(this.context.router.history.location.pathname);
  54. const title = link.props.children[1] && React.cloneElement(link.props.children[1]);
  55. const icon = (link.props.children[0] || link.props.children).props.className.split(' ')[2].split('-')[1];
  56. const view = (index === columnIndex) ?
  57. React.cloneElement(this.props.children) :
  58. <ColumnLoading title={title} icon={icon} />;
  59. return (
  60. <div className='columns-area' key={index}>
  61. {view}
  62. </div>
  63. );
  64. }
  65. renderLoading = () => {
  66. return <ColumnLoading />;
  67. }
  68. renderError = (props) => {
  69. return <BundleColumnError {...props} />;
  70. }
  71. render () {
  72. const { columns, children, singleColumn } = this.props;
  73. const { shouldAnimate } = this.state;
  74. const columnIndex = getIndex(this.context.router.history.location.pathname);
  75. this.pendingIndex = null;
  76. if (singleColumn) {
  77. return columnIndex !== -1 ? (
  78. <ReactSwipeableViews index={columnIndex} onChangeIndex={this.handleSwipe} onTransitionEnd={this.handleAnimationEnd} animateTransitions={shouldAnimate} springConfig={{ duration: '400ms', delay: '0s', easeFunction: 'ease' }} style={{ height: '100%' }}>
  79. {links.map(this.renderView)}
  80. </ReactSwipeableViews>
  81. ) : <div className='columns-area'>{children}</div>;
  82. }
  83. return (
  84. <div className='columns-area'>
  85. {columns.map(column => {
  86. const params = column.get('params', null) === null ? null : column.get('params').toJS();
  87. return (
  88. <BundleContainer key={column.get('uuid')} fetchComponent={componentMap[column.get('id')]} loading={this.renderLoading} error={this.renderError}>
  89. {SpecificComponent => <SpecificComponent columnId={column.get('uuid')} params={params} multiColumn />}
  90. </BundleContainer>
  91. );
  92. })}
  93. {React.Children.map(children, child => React.cloneElement(child, { multiColumn: true }))}
  94. </div>
  95. );
  96. }
  97. }