Show "read more" link on overly long in-stream statuses (#8205)
Show "read more" link on overly long in-stream statuses
This commit is contained in:
		
							parent
							
								
									42ab93c8b2
								
							
						
					
					
						commit
						15fc2b76f9
					
				
					 3 changed files with 59 additions and 5 deletions
				
			
		|  | @ -285,7 +285,7 @@ class Status extends ImmutablePureComponent { | |||
|               </a> | ||||
|             </div> | ||||
| 
 | ||||
|             <StatusContent status={status} onClick={this.handleClick} expanded={!status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} /> | ||||
|             <StatusContent status={status} onClick={this.handleClick} expanded={!status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} collapsable /> | ||||
| 
 | ||||
|             {media} | ||||
| 
 | ||||
|  |  | |||
|  | @ -6,6 +6,8 @@ import { FormattedMessage } from 'react-intl'; | |||
| import Permalink from './permalink'; | ||||
| import classnames from 'classnames'; | ||||
| 
 | ||||
| const MAX_HEIGHT = 322; // 20px * 16 (+ 2px padding at the top)
 | ||||
| 
 | ||||
| export default class StatusContent extends React.PureComponent { | ||||
| 
 | ||||
|   static contextTypes = { | ||||
|  | @ -17,10 +19,12 @@ export default class StatusContent extends React.PureComponent { | |||
|     expanded: PropTypes.bool, | ||||
|     onExpandedToggle: PropTypes.func, | ||||
|     onClick: PropTypes.func, | ||||
|     collapsable: PropTypes.bool, | ||||
|   }; | ||||
| 
 | ||||
|   state = { | ||||
|     hidden: true, | ||||
|     collapsed: null, //  `collapsed: null` indicates that an element doesn't need collapsing, while `true` or `false` indicates that it does (and is/isn't).
 | ||||
|   }; | ||||
| 
 | ||||
|   _updateStatusLinks () { | ||||
|  | @ -53,6 +57,16 @@ export default class StatusContent extends React.PureComponent { | |||
|       link.setAttribute('target', '_blank'); | ||||
|       link.setAttribute('rel', 'noopener'); | ||||
|     } | ||||
| 
 | ||||
|     if ( | ||||
|       this.props.collapsable | ||||
|       && this.props.onClick | ||||
|       && this.state.collapsed === null | ||||
|       && node.clientHeight > MAX_HEIGHT | ||||
|       && this.props.status.get('spoiler_text').length === 0 | ||||
|     ) { | ||||
|       this.setState({ collapsed: true }); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   componentDidMount () { | ||||
|  | @ -113,6 +127,11 @@ export default class StatusContent extends React.PureComponent { | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   handleCollapsedClick = (e) => { | ||||
|     e.preventDefault(); | ||||
|     this.setState({ collapsed: !this.state.collapsed }); | ||||
|   } | ||||
| 
 | ||||
|   setRef = (c) => { | ||||
|     this.node = c; | ||||
|   } | ||||
|  | @ -132,12 +151,19 @@ export default class StatusContent extends React.PureComponent { | |||
|     const classNames = classnames('status__content', { | ||||
|       'status__content--with-action': this.props.onClick && this.context.router, | ||||
|       'status__content--with-spoiler': status.get('spoiler_text').length > 0, | ||||
|       'status__content--collapsed': this.state.collapsed === true, | ||||
|     }); | ||||
| 
 | ||||
|     if (isRtl(status.get('search_index'))) { | ||||
|       directionStyle.direction = 'rtl'; | ||||
|     } | ||||
| 
 | ||||
|     const readMoreButton = ( | ||||
|       <button className='status__content__read-more-button' onClick={this.props.onClick}> | ||||
|         <FormattedMessage id='status.read_more' defaultMessage='Read more' /><i className='fa fa-fw fa-angle-right' /> | ||||
|       </button> | ||||
|     ); | ||||
| 
 | ||||
|     if (status.get('spoiler_text').length > 0) { | ||||
|       let mentionsPlaceholder = ''; | ||||
| 
 | ||||
|  | @ -167,17 +193,23 @@ export default class StatusContent extends React.PureComponent { | |||
|         </div> | ||||
|       ); | ||||
|     } else if (this.props.onClick) { | ||||
|       return ( | ||||
|       const output = [ | ||||
|         <div | ||||
|           ref={this.setRef} | ||||
|           tabIndex='0' | ||||
|           className={classNames} | ||||
|           style={directionStyle} | ||||
|           dangerouslySetInnerHTML={content} | ||||
|           onMouseDown={this.handleMouseDown} | ||||
|           onMouseUp={this.handleMouseUp} | ||||
|           dangerouslySetInnerHTML={content} | ||||
|         /> | ||||
|       ); | ||||
|         />, | ||||
|       ]; | ||||
| 
 | ||||
|       if (this.state.collapsed) { | ||||
|         output.push(readMoreButton); | ||||
|       } | ||||
| 
 | ||||
|       return output; | ||||
|     } else { | ||||
|       return ( | ||||
|         <div | ||||
|  |  | |||
|  | @ -631,11 +631,13 @@ | |||
| 
 | ||||
| .status__content, | ||||
| .reply-indicator__content { | ||||
|   position: relative; | ||||
|   font-size: 15px; | ||||
|   line-height: 20px; | ||||
|   word-wrap: break-word; | ||||
|   font-weight: 400; | ||||
|   overflow: hidden; | ||||
|   text-overflow: ellipsis; | ||||
|   white-space: pre-wrap; | ||||
|   padding-top: 2px; | ||||
|   color: $primary-text-color; | ||||
|  | @ -721,6 +723,26 @@ | |||
|   } | ||||
| } | ||||
| 
 | ||||
| .status__content.status__content--collapsed { | ||||
|   max-height: 20px * 15; // 15 lines is roughly above 500 characters | ||||
| } | ||||
| 
 | ||||
| .status__content__read-more-button { | ||||
|   display: block; | ||||
|   font-size: 15px; | ||||
|   line-height: 20px; | ||||
|   color: lighten($ui-highlight-color, 8%); | ||||
|   border: 0; | ||||
|   background: transparent; | ||||
|   padding: 0; | ||||
|   padding-top: 8px; | ||||
| 
 | ||||
|   &:hover, | ||||
|   &:active { | ||||
|     text-decoration: underline; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .status__content__spoiler-link { | ||||
|   display: inline-block; | ||||
|   border-radius: 2px; | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue