mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-09-13 14:22:25 +03:00
Add option to view user avatar (#2462)
This commit is contained in:
parent
4056cbb11c
commit
23aa5c6f94
3 changed files with 66 additions and 7 deletions
|
@ -1,15 +1,17 @@
|
||||||
import { AvatarFallback, AvatarImage, color } from 'folds';
|
import { AvatarFallback, AvatarImage, color } from 'folds';
|
||||||
import React, { ReactEventHandler, ReactNode, useState } from 'react';
|
import React, { ReactEventHandler, ReactNode, useState } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
import * as css from './UserAvatar.css';
|
import * as css from './UserAvatar.css';
|
||||||
import colorMXID from '../../../util/colorMXID';
|
import colorMXID from '../../../util/colorMXID';
|
||||||
|
|
||||||
type UserAvatarProps = {
|
type UserAvatarProps = {
|
||||||
|
className?: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
src?: string;
|
src?: string;
|
||||||
alt?: string;
|
alt?: string;
|
||||||
renderFallback: () => ReactNode;
|
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 [error, setError] = useState(false);
|
||||||
|
|
||||||
const handleLoad: ReactEventHandler<HTMLImageElement> = (evt) => {
|
const handleLoad: ReactEventHandler<HTMLImageElement> = (evt) => {
|
||||||
|
@ -20,7 +22,7 @@ export function UserAvatar({ userId, src, alt, renderFallback }: UserAvatarProps
|
||||||
return (
|
return (
|
||||||
<AvatarFallback
|
<AvatarFallback
|
||||||
style={{ backgroundColor: colorMXID(userId), color: color.Surface.Container }}
|
style={{ backgroundColor: colorMXID(userId), color: color.Surface.Container }}
|
||||||
className={css.UserAvatar}
|
className={classNames(css.UserAvatar, className)}
|
||||||
>
|
>
|
||||||
{renderFallback()}
|
{renderFallback()}
|
||||||
</AvatarFallback>
|
</AvatarFallback>
|
||||||
|
@ -29,7 +31,7 @@ export function UserAvatar({ userId, src, alt, renderFallback }: UserAvatarProps
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AvatarImage
|
<AvatarImage
|
||||||
className={css.UserAvatar}
|
className={classNames(css.UserAvatar, className)}
|
||||||
src={src}
|
src={src}
|
||||||
alt={alt}
|
alt={alt}
|
||||||
onError={() => setError(true)}
|
onError={() => setError(true)}
|
||||||
|
|
|
@ -1,6 +1,17 @@
|
||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Avatar, Box, Icon, Icons, Text } from 'folds';
|
import {
|
||||||
|
Avatar,
|
||||||
|
Box,
|
||||||
|
Icon,
|
||||||
|
Icons,
|
||||||
|
Modal,
|
||||||
|
Overlay,
|
||||||
|
OverlayBackdrop,
|
||||||
|
OverlayCenter,
|
||||||
|
Text,
|
||||||
|
} from 'folds';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import FocusTrap from 'focus-trap-react';
|
||||||
import * as css from './styles.css';
|
import * as css from './styles.css';
|
||||||
import { UserAvatar } from '../user-avatar';
|
import { UserAvatar } from '../user-avatar';
|
||||||
import colorMXID from '../../../util/colorMXID';
|
import colorMXID from '../../../util/colorMXID';
|
||||||
|
@ -8,6 +19,8 @@ import { getMxIdLocalPart } from '../../utils/matrix';
|
||||||
import { BreakWord, LineClamp3 } from '../../styles/Text.css';
|
import { BreakWord, LineClamp3 } from '../../styles/Text.css';
|
||||||
import { UserPresence } from '../../hooks/useUserPresence';
|
import { UserPresence } from '../../hooks/useUserPresence';
|
||||||
import { AvatarPresence, PresenceBadge } from '../presence';
|
import { AvatarPresence, PresenceBadge } from '../presence';
|
||||||
|
import { ImageViewer } from '../image-viewer';
|
||||||
|
import { stopPropagation } from '../../utils/keyboard';
|
||||||
|
|
||||||
type UserHeroProps = {
|
type UserHeroProps = {
|
||||||
userId: string;
|
userId: string;
|
||||||
|
@ -15,6 +28,8 @@ type UserHeroProps = {
|
||||||
presence?: UserPresence;
|
presence?: UserPresence;
|
||||||
};
|
};
|
||||||
export function UserHero({ userId, avatarUrl, presence }: UserHeroProps) {
|
export function UserHero({ userId, avatarUrl, presence }: UserHeroProps) {
|
||||||
|
const [viewAvatar, setViewAvatar] = useState<string>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box direction="Column" className={css.UserHero}>
|
<Box direction="Column" className={css.UserHero}>
|
||||||
<div
|
<div
|
||||||
|
@ -24,7 +39,9 @@ export function UserHero({ userId, avatarUrl, presence }: UserHeroProps) {
|
||||||
filter: avatarUrl ? undefined : 'brightness(50%)',
|
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>
|
||||||
<div className={css.UserHeroAvatarContainer}>
|
<div className={css.UserHeroAvatarContainer}>
|
||||||
<AvatarPresence
|
<AvatarPresence
|
||||||
|
@ -33,8 +50,14 @@ export function UserHero({ userId, avatarUrl, presence }: UserHeroProps) {
|
||||||
presence && <PresenceBadge presence={presence.presence} status={presence.status} />
|
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
|
<UserAvatar
|
||||||
|
className={css.UserHeroAvatarImg}
|
||||||
userId={userId}
|
userId={userId}
|
||||||
src={avatarUrl}
|
src={avatarUrl}
|
||||||
alt={userId}
|
alt={userId}
|
||||||
|
@ -42,6 +65,28 @@ export function UserHero({ userId, avatarUrl, presence }: UserHeroProps) {
|
||||||
/>
|
/>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
</AvatarPresence>
|
</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>
|
</div>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|
|
@ -39,4 +39,16 @@ export const UserAvatarContainer = style({
|
||||||
});
|
});
|
||||||
export const UserHeroAvatar = style({
|
export const UserHeroAvatar = style({
|
||||||
outline: `${config.borderWidth.B600} solid ${color.Surface.Container}`,
|
outline: `${config.borderWidth.B600} solid ${color.Surface.Container}`,
|
||||||
|
selectors: {
|
||||||
|
'button&': {
|
||||||
|
cursor: 'pointer',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
export const UserHeroAvatarImg = style({
|
||||||
|
selectors: {
|
||||||
|
[`button${UserHeroAvatar}:hover &`]: {
|
||||||
|
filter: 'brightness(0.5)',
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue