Skip to content

Commit c7c2163

Browse files
feat: added Loading and Progressbar commponents (#23)
* feat: added Loading and Progressbar commponents * fix: remove react imports, rename component, fix lint Co-authored-by: honarpour <amir@honarpour.com>
1 parent 3e6f014 commit c7c2163

File tree

13 files changed

+421
-1643
lines changed

13 files changed

+421
-1643
lines changed

package-lock.json

Lines changed: 118 additions & 1635 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/Box/Box.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export type BoxProps = {
1717
bg?: string;
1818
border?: string;
1919
width?: number | string;
20+
height?: number | string;
2021
maxWidth?: number;
2122
};
2223

@@ -32,6 +33,7 @@ const Component = styled.div<BoxProps>(
3233
bg,
3334
border,
3435
width,
36+
height,
3537
maxWidth,
3638
}) => ({
3739
...(theme.BOX[variant] || {}),
@@ -43,6 +45,7 @@ const Component = styled.div<BoxProps>(
4345
...(bg ? { backgroundColor: theme.COLOR[bg] } : {}),
4446
...(border ? { border: getBorder({ theme, border }) } : {}),
4547
...(width ? { width } : {}),
48+
...(height ? { height } : {}),
4649
...(maxWidth ? { maxWidth } : {}),
4750
}),
4851
);
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Meta, Story } from '@storybook/react/types-6-0';
2+
import { Loader, LoaderProps } from '.';
3+
4+
export default {
5+
title: 'Polyblocks/Loader',
6+
component: Loader,
7+
} as Meta;
8+
9+
const Template: Story<LoaderProps> = (args) => <Loader {...args} />;
10+
11+
export const Default = Template.bind({});
12+
Default.args = {
13+
variant: 'default',
14+
} as LoaderProps;
15+
16+
export const Screen = Template.bind({});
17+
Screen.args = {
18+
variant: 'screen',
19+
} as LoaderProps;
20+
21+
export const Dots = Template.bind({});
22+
Dots.args = {
23+
variant: 'dots',
24+
} as LoaderProps;
25+
26+
export const Outlined = Template.bind({});
27+
Outlined.args = {
28+
variant: 'outlined',
29+
} as LoaderProps;

src/components/Loader/Loader.tsx

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import * as sc from './styles';
2+
import { LoaderProps } from './types';
3+
import { Box } from '../Box';
4+
5+
const LoadingDefault = (props: LoaderProps) => (
6+
<sc.Loader {...props}>
7+
<span />
8+
<span />
9+
<span />
10+
</sc.Loader>
11+
);
12+
13+
const LoadingScreen = ({ details, ...props }: LoaderProps) => (
14+
<sc.Backdrop>
15+
<sc.Wrapper variant="raw" padding="l 0 0 0">
16+
<sc.Loader {...props}>
17+
<span />
18+
<span />
19+
</sc.Loader>
20+
{details && (
21+
<Box variant="raw" bg="gray.1" margin="l 0 0 0">
22+
{details}
23+
</Box>
24+
)}
25+
</sc.Wrapper>
26+
</sc.Backdrop>
27+
);
28+
29+
const LoadingDots = (props: LoaderProps) => (
30+
<sc.LoadingDots {...props}>
31+
<span />
32+
<span />
33+
<span />
34+
</sc.LoadingDots>
35+
);
36+
37+
const LoadingDotsOutlined = (props: LoaderProps) => (
38+
<sc.LoadingDotsOutlined {...props}>
39+
<span />
40+
<span />
41+
<span />
42+
</sc.LoadingDotsOutlined>
43+
);
44+
45+
export const Loader = (props: LoaderProps) => {
46+
const { variant } = props;
47+
if (variant === 'default') return <LoadingDefault {...props} />;
48+
else if (variant === 'dots') return <LoadingDots {...props} />;
49+
else if (variant === 'outlined') return <LoadingDotsOutlined {...props} />;
50+
else if (variant === 'screen') return <LoadingScreen {...props} />;
51+
else return <></>;
52+
};

src/components/Loader/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './Loader';
2+
export * from './types';

