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.

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