diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js index 43647acc0..e3ff242a1 100644 --- a/app/javascript/mastodon/components/status.js +++ b/app/javascript/mastodon/components/status.js @@ -285,7 +285,7 @@ export default class Status extends ImmutablePureComponent { - + {media} diff --git a/app/javascript/mastodon/components/status_content.js b/app/javascript/mastodon/components/status_content.js index 81013747e..6aa973df0 100644 --- a/app/javascript/mastodon/components/status_content.js +++ b/app/javascript/mastodon/components/status_content.js @@ -17,11 +17,14 @@ 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 () { const node = this.node; @@ -53,6 +56,13 @@ export default class StatusContent extends React.PureComponent { link.setAttribute('target', '_blank'); link.setAttribute('rel', 'noopener'); } + + if ( + this.props.collapsable + && this.state.collapsed === null + && node.clientHeight > 200 + && this.props.status.get('spoiler_text').length === 0 + ) this.setState({ collapsed: true }); } componentDidMount () { @@ -113,6 +123,11 @@ export default class StatusContent extends React.PureComponent { } } + handleCollapsedClick = (e) => { + e.preventDefault(); + this.setState({ collapsed: !this.state.collapsed }); + } + setRef = (c) => { this.node = c; } @@ -132,6 +147,8 @@ 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, + 'status__content--expanded': this.state.collapsed === false, }); if (isRtl(status.get('search_index'))) { @@ -175,8 +192,17 @@ export default class StatusContent extends React.PureComponent { style={directionStyle} onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp} - dangerouslySetInnerHTML={content} - /> + > +
+ {this.state.collapsed !== null ? + + : null} +
); } else { return ( diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 85d41369d..f64a9d53b 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -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,55 @@ } } +.status__content.status__content--collapsed { + padding-bottom: 25px; + max-height: 200px; + + i { + transform: rotateX(0); + } +} + +.status__content.status__content--expanded, { + padding-bottom: 25px; + height: auto; + + i { + transform: rotateX(180deg); + } +} + +.status__content__collapse-button { + display: block; + position: absolute; + bottom: 0; + left: 0; + right: 0; + width: 100%; + height: 25px; + font-size: 18px; + line-height: 25px; + color: $inverted-text-color; + text-align: center; + background: $action-button-color; + transition: background .2s ease-in-out, color .2s ease-in-out; + border: 0; + border-radius: 2px; + + &:hover { + background: lighten($action-button-color, 7%); + } + + i { + transition: transform .2s ease-in-out; + + &, + &:hover { + color: $inverted-text-color !important; + } + } +} + .status__content__spoiler-link { display: inline-block; border-radius: 2px;