Tweak avatar badge sizing/placement

This commit is contained in:
Evan Hahn 2021-11-20 09:41:48 -06:00 committed by GitHub
parent 829604dbcf
commit d8b230e348
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 79 additions and 32 deletions

View file

@ -45,7 +45,7 @@ export enum AvatarSize {
ONE_HUNDRED_TWELVE = 112, ONE_HUNDRED_TWELVE = 112,
} }
type BadgePlacementType = { size: number; bottom: number; right: number }; type BadgePlacementType = { bottom: number; right: number };
export type Props = { export type Props = {
avatarPath?: string; avatarPath?: string;
@ -78,14 +78,16 @@ export type Props = {
} & Pick<React.HTMLProps<HTMLDivElement>, 'className'>; } & Pick<React.HTMLProps<HTMLDivElement>, 'className'>;
const BADGE_PLACEMENT_BY_SIZE = new Map<number, BadgePlacementType>([ const BADGE_PLACEMENT_BY_SIZE = new Map<number, BadgePlacementType>([
[28, { size: 16, bottom: -4, right: -2 }], [28, { bottom: -4, right: -2 }],
[32, { size: 16, bottom: -4, right: -2 }], [32, { bottom: -4, right: -2 }],
[36, { size: 16, bottom: -3, right: 0 }], [36, { bottom: -3, right: 0 }],
[40, { size: 24, bottom: -6, right: -4 }], [40, { bottom: -6, right: -4 }],
[48, { size: 24, bottom: -6, right: -4 }], [48, { bottom: -6, right: -4 }],
[56, { size: 24, bottom: -6, right: 0 }], [56, { bottom: -6, right: 0 }],
[80, { size: 36, bottom: -8, right: 0 }], [64, { bottom: -6, right: 0 }],
[88, { size: 36, bottom: -4, right: 3 }], [80, { bottom: -8, right: 0 }],
[88, { bottom: -4, right: 3 }],
[112, { bottom: -4, right: 3 }],
]); ]);
const getDefaultBlur = ( const getDefaultBlur = (
@ -241,10 +243,12 @@ export const Avatar: FunctionComponent<Props> = ({
} }
let badgeNode: ReactNode; let badgeNode: ReactNode;
const badgeSize = _getBadgeSize(size);
if ( if (
badge && badge &&
theme && theme &&
!noteToSelf && !noteToSelf &&
badgeSize &&
isBadgeVisible(badge) && isBadgeVisible(badge) &&
shouldShowBadges() shouldShowBadges()
) { ) {
@ -253,15 +257,14 @@ export const Avatar: FunctionComponent<Props> = ({
theme === ThemeType.light ? BadgeImageTheme.Light : BadgeImageTheme.Dark; theme === ThemeType.light ? BadgeImageTheme.Light : BadgeImageTheme.Dark;
const badgeImagePath = getBadgeImageFileLocalPath( const badgeImagePath = getBadgeImageFileLocalPath(
badge, badge,
badgePlacement.size, badgeSize,
badgeTheme badgeTheme
); );
if (badgeImagePath) { if (badgeImagePath) {
const positionStyles: CSSProperties = { const positionStyles: CSSProperties = {
width: badgePlacement.size, width: badgeSize,
height: badgePlacement.size, height: badgeSize,
bottom: badgePlacement.bottom, ...badgePlacement,
right: badgePlacement.right,
}; };
if (onClickBadge) { if (onClickBadge) {
badgeNode = ( badgeNode = (
@ -312,15 +315,26 @@ export const Avatar: FunctionComponent<Props> = ({
); );
}; };
// This is only exported for testing.
export function _getBadgeSize(avatarSize: number): undefined | number {
if (avatarSize < 24) {
return undefined;
}
if (avatarSize <= 36) {
return 16;
}
if (avatarSize <= 64) {
return 24;
}
if (avatarSize <= 112) {
return 36;
}
return Math.round(avatarSize * 0.4);
}
// This is only exported for testing. // This is only exported for testing.
export function _getBadgePlacement( export function _getBadgePlacement(
avatarSize: number avatarSize: number
): Readonly<BadgePlacementType> { ): Readonly<BadgePlacementType> {
return ( return BADGE_PLACEMENT_BY_SIZE.get(avatarSize) || { bottom: 0, right: 0 };
BADGE_PLACEMENT_BY_SIZE.get(avatarSize) || {
size: Math.ceil(avatarSize * 0.425),
bottom: 0,
right: 0,
}
);
} }

View file

@ -3,9 +3,40 @@
import { assert } from 'chai'; import { assert } from 'chai';
import { _getBadgePlacement } from '../../components/Avatar'; import { _getBadgeSize, _getBadgePlacement } from '../../components/Avatar';
describe('<Avatar>', () => { describe('<Avatar>', () => {
describe('_getBadgeSize', () => {
it('returns undefined for sizes under 24px', () => {
assert.isUndefined(_getBadgeSize(1));
assert.isUndefined(_getBadgeSize(23));
});
it('returns 16px for sizes between 24px36px', () => {
assert.strictEqual(_getBadgeSize(24), 16);
assert.strictEqual(_getBadgeSize(30), 16);
assert.strictEqual(_getBadgeSize(36), 16);
});
it('returns 24px for sizes between 37px64px', () => {
assert.strictEqual(_getBadgeSize(37), 24);
assert.strictEqual(_getBadgeSize(50), 24);
assert.strictEqual(_getBadgeSize(64), 24);
});
it('returns 36px for sizes between 65px112px', () => {
assert.strictEqual(_getBadgeSize(65), 36);
assert.strictEqual(_getBadgeSize(100), 36);
assert.strictEqual(_getBadgeSize(112), 36);
});
it('returns ~40% of the size for sizes above 112px (a fallback)', () => {
assert.strictEqual(_getBadgeSize(113), 45);
assert.strictEqual(_getBadgeSize(200), 80);
assert.strictEqual(_getBadgeSize(999), 400);
});
});
describe('_getBadgePlacement', () => { describe('_getBadgePlacement', () => {
const check = ( const check = (
testCases: Map<number, ReturnType<typeof _getBadgePlacement>> testCases: Map<number, ReturnType<typeof _getBadgePlacement>>
@ -22,21 +53,23 @@ describe('<Avatar>', () => {
it('returns values as specified by designs', () => { it('returns values as specified by designs', () => {
const testCases = new Map([ const testCases = new Map([
[28, { size: 16, bottom: -4, right: -2 }], [28, { bottom: -4, right: -2 }],
[36, { size: 16, bottom: -3, right: 0 }], [36, { bottom: -3, right: 0 }],
[40, { size: 24, bottom: -6, right: -4 }], [40, { bottom: -6, right: -4 }],
[48, { size: 24, bottom: -6, right: -4 }], [48, { bottom: -6, right: -4 }],
[56, { size: 24, bottom: -6, right: 0 }], [56, { bottom: -6, right: 0 }],
[80, { size: 36, bottom: -8, right: 0 }], [64, { bottom: -6, right: 0 }],
[88, { size: 36, bottom: -4, right: 3 }], [80, { bottom: -8, right: 0 }],
[88, { bottom: -4, right: 3 }],
[112, { bottom: -4, right: 3 }],
]); ]);
check(testCases); check(testCases);
}); });
it('returns fallback values for sizes not specified by designs', () => { it('returns 0, 0 values for sizes not specified by designs', () => {
const testCases = new Map([ const testCases = new Map([
[16, { size: 7, bottom: 0, right: 0 }], [16, { bottom: 0, right: 0 }],
[200, { size: 85, bottom: 0, right: 0 }], [200, { bottom: 0, right: 0 }],
]); ]);
check(testCases); check(testCases);
}); });