[Glitch] Update `Avatar`, `AvatarComposite`, and `AvatarOverlay` components (#2508)

Various ports including 8dfe5179ee,
d1de7fb7fa and
9f8d34620b.

Co-authored-by: Eugen Rochko <eugen@zeonfederated.com>
Co-authored-by: fusagiko / takayamaki <24884114+takayamaki@users.noreply.github.com>
This commit is contained in:
Claire 2023-12-09 18:33:42 +01:00 committed by GitHub
parent c0e562916c
commit b2647bc3f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 93 additions and 94 deletions

View File

@ -5,49 +5,44 @@ import { autoPlayGif } from '../initial_state';
import type { Account } from '../types/resources';
interface Props {
account: Account | undefined;
className?: string;
account: Account | undefined; // FIXME: remove `undefined` once we know for sure its always there
size: number;
style?: React.CSSProperties;
inline?: boolean;
animate?: boolean;
}
export const Avatar: React.FC<Props> = ({
account,
className,
animate = autoPlayGif,
size = 20,
inline = false,
style: styleFromParent,
}) => {
const { hovering, handleMouseEnter, handleMouseLeave } =
useHovering(autoPlayGif);
const { hovering, handleMouseEnter, handleMouseLeave } = useHovering(animate);
const style = {
...styleFromParent,
width: `${size}px`,
height: `${size}px`,
backgroundSize: `${size}px ${size}px`,
};
if (account) {
style.backgroundImage = `url(${account.get(
hovering ? 'avatar' : 'avatar_static',
)})`;
}
const src =
hovering || animate
? account?.get('avatar')
: account?.get('avatar_static');
return (
<div
className={classNames(
'account__avatar',
{ 'account__avatar-inline': inline },
className,
)}
className={classNames('account__avatar', {
'account__avatar-inline': inline,
})}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
style={style}
data-avatar-of={account && `@${account.get('acct')}`}
role='img'
aria-label={account?.get('acct')}
/>
>
{src && <img src={src} alt={account?.get('acct')} />}
</div>
);
};

View File

@ -5,6 +5,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { autoPlayGif } from '../initial_state';
import { Avatar } from './avatar';
export default class AvatarComposite extends PureComponent {
static propTypes = {
@ -76,12 +78,12 @@ export default class AvatarComposite extends 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} data-avatar-of={`@${account.get('acct')}`} />
<div key={account.get('id')} style={style}>
<Avatar account={account} animate={animate} />
</div>
);
}

View File

@ -1,39 +0,0 @@
import PropTypes from 'prop-types';
import { PureComponent } from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { autoPlayGif } from 'flavours/glitch/initial_state';
export default class AvatarOverlay extends PureComponent {
static propTypes = {
account: ImmutablePropTypes.map.isRequired,
friend: ImmutablePropTypes.map.isRequired,
animate: PropTypes.bool,
};
static defaultProps = {
animate: autoPlayGif,
};
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')})`,
};
return (
<div className='account__avatar-overlay'>
<div className='account__avatar-overlay-base' style={baseStyle} data-avatar-of={`@${account.get('acct')}`} />
<div className='account__avatar-overlay-overlay' style={overlayStyle} data-avatar-of={`@${friend.get('acct')}`} />
</div>
);
}
}

View File

@ -0,0 +1,56 @@
import { useHovering } from '../hooks/useHovering';
import { autoPlayGif } from '../initial_state';
import type { Account } from '../types/resources';
interface Props {
account: Account | undefined; // FIXME: remove `undefined` once we know for sure its always there
friend: Account | undefined; // FIXME: remove `undefined` once we know for sure its always there
size?: number;
baseSize?: number;
overlaySize?: number;
}
export const AvatarOverlay: React.FC<Props> = ({
account,
friend,
size = 46,
baseSize = 36,
overlaySize = 24,
}) => {
const { hovering, handleMouseEnter, handleMouseLeave } =
useHovering(autoPlayGif);
const accountSrc = hovering
? account?.get('avatar')
: account?.get('avatar_static');
const friendSrc = hovering
? friend?.get('avatar')
: friend?.get('avatar_static');
return (
<div
className='account__avatar-overlay'
style={{ width: size, height: size }}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<div className='account__avatar-overlay-base'>
<div
className='account__avatar'
style={{ width: `${baseSize}px`, height: `${baseSize}px` }}
data-avatar-of={`@${account?.get('acct')}`}
>
{accountSrc && <img src={accountSrc} alt={account?.get('acct')} />}
</div>
</div>
<div className='account__avatar-overlay-overlay'>
<div
className='account__avatar'
style={{ width: `${overlaySize}px`, height: `${overlaySize}px` }}
data-avatar-of={`@${friend?.get('acct')}`}
>
{friendSrc && <img src={friendSrc} alt={friend?.get('acct')} />}
</div>
</div>
</div>
);
};

View File

@ -6,7 +6,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
// Mastodon imports.
import { Avatar } from './avatar';
import AvatarOverlay from './avatar_overlay';
import { AvatarOverlay } from './avatar_overlay';
import { DisplayName } from './display_name';
export default class StatusHeader extends PureComponent {
@ -39,7 +39,7 @@ export default class StatusHeader extends PureComponent {
let statusAvatar;
if (friend === undefined || friend === null) {
statusAvatar = <Avatar account={account} size={48} />;
statusAvatar = <Avatar account={account} size={46} />;
} else {
statusAvatar = <AvatarOverlay account={account} friend={friend} />;
}

View File

@ -8,7 +8,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { Icon } from 'flavours/glitch/components/icon';
import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router';
import AvatarOverlay from '../../../components/avatar_overlay';
import { AvatarOverlay } from '../../../components/avatar_overlay';
import { DisplayName } from '../../../components/display_name';
class MovedNote extends ImmutablePureComponent {

View File

@ -5,7 +5,7 @@ import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import AvatarOverlay from 'flavours/glitch/components/avatar_overlay';
import { AvatarOverlay } from 'flavours/glitch/components/avatar_overlay';
import { RelativeTimestamp } from 'flavours/glitch/components/relative_timestamp';
// This needs to be kept in sync with app/models/report.rb

View File

@ -85,10 +85,14 @@
display: block;
position: relative;
cursor: pointer;
width: 36px;
height: 36px;
background-size: 36px 36px;
overflow: hidden;
img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
&-inline {
display: inline-block;
@ -102,7 +106,7 @@
overflow: hidden;
position: relative;
& div {
& > div {
@include avatar-radius;
float: left;
@ -110,6 +114,11 @@
box-sizing: border-box;
}
.account__avatar {
width: 100% !important;
height: 100% !important;
}
&__label {
display: block;
position: absolute;
@ -125,37 +134,13 @@
}
.account__avatar-overlay {
@include avatar-size(48px);
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;
inset-inline-end: 0;
z-index: 1;
img {
@include avatar-radius;
width: 100%;
height: 100%;
}
}
}