From 811fa081a84c1374c5398d8b6b7c7464bed7649e Mon Sep 17 00:00:00 2001 From: Felicio Mununga Date: Wed, 19 Apr 2023 12:56:20 +0200 Subject: [PATCH] Extend Avatar (#371) * add color hash to Avatar * remove compoundVariants * remove outline prop * remove vars * ref figma * remove example * add background color to Image * extend radius variants in Image * use union type * add channel avatar to stories * add channel avatar as Avatar type * resolve typecheck errors * add name prop * add icon avatar as Avatar type * add community avatar * move fallback * set default icon color * add group avatar * add wallet avatar * join user type * join channel type * remove 32 text variant * assert LockBase variant * remove fn type guards * fix icon import * set icon sizes based on props * set default variants and use render fns * uses raidus tokens * add outline * remove outline * fix overlapping background on loaded image * fix indicator position * fix background color --- .../components/src/avatar/avatar.stories.tsx | 368 +++++++++++++- packages/components/src/avatar/avatar.tsx | 481 ++++++++++++++---- .../components/src/avatar/channel-avatar.tsx | 85 ---- .../components/src/avatar/icon-avatar.tsx | 44 -- packages/components/src/avatar/index.tsx | 2 - packages/components/src/avatar/utils.tsx | 60 +++ .../src/channel/channel.stories.tsx | 4 +- packages/components/src/channel/channel.tsx | 4 +- .../sidebar-community/sidebar-community.tsx | 20 +- .../src/context-tag/context-tag.tsx | 2 +- packages/components/src/image/image.tsx | 14 + packages/components/src/messages/message.tsx | 2 + packages/components/src/reply/reply.tsx | 2 +- .../added-users-message-content.tsx | 28 +- .../components/deleted-message-content.tsx | 11 +- .../components/pinned-message-content.tsx | 13 +- packages/components/src/text/text.tsx | 5 +- .../components/src/user-list/user-list.tsx | 12 +- 18 files changed, 878 insertions(+), 279 deletions(-) delete mode 100644 packages/components/src/avatar/channel-avatar.tsx delete mode 100644 packages/components/src/avatar/icon-avatar.tsx create mode 100644 packages/components/src/avatar/utils.tsx diff --git a/packages/components/src/avatar/avatar.stories.tsx b/packages/components/src/avatar/avatar.stories.tsx index bf3c65a6..c46b10a1 100644 --- a/packages/components/src/avatar/avatar.stories.tsx +++ b/packages/components/src/avatar/avatar.stories.tsx @@ -1,64 +1,382 @@ +import { PlaceholderIcon } from '@status-im/icons' import { Stack } from '@tamagui/core' import { Avatar } from './avatar' +import type { + AccountAvatarProps, + ChannelAvatarProps, + CommunityAvatarProps, + GroupAvatarProps, + IconAvatarProps, + UserAvatarProps, + WalletAvatarProps, +} 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 = { component: Avatar, argTypes: {}, + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/IBmFKgGL1B4GzqD8LQTw6n/Design-System-for-Desktop%2FWeb?node-id=102-5246&t=i4haPXGOeNtaLaEz-0', + }, + }, } -type Story = StoryObj +type UserArgs = Pick // More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args -export const Default: Story = { +export const User: StoryObj = { + // todo?: https://github.com/storybookjs/storybook/issues/13747 args: { + type: 'user', + name: 'John Doe', 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', + } as UserArgs, + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/IBmFKgGL1B4GzqD8LQTw6n/Design-System-for-Desktop%2FWeb?node-id=115-6787&t=kcsW0DN5ochMPO1u-4', + }, }, render: args => ( - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + ), } -export const Rounded: Story = { +export const Group: StoryObj = { args: { + type: 'group', 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', - shape: 'rounded', + }, + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/IBmFKgGL1B4GzqD8LQTw6n/Design-System-for-Desktop%2FWeb?node-id=14584-169312&t=kcsW0DN5ochMPO1u-4', + }, + }, + render: args => ( + + + + + + + + + + + + + + + + + ), +} + +export const Wallet: StoryObj = { + args: { + type: 'wallet', + name: 'Wallet 1', + }, + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/IBmFKgGL1B4GzqD8LQTw6n/Design-System-for-Desktop%2FWeb?node-id=114-7646&t=kcsW0DN5ochMPO1u-4', + }, + }, + render: args => ( + + + + + + + + + + ), +} + +export const Account: StoryObj = { + args: { + type: 'account', + name: 'My Account', + 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', + }, + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/IBmFKgGL1B4GzqD8LQTw6n/Design-System-for-Desktop%2FWeb?node-id=483-19401&t=kcsW0DN5ochMPO1u-4', + }, }, render: args => ( - - + + ), +} + +export const community: StoryObj = { + args: { + type: 'community', + 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', + }, + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/IBmFKgGL1B4GzqD8LQTw6n/Design-System-for-Desktop%2FWeb?node-id=8824-149725&t=kcsW0DN5ochMPO1u-4', + }, + }, + render: args => ( + + + + + + + + ), +} + +type ChannelArgs = Pick + +export const Channel: StoryObj = { + args: { + type: 'channel', + emoji: '🍑', + } as ChannelArgs, + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/IBmFKgGL1B4GzqD8LQTw6n/Design-System-for-Desktop%2FWeb?node-id=399-20709&t=kcsW0DN5ochMPO1u-4', + }, + }, + render: args => ( + + + + + + + + + + + + + + + + + + + + + ), +} + +export const Icon: StoryObj = { + args: { + type: 'icon', + }, + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/IBmFKgGL1B4GzqD8LQTw6n/Design-System-for-Desktop%2FWeb?node-id=2931-44944&t=kcsW0DN5ochMPO1u-4', + }, + }, + render: args => ( + + + } /> + } /> + } /> + ), } diff --git a/packages/components/src/avatar/avatar.tsx b/packages/components/src/avatar/avatar.tsx index b679eeb9..5446edb6 100644 --- a/packages/components/src/avatar/avatar.tsx +++ b/packages/components/src/avatar/avatar.tsx @@ -1,72 +1,354 @@ -import { useEffect, useState } from 'react' +import { cloneElement, useMemo, useState } from 'react' -import { Stack, styled, Text, Unspaced } from '@tamagui/core' +import { LockedIcon, MembersIcon, UnlockedIcon } from '@status-im/icons' +import { Stack, styled, Unspaced } from '@tamagui/core' +import { Platform } from 'react-native' import { Image } from '../image' +import { Text } from '../text' +import { tokens } from '../tokens' +import { generateIdenticonRing } from './utils' -import type { GetStyledVariants } from '@tamagui/core' +import type { TextProps } from '../text' +import type { RadiusTokens } from '../tokens' +import type { IconProps } from '@status-im/icons' +import type { ColorTokens, GetStyledVariants } from '@tamagui/core' -type Variants = GetStyledVariants - -type Props = { - src: string +type UserAvatarProps = { + type: 'user' size: 80 | 56 | 48 | 32 | 28 | 24 | 20 | 16 - shape?: Variants['shape'] - outline?: Variants['outline'] + name: string + src?: string + backgroundColor?: ColorTokens indicator?: GetStyledVariants['state'] + colorHash?: number[][] } -type ImageLoadingStatus = 'idle' | 'loading' | 'loaded' | 'error' +type GroupAvatarProps = { + type: 'group' + size: 80 | 48 | 32 | 28 | 20 + name: string + src?: string + backgroundColor?: ColorTokens +} -const Avatar = (props: Props) => { - const { - src, - size, - shape = 'circle', - outline = false, - indicator = 'none', - } = props +type WalletAvatarProps = { + type: 'wallet' + size: 80 | 48 | 32 | 28 | 20 + name: string + backgroundColor?: ColorTokens +} - const [status, setStatus] = useState('idle') +type ChannelAvatarProps = { + type: 'channel' + size: 80 | 32 | 24 | 20 + emoji: string + backgroundColor?: ColorTokens + background?: ColorTokens + lock?: 'locked' | 'unlocked' +} - useEffect(() => { - setStatus('idle') - }, [src]) +type CommunityAvatarProps = { + type: 'community' + size: 80 | 32 | 24 | 20 + name: string + src?: string + backgroundColor?: ColorTokens +} + +type AccountAvatarProps = { + type: 'account' + size: 80 | 48 | 32 | 28 | 24 | 20 + name: string + src?: string + backgroundColor?: ColorTokens +} + +type IconAvatarProps = { + type: 'icon' + size: 48 | 32 | 20 + icon: React.ReactElement + backgroundColor?: ColorTokens + color?: ColorTokens +} + +type AvatarProps = + | UserAvatarProps + | GroupAvatarProps + | WalletAvatarProps + | ChannelAvatarProps + | CommunityAvatarProps + | AccountAvatarProps + | IconAvatarProps + +type ImageLoadingStatus = 'loading' | 'loaded' | 'error' + +const userPaddingSizes: Record = { + '80': 4, + '56': 2, + '48': 2, + '32': 2, + '28': 0, + '24': 0, + '20': 0, + '16': 0, +} + +const accountRadiusSizes: Record = { + '80': '$16', + '48': '$12', + '32': '$10', + '28': '$8', + '24': '$8', + '20': '$6', +} + +const channelEmojiSizes: Record = + { + // todo: design review + '80': 27, + '32': 15, + '24': 13, + '20': 11, + } + +const textSizes: Record, TextProps['size']> = { + '80': 27, + '56': 19, + '48': 19, + '32': 15, + '28': 13, + '24': 13, + '20': 11, + '16': 11, +} + +const groupMembersIconSizes: Record< + GroupAvatarProps['size'], + IconProps['size'] | number // to scales SVG +> = { + // todo: design review + '80': 36, + '48': 20, + '32': 16, + '28': 16, + '20': 12, +} + +const channelLockIconVariants: Record< + ChannelAvatarProps['size'], + { + baseVariant: GetStyledVariants['variant'] + iconSize: IconProps['size'] | number // to scales SVG + } +> = { + // todo: design review + '80': { baseVariant: 80, iconSize: 40 }, + '32': { baseVariant: 24, iconSize: 12 }, + '24': { baseVariant: 24, iconSize: 12 }, + '20': { baseVariant: 20, iconSize: 12 }, +} + +const Avatar = (props: AvatarProps) => { + const colorHash = 'colorHash' in props ? props.colorHash : undefined + const identiconRing = useMemo(() => { + if (colorHash) { + const gradient = generateIdenticonRing(colorHash) + return `conic-gradient(from 90deg, ${gradient})` + } + }, [colorHash]) + + const [status, setStatus] = useState() + + const padding = + props.type === 'user' && identiconRing ? userPaddingSizes[props.size] : 0 + const radius: RadiusTokens = + props.type === 'account' ? accountRadiusSizes[props.size] : '$full' + const backgroundColor = getBackgroundColor() + + function getBackgroundColor(): ColorTokens { + if ('src' in props && props.src) { + switch (status) { + case 'error': + break + case 'loaded': + return '$transparent' + case 'loading': + default: + return '$white-100' + } + } + + if (props.backgroundColor) { + return props.backgroundColor + } + + if (props.type === 'channel') { + return '$blue-50-opa-20' + } + + return '$neutral-95' + } + + const renderContent = () => { + switch (props.type) { + case 'user': + case 'account': + case 'group': + case 'community': { + if (!props.src) { + return ( + + {/* todo?: contrasting color to background */} + {props.type === 'group' ? ( + cloneElement( + , + { + color: '$white-100', + } + ) + ) : ( + + {props.name.slice(0, 2).toUpperCase()} + + )} + + ) + } + + return ( + <> + { + if (status) { + return + } + + setStatus('loading') + }} + onLoad={() => setStatus('loaded')} + onError={() => setStatus('error')} + /> + {/* todo?: add fallback to Image */} + {status === 'error' && ( + + )} + + ) + } + case 'wallet': + return ( + + + {props.name.slice(0, 2).toUpperCase()} + + + ) + case 'channel': + return {props.emoji} + case 'icon': + return cloneElement(props.icon, { color: props.color ?? '$white-100' }) + default: + return + } + } + + const renderBadge = () => { + switch (props.type) { + case 'user': { + if (!props.indicator) { + return + } + + return ( + + + + ) + } + case 'channel': { + if (!props.lock) { + return + } + + const iconVariant = channelLockIconVariants[props.size] + + return ( + + {props.lock === 'locked' ? ( + + ) : ( + + )} + + ) + } + default: + return + } + } return ( - - {indicator !== 'none' && ( - - - - )} - - setStatus('loaded')} - onError={() => setStatus('error')} - /> - - {status === 'error' && ( - - PP - - )} - - + + + {renderContent()} + + {renderBadge()} + ) } export { Avatar } -export type { Props as AvatarProps } +export type { + AccountAvatarProps, + AvatarProps, + ChannelAvatarProps, + CommunityAvatarProps, + GroupAvatarProps, + IconAvatarProps, + UserAvatarProps, + WalletAvatarProps, +} const Base = styled(Stack, { name: 'Avatar', @@ -74,54 +356,54 @@ const Base = styled(Stack, { position: 'relative', justifyContent: 'center', alignItems: 'center', + overflow: 'hidden', variants: { - // defined in Avatar props size: { - '...': (size: number) => { - return { - width: size, - height: size, - } + 80: { + width: 80, + height: 80, }, - }, - - shape: { - circle: { - borderRadius: '$full', + 56: { + width: 56, + height: 56, }, - rounded: { - borderRadius: '$16', + 48: { + width: 48, + height: 48, }, - }, - - outline: { - true: { - borderWidth: 2, - borderColor: '$white-100', + 32: { + width: 32, + height: 32, + }, + 28: { + width: 28, + height: 28, + }, + 24: { + width: 24, + height: 24, + }, + 20: { + width: 20, + height: 20, + }, + 16: { + width: 16, + height: 16, }, }, } as const, }) -const Shape = styled(Stack, { - name: 'AvatarShape', +const Fallback = styled(Stack, { + name: 'AvatarFallback', + + justifyContent: 'center', + alignItems: 'center', width: '100%', height: '100%', - backgroundColor: '$white-100', - overflow: 'hidden', - - variants: { - shape: { - circle: { - borderRadius: '$full', - }, - rounded: { - borderRadius: '$16', - }, - }, - }, }) const Indicator = styled(Stack, { @@ -191,6 +473,31 @@ const Indicator = styled(Stack, { } as const, }) -const Fallback = styled(Text, { - name: 'AvatarFallback', +const LockBase = styled(Stack, { + justifyContent: 'center', + alignItems: 'center', + width: 16, + height: 16, + backgroundColor: '$white-100', + position: 'absolute', + borderRadius: '$full', + + variants: { + variant: { + 80: { + width: 48, + height: 48, + right: -14, + bottom: -14, + }, + 24: { + right: -4, + bottom: -4, + }, + 20: { + right: -6, + bottom: -6, + }, + }, + } as const, }) diff --git a/packages/components/src/avatar/channel-avatar.tsx b/packages/components/src/avatar/channel-avatar.tsx deleted file mode 100644 index 576008e3..00000000 --- a/packages/components/src/avatar/channel-avatar.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { LockedIcon, UnlockedIcon } from '@status-im/icons' -import { type ColorTokens, Stack, styled, Text } from '@tamagui/core' - -type Props = { - emoji: string - color?: ColorTokens - background?: ColorTokens - size: 32 | 24 | 20 - lock?: 'locked' | 'unlocked' | 'none' -} - -const emojiSizes: Record = { - 32: 14, - 24: 13, - 20: 11, -} - -// https://www.figma.com/file/IBmFKgGL1B4GzqD8LQTw6n/Design-System-for-Desktop%2FWeb?node-id=399-20709&t=kX5LC5OYFnSF8BiZ-11 -const ChannelAvatar = (props: Props) => { - const { emoji, background = '$blue-50-opa-20', size, lock = 'none' } = props - - return ( - - {lock !== 'none' && ( - - {lock === 'locked' ? ( - - ) : ( - - )} - - )} - - {emoji} - - ) -} - -export { ChannelAvatar } -export type { Props as ChannelAvatarProps } - -const Base = styled(Stack, { - position: 'relative', - justifyContent: 'center', - alignItems: 'center', - - variants: { - size: { - '...': (size: number) => { - return { - width: size, - height: size, - borderRadius: size / 2, - } - }, - }, - }, -}) - -const LockBase = styled(Stack, { - justifyContent: 'center', - alignItems: 'center', - width: 16, - height: 16, - backgroundColor: '$white-100', - position: 'absolute', - borderRadius: '$16', - - variants: { - variant: { - 32: { - right: -4, - bottom: -4, - }, - 24: { - right: -4, - bottom: -4, - }, - 20: { - right: -6, - bottom: -6, - }, - }, - }, -}) diff --git a/packages/components/src/avatar/icon-avatar.tsx b/packages/components/src/avatar/icon-avatar.tsx deleted file mode 100644 index e972d577..00000000 --- a/packages/components/src/avatar/icon-avatar.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { cloneElement } from 'react' - -import { type ColorTokens, Stack, styled } from '@tamagui/core' - -type Props = { - children: React.ReactElement - backgroundColor?: ColorTokens - color?: ColorTokens - size?: 20 | 32 | 48 -} - -const IconAvatar = (props: Props) => { - const { - children, - color = '$blue-50', - backgroundColor = '$blue-50-opa-20', - size = 32, - } = props - return ( - - {cloneElement(children, { color })} - - ) -} - -const Base = styled(Stack, { - borderRadius: '$full', - justifyContent: 'center', - alignItems: 'center', - - variants: { - size: { - '...': (size: number) => { - return { - width: size, - height: size, - } - }, - }, - }, -}) - -export { IconAvatar } -export type { Props as IconAvatarProps } diff --git a/packages/components/src/avatar/index.tsx b/packages/components/src/avatar/index.tsx index e4535795..886c6ec3 100644 --- a/packages/components/src/avatar/index.tsx +++ b/packages/components/src/avatar/index.tsx @@ -1,3 +1 @@ export * from './avatar' -export * from './channel-avatar' -export * from './icon-avatar' diff --git a/packages/components/src/avatar/utils.tsx b/packages/components/src/avatar/utils.tsx new file mode 100644 index 00000000..61984fb7 --- /dev/null +++ b/packages/components/src/avatar/utils.tsx @@ -0,0 +1,60 @@ +/** + * returns value for conic-gradient + */ +export const generateIdenticonRing = (colorHash: number[][]) => { + const segments = colorHash.reduce((acc, segment) => (acc += segment[0]), 0) + + let prevAngle = 0 + const gradient = colorHash.reduce((acc, segment, index) => { + const [length, colorIndex] = segment + const color = COLORS[colorIndex] + const nextAngle = Math.round(prevAngle + (length * 360) / segments) + + acc += `${color} ${prevAngle}deg ${nextAngle}deg` + + if (index !== colorHash.length - 1) { + acc += `, ` + } + + prevAngle = nextAngle + + return acc + }, '') + + return gradient +} + +const COLORS = [ + '#000000', + '#726F6F', + '#C4C4C4', + '#E7E7E7', + '#FFFFFF', + '#00FF00', + '#009800', + '#B8FFBB', + '#FFC413', + '#9F5947', + '#FFFF00', + '#A8AC00', + '#FFFFB0', + '#FF5733', + '#FF0000', + '#9A0000', + '#FF9D9D', + '#FF0099', + '#C80078', + '#FF00FF', + '#900090', + '#FFB0FF', + '#9E00FF', + '#0000FF', + '#000086', + '#9B81FF', + '#3FAEF9', + '#9A6600', + '#00FFFF', + '#008694', + '#C2FFFF', + '#00F0B6', +] diff --git a/packages/components/src/channel/channel.stories.tsx b/packages/components/src/channel/channel.stories.tsx index 41ccedb1..acfd8058 100644 --- a/packages/components/src/channel/channel.stories.tsx +++ b/packages/components/src/channel/channel.stories.tsx @@ -44,9 +44,7 @@ type Story = StoryObj // More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args export const Default: Story = { - args: { - lock: 'none', - }, + args: {}, } export const Locked: Story = { diff --git a/packages/components/src/channel/channel.tsx b/packages/components/src/channel/channel.tsx index 01b6ab51..78d979bf 100644 --- a/packages/components/src/channel/channel.tsx +++ b/packages/components/src/channel/channel.tsx @@ -3,7 +3,7 @@ import { useState } from 'react' import { MutedIcon, NotificationIcon, OptionsIcon } from '@status-im/icons' import { Stack, styled } from 'tamagui' -import { ChannelAvatar } from '../avatar' +import { Avatar } from '../avatar' import { Counter } from '../counter' import { DropdownMenu } from '../dropdown-menu' import { Text } from '../text' @@ -95,7 +95,7 @@ const Channel = (props: Props) => { state={active ? 'active' : selected ? 'selected' : undefined} > - + # {children} diff --git a/packages/components/src/community/sidebar-community/sidebar-community.tsx b/packages/components/src/community/sidebar-community/sidebar-community.tsx index 53eb04d3..6a2a4be1 100644 --- a/packages/components/src/community/sidebar-community/sidebar-community.tsx +++ b/packages/components/src/community/sidebar-community/sidebar-community.tsx @@ -63,11 +63,21 @@ const SidebarCommunity = (props: Props) => { > - + + + + + diff --git a/packages/components/src/context-tag/context-tag.tsx b/packages/components/src/context-tag/context-tag.tsx index 2297d023..b8ebfcaa 100644 --- a/packages/components/src/context-tag/context-tag.tsx +++ b/packages/components/src/context-tag/context-tag.tsx @@ -65,7 +65,7 @@ const ContextTag = (props: Props) => { return ( - {src && } + {src && } {icon && cloneElement(icon, { color: '$neutral-50' })} {Array.isArray(label) ? ( diff --git a/packages/components/src/image/image.tsx b/packages/components/src/image/image.tsx index 56e8471e..ce0c2b28 100644 --- a/packages/components/src/image/image.tsx +++ b/packages/components/src/image/image.tsx @@ -59,12 +59,26 @@ const Base = styled(RNImage, { variants: { radius: { none: {}, + 6: { + borderRadius: 6, + }, + 8: { + borderRadius: 8, + }, + 10: { + borderRadius: 10, + }, 12: { borderRadius: 12, // fix this once Image is migrated to tamagui image }, + 16: { + borderRadius: 16, + }, full: { borderRadius: 999, // fix this once Image is migrated to tamagui image }, }, }, + + backgroundColor: '$white-100', }) diff --git a/packages/components/src/messages/message.tsx b/packages/components/src/messages/message.tsx index 112cf6e1..ee51983a 100644 --- a/packages/components/src/messages/message.tsx +++ b/packages/components/src/messages/message.tsx @@ -103,6 +103,8 @@ const Message = (props: MessageProps) => { { - + {name} diff --git a/packages/components/src/system-message/components/added-users-message-content.tsx b/packages/components/src/system-message/components/added-users-message-content.tsx index 876c2416..0364134a 100644 --- a/packages/components/src/system-message/components/added-users-message-content.tsx +++ b/packages/components/src/system-message/components/added-users-message-content.tsx @@ -1,7 +1,7 @@ import { AddUserIcon } from '@status-im/icons' import { Stack } from 'tamagui' -import { Avatar, IconAvatar } from '../../avatar' +import { Avatar } from '../../avatar' import { Text } from '../../text' import type { SystemMessageState, User } from '../system-message' @@ -18,22 +18,29 @@ const AddedUsersMessageContent = (props: Props) => { return ( <> - } + size={32} backgroundColor={state === 'landed' ? '$transparent' : '$blue-50-opa-5'} color="$blue-50" - > - - + /> - + {user.name} added {users.length === 1 && ( - + {users[0].name} @@ -56,7 +63,12 @@ const AddedUsersMessageContent = (props: Props) => { {users.length === i + 1 ? ' and ' : null} - + {user.name} diff --git a/packages/components/src/system-message/components/deleted-message-content.tsx b/packages/components/src/system-message/components/deleted-message-content.tsx index ec5625f5..b040ee93 100644 --- a/packages/components/src/system-message/components/deleted-message-content.tsx +++ b/packages/components/src/system-message/components/deleted-message-content.tsx @@ -1,7 +1,7 @@ import { LoadingIcon, TrashIcon } from '@status-im/icons' import { Stack } from 'tamagui' -import { IconAvatar } from '../../avatar' +import { Avatar } from '../../avatar' import { Button } from '../../button' import { Text } from '../../text' @@ -22,12 +22,13 @@ const DeletedMessageContent = (props: Props) => { return ( <> - } backgroundColor={state === 'landed' ? '$transparent' : '$red-50-opa-5'} color="$neutral-100" - > - - + /> { return ( <> - } backgroundColor={state === 'landed' ? '$transparent' : '$blue-50-opa-5'} color="$neutral-100" - > - - + /> { flexBasis="max-content" > - + {author.name} diff --git a/packages/components/src/text/text.tsx b/packages/components/src/text/text.tsx index f57c347e..37185c6b 100644 --- a/packages/components/src/text/text.tsx +++ b/packages/components/src/text/text.tsx @@ -12,6 +12,7 @@ type Weight = NonNullable type Props = { children: React.ReactNode + size?: 27 | 19 | 15 | 13 | 11 | undefined color?: ColorTokens truncate?: boolean wrap?: false @@ -26,8 +27,8 @@ type Props = { // TODO: monospace should be used only for variant. Extract to separate
component? // TODO: Ubuntu Mono should be used only for code snippets. Extract to separate component? const Text = (props: Props, ref: Ref) => { - const { color = '$neutral-100', ...rest } = props - return + const { color = '$neutral-100', size = 13, ...rest } = props + return } const Base = styled(BaseText, { diff --git a/packages/components/src/user-list/user-list.tsx b/packages/components/src/user-list/user-list.tsx index 71d4dac4..5067fa56 100644 --- a/packages/components/src/user-list/user-list.tsx +++ b/packages/components/src/user-list/user-list.tsx @@ -5,10 +5,10 @@ import { Avatar } from '../avatar' import { Text } from '../text' import type { AuthorProps } from '../author/author' -import type { AvatarProps } from '../avatar' +import type { UserAvatarProps } from '../avatar' type Props = { - users: (Pick & AuthorProps)[] + users: (Pick & AuthorProps)[] } const UserList = (props: Props) => { @@ -31,7 +31,13 @@ const UserList = (props: Props) => { backgroundColor: '$primary-50-opa-5', }} > - +