The code powering m.abunchtell.com https://m.abunchtell.com
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.
 
 
 
 

178 lines
5.5 KiB

  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import classNames from 'classnames';
  4. import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
  5. import Icon from 'mastodon/components/icon';
  6. const messages = defineMessages({
  7. show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' },
  8. hide: { id: 'column_header.hide_settings', defaultMessage: 'Hide settings' },
  9. moveLeft: { id: 'column_header.moveLeft_settings', defaultMessage: 'Move column to the left' },
  10. moveRight: { id: 'column_header.moveRight_settings', defaultMessage: 'Move column to the right' },
  11. });
  12. export default @injectIntl
  13. class ColumnHeader extends React.PureComponent {
  14. static contextTypes = {
  15. router: PropTypes.object,
  16. };
  17. static propTypes = {
  18. intl: PropTypes.object.isRequired,
  19. title: PropTypes.node,
  20. icon: PropTypes.string,
  21. active: PropTypes.bool,
  22. multiColumn: PropTypes.bool,
  23. extraButton: PropTypes.node,
  24. showBackButton: PropTypes.bool,
  25. children: PropTypes.node,
  26. pinned: PropTypes.bool,
  27. onPin: PropTypes.func,
  28. onMove: PropTypes.func,
  29. onClick: PropTypes.func,
  30. };
  31. state = {
  32. collapsed: true,
  33. animating: false,
  34. };
  35. historyBack = () => {
  36. if (window.history && window.history.length === 1) {
  37. this.context.router.history.push('/');
  38. } else {
  39. this.context.router.history.goBack();
  40. }
  41. }
  42. handleToggleClick = (e) => {
  43. e.stopPropagation();
  44. this.setState({ collapsed: !this.state.collapsed, animating: true });
  45. }
  46. handleTitleClick = () => {
  47. this.props.onClick();
  48. }
  49. handleMoveLeft = () => {
  50. this.props.onMove(-1);
  51. }
  52. handleMoveRight = () => {
  53. this.props.onMove(1);
  54. }
  55. handleBackClick = () => {
  56. this.historyBack();
  57. }
  58. handleTransitionEnd = () => {
  59. this.setState({ animating: false });
  60. }
  61. handlePin = () => {
  62. if (!this.props.pinned) {
  63. this.historyBack();
  64. }
  65. this.props.onPin();
  66. }
  67. render () {
  68. const { title, icon, active, children, pinned, multiColumn, extraButton, showBackButton, intl: { formatMessage } } = this.props;
  69. const { collapsed, animating } = this.state;
  70. const wrapperClassName = classNames('column-header__wrapper', {
  71. 'active': active,
  72. });
  73. const buttonClassName = classNames('column-header', {
  74. 'active': active,
  75. });
  76. const collapsibleClassName = classNames('column-header__collapsible', {
  77. 'collapsed': collapsed,
  78. 'animating': animating,
  79. });
  80. const collapsibleButtonClassName = classNames('column-header__button', {
  81. 'active': !collapsed,
  82. });
  83. let extraContent, pinButton, moveButtons, backButton, collapseButton;
  84. if (children) {
  85. extraContent = (
  86. <div key='extra-content' className='column-header__collapsible__extra'>
  87. {children}
  88. </div>
  89. );
  90. }
  91. if (multiColumn && pinned) {
  92. pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><Icon id='times' /> <FormattedMessage id='column_header.unpin' defaultMessage='Unpin' /></button>;
  93. moveButtons = (
  94. <div key='move-buttons' className='column-header__setting-arrows'>
  95. <button title={formatMessage(messages.moveLeft)} aria-label={formatMessage(messages.moveLeft)} className='text-btn column-header__setting-btn' onClick={this.handleMoveLeft}><Icon id='chevron-left' /></button>
  96. <button title={formatMessage(messages.moveRight)} aria-label={formatMessage(messages.moveRight)} className='text-btn column-header__setting-btn' onClick={this.handleMoveRight}><Icon id='chevron-right' /></button>
  97. </div>
  98. );
  99. } else if (multiColumn) {
  100. pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><Icon id='plus' /> <FormattedMessage id='column_header.pin' defaultMessage='Pin' /></button>;
  101. }
  102. if (!pinned && (multiColumn || showBackButton)) {
  103. backButton = (
  104. <button onClick={this.handleBackClick} className='column-header__back-button'>
  105. <Icon id='chevron-left' className='column-back-button__icon' fixedWidth />
  106. <FormattedMessage id='column_back_button.label' defaultMessage='Back' />
  107. </button>
  108. );
  109. }
  110. const collapsedContent = [
  111. extraContent,
  112. ];
  113. if (multiColumn) {
  114. collapsedContent.push(moveButtons);
  115. collapsedContent.push(pinButton);
  116. }
  117. if (children || multiColumn) {
  118. collapseButton = <button className={collapsibleButtonClassName} title={formatMessage(collapsed ? messages.show : messages.hide)} aria-label={formatMessage(collapsed ? messages.show : messages.hide)} aria-pressed={collapsed ? 'false' : 'true'} onClick={this.handleToggleClick}><Icon id='sliders' /></button>;
  119. }
  120. const hasTitle = icon && title;
  121. return (
  122. <div className={wrapperClassName}>
  123. <h1 className={buttonClassName}>
  124. {hasTitle && (
  125. <button onClick={this.handleTitleClick}>
  126. <Icon id={icon} fixedWidth className='column-header__icon' />
  127. {title}
  128. </button>
  129. )}
  130. {!hasTitle && backButton}
  131. <div className='column-header__buttons'>
  132. {hasTitle && backButton}
  133. {extraButton}
  134. {collapseButton}
  135. </div>
  136. </h1>
  137. <div className={collapsibleClassName} tabIndex={collapsed ? -1 : null} onTransitionEnd={this.handleTransitionEnd}>
  138. <div className='column-header__collapsible-inner'>
  139. {(!collapsed || animating) && collapsedContent}
  140. </div>
  141. </div>
  142. </div>
  143. );
  144. }
  145. }