diff --git a/app/YtManagerApp/static/YtManagerApp/css/lib/_hamburger.css b/app/YtManagerApp/static/YtManagerApp/css/lib/_hamburger.css
new file mode 100644
index 0000000..708f0ca
--- /dev/null
+++ b/app/YtManagerApp/static/YtManagerApp/css/lib/_hamburger.css
@@ -0,0 +1,45 @@
+#hamburger-button {
+ margin-right: 0.5rem; }
+ #hamburger-button span {
+ display: block;
+ width: 1.75rem;
+ height: 0.25rem;
+ margin-bottom: 0.25rem;
+ position: relative;
+ background: #cdcdcd;
+ border-radius: 0.25rem;
+ z-index: 100;
+ transform-origin: 50% 50%;
+ transition: transform 0.5s cubic-bezier(0.77, 0.2, 0.05, 1), background 0.5s cubic-bezier(0.77, 0.2, 0.05, 1), opacity 0.55s ease; }
+ #hamburger-button span:nth-child(1) {
+ margin-top: 0.25rem; }
+ #hamburger-button span:nth-child(2) {
+ transform-origin: 20% 50%; }
+ #hamburger-button.hamburger-show span {
+ opacity: 1;
+ background: #232323; }
+ #hamburger-button.hamburger-show span:nth-child(1) {
+ transform: rotate(-45deg) translate(-0.1875rem, 0.0625rem) scale(0.625, 1); }
+ #hamburger-button.hamburger-show span:nth-child(2) {
+ opacity: 0;
+ transform: rotate(0deg) scale(0, 1); }
+ #hamburger-button.hamburger-show span:nth-child(3) {
+ transform: rotate(45deg) translate(-0.1875rem, -0.0625rem) scale(0.625, 1); }
+
+#hamburger {
+ position: fixed;
+ background: white;
+ height: 100%;
+ width: 20rem;
+ z-index: 99;
+ top: 0;
+ padding-top: 5rem;
+ left: -100%;
+ transition: left 0.5s ease; }
+ #hamburger.hamburger-show {
+ left: 0; }
+ @media (max-width: 768px) {
+ #hamburger {
+ width: 100%; } }
+
+/*# sourceMappingURL=_hamburger.css.map */
diff --git a/app/YtManagerApp/static/YtManagerApp/css/lib/_hamburger.css.map b/app/YtManagerApp/static/YtManagerApp/css/lib/_hamburger.css.map
new file mode 100644
index 0000000..b59ab3e
--- /dev/null
+++ b/app/YtManagerApp/static/YtManagerApp/css/lib/_hamburger.css.map
@@ -0,0 +1,7 @@
+{
+"version": 3,
+"mappings": "AAEA,iBAAkB;EACd,YAAY,EAAE,MAAM;EAEpB,sBAAK;IACD,OAAO,EAAE,KAAK;IACd,KAAK,EAAE,OAAO;IACd,MAAM,EAAE,OAAO;IACf,aAAa,EAAE,OAAO;IACtB,QAAQ,EAAE,QAAQ;IAElB,UAAU,EAAE,OAAO;IACnB,aAAa,EAAE,OAAO;IAEtB,OAAO,EAAE,GAAG;IAEZ,gBAAgB,EAAE,OAAO;IAEzB,UAAU,EAAE,qHAEkB;IAE9B,mCAAe;MACX,UAAU,EAAE,OAAO;IAEvB,mCAAe;MACX,gBAAgB,EAAE,OAAO;EAK7B,qCAAK;IACD,OAAO,EAAE,CAAC;IACV,UAAU,EAAE,OAAO;IAEnB,kDAAe;MACX,SAAS,EAAE,+DAA8D;IAE7E,kDAAe;MACX,OAAO,EAAE,CAAC;MACV,SAAS,EAAE,wBAAwB;IAEvC,kDAAe;MACX,SAAS,EAAE,+DAA+D;;AAM1F,UAAW;EACP,QAAQ,EAAE,KAAK;EACf,UAAU,EAAE,KAAK;EACjB,MAAM,EAAE,IAAI;EACZ,KAAK,EAAE,KAAK;EACZ,OAAO,EAAE,EAAE;EAEX,GAAG,EAAE,CAAC;EACN,WAAW,EAAE,IAAI;EACjB,IAAI,EAAE,KAAK;EAEX,UAAU,EAAE,cAAc;EAE1B,yBAAiB;IACb,IAAI,EAAE,CAAC;EAGX,yBAAmC;IAjBvC,UAAW;MAkBH,KAAK,EAAE,IAAI",
+"sources": ["_hamburger.scss"],
+"names": [],
+"file": "_hamburger.css"
+}
diff --git a/app/YtManagerApp/static/YtManagerApp/css/lib/_hamburger.scss b/app/YtManagerApp/static/YtManagerApp/css/lib/_hamburger.scss
new file mode 100644
index 0000000..8d2b096
--- /dev/null
+++ b/app/YtManagerApp/static/YtManagerApp/css/lib/_hamburger.scss
@@ -0,0 +1,88 @@
+@import "variables";
+
+#hamburger-button {
+ margin-right: 0.5rem;
+
+ span {
+ position: relative;
+
+ width: 1.75rem;
+ height: 0.25rem;
+ margin-bottom: 0.25rem;
+
+ display: block;
+ background: #cdcdcd;
+ border-radius: 0.25rem;
+
+ transform-origin: 50% 50%;
+
+ transition: transform 0.5s cubic-bezier(0.77, 0.2, 0.05, 1.0),
+ background 0.5s cubic-bezier(0.77, 0.2, 0.05, 1.0),
+ opacity 0.55s ease;
+
+ &:nth-child(1) {
+ margin-top: 0.25rem;
+ }
+ &:nth-child(2) {
+ transform-origin: 20% 50%;
+ }
+ }
+
+ &.hamburger-show {
+ span {
+ opacity: 1;
+ background: #232323;
+
+ &:nth-child(1) {
+ transform: rotate(-45deg) translate(-.1875rem, 0.0625rem) scale(0.625, 1);
+ }
+ &:nth-child(2) {
+ opacity: 0;
+ transform: rotate(0deg) scale(0, 1);
+ }
+ &:nth-child(3) {
+ transform: rotate(45deg) translate(-0.1875rem, -0.0625rem) scale(0.625, 1);
+ }
+ }
+ }
+}
+
+#hamburger {
+ position: fixed;
+ top: 0;
+ left: -100%;
+ z-index: 99;
+ padding-top: 5rem;
+
+ width: 20rem;
+ height: 100%;
+
+ display: flex;
+ background: white;
+ flex-direction: column;
+
+ transition: left 0.5s ease;
+
+ &.hamburger-show {
+ left: 0;
+ }
+
+ @media (max-width: $breakpoint-md) {
+ width: 100%;
+ }
+}
+
+#hamburger-footer {
+ width: 100%;
+ flex: 0;
+
+ a {
+ margin-left: 0.5rem;
+ margin-right: 0.5rem;
+ }
+}
+
+#hamburger-content {
+ overflow-y: auto;
+ flex: 1;
+}
\ No newline at end of file
diff --git a/app/YtManagerApp/static/YtManagerApp/css/lib/_loading.css b/app/YtManagerApp/static/YtManagerApp/css/lib/_loading.css
new file mode 100644
index 0000000..3b962e9
--- /dev/null
+++ b/app/YtManagerApp/static/YtManagerApp/css/lib/_loading.css
@@ -0,0 +1,44 @@
+/* Loading animation */
+.loading-dual-ring {
+ display: inline-block;
+ width: 64px;
+ height: 64px; }
+ .loading-dual-ring:after {
+ content: " ";
+ display: block;
+ width: 46px;
+ height: 46px;
+ margin: 1px;
+ border-radius: 50%;
+ border: 5px solid var(--primary);
+ border-color: var(--primary) transparent var(--primary) transparent;
+ animation: loading-dual-ring 1.2s linear infinite; }
+
+.loading-dual-ring-small {
+ display: inline-block;
+ width: 32px;
+ height: 32px; }
+ .loading-dual-ring-small:after {
+ content: " ";
+ display: block;
+ width: 23px;
+ height: 23px;
+ margin: 1px;
+ border-radius: 50%;
+ border: 2.5px solid var(--primary);
+ border-color: var(--primary) transparent var(--primary) transparent;
+ animation: loading-dual-ring 1.2s linear infinite; }
+
+@keyframes loading-dual-ring {
+ 0% {
+ transform: rotate(0deg); }
+ 100% {
+ transform: rotate(360deg); } }
+.loading-dual-ring-center-screen {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ margin-top: -32px;
+ margin-left: -32px; }
+
+/*# sourceMappingURL=_loading.css.map */
diff --git a/app/YtManagerApp/static/YtManagerApp/css/lib/_loading.css.map b/app/YtManagerApp/static/YtManagerApp/css/lib/_loading.css.map
new file mode 100644
index 0000000..e07099e
--- /dev/null
+++ b/app/YtManagerApp/static/YtManagerApp/css/lib/_loading.css.map
@@ -0,0 +1,7 @@
+{
+"version": 3,
+"mappings": "AAmBA,uBAAuB;AACvB,kBAAmB;EAlBf,OAAO,EAAE,YAAY;EACrB,KAAK,EAAE,IAAa;EACpB,MAAM,EAAE,IAAa;EAErB,wBAAQ;IACJ,OAAO,EAAE,GAAG;IACZ,OAAO,EAAE,KAAK;IACd,KAAK,EAAE,IAAa;IACpB,MAAM,EAAE,IAAa;IACrB,MAAM,EAAE,GAAG;IACX,aAAa,EAAE,GAAG;IAClB,MAAM,EAAE,wBAAmC;IAC3C,YAAY,EAAE,qDAAqD;IACnE,SAAS,EAAE,sCAAsC;;AASzD,wBAAyB;EAtBrB,OAAO,EAAE,YAAY;EACrB,KAAK,EAAE,IAAa;EACpB,MAAM,EAAE,IAAa;EAErB,8BAAQ;IACJ,OAAO,EAAE,GAAG;IACZ,OAAO,EAAE,KAAK;IACd,KAAK,EAAE,IAAa;IACpB,MAAM,EAAE,IAAa;IACrB,MAAM,EAAE,GAAG;IACX,aAAa,EAAE,GAAG;IAClB,MAAM,EAAE,0BAAmC;IAC3C,YAAY,EAAE,qDAAqD;IACnE,SAAS,EAAE,sCAAsC;;AAazD,4BAOC;EANG,EAAG;IACC,SAAS,EAAE,YAAY;EAE3B,IAAK;IACD,SAAS,EAAE,cAAc;AAIjC,gCAAiC;EAC7B,QAAQ,EAAE,KAAK;EACf,GAAG,EAAE,GAAG;EACR,IAAI,EAAE,GAAG;EACT,UAAU,EAAE,KAAK;EACjB,WAAW,EAAE,KAAK",
+"sources": ["_loading.scss"],
+"names": [],
+"file": "_loading.css"
+}
diff --git a/app/YtManagerApp/static/YtManagerApp/css/lib/_loading.scss b/app/YtManagerApp/static/YtManagerApp/css/lib/_loading.scss
new file mode 100644
index 0000000..7e7d3ff
--- /dev/null
+++ b/app/YtManagerApp/static/YtManagerApp/css/lib/_loading.scss
@@ -0,0 +1,44 @@
+
+@mixin loading-dual-ring($scale : 1) {
+ display: inline-block;
+ width: $scale * 64px;
+ height: $scale * 64px;
+
+ &:after {
+ content: " ";
+ display: block;
+ width: $scale * 46px;
+ height: $scale * 46px;
+ margin: 1px;
+ border-radius: 50%;
+ border: ($scale * 5px) solid var(--primary);
+ border-color: var(--primary) transparent var(--primary) transparent;
+ animation: loading-dual-ring 1.2s linear infinite;
+ }
+}
+
+/* Loading animation */
+.loading-dual-ring {
+ @include loading-dual-ring(1.0);
+}
+
+.loading-dual-ring-small {
+ @include loading-dual-ring(0.5);
+}
+
+@keyframes loading-dual-ring {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(360deg);
+ }
+}
+
+.loading-dual-ring-center-screen {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ margin-top: -32px;
+ margin-left: -32px;
+}
\ No newline at end of file
diff --git a/app/YtManagerApp/static/YtManagerApp/css/lib/_theme.css b/app/YtManagerApp/static/YtManagerApp/css/lib/_theme.css
new file mode 100644
index 0000000..397130e
--- /dev/null
+++ b/app/YtManagerApp/static/YtManagerApp/css/lib/_theme.css
@@ -0,0 +1,41 @@
+:root {
+ --blue: #007bff;
+ --indigo: #6610f2;
+ --purple: #6f42c1;
+ --pink: #e83e8c;
+ --red: #dc3545;
+ --orange: #fd7e14;
+ --yellow: #ffc107;
+ --green: #28a745;
+ --teal: #20c997;
+ --cyan: #17a2b8;
+ --white: #fff;
+ --gray: #6c757d;
+ --gray-dark: #343a40;
+ --primary: #007bff;
+ --secondary: #6c757d;
+ --success: #28a745;
+ --info: #17a2b8;
+ --warning: #ffc107;
+ --danger: #dc3545;
+ --light: #f8f9fa;
+ --dark: #343a40;
+ --breakpoint-xs: 0;
+ --breakpoint-sm: 576px;
+ --breakpoint-md: 768px;
+ --breakpoint-lg: 992px;
+ --breakpoint-xl: 1200px;
+ --font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ --font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; }
+
+[data-theme="dark"] {
+ --primary: #007bff;
+ --secondary: #6c757d;
+ --success: #28a745;
+ --info: #17a2b8;
+ --warning: #ffc107;
+ --danger: #dc3545;
+ --light: #343a40;
+ --dark: #f8f9fa; }
+
+/*# sourceMappingURL=_theme.css.map */
diff --git a/app/YtManagerApp/static/YtManagerApp/css/lib/_theme.css.map b/app/YtManagerApp/static/YtManagerApp/css/lib/_theme.css.map
new file mode 100644
index 0000000..553591b
--- /dev/null
+++ b/app/YtManagerApp/static/YtManagerApp/css/lib/_theme.css.map
@@ -0,0 +1,7 @@
+{
+"version": 3,
+"mappings": "AAAA,KAAM;EAEF,MAAM,CAAC,QAAQ;EACf,QAAQ,CAAC,QAAQ;EACjB,QAAQ,CAAC,QAAQ;EACjB,MAAM,CAAC,QAAQ;EACf,KAAK,CAAC,QAAQ;EACd,QAAQ,CAAC,QAAQ;EACjB,QAAQ,CAAC,QAAQ;EACjB,OAAO,CAAC,QAAQ;EAChB,MAAM,CAAC,QAAQ;EACf,MAAM,CAAC,QAAQ;EACf,OAAO,CAAC,KAAK;EACb,MAAM,CAAC,QAAQ;EACf,WAAW,CAAC,QAAQ;EAGpB,SAAS,CAAC,QAAQ;EAClB,WAAW,CAAC,QAAQ;EACpB,SAAS,CAAC,QAAQ;EAClB,MAAM,CAAC,QAAQ;EACf,SAAS,CAAC,QAAQ;EAClB,QAAQ,CAAC,QAAQ;EACjB,OAAO,CAAC,QAAQ;EAChB,MAAM,CAAC,QAAQ;EAGf,eAAe,CAAC,EAAE;EAClB,eAAe,CAAC,MAAM;EACtB,eAAe,CAAC,MAAM;EACtB,eAAe,CAAC,MAAM;EACtB,eAAe,CAAC,OAAO;EACvB,wBAAwB,CAAC,sLAAsL;EAC/M,uBAAuB,CAAC,qFAAqF;;AAGjH,mBAAoB;EAChB,SAAS,CAAC,QAAQ;EAClB,WAAW,CAAC,QAAQ;EACpB,SAAS,CAAC,QAAQ;EAClB,MAAM,CAAC,QAAQ;EACf,SAAS,CAAC,QAAQ;EAClB,QAAQ,CAAC,QAAQ;EACjB,OAAO,CAAC,QAAQ;EAChB,MAAM,CAAC,QAAQ",
+"sources": ["_theme.scss"],
+"names": [],
+"file": "_theme.css"
+}
diff --git a/app/YtManagerApp/static/YtManagerApp/css/lib/_theme.scss b/app/YtManagerApp/static/YtManagerApp/css/lib/_theme.scss
new file mode 100644
index 0000000..4e2cf3c
--- /dev/null
+++ b/app/YtManagerApp/static/YtManagerApp/css/lib/_theme.scss
@@ -0,0 +1,46 @@
+:root {
+ // base colors
+ --blue: #007bff;
+ --indigo: #6610f2;
+ --purple: #6f42c1;
+ --pink: #e83e8c;
+ --red: #dc3545;
+ --orange: #fd7e14;
+ --yellow: #ffc107;
+ --green: #28a745;
+ --teal: #20c997;
+ --cyan: #17a2b8;
+ --white: #fff;
+ --gray: #6c757d;
+ --gray-dark: #343a40;
+
+ // theme colors
+ --primary: #007bff;
+ --secondary: #6c757d;
+ --success: #28a745;
+ --info: #17a2b8;
+ --warning: #ffc107;
+ --danger: #dc3545;
+ --light: #f8f9fa;
+ --dark: #343a40;
+
+ // misc
+ --breakpoint-xs: 0;
+ --breakpoint-sm: 576px;
+ --breakpoint-md: 768px;
+ --breakpoint-lg: 992px;
+ --breakpoint-xl: 1200px;
+ --font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ --font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+}
+
+[data-theme="dark"] {
+ --primary: #007bff;
+ --secondary: #6c757d;
+ --success: #28a745;
+ --info: #17a2b8;
+ --warning: #ffc107;
+ --danger: #dc3545;
+ --light: #343a40;
+ --dark: #f8f9fa;
+}
diff --git a/app/YtManagerApp/static/YtManagerApp/css/lib/_toast.scss b/app/YtManagerApp/static/YtManagerApp/css/lib/_toast.scss
new file mode 100644
index 0000000..e4a410b
--- /dev/null
+++ b/app/YtManagerApp/static/YtManagerApp/css/lib/_toast.scss
@@ -0,0 +1,47 @@
+@import "variables";
+
+#toast-wrapper {
+ position: fixed;
+ right: 2rem;
+ top: 2rem;
+ z-index: 1000;
+}
+
+.toast {
+ min-width: 15rem;
+ line-height: 1.5rem;
+ .typcn {
+ font-size: 1.5rem;
+ }
+
+ &.bg-success {
+ background-color: rgba(lighten($success-color, 30), .98) !important;
+ .toast-header {
+ background-color: rgba($success-color, .75);
+ color: $light-color;
+ > * {
+ color: $light-color;
+ }
+ }
+ }
+ &.bg-warning {
+ background-color: rgba(lighten($warning-color, 30), .98) !important;
+ .toast-header {
+ background-color: rgba(darken($warning-color, 10), .75);
+ color: $light-color;
+ > * {
+ color: $light-color;
+ }
+ }
+ }
+ &.bg-danger {
+ background-color: rgba(lighten($danger-color, 30), .98) !important;
+ .toast-header {
+ background-color: rgba($danger-color, .75);
+ color: $light-color;
+ > * {
+ color: $light-color;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/YtManagerApp/static/YtManagerApp/css/lib/_utils.css b/app/YtManagerApp/static/YtManagerApp/css/lib/_utils.css
new file mode 100644
index 0000000..45524bf
--- /dev/null
+++ b/app/YtManagerApp/static/YtManagerApp/css/lib/_utils.css
@@ -0,0 +1,3 @@
+
+
+/*# sourceMappingURL=_utils.css.map */
diff --git a/app/YtManagerApp/static/YtManagerApp/css/lib/_utils.css.map b/app/YtManagerApp/static/YtManagerApp/css/lib/_utils.css.map
new file mode 100644
index 0000000..ffaec49
--- /dev/null
+++ b/app/YtManagerApp/static/YtManagerApp/css/lib/_utils.css.map
@@ -0,0 +1,7 @@
+{
+"version": 3,
+"mappings": "",
+"sources": [],
+"names": [],
+"file": "_utils.css"
+}
diff --git a/app/YtManagerApp/static/YtManagerApp/css/lib/_utils.scss b/app/YtManagerApp/static/YtManagerApp/css/lib/_utils.scss
new file mode 100644
index 0000000..31074ac
--- /dev/null
+++ b/app/YtManagerApp/static/YtManagerApp/css/lib/_utils.scss
@@ -0,0 +1,50 @@
+
+// cross browser keyframes
+@mixin keyframes($animation-name) {
+ @-webkit-keyframes #{$animation-name} {
+ @content;
+ }
+ @-moz-keyframes #{$animation-name} {
+ @content;
+ }
+ @-ms-keyframes #{$animation-name} {
+ @content;
+ }
+ @-o-keyframes #{$animation-name} {
+ @content;
+ }
+ @keyframes #{$animation-name} {
+ @content;
+ }
+}
+
+// cross browser animation
+@mixin animation($str) {
+ -webkit-animation: #{$str};
+ -moz-animation: #{$str};
+ -ms-animation: #{$str};
+ -o-animation: #{$str};
+ animation: #{$str};
+}
+
+// cross browser transition
+@mixin transition($args...) {
+ -webkit-transition: $args;
+ -moz-transition: $args;
+ -ms-transition: $args;
+ -o-transition: $args;
+ transition: $args;
+}
+
+// cross browser opacity
+@mixin opacity($opacity) {
+ opacity: $opacity;
+ $opacity-ie: $opacity * 100;
+ filter: alpha(opacity=$opacity-ie); //IE8
+}
+
+// cross browser transform
+@mixin transform($args...) {
+ -ms-transform: $args;
+ transform: $args;
+}
\ No newline at end of file
diff --git a/app/YtManagerApp/static/YtManagerApp/css/lib/_variables.css b/app/YtManagerApp/static/YtManagerApp/css/lib/_variables.css
new file mode 100644
index 0000000..36de350
--- /dev/null
+++ b/app/YtManagerApp/static/YtManagerApp/css/lib/_variables.css
@@ -0,0 +1,3 @@
+
+
+/*# sourceMappingURL=_variables.css.map */
diff --git a/app/YtManagerApp/static/YtManagerApp/css/lib/_variables.css.map b/app/YtManagerApp/static/YtManagerApp/css/lib/_variables.css.map
new file mode 100644
index 0000000..9c4347b
--- /dev/null
+++ b/app/YtManagerApp/static/YtManagerApp/css/lib/_variables.css.map
@@ -0,0 +1,7 @@
+{
+"version": 3,
+"mappings": "",
+"sources": [],
+"names": [],
+"file": "_variables.css"
+}
diff --git a/app/YtManagerApp/static/YtManagerApp/css/lib/_variables.scss b/app/YtManagerApp/static/YtManagerApp/css/lib/_variables.scss
new file mode 100644
index 0000000..81a5406
--- /dev/null
+++ b/app/YtManagerApp/static/YtManagerApp/css/lib/_variables.scss
@@ -0,0 +1,15 @@
+$breakpoint-xs: 0;
+$breakpoint-sm: 576px;
+$breakpoint-md: 768px;
+$breakpoint-lg: 992px;
+$breakpoint-xl: 1200px;
+
+$accent-color: #007bff;
+$primary-color: #007bff;
+$secondary-color: #6c757d;
+$success-color: #28a745;
+$info-color: #17a2b8;
+$warning-color: #ffc107;
+$danger-color: #dc3545;
+$light-color: #f8f9fa;
+$dark-color: #343a40;
\ No newline at end of file
diff --git a/app/YtManagerApp/static/YtManagerApp/js/components/ProgressRing.js b/app/YtManagerApp/static/YtManagerApp/js/components/ProgressRing.js
new file mode 100644
index 0000000..75f6989
--- /dev/null
+++ b/app/YtManagerApp/static/YtManagerApp/js/components/ProgressRing.js
@@ -0,0 +1,33 @@
+export class ProgressRing
+{
+ wrapperElement = null;
+ svgElement = null;
+ circleElement = null;
+
+ constructor(wrapperElement) {
+ this.wrapperElement = wrapperElement;
+ this.buildDom();
+ }
+
+ buildDom() {
+ let bounds = this.wrapperElement.getBoundingClientRect();
+ this.svgElement = $(``);
+ this.svgElement.appendTo(this.wrapperElement);
+ this.circleElement = $(`