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 {
bottom: 0;
position: absolute;
right: 0;
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: [],
size: 80,
title: overrideProps.title || '',
theme: overrideProps.theme,
});
const sizes: Array<Props['size']> = [112, 96, 80, 52, 32, 28];

View file

@ -44,6 +44,8 @@ export enum AvatarSize {
ONE_HUNDRED_TWELVE = 112,
}
type BadgePlacementType = { size: number; bottom: number; right: number };
export type Props = {
avatarPath?: string;
badge?: BadgeType;
@ -72,6 +74,17 @@ export type Props = {
i18n: LocalizerType;
} & 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 = (
...args: Parameters<typeof shouldBlurAvatar>
): AvatarBlur =>
@ -221,12 +234,12 @@ export const Avatar: FunctionComponent<Props> = ({
isBadgeVisible(badge) &&
shouldShowBadges()
) {
const badgeSize = Math.ceil(size * 0.425);
const badgePlacement = _getBadgePlacement(size);
const badgeTheme =
theme === ThemeType.light ? BadgeImageTheme.Light : BadgeImageTheme.Dark;
const badgeImagePath = getBadgeImageFileLocalPath(
badge,
badgeSize,
badgePlacement.size,
badgeTheme
);
if (badgeImagePath) {
@ -236,8 +249,10 @@ export const Avatar: FunctionComponent<Props> = ({
className="module-Avatar__badge"
src={badgeImagePath}
style={{
width: badgeSize,
height: badgeSize,
width: badgePlacement.size,
height: badgePlacement.size,
bottom: badgePlacement.bottom,
right: badgePlacement.right,
}}
/>
);
@ -266,3 +281,16 @@ export const Avatar: FunctionComponent<Props> = ({
</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);
});
});
});