Skip to content

Commit 472f02f

Browse files
committed
feat(foundation): added profile card ui
1 parent da5357a commit 472f02f

File tree

7 files changed

+168
-2
lines changed

7 files changed

+168
-2
lines changed

packages/uikit-react-native-foundation/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export { default as Header } from './ui/Header';
2525
export { default as LoadingSpinner } from './ui/LoadingSpinner';
2626
export { default as MenuBar, MenuBarProps } from './ui/MenuBar';
2727
export { default as Placeholder } from './ui/Placeholder';
28+
export { default as ProfileCard } from './ui/ProfileCard';
2829
export { default as Prompt } from './ui/Prompt';
2930
export { default as Toast, useToast, ToastProvider } from './ui/Toast';
3031

packages/uikit-react-native-foundation/src/theme/DarkUIKitTheme.ts

+10
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,16 @@ const DarkUIKitTheme = createTheme({
169169
},
170170
},
171171
},
172+
profileCard: {
173+
default: {
174+
none: {
175+
textUsername: palette.onBackgroundDark01,
176+
textBodyLabel: palette.onBackgroundDark02,
177+
textBody: palette.onBackgroundDark01,
178+
background: palette.background500,
179+
},
180+
},
181+
},
172182
},
173183
}),
174184
});

packages/uikit-react-native-foundation/src/theme/LightUIKitTheme.ts

+10
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,16 @@ const LightUIKitTheme = createTheme({
169169
},
170170
},
171171
},
172+
profileCard: {
173+
default: {
174+
none: {
175+
textUsername: palette.onBackgroundLight01,
176+
textBodyLabel: palette.onBackgroundLight02,
177+
textBody: palette.onBackgroundLight01,
178+
background: palette.background50,
179+
},
180+
},
181+
},
172182
},
173183
}),
174184
});

