import { AvatarFallback, AvatarImage, color } from 'folds';
import React, { ReactEventHandler, ReactNode, useState } from 'react';
+import classNames from 'classnames';
import * as css from './UserAvatar.css';
import colorMXID from '../../../util/colorMXID';
type UserAvatarProps = {
+ className?: string;
userId: string;
src?: string;
alt?: string;
renderFallback: () => ReactNode;
};
-export function UserAvatar({ userId, src, alt, renderFallback }: UserAvatarProps) {
+export function UserAvatar({ className, userId, src, alt, renderFallback }: UserAvatarProps) {
const [error, setError] = useState(false);
const handleLoad: ReactEventHandler<HTMLImageElement> = (evt) => {
return (
<AvatarFallback
style={{ backgroundColor: colorMXID(userId), color: color.Surface.Container }}
- className={css.UserAvatar}
+ className={classNames(css.UserAvatar, className)}
>
{renderFallback()}
</AvatarFallback>
return (
<AvatarImage
- className={css.UserAvatar}
+ className={classNames(css.UserAvatar, className)}
src={src}
alt={alt}
onError={() => setError(true)}
-import React from 'react';
-import { Avatar, Box, Icon, Icons, Text } from 'folds';
+import React, { useState } from 'react';
+import {
+ Avatar,
+ Box,
+ Icon,
+ Icons,
+ Modal,
+ Overlay,
+ OverlayBackdrop,
+ OverlayCenter,
+ Text,
+} from 'folds';
import classNames from 'classnames';
+import FocusTrap from 'focus-trap-react';
import * as css from './styles.css';
import { UserAvatar } from '../user-avatar';
import colorMXID from '../../../util/colorMXID';
import { BreakWord, LineClamp3 } from '../../styles/Text.css';
import { UserPresence } from '../../hooks/useUserPresence';
import { AvatarPresence, PresenceBadge } from '../presence';
+import { ImageViewer } from '../image-viewer';
+import { stopPropagation } from '../../utils/keyboard';
type UserHeroProps = {
userId: string;
presence?: UserPresence;
};
export function UserHero({ userId, avatarUrl, presence }: UserHeroProps) {
+ const [viewAvatar, setViewAvatar] = useState<string>();
+
return (
<Box direction="Column" className={css.UserHero}>
<div
filter: avatarUrl ? undefined : 'brightness(50%)',
}}
>
- {avatarUrl && <img className={css.UserHeroCover} src={avatarUrl} alt={userId} />}
+ {avatarUrl && (
+ <img className={css.UserHeroCover} src={avatarUrl} alt={userId} draggable="false" />
+ )}
</div>
<div className={css.UserHeroAvatarContainer}>
<AvatarPresence
presence && <PresenceBadge presence={presence.presence} status={presence.status} />
}
>
- <Avatar className={css.UserHeroAvatar} size="500">
+ <Avatar
+ as={avatarUrl ? 'button' : 'div'}
+ onClick={avatarUrl ? () => setViewAvatar(avatarUrl) : undefined}
+ className={css.UserHeroAvatar}
+ size="500"
+ >
<UserAvatar
+ className={css.UserHeroAvatarImg}
userId={userId}
src={avatarUrl}
alt={userId}
/>
</Avatar>
</AvatarPresence>
+ {viewAvatar && (
+ <Overlay open backdrop={<OverlayBackdrop />}>
+ <OverlayCenter>
+ <FocusTrap
+ focusTrapOptions={{
+ initialFocus: false,
+ onDeactivate: () => setViewAvatar(undefined),
+ clickOutsideDeactivates: true,
+ escapeDeactivates: stopPropagation,
+ }}
+ >
+ <Modal size="500" onContextMenu={(evt: any) => evt.stopPropagation()}>
+ <ImageViewer
+ src={viewAvatar}
+ alt={userId}
+ requestClose={() => setViewAvatar(undefined)}
+ />
+ </Modal>
+ </FocusTrap>
+ </OverlayCenter>
+ </Overlay>
+ )}
</div>
</Box>
);