Last active
October 6, 2022 23:51
-
-
Save tzynwang/2ba1ebc33cea47d511be59cbb9ae057d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { memo, useCallback, useMemo, useState } from 'react'; | |
import { css } from '@emotion/css'; | |
import cn from 'classnames'; | |
import { PersonIcon } from '@Assets/icons'; | |
import ImageBase from '@Components/Base/ImageBase'; | |
import type { AvatarProps } from './types'; | |
const figureStyle = css({ | |
border: '4px solid #f9f4ef', | |
backgroundColor: '#f9f4ef', | |
}); | |
const imgStyle = css({ | |
height: '48px', | |
width: '48px', | |
boxSizing: 'content-box', | |
display: 'inline-flex', | |
justifyContent: 'center', | |
alignItems: 'center', | |
borderRadius: '50%', | |
}); | |
const onErrorStyle = css({ | |
width: '48px', | |
height: '48px', | |
display: 'inline-block', | |
'&::after': { | |
content: '""', | |
width: '100%', | |
height: '100%', | |
position: 'absolute', | |
top: 0, | |
left: 0, | |
}, | |
}); | |
const withChildrenStyle = css({ | |
backgroundColor: '#4e342e', | |
color: '#fff', | |
fontSize: '24px', | |
}); | |
const withChildrenBorderStyle = css({ | |
border: '4px solid #f9f4ef', | |
}); | |
function Avatar(props: AvatarProps): React.ReactElement { | |
/* States */ | |
const { src, children = null, withBorder = false } = props; | |
const [onError, setOnError] = useState<boolean>(false); | |
/* Functions */ | |
const fallBackToText = useCallback(() => { | |
setOnError(true); | |
}, []); | |
/* Views */ | |
const finalRender = useMemo(() => { | |
if (onError) { | |
return ( | |
<div | |
className={cn(imgStyle, withBorder && figureStyle, withChildrenStyle)} | |
> | |
<PersonIcon fill="#fff" /> | |
</div> | |
); | |
} | |
if (children) { | |
return ( | |
<div | |
className={cn( | |
imgStyle, | |
withBorder && figureStyle, | |
withChildrenStyle, | |
withBorder && withChildrenBorderStyle | |
)} | |
> | |
{children} | |
</div> | |
); | |
} | |
if (src) { | |
return ( | |
<ImageBase | |
src={src} | |
classes={{ | |
figure: cn(withBorder && figureStyle, imgStyle), | |
img: imgStyle, | |
onError: onErrorStyle, | |
}} | |
onError={fallBackToText} | |
/> | |
); | |
} | |
return ( | |
<div | |
className={cn(imgStyle, withBorder && figureStyle, withChildrenStyle)} | |
> | |
<PersonIcon fill="#fff" /> | |
</div> | |
); | |
}, [children, src, onError, withBorder, fallBackToText]); | |
/* Main */ | |
return finalRender; | |
} | |
export default memo(Avatar); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
export interface AvatarProps { | |
children?: React.ReactNode; | |
src?: string; | |
withBorder?: boolean; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { memo } from 'react'; | |
import Avatar from '@Components/Common/Avatar'; | |
import AvatarGroup from '@Components/Common/AvatarGroup'; | |
import Stack from '@Components/Layout/Stack'; | |
import SpaceWrapper from '@Components/Layout/SpaceWrapper'; | |
import foxSrc from '@Assets/alexander-andrews-mEdKuPYJe1I-unsplash.jpg'; | |
import { PhotoCameraIcon } from '@Assets/icons'; | |
function AvatarDemo(): React.ReactElement { | |
/* Main */ | |
return ( | |
<Stack> | |
<SpaceWrapper padding={8}> | |
<Avatar src={foxSrc} /> | |
</SpaceWrapper> | |
<SpaceWrapper padding={8}> | |
<Avatar>C</Avatar> | |
</SpaceWrapper> | |
<SpaceWrapper padding={8}> | |
<Avatar> | |
<PhotoCameraIcon fill="#fff" /> | |
</Avatar> | |
</SpaceWrapper> | |
<SpaceWrapper padding={8}> | |
<AvatarGroup> | |
<Avatar src={foxSrc} /> | |
<Avatar>C</Avatar> | |
<Avatar /> | |
<Avatar> | |
<PhotoCameraIcon fill="#fff" /> | |
</Avatar> | |
<Avatar>F</Avatar> | |
</AvatarGroup> | |
</SpaceWrapper> | |
<SpaceWrapper padding={8}> | |
<AvatarGroup max={4}> | |
<Avatar src={foxSrc} /> | |
<Avatar>C</Avatar> | |
<Avatar src="..." /> | |
<Avatar> | |
<PhotoCameraIcon fill="#fff" /> | |
</Avatar> | |
<Avatar>F</Avatar> | |
</AvatarGroup> | |
</SpaceWrapper> | |
</Stack> | |
); | |
} | |
export default memo(AvatarDemo); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { memo, useEffect, useState } from 'react'; | |
import { css } from '@emotion/css'; | |
import cn from 'classnames'; | |
import Avatar from '@Components/Common/Avatar'; | |
import type { AvatarGroupProps } from './types'; | |
const baseStyle = css({ | |
display: 'flex', | |
flexDirection: 'row-reverse', | |
justifyContent: 'flex-end', | |
paddingLeft: 'calc(12px - 2px - 2px)', | |
'& > div': { | |
marginLeft: '-12px', | |
}, | |
}); | |
function AvatarGroup(props: AvatarGroupProps): React.ReactElement { | |
/* States */ | |
const { children, max, className, ...rest } = props; | |
const [childrenArr, setChildrenArr] = useState<JSX.Element[]>([]); | |
/* Hooks */ | |
useEffect(() => { | |
let result: JSX.Element[] = []; | |
React.Children.forEach(children, (child) => { | |
const c = child as JSX.Element; | |
result.push(React.cloneElement(c, { withBorder: true })); | |
}); | |
const childrenLength = React.Children.count(children); | |
if (typeof max === 'number' && max > 1 && max < childrenLength) { | |
result = result.slice(0, max - 1); | |
result.push(<Avatar withBorder>+{childrenLength - (max - 1)}</Avatar>); | |
} | |
setChildrenArr(result.reverse()); | |
}, [children, max]); | |
/* Main */ | |
return ( | |
<div className={cn(baseStyle, className)} {...rest}> | |
{childrenArr.map((child, index) => ( | |
<React.Fragment key={index}>{child}</React.Fragment> | |
))} | |
</div> | |
); | |
} | |
export default memo(AvatarGroup); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import type React from 'react'; | |
export interface AvatarGroupProps extends React.HTMLAttributes<HTMLDivElement> { | |
children: React.ReactNode; | |
max?: number; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment