diff --git a/client/package.json b/client/package.json
index 14c20e8d9..7e23d4d75 100644
--- a/client/package.json
+++ b/client/package.json
@@ -34,6 +34,7 @@
"@angular/platform-browser-dynamic": "~5.1.0",
"@angular/router": "~5.1.0",
"@angularclass/hmr": "^2.1.3",
+ "@ngx-loading-bar/http-client": "^1.0.0-rc.1",
"@ngx-meta/core": "^4.0.1",
"@types/core-js": "^0.9.28",
"@types/markdown-it": "^0.0.4",
diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html
index da4273dda..1a808b397 100644
--- a/client/src/app/app.component.html
+++ b/client/src/app/app.component.html
@@ -34,5 +34,6 @@
+
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts
index d0e163f69..5af118c98 100644
--- a/client/src/app/shared/shared.module.ts
+++ b/client/src/app/shared/shared.module.ts
@@ -3,6 +3,7 @@ import { HttpClientModule } from '@angular/common/http'
import { NgModule } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { RouterModule } from '@angular/router'
+import { LoadingBarHttpClientModule } from '@ngx-loading-bar/http-client'
import { BsDropdownModule } from 'ngx-bootstrap/dropdown'
import { ModalModule } from 'ngx-bootstrap/modal'
@@ -33,6 +34,8 @@ import { VideoService } from './video/video.service'
RouterModule,
HttpClientModule,
+ LoadingBarHttpClientModule,
+
BsDropdownModule.forRoot(),
ModalModule.forRoot(),
@@ -59,6 +62,8 @@ import { VideoService } from './video/video.service'
RouterModule,
HttpClientModule,
+ LoadingBarHttpClientModule,
+
BsDropdownModule,
ModalModule,
DataTableModule,
diff --git a/client/src/sass/application.scss b/client/src/sass/application.scss
index 08131406a..968dc5f58 100644
--- a/client/src/sass/application.scss
+++ b/client/src/sass/application.scss
@@ -10,7 +10,9 @@ $FontPathSourceSansPro: '../../node_modules/npm-font-source-sans-pro/fonts';
@import '~primeng/resources/themes/bootstrap/theme.css';
@import '~primeng/resources/primeng.css';
@import '~video.js/dist/video-js.css';
-@import './video-js-custom.scss';
+
+@import './video-js-custom';
+@import './loading-bar';
[hidden] {
display: none !important;
diff --git a/client/src/sass/loading-bar.scss b/client/src/sass/loading-bar.scss
new file mode 100644
index 000000000..d34bf83ee
--- /dev/null
+++ b/client/src/sass/loading-bar.scss
@@ -0,0 +1,93 @@
+// Thanks: https://github.com/aitboudad/ngx-loading-bar/blob/master/loading-bar.css
+
+/* Make clicks pass-through */
+#loading-bar,
+#loading-bar-spinner {
+ pointer-events: none;
+ -webkit-pointer-events: none;
+ -webkit-transition: 350ms linear all;
+ -moz-transition: 350ms linear all;
+ -o-transition: 350ms linear all;
+ transition: 350ms linear all;
+ color: #29d;
+}
+
+#loading-bar .bar {
+ -webkit-transition: width 350ms;
+ -moz-transition: width 350ms;
+ -o-transition: width 350ms;
+ transition: width 350ms;
+
+ background: #29d;
+ position: fixed;
+ z-index: 10002;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 2px;
+ border-bottom-right-radius: 1px;
+ border-top-right-radius: 1px;
+}
+
+/* Fancy blur effect */
+#loading-bar .peg {
+ position: absolute;
+ width: 70px;
+ right: 0;
+ top: 0;
+ height: 2px;
+ opacity: .45;
+ -moz-box-shadow: 1px 0 6px 1px;
+ -ms-box-shadow: 1px 0 6px 1px;
+ -webkit-box-shadow: 1px 0 6px 1px;
+ box-shadow: 1px 0 6px 1px;
+ color: inherit;
+ -moz-border-radius: 100%;
+ -webkit-border-radius: 100%;
+ border-radius: 100%;
+}
+
+#loading-bar-spinner {
+ display: block;
+ position: fixed;
+ z-index: 10002;
+ top: 10px;
+ left: 10px;
+}
+
+#loading-bar-spinner .spinner-icon {
+ width: 14px;
+ height: 14px;
+
+ border: solid 2px transparent;
+ border-top-color: inherit;
+ border-left-color: inherit;
+ border-radius: 50%;
+
+ -webkit-animation: loading-bar-spinner 400ms linear infinite;
+ -moz-animation: loading-bar-spinner 400ms linear infinite;
+ -ms-animation: loading-bar-spinner 400ms linear infinite;
+ -o-animation: loading-bar-spinner 400ms linear infinite;
+ animation: loading-bar-spinner 400ms linear infinite;
+}
+
+@-webkit-keyframes loading-bar-spinner {
+ 0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); }
+ 100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); }
+}
+@-moz-keyframes loading-bar-spinner {
+ 0% { -moz-transform: rotate(0deg); transform: rotate(0deg); }
+ 100% { -moz-transform: rotate(360deg); transform: rotate(360deg); }
+}
+@-o-keyframes loading-bar-spinner {
+ 0% { -o-transform: rotate(0deg); transform: rotate(0deg); }
+ 100% { -o-transform: rotate(360deg); transform: rotate(360deg); }
+}
+@-ms-keyframes loading-bar-spinner {
+ 0% { -ms-transform: rotate(0deg); transform: rotate(0deg); }
+ 100% { -ms-transform: rotate(360deg); transform: rotate(360deg); }
+}
+@keyframes loading-bar-spinner {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
diff --git a/client/yarn.lock b/client/yarn.lock
index 5c63a68a6..10f15bcd6 100644
--- a/client/yarn.lock
+++ b/client/yarn.lock
@@ -178,6 +178,19 @@
source-map "^0.5.6"
tree-kill "^1.0.0"
+"@ngx-loading-bar/core@1.0.0-rc.1":
+ version "1.0.0-rc.1"
+ resolved "https://registry.yarnpkg.com/@ngx-loading-bar/core/-/core-1.0.0-rc.1.tgz#6809578979c924fa514c0a094c0f479817635c63"
+ dependencies:
+ tslib "^1.7.1"
+
+"@ngx-loading-bar/http-client@^1.0.0-rc.1":
+ version "1.0.0-rc.1"
+ resolved "https://registry.yarnpkg.com/@ngx-loading-bar/http-client/-/http-client-1.0.0-rc.1.tgz#f4c15d9e46445bf8fe7a945c7f4eb0ef443bddd8"
+ dependencies:
+ "@ngx-loading-bar/core" "1.0.0-rc.1"
+ tslib "^1.7.1"
+
"@ngx-meta/core@^4.0.1":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@ngx-meta/core/-/core-4.0.1.tgz#b035febeeb92876920480f70719fcf953dc0245f"