signal-desktop/ts/components/CollidingAvatars.tsx
Fedor Indutny eb82ace2de
Conversation details changes for PNP
Co-authored-by: Scott Nonnenberg <scott@signal.org>
2024-02-05 18:13:13 -08:00

80 lines
2.1 KiB
TypeScript

// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { v4 as uuid } from 'uuid';
import React, { useMemo, useCallback } from 'react';
import type { LocalizerType } from '../types/Util';
import type { ConversationType } from '../state/ducks/conversations';
import { Avatar, AvatarSize } from './Avatar';
export type PropsType = Readonly<{
i18n: LocalizerType;
conversations: ReadonlyArray<ConversationType>;
}>;
const MAX_AVATARS = 2;
export function CollidingAvatars({
i18n,
conversations,
}: PropsType): JSX.Element {
const clipId = useMemo(() => uuid(), []);
const onRef = useCallback(
(elem: HTMLDivElement | null): void => {
if (elem) {
// Note that these cannot be set through html attributes
elem.style.setProperty('--clip-path', `url(#${clipId})`);
}
},
[clipId]
);
return (
<div className="CollidingAvatars" ref={onRef}>
{conversations.slice(0, MAX_AVATARS).map(({ id, type, ...convo }) => {
return (
<Avatar
key={id}
className="CollidingAvatars__avatar"
i18n={i18n}
size={AvatarSize.TWENTY_FOUR}
conversationType={type}
badge={undefined}
{...convo}
/>
);
})}
{/*
This clip path is a rectangle with the right-bottom corner cut off
by a circle:
AAAAAAA
AAAAAAA
AAAAA
AAA
AAA
AA
AA
The idea is that we cut a circle away from the top avatar so that there
is a bit of transparent area between two avatars:
AAAAAAA
AAAAAAA
AAAAA
AAA B
AAA BB
AA BBB
AA BBB
See CollidingAvatars.scss for how this clipPath is applied.
*/}
<svg width={0} height={0} className="CollidingAvatars__clip_svg">
<clipPath id={clipId} clipPathUnits="objectBoundingBox">
<path d="M0 0 h1 v0.4166 A0.54166 0.54166 0 0 0.4166 1 H0 Z" />
</clipPath>
</svg>
</div>
);
}