82 lines
2.1 KiB
TypeScript
82 lines
2.1 KiB
TypeScript
|
export interface LoaderProps {
|
||
|
width?: number
|
||
|
height?: number
|
||
|
className?: string
|
||
|
}
|
||
|
|
||
|
export const Loader: React.FC<LoaderProps> = (props) => {
|
||
|
const { width = 50, height = 50 } = props
|
||
|
|
||
|
return (
|
||
|
<div className={props.className}>
|
||
|
<div data-cy='progress-spinner' className='progress-spinner'>
|
||
|
<svg className='progress-spinner-svg' viewBox='25 25 50 50'>
|
||
|
<circle
|
||
|
className='progress-spinner-circle'
|
||
|
cx='50'
|
||
|
cy='50'
|
||
|
r='20'
|
||
|
fill='none'
|
||
|
strokeWidth='2'
|
||
|
strokeMiterlimit='10'
|
||
|
/>
|
||
|
</svg>
|
||
|
</div>
|
||
|
|
||
|
<style jsx>
|
||
|
{`
|
||
|
.progress-spinner {
|
||
|
position: relative;
|
||
|
margin: 0 auto;
|
||
|
width: ${width}px;
|
||
|
height: ${height}px;
|
||
|
}
|
||
|
.progress-spinner::before {
|
||
|
content: '';
|
||
|
display: block;
|
||
|
padding-top: 100%;
|
||
|
}
|
||
|
.progress-spinner-svg {
|
||
|
animation: progress-spinner-rotate 2s linear infinite;
|
||
|
height: 100%;
|
||
|
transform-origin: center center;
|
||
|
width: 100%;
|
||
|
position: absolute;
|
||
|
top: 0;
|
||
|
bottom: 0;
|
||
|
left: 0;
|
||
|
right: 0;
|
||
|
margin: auto;
|
||
|
}
|
||
|
.progress-spinner-circle {
|
||
|
stroke-dasharray: 89, 200;
|
||
|
stroke-dashoffset: 0;
|
||
|
stroke: #27b05e;
|
||
|
animation: progress-spinner-dash 1.5s ease-in-out infinite;
|
||
|
stroke-linecap: round;
|
||
|
}
|
||
|
@keyframes progress-spinner-rotate {
|
||
|
100% {
|
||
|
transform: rotate(360deg);
|
||
|
}
|
||
|
}
|
||
|
@keyframes progress-spinner-dash {
|
||
|
0% {
|
||
|
stroke-dasharray: 1, 200;
|
||
|
stroke-dashoffset: 0;
|
||
|
}
|
||
|
50% {
|
||
|
stroke-dasharray: 89, 200;
|
||
|
stroke-dashoffset: -35px;
|
||
|
}
|
||
|
100% {
|
||
|
stroke-dasharray: 89, 200;
|
||
|
stroke-dashoffset: -124px;
|
||
|
}
|
||
|
}
|
||
|
`}
|
||
|
</style>
|
||
|
</div>
|
||
|
)
|
||
|
}
|