diff --git a/src/components/common/SkeletonCommon/SkeletonCommon.module.scss b/src/components/common/SkeletonCommon/SkeletonCommon.module.scss
new file mode 100644
index 000000000..e388525e5
--- /dev/null
+++ b/src/components/common/SkeletonCommon/SkeletonCommon.module.scss
@@ -0,0 +1,32 @@
+@import '../../../styles/utilities';
+
+$base-color: #ddd;
+$shine-color: #e8e8e8;
+$animation-duration: 1.6s;
+
+@mixin background-gradient {
+ background-image: linear-gradient(90deg, $base-color 0px, $shine-color 40px, $base-color 80px) ;
+ background-size: 600px;
+}
+
+.skeletonCommon:empty {
+ margin: auto;
+ height: 14rem;
+ width: 14rem;
+ animation: name duration timing-function delay iteration-count direction fill-mode;
+
+ @include background-gradient;
+ animation: shine-lines $animation-duration infinite linear;
+}
+
+@keyframes shine-lines {
+ 0% {
+ background-position: -100px;
+ }
+ 40% {
+ background-position: 140px;
+ }
+ 100% {
+ background-position: 140px;
+ }
+}
\ No newline at end of file
diff --git a/src/components/common/SkeletonCommon/SkeletonCommon.tsx b/src/components/common/SkeletonCommon/SkeletonCommon.tsx
new file mode 100644
index 000000000..6b0631aef
--- /dev/null
+++ b/src/components/common/SkeletonCommon/SkeletonCommon.tsx
@@ -0,0 +1,17 @@
+import React from "react";
+import s from './SkeletonCommon.module.scss'
+
+interface SkeletonCommonProps {
+ children? : React.ReactNode;
+}
+
+const SkeletonCommon = ({ children }: SkeletonCommonProps) => {
+
+ return (
+
+ {children}
+
+ )
+}
+
+export default SkeletonCommon
\ No newline at end of file
diff --git a/src/components/common/SkeletonCommon/components/SkeletonAvatar/SkeletonAvatar.module.scss b/src/components/common/SkeletonCommon/components/SkeletonAvatar/SkeletonAvatar.module.scss
new file mode 100644
index 000000000..82286d7a0
--- /dev/null
+++ b/src/components/common/SkeletonCommon/components/SkeletonAvatar/SkeletonAvatar.module.scss
@@ -0,0 +1,51 @@
+@import '../../../../../styles/utilities';
+
+$base-color: #8F8F8F;
+$shine-color: #ebebeb;
+$animation-duration: 1.6s;
+$avatar-offset: 52 + 16;
+
+@mixin background-gradient {
+ background-image: linear-gradient(90deg, $base-color 0px, $shine-color 40px, $base-color 80px) ;
+ background-size: 600px;
+}
+
+.skeletonAvatar {
+
+ &.active {
+ @include background-gradient;
+ animation: shine-avatar $animation-duration infinite linear;
+ }
+
+ &.circle {
+ border-radius: 50%;
+ }
+
+ &.square {
+ border-radius: 0;
+ }
+
+ &.small {
+ width: 3.2rem;
+ height: 3.2rem;
+ }
+ &.default {
+ width: 4.8rem;
+ height: 4.8rem;
+ }
+ &.large {
+ width: 6.4rem;
+ height: 6.4rem;
+ }
+}
+
+@keyframes shine-avatar {
+ 0% {
+ background-position: -100px + $avatar-offset
+ }
+
+ 40%, 100% {
+ background-position: 140px + $avatar-offset
+ }
+
+}
diff --git a/src/components/common/SkeletonCommon/components/SkeletonAvatar/SkeletonAvatar.tsx b/src/components/common/SkeletonCommon/components/SkeletonAvatar/SkeletonAvatar.tsx
new file mode 100644
index 000000000..d5d20165b
--- /dev/null
+++ b/src/components/common/SkeletonCommon/components/SkeletonAvatar/SkeletonAvatar.tsx
@@ -0,0 +1,25 @@
+import classNames from "classnames";
+import React from "react";
+import s from './SkeletonAvatar.module.scss'
+
+interface SkeletonAvatarProps {
+ active?: boolean,
+ shape?: "circle" | "square",
+ size?: "small" | "default" | "large",
+ children: React.ReactNode
+}
+
+const SkeletonAvatar = ({ active=true, shape="circle", size="default", children }: SkeletonAvatarProps) => {
+
+ return (
+
+ {children}
+
+ )
+}
+
+export default SkeletonAvatar
\ No newline at end of file
diff --git a/src/components/common/SkeletonCommon/components/SkeletonParagraph/SkeletonParagraph.module.scss b/src/components/common/SkeletonCommon/components/SkeletonParagraph/SkeletonParagraph.module.scss
new file mode 100644
index 000000000..259c1574c
--- /dev/null
+++ b/src/components/common/SkeletonCommon/components/SkeletonParagraph/SkeletonParagraph.module.scss
@@ -0,0 +1,41 @@
+@import '../../../../../styles/utilities';
+
+$base-color: #DDD;
+$shine-color: #ebebeb;
+$animation-duration: 2s;
+
+@mixin background-gradient {
+ background-image: linear-gradient(90deg, $base-color 0px, $shine-color 40px, $base-color 80px) ;
+ background-size: 100%;
+}
+
+.skeletonParagraph {
+ @apply bg-white;
+ height: fit-content;
+ width: 100%;
+
+ .row {
+ height: 2rem;
+ margin: 1rem;
+ animation: shine-lines $animation-duration infinite linear;
+ @include background-gradient;
+ }
+
+ .lastRow {
+ height: 2rem;
+ margin: 1rem;
+ width: 85%;
+ animation: shine-lines $animation-duration infinite linear;
+ @include background-gradient;
+ }
+}
+
+@keyframes shine-lines {
+ 0% {
+ background-position: -100px;
+ }
+ 40%, 100% {
+ background-position: 100%;
+ }
+}
+
diff --git a/src/components/common/SkeletonCommon/components/SkeletonParagraph/SkeletonParagraph.tsx b/src/components/common/SkeletonCommon/components/SkeletonParagraph/SkeletonParagraph.tsx
new file mode 100644
index 000000000..5c3620f0a
--- /dev/null
+++ b/src/components/common/SkeletonCommon/components/SkeletonParagraph/SkeletonParagraph.tsx
@@ -0,0 +1,30 @@
+import classNames from "classnames";
+import React from "react";
+import s from './SkeletonParagraph.module.scss'
+
+interface SkeletonParagraphProps {
+ active?: boolean,
+ rows?: number // number of rows in paragraph
+ children: React.ReactNode
+}
+
+const SkeletonParagraph = ({ active=true, rows=2, children }: SkeletonParagraphProps) => {
+
+ return (
+
+ {
+ [...Array(rows)].map((e, i) => {
+ if (i === rows-1) {
+ return
+ }
+ return
+ })
+ }
+ {children}
+
+ )
+}
+
+export default SkeletonParagraph
\ No newline at end of file
diff --git a/src/components/common/SkeletonCommon/components/SkeletonTitle/SkeletonTitle.module.scss b/src/components/common/SkeletonCommon/components/SkeletonTitle/SkeletonTitle.module.scss
new file mode 100644
index 000000000..0dbb139d3
--- /dev/null
+++ b/src/components/common/SkeletonCommon/components/SkeletonTitle/SkeletonTitle.module.scss
@@ -0,0 +1,27 @@
+@import '../../../../../styles/utilities';
+
+$base-color: #8F8F8F;
+$shine-color: #ebebeb;
+$animation-duration: 1.6s;
+
+@mixin background-gradient {
+ background-image: linear-gradient(90deg, $base-color 0px, $shine-color 40px, $base-color 80px) ;
+ background-size: 600px;
+}
+
+.skeletonTitle {
+ &.active {
+ @include background-gradient;
+ animation: shine-lines $animation-duration infinite linear;
+ }
+}
+
+@keyframes shine-lines {
+ 0% {
+ background-position: -100px;
+ }
+ 40%, 100% {
+ background-position: 50rem;
+ }
+}
+
diff --git a/src/components/common/SkeletonCommon/components/SkeletonTitle/SkeletonTitle.tsx b/src/components/common/SkeletonCommon/components/SkeletonTitle/SkeletonTitle.tsx
new file mode 100644
index 000000000..40d747d8f
--- /dev/null
+++ b/src/components/common/SkeletonCommon/components/SkeletonTitle/SkeletonTitle.tsx
@@ -0,0 +1,28 @@
+import classNames from "classnames";
+import React from "react";
+import s from './SkeletonTitle.module.scss'
+
+interface SkeletonTitleProps {
+ active?: boolean,
+ width: string | number, // number px
+ height: string | number,
+ children: React.ReactNode
+}
+
+const SkeletonTitle = ({ active=true, width, height, children }: SkeletonTitleProps) => {
+
+ const styles = {
+ width: width,
+ height: height
+ }
+
+ return (
+
+ {children}
+
+ )
+}
+
+export default SkeletonTitle
\ No newline at end of file