packages/uikit-react-native-foundation/src/types.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ export type Component =
3939
| 'Placeholder'
4040
| 'Message'
4141
| 'DateSeparator'
42-
| 'GroupChannelPreview';
42+
| 'GroupChannelPreview'
43+
| 'ProfileCard';
44+
4345
export type GetColorTree<
4446
Tree extends {
4547
Variant: {
@@ -65,6 +67,7 @@ export type ComponentColorTree = GetColorTree<{
6567
Message: 'incoming' | 'outgoing';
6668
DateSeparator: 'default';
6769
GroupChannelPreview: 'default';
70+
ProfileCard: 'default';
6871
};
6972
State: {
7073
Header: 'none';
@@ -76,6 +79,7 @@ export type ComponentColorTree = GetColorTree<{
7679
Message: 'enabled' | 'pressed';
7780
DateSeparator: 'none';
7881
GroupChannelPreview: 'none';
82+
ProfileCard: 'none';
7983
};
8084
ColorPart: {
8185
Header: 'background' | 'borderBottom';
@@ -96,6 +100,7 @@ export type ComponentColorTree = GetColorTree<{
96100
| 'coverBackground'
97101
| 'bodyIconBackground'
98102
| 'separator';
103+
ProfileCard: 'textUsername' | 'textBodyLabel' | 'textBody' | 'background';
99104
};
100105
}>;
101106
export type ComponentColors<T extends Component> = {
@@ -139,6 +144,7 @@ export interface UIKitColors {
139144
message: ComponentColors<'Message'>;
140145
dateSeparator: ComponentColors<'DateSeparator'>;
141146
groupChannelPreview: ComponentColors<'GroupChannelPreview'>;
147+
profileCard: ComponentColors<'ProfileCard'>;
142148
};
143149
}
144150

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import React from 'react';
2+
import { Pressable, StyleProp, View, ViewStyle } from 'react-native';
3+
4+
import Divider from '../../components/Divider';
5+
import Text from '../../components/Text';
6+
import createStyleSheet from '../../styles/createStyleSheet';
7+
import useUIKitTheme from '../../theme/useUIKitTheme';
8+
import Avatar from '../Avatar';
9+
10+
type Props = {
11+
uri: string;
12+
username: string;
13+
14+
bodyLabel: string;
15+
body: string;
16+
};
17+
18+
// TODO: Extract as component
19+
type OutlinedButtonProps = {
20+
children: string;
21+
containerStyle?: StyleProp<ViewStyle>;
22+
};
23+
24+
const OutlinedButton = ({ children, containerStyle }: OutlinedButtonProps) => {
25+
return (
26+
<Pressable style={[styles.outlinedButton, containerStyle]}>
27+
<Text button numberOfLines={1} style={styles.outlinedButtonText}>
28+
{children}
29+
</Text>
30+
</Pressable>
31+
);
32+
};
33+
34+
const ProfileCard = ({ uri, username, bodyLabel, body }: Props) => {
35+
const { colors } = useUIKitTheme();
36+
const color = colors.ui.profileCard.default.none;
37+
38+
return (
39+
<View style={[styles.container, { backgroundColor: color.background }]}>
40+
<View style={styles.profileContainer}>
41+
<Avatar uri={uri} size={80} containerStyle={styles.profileAvatar} />
42+
<Text h1 color={color.textUsername}>
43+
{username}
44+
</Text>
45+
</View>
46+
<OutlinedButton containerStyle={styles.messageButton}>{'Message'}</OutlinedButton>
47+
<Divider space={16} />
48+
<View style={styles.profileInfoContainer}>
49+
<Text body2 color={color.textBodyLabel} style={styles.profileInfoBodyLabel}>
50+
{bodyLabel}
51+
</Text>
52+
<Text body3 color={color.textBody}>
53+
{body}
54+
</Text>
55+
</View>
56+
</View>
57+
);
58+
};
59+
60+
const styles = createStyleSheet({
61+
outlinedButton: {
62+
borderRadius: 4,
63+
padding: 16,
64+
borderWidth: 1,
65+
alignItems: 'center',
66+
justifyContent: 'center',
67+
},
68+
outlinedButtonText: {
69+
textAlign: 'center',
70+
width: '100%',
71+
},
72+
73+
container: {
74+
paddingTop: 32,
75+
width: '100%',
76+
},
77+
profileContainer: {
78+
alignItems: 'center',
79+
paddingHorizontal: 16,
80+
marginBottom: 24,
81+
},
82+
profileAvatar: {
83+
marginBottom: 8,
84+
},
85+
profileInfoContainer: {
86+
padding: 16,
87+
},
88+
profileInfoBodyLabel: {
89+
marginBottom: 4,
90+
},
91+
messageButton: {
92+
marginHorizontal: 24,
93+
marginBottom: 24,
94+
},
95+
});
96+
97+
export default ProfileCard;

sample/.storybook/storybook.requires.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ if (parameters) {
2424
addParameters(parameters);
2525
}
2626

27-
argsEnhancers.forEach((enhancer) => addArgsEnhancer(enhancer));
27+
// temporary fix for https://github.com/storybookjs/react-native/issues/327 whilst the issue is investigated
28+
try {
29+
argsEnhancers.forEach((enhancer) => addArgsEnhancer(enhancer));
30+
} catch {}
2831

2932
const getStories = () => {
3033
return [
@@ -35,6 +38,7 @@ const getStories = () => {
3538
require("../stories/GroupChannelPreview.stories.tsx"),
3639
require("../stories/Icon.stories.tsx"),
3740
require("../stories/Placeholder.stories.tsx"),
41+
require("../stories/ProfileCard.stories.tsx"),
3842
require("../stories/Switch.stories.tsx"),
3943
require("../stories/Text.stories.tsx"),
4044
];
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import type { ComponentMeta, ComponentStory } from '@storybook/react-native';
2+
import React from 'react';
3+
4+
import { ProfileCard as ProfileCardComponent } from '@sendbird/uikit-react-native-foundation';
5+
6+
const ProfileCardMeta: ComponentMeta<typeof ProfileCardComponent> = {
7+
title: 'ProfileCard',
8+
component: ProfileCardComponent,
9+
argTypes: {
10+
uri: {
11+
name: 'Profile URI',
12+
control: { type: 'text' },
13+
},
14+
username: {
15+
name: 'Username',
16+
control: { type: 'text' },
17+
},
18+
bodyLabel: {
19+
name: 'Body label',
20+
control: { type: 'text' },
21+
},
22+
body: {
23+
name: 'Body',
24+
control: { type: 'text' },
25+
},
26+
},
27+
args: {
28+
uri: 'https://static.sendbird.com/sample/cover/cover_15.jpg',
29+
username: 'Member name',
30+
bodyLabel: 'User ID',
31+
body: 'User1',
32+
},
33+
};
34+
35+
export default ProfileCardMeta;
36+
37+
type ProfileCardStory = ComponentStory<typeof ProfileCardComponent>;
38+
export const Default: ProfileCardStory = (args) => <ProfileCardComponent {...args} />;

0 commit comments

Comments
 (0)