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
This commit is contained in:
parent
bf8031e984
commit
383c0b7802
|
@ -25,9 +25,15 @@ class Avatar extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { src, size, staticSrc, animate } = this.props;
|
const { src, size, staticSrc, animate, inline } = this.props;
|
||||||
const { hovering } = this.state;
|
const { hovering } = this.state;
|
||||||
|
|
||||||
|
let className = 'account__avatar';
|
||||||
|
|
||||||
|
if (inline) {
|
||||||
|
className = className + ' account__avatar-inline';
|
||||||
|
}
|
||||||
|
|
||||||
const style = {
|
const style = {
|
||||||
...this.props.style,
|
...this.props.style,
|
||||||
width: `${size}px`,
|
width: `${size}px`,
|
||||||
|
@ -43,7 +49,7 @@ class Avatar extends React.PureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className='account__avatar'
|
className={className}
|
||||||
onMouseEnter={this.handleMouseEnter}
|
onMouseEnter={this.handleMouseEnter}
|
||||||
onMouseLeave={this.handleMouseLeave}
|
onMouseLeave={this.handleMouseLeave}
|
||||||
style={style}
|
style={style}
|
||||||
|
@ -58,11 +64,14 @@ Avatar.propTypes = {
|
||||||
staticSrc: PropTypes.string,
|
staticSrc: PropTypes.string,
|
||||||
size: PropTypes.number.isRequired,
|
size: PropTypes.number.isRequired,
|
||||||
style: PropTypes.object,
|
style: PropTypes.object,
|
||||||
animate: PropTypes.bool
|
animate: PropTypes.bool,
|
||||||
|
inline: PropTypes.bool
|
||||||
};
|
};
|
||||||
|
|
||||||
Avatar.defaultProps = {
|
Avatar.defaultProps = {
|
||||||
animate: false
|
animate: false,
|
||||||
|
size: 20,
|
||||||
|
inline: false
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Avatar;
|
export default Avatar;
|
||||||
|
|
30
app/javascript/mastodon/components/avatar_overlay.js
Normal file
30
app/javascript/mastodon/components/avatar_overlay.js
Normal file
|
@ -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;
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Avatar from './avatar';
|
import Avatar from './avatar';
|
||||||
|
import AvatarOverlay from './avatar_overlay';
|
||||||
import RelativeTimestamp from './relative_timestamp';
|
import RelativeTimestamp from './relative_timestamp';
|
||||||
import DisplayName from './display_name';
|
import DisplayName from './display_name';
|
||||||
import MediaGallery from './media_gallery';
|
import MediaGallery from './media_gallery';
|
||||||
|
@ -36,7 +37,8 @@ class Status extends ImmutablePureComponent {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let media = '';
|
let media = '';
|
||||||
const { status, ...other } = this.props;
|
let statusAvatar;
|
||||||
|
const { status, account, ...other } = this.props;
|
||||||
|
|
||||||
if (status === null) {
|
if (status === null) {
|
||||||
return <div />;
|
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> }} />
|
<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>
|
</div>
|
||||||
|
|
||||||
<Status {...other} wrapped={true} status={status.get('reblog')} />
|
<Status {...other} wrapped={true} status={status.get('reblog')} account={status.get('account')} />
|
||||||
</div>
|
</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 (
|
return (
|
||||||
<div className={this.props.muted ? 'status muted' : 'status'}>
|
<div className={this.props.muted ? 'status muted' : 'status'}>
|
||||||
<div className='status__info'>
|
<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'>
|
<a onClick={this.handleAccountClick.bind(this, status.getIn(['account', 'id']))} href={status.getIn(['account', 'url'])} className='status__display-name'>
|
||||||
<div className='status__avatar'>
|
<div className='status__avatar'>
|
||||||
<Avatar src={status.getIn(['account', 'avatar'])} staticSrc={status.getIn(['account', 'avatar_static'])} size={48} />
|
{statusAvatar}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DisplayName account={status.get('account')} />
|
<DisplayName account={status.get('account')} />
|
||||||
|
@ -106,6 +114,7 @@ Status.contextTypes = {
|
||||||
|
|
||||||
Status.propTypes = {
|
Status.propTypes = {
|
||||||
status: ImmutablePropTypes.map,
|
status: ImmutablePropTypes.map,
|
||||||
|
account: ImmutablePropTypes.map,
|
||||||
wrapped: PropTypes.bool,
|
wrapped: PropTypes.bool,
|
||||||
onReply: PropTypes.func,
|
onReply: PropTypes.func,
|
||||||
onFavourite: PropTypes.func,
|
onFavourite: PropTypes.func,
|
||||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import StatusContainer from '../../../containers/status_container';
|
import StatusContainer from '../../../containers/status_container';
|
||||||
import AccountContainer from '../../../containers/account_container';
|
import AccountContainer from '../../../containers/account_container';
|
||||||
|
import Avatar from '../../../components/avatar';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import Permalink from '../../../components/permalink';
|
import Permalink from '../../../components/permalink';
|
||||||
import emojify from '../../../emoji';
|
import emojify from '../../../emoji';
|
||||||
|
@ -37,11 +38,10 @@ class Notification extends ImmutablePureComponent {
|
||||||
<div className='notification__favourite-icon-wrapper'>
|
<div className='notification__favourite-icon-wrapper'>
|
||||||
<i className='fa fa-fw fa-star star-icon'/>
|
<i className='fa fa-fw fa-star star-icon'/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FormattedMessage id='notification.favourite' defaultMessage='{name} favourited your status' values={{ name: link }} />
|
<FormattedMessage id='notification.favourite' defaultMessage='{name} favourited your status' values={{ name: link }} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<StatusContainer id={notification.get('status')} muted={true} />
|
<StatusContainer id={notification.get('status')} account={notification.get('account')} muted={true} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -53,11 +53,10 @@ class Notification extends ImmutablePureComponent {
|
||||||
<div className='notification__favourite-icon-wrapper'>
|
<div className='notification__favourite-icon-wrapper'>
|
||||||
<i className='fa fa-fw fa-retweet' />
|
<i className='fa fa-fw fa-retweet' />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FormattedMessage id='notification.reblog' defaultMessage='{name} boosted your status' values={{ name: link }} />
|
<FormattedMessage id='notification.reblog' defaultMessage='{name} boosted your status' values={{ name: link }} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<StatusContainer id={notification.get('status')} muted={true} />
|
<StatusContainer id={notification.get('status')} account={notification.get('account')} muted={true} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
12
app/javascript/styles/_mixins.scss
Normal file
12
app/javascript/styles/_mixins.scss
Normal file
|
@ -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,3 +1,4 @@
|
||||||
|
@import 'mixins';
|
||||||
@import 'variables';
|
@import 'variables';
|
||||||
@import 'fonts/roboto';
|
@import 'fonts/roboto';
|
||||||
@import 'fonts/roboto-mono';
|
@import 'fonts/roboto-mono';
|
||||||
|
|
|
@ -673,11 +673,33 @@ a.status__content__spoiler-link {
|
||||||
}
|
}
|
||||||
|
|
||||||
.account__avatar {
|
.account__avatar {
|
||||||
border-radius: 4px;
|
@include avatar-radius();
|
||||||
background: transparent no-repeat;
|
|
||||||
background-position: 50%;
|
|
||||||
background-clip: padding-box;
|
|
||||||
position: relative;
|
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 {
|
.account__relationship {
|
||||||
|
|
Reference in a new issue