mirror of
				https://github.com/cinnyapp/cinny.git
				synced 2025-11-04 06:20:28 +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