add avatar component

This commit is contained in:
Pavel Prichodko 2023-01-16 13:10:25 +01:00
parent 428473f170
commit 91875f1b26
No known key found for this signature in database
GPG Key ID: 0EB8D75C775AB6F1
3 changed files with 155 additions and 0 deletions

View File

@ -0,0 +1,46 @@
import { Stack } from '@tamagui/core'
import { Avatar } from './avatar'
import type { Meta, StoryObj } from '@storybook/react'
// More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction
const meta: Meta<typeof Avatar> = {
component: Avatar,
argTypes: {},
}
type Story = StoryObj<typeof Avatar>
// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args
export const Default: Story = {
args: {
src: 'https://images.unsplash.com/photo-1518020382113-a7e8fc38eac9?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&h=500&q=80',
},
render: args => (
<Stack space>
<Avatar {...args} size={56} />
<Avatar {...args} size={52} />
<Avatar {...args} size={48} />
<Avatar {...args} size={32} />
<Avatar {...args} size={20} />
</Stack>
),
}
export const Rounded: Story = {
args: {
src: 'https://images.unsplash.com/photo-1518020382113-a7e8fc38eac9?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&h=500&q=80',
},
render: args => (
<Stack space>
<Avatar {...args} size={56} shape="rounded" />
<Avatar {...args} size={52} shape="rounded" />
<Avatar {...args} size={48} shape="rounded" />
<Avatar {...args} size={32} shape="rounded" />
<Avatar {...args} size={20} shape="rounded" />
</Stack>
),
}
export default meta

View File

@ -0,0 +1,108 @@
import { useEffect, useState } from 'react'
import { Stack, styled, Text } from '@tamagui/core'
import { Image } from '../image'
import type { GetProps } from '@tamagui/core'
// import { Button as RNButton } from 'react-native'
// setupReactNative({ Button: RNButton })
// import type { GetProps} from '@tamagui/core';
const Base = styled(Stack, {
name: 'Avatar',
display: 'inline-flex',
position: 'relative',
overflow: 'hidden',
backgroundColor: 'rgb(255,255,255)',
variants: {
size: {
56: {
width: 56,
height: 56,
borderRadius: 56 / 2,
},
52: {
width: 52,
height: 52,
borderRadius: 52 / 2,
},
48: {
width: 48,
height: 48,
borderRadius: 48 / 2,
},
32: {
width: 32,
height: 32,
borderRadius: 32 / 2,
},
20: {
width: 20,
height: 20,
borderRadius: 20 / 2,
},
},
shape: {
circle: {},
rounded: {
borderRadius: 16,
},
},
} as const,
})
const Fallback = styled(Text, {
name: 'AvatarFallback',
})
type BaseProps = GetProps<typeof Base>
interface Props {
src: string
size: NonNullable<BaseProps['size']>
indicator?: 'online' | 'offline'
shape?: 'circle' | 'rounded'
}
type ImageLoadingStatus = 'idle' | 'loading' | 'loaded' | 'error'
const Avatar = (props: Props) => {
const { src, size, shape = 'circle' } = props
const [status, setStatus] = useState<ImageLoadingStatus>('idle')
useEffect(() => {
setStatus('idle')
}, [JSON.stringify(src)])
return (
<Base size={size} shape={shape}>
<Image
src={src}
width={size}
height={size}
onLoad={() => setStatus('loaded')}
onError={() => setStatus('error')}
/>
<Fallback
width={size}
height={size}
display="flex"
alignItems="center"
justifyContent="center"
>
PP
</Fallback>
</Base>
)
}
export { Avatar }
export type { Props as AvatarProps }

View File

@ -0,0 +1 @@
export { Avatar } from './avatar'