Skip to content

Commit 2319928

Browse files
feat: new ProfilePicture and SelectCard components (#36)
* feat: new ProfilePicture and SelectCard components * feat: linting fixes
1 parent 248586d commit 2319928

9 files changed

Lines changed: 252 additions & 1 deletion

File tree

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { ComponentProps } from 'react';
2+
import { Story } from '@storybook/react';
3+
4+
import { ProfilePicture } from './ProfilePicture';
5+
6+
export default {
7+
title: 'Polyblocks/ProfilePicture',
8+
component: ProfilePicture,
9+
};
10+
11+
const Template: Story<ComponentProps<typeof ProfilePicture>> = (props: any) => (
12+
<ProfilePicture {...props} />
13+
);
14+
15+
export const WithIcon = Template.bind({});
16+
WithIcon.args = {
17+
variant: 'icon',
18+
};
19+
20+
export const WithImage = Template.bind({});
21+
WithImage.args = {
22+
variant: 'image',
23+
image: 'https://www.w3schools.com/howto/img_avatar2.png',
24+
};
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { FC } from 'react';
2+
import styled from 'styled-components';
3+
import { Flex } from '../Flex';
4+
import { polyIcons } from '../../theme/icons';
5+
import { Icon } from '../Icon';
6+
7+
export type ProfilePictureVariant = 'text' | 'icon' | 'image';
8+
9+
export type ProfilePictureProps = {
10+
text?: string;
11+
image?: string;
12+
variant?: ProfilePictureVariant;
13+
size?: 's' | 'm' | 'l';
14+
};
15+
16+
const iconSizeMap: Record<string, string> = {
17+
s: '16px',
18+
m: '26px',
19+
l: '36px',
20+
};
21+
22+
const textSizeMap: Record<string, Record<string, string>> = {
23+
s: {
24+
fontWeight: '500',
25+
fontSize: '14px',
26+
lineHeight: '24px',
27+
},
28+
m: {
29+
fontWeight: '500',
30+
fontSize: '24px',
31+
lineHeight: '32px',
32+
},
33+
l: {
34+
fontWeight: '500',
35+
fontSize: '34px',
36+
lineHeight: '44px',
37+
},
38+
};
39+
40+
const ComponentSizeMap: Record<string, Record<string, string>> = {
41+
s: {
42+
width: '40px',
43+
height: '40px',
44+
},
45+
m: {
46+
width: '88px',
47+
height: '88px',
48+
},
49+
l: {
50+
width: '128px',
51+
height: '128px',
52+
},
53+
};
54+
55+
const Component = styled(Flex)<any>(({ theme, size, variant, image }) => ({
56+
...ComponentSizeMap[size],
57+
...theme.PROFILE_PICTURE,
58+
...(variant === 'image' && { backgroundImage: `url(${image})` }),
59+
}));
60+
61+
const StyledText = styled.p<any>(({ size }) => ({
62+
...textSizeMap[size],
63+
}));
64+
65+
const renderChildren = (
66+
variant: string,
67+
text: string | undefined,
68+
size: string,
69+
) => {
70+
if (variant === 'icon') {
71+
return (
72+
<Icon
73+
size={iconSizeMap[size]}
74+
color="brandDarkest"
75+
icon={polyIcons.Account}
76+
variant="basic"
77+
margin="0"
78+
/>
79+
);
80+
} else if (variant === 'text') {
81+
return <StyledText size={size}>{text}</StyledText>;
82+
} else if (variant === 'image') {
83+
return <StyledText size={size}>{text}</StyledText>;
84+
}
85+
};
86+
87+
export const ProfilePicture: FC<ProfilePictureProps> = (props) => {
88+
const { text, variant = 'icon', size = 'm', image } = props;
89+
return (
90+
<Component
91+
size={size}
92+
image={image}
93+
variant={variant}
94+
align="center"
95+
justify="center"
96+
{...props}
97+
>
98+
{renderChildren(variant, text, size)}
99+
</Component>
100+
);
101+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './ProfilePicture';
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { ComponentProps } from 'react';
2+
import { Story } from '@storybook/react';
3+
import { polyIcons } from '../../theme';
4+
import { SelectCard } from './SelectCard';
5+
6+
export default {
7+
title: 'Polyblocks/SelectCard',
8+
component: SelectCard,
9+
};
10+
11+
const Template: Story<ComponentProps<typeof SelectCard>> = (props: any) => (
12+
<SelectCard {...props} />
13+
);
14+
15+
export const Basic = Template.bind({});
16+
Basic.args = {
17+
title: 'Card title',
18+
description: 'Some description text here.',
19+
onChange: () => {},
20+
};
21+
22+
export const Checked = Template.bind({});
23+
Checked.args = {
24+
title: 'Card title',
25+
description: 'Some description text here.',
26+
checked: true,
27+
onChange: () => {},
28+
};
29+
30+
export const WithIcon = Template.bind({});
31+
WithIcon.args = {
32+
title: 'Card title',
33+
description: 'Some description text here.',
34+
icon: polyIcons.Image,
35+
onChange: () => {},
36+
};
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { ComponentType, FC, ChangeEventHandler, useState } from 'react';
2+
import styled from 'styled-components';
3+
import { Flex } from '../Flex';
4+
import { Text } from '../Text';
5+
import { Checkbox } from '../Checkbox';
6+
import { Icon } from '../Icon';
7+
8+
export type SelectCardProps = {
9+
title?: string;
10+
description?: string;
11+
icon?: ComponentType;
12+
checked?: boolean;
13+
onChange: ChangeEventHandler<HTMLInputElement>;
14+
};
15+
16+
const Component = styled(Flex)<any>(({ theme }) => ({
17+
...theme.SELECT_CARD,
18+
}));
19+
20+
export const SelectCard: FC<SelectCardProps> = (props) => {
21+
const { title, description, checked, icon, onChange } = props;
22+
const [isActive, setIsActive] = useState(checked ?? false);
23+
return (
24+
<Component
25+
onClick={() => setIsActive(!isActive)}
26+
align="center"
27+
justify="spaced"
28+
{...props}
29+
>
30+
<Flex width="100%" padding="0" justify="spaced" variant="basic">
31+
<Flex padding="0" variant="basic" dir="column">
32+
<Checkbox
33+
variant="basic"
34+
checked={isActive}
35+
onChange={(e) => {
36+
setIsActive(isActive);
37+
onChange(e);
38+
}}
39+
label={
40+
<Text as="span" variant="h6" margin="0 18px">
41+
{title}
42+
</Text>
43+
}
44+
/>
45+
<Text margin="0 0 0 36px" as="span" variant="b2">
46+
{description}
47+
</Text>
48+
</Flex>
49+
{icon && (
50+
<Icon
51+
size="48px"
52+
color={isActive ? 'brandMain' : 'gray1'}
53+
bg={isActive ? 'brandLightest' : 'gray5'}
54+
icon={icon}
55+
variant="circle"
56+
margin="0"
57+
/>
58+
)}
59+
</Flex>
60+
</Component>
61+
);
62+
};

src/components/SelectCard/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './SelectCard';

src/components/Text/Text.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ import { getMargin } from '../../theme/utils';
66

77
export type TextAs = 'p' | 'span' | 'label';
88
export type TextVariant =
9+
| 'h1'
10+
| 'h2'
11+
| 'h3'
12+
| 'h4'
13+
| 'h5'
14+
| 'h6'
915
| 'b1m'
1016
| 'b1'
1117
| 'b2m'

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,5 @@ export * from './components/Loader';
5656
export * from './components/ProgressBar';
5757
export * from './components/TabBar';
5858
export * from './components/Table';
59+
export * from './components/ProfilePicture';
60+
export * from './components/SelectCard';

src/theme/definitions/launchpad.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ export const TYPOGRAPHY: any = {
150150
h6: {
151151
margin: `0 0 ${GAP.s} 0`,
152152
lineHeight: '27px',
153-
fontWeight: 400,
153+
fontWeight: 500,
154154
fontSize: '18px',
155155
color: COLOR.gray1,
156156
},
@@ -842,6 +842,24 @@ export const INFOBOXTITLE: Record<InfoBoxVariant, CSSPropertiesExtended> = {
842842
},
843843
};
844844

845+
export const PROFILE_PICTURE: CSSPropertiesExtended = {
846+
borderRadius: '100px',
847+
background: COLOR.brandLightest,
848+
backgroundSize: 'contain',
849+
};
850+
export const SELECT_CARD: CSSPropertiesExtended = {
851+
padding: '16px',
852+
border: `1px solid ${COLOR.gray4}`,
853+
borderRadius: RADIUS.xl,
854+
cursor: 'pointer',
855+
'&:hover': {
856+
border: `1px solid ${COLOR.gray1}`,
857+
},
858+
'&:active': {
859+
border: `1px solid ${COLOR.brandMain}`,
860+
},
861+
};
862+
845863
export const CHIPS: Record<ChipsVariant, CSSPropertiesExtended> = {
846864
default: {
847865
...TYPOGRAPHY.b2m,

0 commit comments

Comments
 (0)