Update avatar badge placements to match designs

This commit is contained in:
Evan Hahn 2021-11-09 14:34:47 -06:00 committed by GitHub
parent e50f76a909
commit 9ce8acc846
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 81 additions and 6 deletions

View file

@ -107,9 +107,11 @@
} }
&__badge { &__badge {
bottom: 0;
position: absolute; position: absolute;
right: 0;
z-index: 1; z-index: 1;
// Positioning should be overridden by JavaScript. These are set defensively.
bottom: 0;
right: 0;
} }
} }

View file

@ -57,6 +57,7 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
sharedGroupNames: [], sharedGroupNames: [],
size: 80, size: 80,
title: overrideProps.title || '', title: overrideProps.title || '',
theme: overrideProps.theme,
}); });
const sizes: Array<Props['size']> = [112, 96, 80, 52, 32, 28]; const sizes: Array<Props['size']> = [112, 96, 80, 52, 32, 28];

View file

@ -44,6 +44,8 @@ export enum AvatarSize {
ONE_HUNDRED_TWELVE = 112, ONE_HUNDRED_TWELVE = 112,
} }
type BadgePlacementType = { size: number; bottom: number; right: number };
export type Props = { export type Props = {
avatarPath?: string; avatarPath?: string;
badge?: BadgeType; badge?: BadgeType;
@ -72,6 +74,17 @@ export type Props = {
i18n: LocalizerType; i18n: LocalizerType;
} & Pick<React.HTMLProps<HTMLDivElement>, 'className'>; } & Pick<React.HTMLProps<HTMLDivElement>, 'className'>;
const BADGE_PLACEMENT_BY_SIZE = new Map<number, BadgePlacementType>([
[28, { size: 16, bottom: -4, right: -2 }],
[32, { size: 16, bottom: -4, right: -2 }],
[36, { size: 16, bottom: -3, right: 0 }],
[40, { size: 24, bottom: -6, right: -4 }],
[48, { size: 24, bottom: -6, right: -4 }],
[56, { size: 24, bottom: -6, right: 0 }],
[80, { size: 36, bottom: -8, right: 0 }],
[88, { size: 36, bottom: -4, right: 3 }],
]);
const getDefaultBlur = ( const getDefaultBlur = (
...args: Parameters<typeof shouldBlurAvatar> ...args: Parameters<typeof shouldBlurAvatar>
): AvatarBlur => ): AvatarBlur =>
@ -221,12 +234,12 @@ export const Avatar: FunctionComponent<Props> = ({
isBadgeVisible(badge) && isBadgeVisible(badge) &&
shouldShowBadges() shouldShowBadges()
) { ) {
const badgeSize = Math.ceil(size * 0.425); const badgePlacement = _getBadgePlacement(size);
const badgeTheme = const badgeTheme =
theme === ThemeType.light ? BadgeImageTheme.Light : BadgeImageTheme.Dark; theme === ThemeType.light ? BadgeImageTheme.Light : BadgeImageTheme.Dark;
const badgeImagePath = getBadgeImageFileLocalPath( const badgeImagePath = getBadgeImageFileLocalPath(
badge, badge,
badgeSize, badgePlacement.size,
badgeTheme badgeTheme
); );
if (badgeImagePath) { if (badgeImagePath) {
@ -236,8 +249,10 @@ export const Avatar: FunctionComponent<Props> = ({
className="module-Avatar__badge" className="module-Avatar__badge"
src={badgeImagePath} src={badgeImagePath}
style={{ style={{
width: badgeSize, width: badgePlacement.size,
height: badgeSize, height: badgePlacement.size,
bottom: badgePlacement.bottom,
right: badgePlacement.right,
}} }}
/> />
); );
@ -266,3 +281,16 @@ export const Avatar: FunctionComponent<Props> = ({
</div> </div>
); );
}; };
// This is only exported for testing.
export function _getBadgePlacement(
avatarSize: number
): Readonly<BadgePlacementType> {
return (
BADGE_PLACEMENT_BY_SIZE.get(avatarSize) || {
size: Math.ceil(avatarSize * 0.425),
bottom: 0,
right: 0,
}
);
}

View file

@ -0,0 +1,44 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import { _getBadgePlacement } from '../../components/Avatar';
describe('<Avatar>', () => {
describe('_getBadgePlacement', () => {
const check = (
testCases: Map<number, ReturnType<typeof _getBadgePlacement>>
) => {
for (const [input, expected] of testCases.entries()) {
const actual = _getBadgePlacement(input);
assert.deepStrictEqual(
actual,
expected,
`Invalid result for size ${input}`
);
}
};
it('returns values as specified by designs', () => {
const testCases = new Map([
[28, { size: 16, bottom: -4, right: -2 }],
[36, { size: 16, bottom: -3, right: 0 }],
[40, { size: 24, bottom: -6, right: -4 }],
[48, { size: 24, bottom: -6, right: -4 }],
[56, { size: 24, bottom: -6, right: 0 }],
[80, { size: 36, bottom: -8, right: 0 }],
[88, { size: 36, bottom: -4, right: 3 }],
]);
check(testCases);
});
it('returns fallback values for sizes not specified by designs', () => {
const testCases = new Map([
[16, { size: 7, bottom: 0, right: 0 }],
[200, { size: 85, bottom: 0, right: 0 }],
]);
check(testCases);
});
});
});