Browse Source

Show boosted user's avatar (#2518)

* Show boosted user's avatar

* add .status__avatar-boost

* margin

* apply to notifications too.

* account__avatar-boost

* Add inline prop to Avatar component

* Add AvatarOverlay component

* rename mixins.scss

* move files for latest master

* fixed for webpack
kawax 7 years ago
parent
commit
383c0b7802

+ 13 - 4
app/javascript/mastodon/components/avatar.js

@@ -25,9 +25,15 @@ class Avatar extends React.PureComponent {
   }
 
   render () {
-    const { src, size, staticSrc, animate } = this.props;
+    const { src, size, staticSrc, animate, inline } = this.props;
     const { hovering } = this.state;
 
+    let className = 'account__avatar';
+
+    if (inline) {
+      className = className + ' account__avatar-inline';
+    }
+
     const style = {
       ...this.props.style,
       width: `${size}px`,
@@ -43,7 +49,7 @@ class Avatar extends React.PureComponent {
 
     return (
       <div
-        className='account__avatar'
+        className={className}
         onMouseEnter={this.handleMouseEnter}
         onMouseLeave={this.handleMouseLeave}
         style={style}
@@ -58,11 +64,14 @@ Avatar.propTypes = {
   staticSrc: PropTypes.string,
   size: PropTypes.number.isRequired,
   style: PropTypes.object,
-  animate: PropTypes.bool
+  animate: PropTypes.bool,
+  inline: PropTypes.bool
 };
 
 Avatar.defaultProps = {
-  animate: false
+  animate: false,
+  size: 20,
+  inline: false
 };
 
 export default Avatar;

+ 30 - 0
app/javascript/mastodon/components/avatar_overlay.js

@@ -0,0 +1,30 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+class AvatarOverlay extends React.PureComponent {
+  render() {
+    const {staticSrc, overlaySrc} = this.props;
+
+    const baseStyle = {
+      backgroundImage: `url(${staticSrc})`
+    };
+
+    const overlayStyle = {
+      backgroundImage: `url(${overlaySrc})`
+    };
+
+    return (
+      <div className='account__avatar-overlay'>
+        <div className="account__avatar-overlay-base" style={baseStyle} />
+        <div className="account__avatar-overlay-overlay" style={overlayStyle} />
+      </div>
+    );
+  }
+}
+
+AvatarOverlay.propTypes = {
+  staticSrc: PropTypes.string.isRequired,
+  overlaySrc: PropTypes.string.isRequired,
+};
+
+export default AvatarOverlay;

+ 12 - 3
app/javascript/mastodon/components/status.js

@@ -2,6 +2,7 @@ import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import Avatar from './avatar';
+import AvatarOverlay from './avatar_overlay';
 import RelativeTimestamp from './relative_timestamp';
 import DisplayName from './display_name';
 import MediaGallery from './media_gallery';
@@ -36,7 +37,8 @@ class Status extends ImmutablePureComponent {
 
   render () {
     let media = '';
-    const { status, ...other } = this.props;
+    let statusAvatar;
+    const { status, account, ...other } = this.props;
 
     if (status === null) {
       return <div />;
@@ -58,7 +60,7 @@ class Status extends ImmutablePureComponent {
             <FormattedMessage id='status.reblogged_by' defaultMessage='{name} boosted' values={{ name: <a onClick={this.handleAccountClick.bind(this, status.getIn(['account', 'id']))} href={status.getIn(['account', 'url'])} className='status__display-name muted'><strong dangerouslySetInnerHTML={displayNameHTML} /></a> }} />
           </div>
 
-          <Status {...other} wrapped={true} status={status.get('reblog')} />
+          <Status {...other} wrapped={true} status={status.get('reblog')} account={status.get('account')} />
         </div>
       );
     }
@@ -73,6 +75,12 @@ class Status extends ImmutablePureComponent {
       }
     }
 
+    if (account === undefined || account === null) {
+      statusAvatar = <Avatar src={status.getIn(['account', 'avatar'])} staticSrc={status.getIn(['account', 'avatar_static'])} size={48}/>;
+    }else{
+      statusAvatar = <AvatarOverlay staticSrc={status.getIn(['account', 'avatar_static'])} overlaySrc={account.get('avatar_static')} />;
+    }
+
     return (
       <div className={this.props.muted ? 'status muted' : 'status'}>
         <div className='status__info'>
@@ -82,7 +90,7 @@ class Status extends ImmutablePureComponent {
 
           <a onClick={this.handleAccountClick.bind(this, status.getIn(['account', 'id']))} href={status.getIn(['account', 'url'])} className='status__display-name'>
             <div className='status__avatar'>
-              <Avatar src={status.getIn(['account', 'avatar'])} staticSrc={status.getIn(['account', 'avatar_static'])} size={48} />
+              {statusAvatar}
             </div>
 
             <DisplayName account={status.get('account')} />
@@ -106,6 +114,7 @@ Status.contextTypes = {
 
 Status.propTypes = {
   status: ImmutablePropTypes.map,
+  account: ImmutablePropTypes.map,
   wrapped: PropTypes.bool,
   onReply: PropTypes.func,
   onFavourite: PropTypes.func,

+ 3 - 4
app/javascript/mastodon/features/notifications/components/notification.js

@@ -2,6 +2,7 @@ import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import StatusContainer from '../../../containers/status_container';
 import AccountContainer from '../../../containers/account_container';
+import Avatar from '../../../components/avatar';
 import { FormattedMessage } from 'react-intl';
 import Permalink from '../../../components/permalink';
 import emojify from '../../../emoji';
@@ -37,11 +38,10 @@ class Notification extends ImmutablePureComponent {
           <div className='notification__favourite-icon-wrapper'>
             <i className='fa fa-fw fa-star star-icon'/>
           </div>
-
           <FormattedMessage id='notification.favourite' defaultMessage='{name} favourited your status' values={{ name: link }} />
         </div>
 
-        <StatusContainer id={notification.get('status')} muted={true} />
+        <StatusContainer id={notification.get('status')} account={notification.get('account')} muted={true} />
       </div>
     );
   }
@@ -53,11 +53,10 @@ class Notification extends ImmutablePureComponent {
           <div className='notification__favourite-icon-wrapper'>
             <i className='fa fa-fw fa-retweet' />
           </div>
-
           <FormattedMessage id='notification.reblog' defaultMessage='{name} boosted your status' values={{ name: link }} />
         </div>
 
-        <StatusContainer id={notification.get('status')} muted={true} />
+        <StatusContainer id={notification.get('status')} account={notification.get('account')} muted={true} />
       </div>
     );
   }

+ 12 - 0
app/javascript/styles/_mixins.scss

@@ -0,0 +1,12 @@
+@mixin avatar-radius() {
+  border-radius: 4px;
+  background: transparent no-repeat;
+  background-position: 50%;
+  background-clip: padding-box;
+}
+
+@mixin avatar-size($size:48px) {
+  width: $size;
+  height: $size;
+  background-size: $size $size;
+}

+ 1 - 0
app/javascript/styles/application.scss

@@ -1,3 +1,4 @@
+@import 'mixins';
 @import 'variables';
 @import 'fonts/roboto';
 @import 'fonts/roboto-mono';

+ 26 - 4
app/javascript/styles/components.scss

@@ -673,11 +673,33 @@ a.status__content__spoiler-link {
 }
 
 .account__avatar {
-  border-radius: 4px;
-  background: transparent no-repeat;
-  background-position: 50%;
-  background-clip: padding-box;
+  @include avatar-radius();
   position: relative;
+
+  &-inline {
+    display: inline-block;
+    vertical-align: middle;
+    margin-right: 5px;
+  }
+}
+
+.account__avatar-overlay {
+  @include avatar-size(48px);
+
+  &-base {
+    @include avatar-radius();
+    @include avatar-size(36px);
+  }
+
+  &-overlay {
+    @include avatar-radius();
+    @include avatar-size(24px);
+
+    position: absolute;
+    bottom: 0;
+    right: 0;
+    z-index: 1;
+  }
 }
 
 .account__relationship {