src/components/Loader/styles.ts

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import styled, { keyframes } from 'styled-components';
2+
import { LoaderProps } from './types';
3+
import { Box } from '../Box';
4+
5+
const wave = keyframes`
6+
0%, 60%, 100% {
7+
transform: initial;
8+
}
9+
10+
30% {
11+
transform: translateY(-15px);
12+
}
13+
`;
14+
15+
export const LoadingDots = styled.div<LoaderProps>`
16+
position: relative;
17+
text-align: center;
18+
width: 48px;
19+
height: 48px;
20+
margin-left: auto;
21+
margin-right: auto;
22+
background: ${({ theme }) => theme.COLOR.brandLightest};
23+
border-radius: 50%;
24+
span {
25+
display: inline-block;
26+
width: 7px;
27+
height: 7px;
28+
border-radius: 50%;
29+
margin-right: 2px;
30+
margin-top: 21px;
31+
background-color: ${({ theme }) => theme.COLOR.brandMain};
32+
animation: ${wave} 1.3s linear infinite;
33+
}
34+
span:nth-child(2) {
35+
animation-delay: -1.1s;
36+
}
37+
span:nth-child(3) {
38+
animation-delay: -0.9s;
39+
}
40+
`;
41+
42+
export const LoadingDotsOutlined = styled.div<LoaderProps>`
43+
position: relative;
44+
text-align: center;
45+
width: 48px;
46+
height: 48px;
47+
margin-left: auto;
48+
margin-right: auto;
49+
border-radius: 50%;
50+
span {
51+
display: inline-block;
52+
width: 7px;
53+
height: 7px;
54+
border-radius: 50%;
55+
margin-right: 2px;
56+
margin-top: 21px;
57+
animation: ${wave} 1.3s linear infinite;
58+
border: 2px solid ${({ theme }) => theme.COLOR.brandMain};
59+
}
60+
span:nth-child(2) {
61+
animation-delay: -1.1s;
62+
}
63+
span:nth-child(3) {
64+
animation-delay: -0.9s;
65+
}
66+
`;
67+
68+
const spin = keyframes`
69+
0% {
70+
transform: rotate(0deg);
71+
}
72+
100% {
73+
transform: rotate(359deg);
74+
}
75+
`;
76+
77+
const mask = keyframes`
78+
0% {
79+
transform: rotate(0deg);
80+
}
81+
25% {
82+
transform: rotate(180deg);
83+
}
84+
50% {
85+
transform: rotate(180deg);
86+
}
87+
75% {
88+
transform: rotate(360deg);
89+
}
90+
100% {
91+
transform: rotate(360deg);
92+
}
93+
`;
94+
95+
export const Backdrop = styled.div`
96+
position: fixed;
97+
top: 0;
98+
left: 0;
99+
width: 100vw;
100+
height: 100vh;
101+
background-color: rgba(21, 41, 53, 0.3);
102+
z-index: 999;
103+
`;
104+
105+
export const Wrapper = styled(Box)`
106+
position: fixed;
107+
top: 50%;
108+
left: 50%;
109+
transform: translate(-50%, -50%);
110+
text-align: center;
111+
z-index: 9999;
112+
background-color: ${({ theme }) => theme.COLOR.light};
113+
border-radius: ${({ theme }) => theme.RADIUS.m};
114+
box-shadow: ${({ theme }) => theme.SHADOW.s};
115+
padding: 40px 40px;
116+
`;
117+
118+
export const Loader = styled.div<LoaderProps>`
119+
margin: 0 auto;
120+
width: ${(props: any) => (props.small ? '32px' : '64px')};
121+
height: ${(props: any) => (props.small ? '32px' : '64px')};
122+
animation: 1s ${spin} infinite cubic-bezier(0.255, 0.2, 0.315, 0.455);
123+
span,
124+
span:before {
125+
position: absolute;
126+
top: 0;
127+
left: 0;
128+
width: ${(props: any) => (props.small ? '16px' : '32px')};
129+
height: ${(props: any) => (props.small ? '32px' : '64px')};
130+
overflow: hidden;
131+
box-sizing: border-box;
132+
transform-origin: 100% 50%;
133+
border-top-left-radius: 32px;
134+
border-bottom-left-radius: 32px;
135+
}
136+
span:before {
137+
content: '';
138+
border-width: ${(props: any) => (props.small ? '4px' : '5px')};
139+
border-color: ${({ theme }) => theme.COLOR.brandMain};
140+
border-style: solid;
141+
border-right-color: transparent;
142+
animation: 4s ${mask} infinite linear;
143+
}
144+
span:nth-child(1) {
145+
transform: rotate(180deg);
146+
}
147+
span:nth-child(2) {
148+
transform: rotate(360deg);
149+
&:before {
150+
animation-delay: 1s;
151+
}
152+
}
153+
`;

src/components/Loader/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export interface LoaderProps {
2+
variant: 'default' | 'dots' | 'outlined' | 'screen';
3+
small?: boolean;
4+
details?: string;
5+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Meta, Story } from '@storybook/react/types-6-0';
2+
import { ProgressBar, ProgressBarProps } from '.';
3+
4+
export default {
5+
title: 'Polyblocks/ProgressBar',
6+
component: ProgressBar,
7+
} as Meta;
8+
9+
const Template: Story<ProgressBarProps> = (args) => <ProgressBar {...args} />;
10+
11+
export const Default = Template.bind({});
12+
Default.args = { percent: 75 } as ProgressBarProps;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { FC } from 'react';
2+
import { Box } from '../Box';
3+
4+
export type ProgressBarProps = {
5+
percent: number;
6+
height?: string;
7+
width?: number | string;
8+
bg?: string;
9+
bar?: string;
10+
};
11+
12+
export const ProgressBar: FC<ProgressBarProps> = ({
13+
percent = 0,
14+
height = '8px',
15+
width = '100%',
16+
bg = 'brandLightest',
17+
bar = 'brandMain',
18+
...restProps
19+
}) => {
20+
return (
21+
<Box
22+
variant="basic"
23+
bg={bg}
24+
radius="m"
25+
height={height}
26+
width={width}
27+
padding="0px"
28+
{...restProps}
29+
>
30+
<Box
31+
variant="raw"
32+
bg={bar}
33+
radius="m"
34+
height={height}
35+
width={`${percent}%`}
36+
/>
37+
</Box>
38+
);
39+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './ProgressBar';

0 commit comments

Comments
 (0)