diff --git a/app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap index f5c10aa37..7fbdedeb2 100644 --- a/app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap +++ b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap @@ -2,36 +2,38 @@ exports[`<Avatar /> Autoplay renders a animated avatar 1`] = ` <div - aria-label="alice" className="account__avatar" onMouseEnter={[Function]} onMouseLeave={[Function]} - role="img" style={ { - "backgroundImage": "url(/animated/alice.gif)", - "backgroundSize": "100px 100px", "height": "100px", "width": "100px", } } -/> +> + <img + alt="alice" + src="/animated/alice.gif" + /> +</div> `; exports[`<Avatar /> Still renders a still avatar 1`] = ` <div - aria-label="alice" className="account__avatar" onMouseEnter={[Function]} onMouseLeave={[Function]} - role="img" style={ { - "backgroundImage": "url(/static/alice.jpg)", - "backgroundSize": "100px 100px", "height": "100px", "width": "100px", } } -/> +> + <img + alt="alice" + src="/static/alice.jpg" + /> +</div> `; diff --git a/app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.js.snap b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.js.snap index 58f27a321..f8385357a 100644 --- a/app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.js.snap +++ b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.js.snap @@ -3,22 +3,52 @@ exports[`<AvatarOverlay renders a overlay avatar 1`] = ` <div className="account__avatar-overlay" + style={ + { + "height": 46, + "width": 46, + } + } > <div className="account__avatar-overlay-base" - style={ - { - "backgroundImage": "url(/static/alice.jpg)", + > + <div + className="account__avatar" + onMouseEnter={[Function]} + onMouseLeave={[Function]} + style={ + { + "height": "36px", + "width": "36px", + } } - } - /> + > + <img + alt="alice" + src="/static/alice.jpg" + /> + </div> + </div> <div className="account__avatar-overlay-overlay" - style={ - { - "backgroundImage": "url(/static/eve.jpg)", + > + <div + className="account__avatar" + onMouseEnter={[Function]} + onMouseLeave={[Function]} + style={ + { + "height": "24px", + "width": "24px", + } } - } - /> + > + <img + alt="eve@blackhat.lair" + src="/static/eve.jpg" + /> + </div> + </div> </div> `; diff --git a/app/javascript/mastodon/components/avatar.js b/app/javascript/mastodon/components/avatar.js index dd3932ae6..207b26691 100644 --- a/app/javascript/mastodon/components/avatar.js +++ b/app/javascript/mastodon/components/avatar.js @@ -42,30 +42,20 @@ export default class Avatar extends React.PureComponent { ...this.props.style, width: `${size}px`, height: `${size}px`, - backgroundSize: `${size}px ${size}px`, }; - if (account) { - const src = account.get('avatar'); - const staticSrc = account.get('avatar_static'); + let src; - if (hovering || animate) { - style.backgroundImage = `url(${src})`; - } else { - style.backgroundImage = `url(${staticSrc})`; - } + if (hovering || animate) { + src = account?.get('avatar'); + } else { + src = account?.get('avatar_static'); } - return ( - <div - className={classNames('account__avatar', { 'account__avatar-inline': inline })} - onMouseEnter={this.handleMouseEnter} - onMouseLeave={this.handleMouseLeave} - style={style} - role='img' - aria-label={account?.get('acct')} - /> + <div className={classNames('account__avatar', { 'account__avatar-inline': inline })} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} style={style}> + <img src={src} alt={account?.get('acct')} /> + </div> ); } diff --git a/app/javascript/mastodon/components/avatar_composite.js b/app/javascript/mastodon/components/avatar_composite.js index 5d5b89749..220bf5b4f 100644 --- a/app/javascript/mastodon/components/avatar_composite.js +++ b/app/javascript/mastodon/components/avatar_composite.js @@ -2,6 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { autoPlayGif } from '../initial_state'; +import Avatar from './avatar'; export default class AvatarComposite extends React.PureComponent { @@ -74,12 +75,12 @@ export default class AvatarComposite extends React.PureComponent { bottom: bottom, width: `${width}%`, height: `${height}%`, - backgroundSize: 'cover', - backgroundImage: `url(${account.get(animate ? 'avatar' : 'avatar_static')})`, }; return ( - <div key={account.get('id')} style={style} /> + <div key={account.get('id')} style={style}> + <Avatar account={account} animate={animate} /> + </div> ); } diff --git a/app/javascript/mastodon/components/avatar_overlay.js b/app/javascript/mastodon/components/avatar_overlay.js index 3ec1d7730..8d5d44ea5 100644 --- a/app/javascript/mastodon/components/avatar_overlay.js +++ b/app/javascript/mastodon/components/avatar_overlay.js @@ -2,6 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { autoPlayGif } from '../initial_state'; +import Avatar from './avatar'; export default class AvatarOverlay extends React.PureComponent { @@ -9,27 +10,40 @@ export default class AvatarOverlay extends React.PureComponent { account: ImmutablePropTypes.map.isRequired, friend: ImmutablePropTypes.map.isRequired, animate: PropTypes.bool, + size: PropTypes.number, + baseSize: PropTypes.number, + overlaySize: PropTypes.number, }; static defaultProps = { animate: autoPlayGif, + size: 46, + baseSize: 36, + overlaySize: 24, }; + state = { + hovering: false, + }; + + handleMouseEnter = () => { + if (this.props.animate) return; + this.setState({ hovering: true }); + } + + handleMouseLeave = () => { + if (this.props.animate) return; + this.setState({ hovering: false }); + } + render() { - const { account, friend, animate } = this.props; - - const baseStyle = { - backgroundImage: `url(${account.get(animate ? 'avatar' : 'avatar_static')})`, - }; - - const overlayStyle = { - backgroundImage: `url(${friend.get(animate ? 'avatar' : 'avatar_static')})`, - }; + const { account, friend, animate, size, baseSize, overlaySize } = this.props; + const { hovering } = this.state; return ( - <div className='account__avatar-overlay'> - <div className='account__avatar-overlay-base' style={baseStyle} /> - <div className='account__avatar-overlay-overlay' style={overlayStyle} /> + <div className='account__avatar-overlay' style={{ width: size, height: size }}> + <div className='account__avatar-overlay-base'><Avatar animate={hovering || animate} account={account} size={baseSize} /></div> + <div className='account__avatar-overlay-overlay'><Avatar animate={hovering || animate} account={friend} size={overlaySize} /></div> </div> ); } diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 633b9ed70..69301fb05 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -1382,6 +1382,14 @@ display: block; position: relative; + overflow: hidden; + + img { + display: block; + width: 100%; + height: 100%; + object-fit: cover; + } &-inline { display: inline-block; @@ -1390,8 +1398,6 @@ } &-composite { - @include avatar-radius; - border-radius: 50%; overflow: hidden; position: relative; @@ -1402,6 +1408,11 @@ box-sizing: border-box; } + .account__avatar { + width: 100% !important; + height: 100% !important; + } + &__label { display: block; position: absolute; @@ -1421,37 +1432,13 @@ a .account__avatar { } .account__avatar-overlay { - @include avatar-size(46px); - position: relative; - &-base { - @include avatar-radius; - @include avatar-size(36px); - - img { - @include avatar-radius; - - width: 100%; - height: 100%; - } - } - &-overlay { - @include avatar-radius; - @include avatar-size(24px); - position: absolute; bottom: 0; right: 0; z-index: 1; - - img { - @include avatar-radius; - - width: 100%; - height: 100%; - } } }