diff --git a/src/assets/images/loader.png b/src/assets/images/loader.png
new file mode 100644
index 0000000..c897b94
Binary files /dev/null and b/src/assets/images/loader.png differ
diff --git a/src/assets/images/loaderGrey.png b/src/assets/images/loaderGrey.png
new file mode 100644
index 0000000..9bdbd92
Binary files /dev/null and b/src/assets/images/loaderGrey.png differ
diff --git a/src/assets/images/loaderGreySmall.png b/src/assets/images/loaderGreySmall.png
new file mode 100644
index 0000000..bed8549
Binary files /dev/null and b/src/assets/images/loaderGreySmall.png differ
diff --git a/src/assets/images/loaderSmall.png b/src/assets/images/loaderSmall.png
new file mode 100644
index 0000000..7d47b2b
Binary files /dev/null and b/src/assets/images/loaderSmall.png differ
diff --git a/src/components/loader/__docs__/docs.mdx b/src/components/loader/__docs__/docs.mdx
new file mode 100644
index 0000000..074233c
--- /dev/null
+++ b/src/components/loader/__docs__/docs.mdx
@@ -0,0 +1,28 @@
+import {ArgsTable, Canvas, Meta, Story} from '@storybook/addon-docs';
+import {Loader} from '../loader';
+
+
+
+# Loader
+
+
+
+
+```typescript
+import {Loader} from '@frontapp/ui-kit';
+```
+
+Indicates that content is loading or that an action is taking place.
+
+
+
+## Props
+
+
+
+
+
diff --git a/src/components/loader/__docs__/index.stories.tsx b/src/components/loader/__docs__/index.stories.tsx
new file mode 100644
index 0000000..7f763dc
--- /dev/null
+++ b/src/components/loader/__docs__/index.stories.tsx
@@ -0,0 +1,28 @@
+/* eslint-disable storybook/story-exports */
+import {ComponentMeta} from '@storybook/react';
+
+import {Loader} from '../loader';
+import DocumentationMDX from './docs.mdx';
+
+/*
+ * Storybook.
+ */
+
+export default {
+ title: 'Components/Loader',
+ component: Loader,
+ parameters: {
+ docs: {
+ page: DocumentationMDX
+ },
+ previewTabs: {
+ canvas: {
+ hidden: true
+ }
+ },
+ viewMode: 'docs'
+ },
+ id: 'Components/Loader'
+} as ComponentMeta;
+
+export {Basic, Big} from './stories/basic.stories';
diff --git a/src/components/loader/__docs__/stories/basic.stories.tsx b/src/components/loader/__docs__/stories/basic.stories.tsx
new file mode 100644
index 0000000..5de2f9f
--- /dev/null
+++ b/src/components/loader/__docs__/stories/basic.stories.tsx
@@ -0,0 +1,20 @@
+import {ComponentStory} from '@storybook/react';
+import React from 'react';
+
+import {PaletteColorsEnum} from '../../../../helpers/colorHelpers';
+import {VisualSizesEnum} from '../../../../helpers/fontHelpers';
+import {Loader} from '../../loader';
+
+export const Basic: ComponentStory = (args) => (
+
+
+
+
+);
+
+export const Big: ComponentStory = (args) => (
+
+
+
+
+);
diff --git a/src/components/loader/loader.tsx b/src/components/loader/loader.tsx
new file mode 100644
index 0000000..fe74cc6
--- /dev/null
+++ b/src/components/loader/loader.tsx
@@ -0,0 +1,85 @@
+import React, {FC} from 'react';
+import styled, {css, keyframes} from 'styled-components';
+
+import loader from '../../assets/images/loader.png';
+import loaderGrey from '../../assets/images/loaderGrey.png';
+import loaderGreySmall from '../../assets/images/loaderGreySmall.png';
+import loaderSmall from '../../assets/images/loaderSmall.png';
+import {PaletteColorsEnum} from '../../helpers/colorHelpers';
+import {VisualSizesEnum} from '../../helpers/fontHelpers';
+import {makeSizeConstants} from '../../helpers/styleHelpers';
+
+/*
+ * Props.
+ */
+
+interface LoaderProps {
+ className?: string;
+ /** Size of the loader. */
+ size?: VisualSizesEnum;
+ /** Color scheme of the loader. */
+ color?: PaletteColorsEnum.GREY | PaletteColorsEnum.BLUE;
+ /** Whether or not the loader rotates. */
+ isAnimated?: boolean;
+}
+
+const defaultProps = {
+ size: VisualSizesEnum.LARGE,
+ color: PaletteColorsEnum.BLUE,
+ isAnimated: true
+} as const;
+
+/*
+ * Style.
+ */
+
+const sizes = makeSizeConstants(16, 20, 40);
+const images = {
+ [PaletteColorsEnum.BLUE]: makeSizeConstants(loaderSmall, loaderSmall, loader),
+ [PaletteColorsEnum.GREY]: makeSizeConstants(loaderGreySmall, loaderGreySmall, loaderGrey)
+};
+
+interface LoaderStyleProps {
+ $size: VisualSizesEnum;
+ $variant: PaletteColorsEnum.GREY | PaletteColorsEnum.BLUE;
+ $isEnabled: boolean;
+}
+const StyledLoaderDiv = styled.div`
+ width: ${(p) => sizes[p.$size]}px;
+ height: ${(p) => sizes[p.$size]}px;
+ background-image: url(${(p) => images[p.$variant][p.$size]});
+ background-size: ${(p) => sizes[p.$size]}px;
+
+ ${(p) => maybeAnimate(p.$isEnabled)};
+`;
+
+const rotate360 = keyframes`
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+`;
+
+function maybeAnimate(isEnabled: boolean) {
+ if (!isEnabled) return '';
+
+ return css`
+ animation: ${rotate360} 0.6s linear infinite;
+ `;
+}
+
+/*
+ * Component.
+ */
+
+export const Loader: FC = (props) => (
+
+);
diff --git a/src/custom.d.ts b/src/custom.d.ts
index 0cda6eb..4445e1b 100644
--- a/src/custom.d.ts
+++ b/src/custom.d.ts
@@ -7,3 +7,8 @@ declare module '*.svg' {
export {ReactComponent};
export default ReactComponent;
}
+
+declare module '*.png' {
+ const content: string;
+ export default content;
+}