Files
cinny/src/app/components/presence/PresenceAvatar.tsx

77 lines
2.1 KiB
TypeScript

import React, { CSSProperties, ReactElement, cloneElement, isValidElement } from 'react';
import classNames from 'classnames';
import { config } from 'folds';
import { Presence } from '../../hooks/useUserPresence';
type PresenceAvatarProps = {
presence?: Presence;
children: ReactElement;
className?: string;
};
const PRESENCE_COLOR: Record<Presence, string> = {
[Presence.Online]: '#38842b',
[Presence.Unavailable]: '#959e30',
[Presence.Offline]: '#454545',
};
const rowStyle: CSSProperties = {
display: 'inline-flex',
flexDirection: 'row',
alignItems: 'stretch',
flexShrink: 0,
lineHeight: 0,
};
const faceStyle: CSSProperties = {
borderTopLeftRadius: 0,
borderBottomLeftRadius: 0,
// Keep the right side rounded to match size-200 nav avatars.
borderTopRightRadius: config.radii.R400,
borderBottomRightRadius: config.radii.R400,
};
/**
* Presence strip as a real sibling (not ::before).
* Folds Avatar uses overflow:hidden, which clips outside ::before bars.
*/
export function PresenceAvatar({
presence = Presence.Offline,
children,
className,
}: PresenceAvatarProps) {
const stripColor = PRESENCE_COLOR[presence] ?? PRESENCE_COLOR[Presence.Offline];
const face = isValidElement(children)
? cloneElement(children, {
className: classNames((children.props as { className?: string }).className),
style: {
...((children.props as { style?: CSSProperties }).style ?? {}),
...faceStyle,
},
// Avoid the folds radii shorthand fighting the square-left corners.
radii: '0',
} as Partial<unknown>)
: children;
return (
<div className={className} style={rowStyle} data-presence={presence}>
<span
aria-hidden
style={{
display: 'block',
width: 4,
minWidth: 4,
flex: '0 0 4px',
alignSelf: 'stretch',
// Match folds Avatar size="200" so the strip can't collapse to 0 height.
minHeight: config.size.X200,
borderRadius: '5px 0 0 5px',
backgroundColor: stripColor,
}}
/>
{face}
</div>
);
}