Add user notification animation
authorChocobozzz <me@florianbigard.com>
Wed, 20 Feb 2019 09:16:04 +0000 (10:16 +0100)
committerChocobozzz <me@florianbigard.com>
Wed, 20 Feb 2019 09:16:04 +0000 (10:16 +0100)
13 files changed:
client/src/app/core/notification/user-notification-socket.service.ts
client/src/app/menu/avatar-notification.component.html
client/src/app/menu/avatar-notification.component.scss
client/src/app/menu/avatar-notification.component.ts
client/src/app/shared/misc/loader.component.html
client/src/app/shared/misc/loader.component.scss [new file with mode: 0644]
client/src/app/shared/misc/loader.component.ts
client/src/app/shared/misc/small-loader.component.html [new file with mode: 0644]
client/src/app/shared/misc/small-loader.component.ts [new file with mode: 0644]
client/src/app/shared/shared.module.ts
client/src/app/shared/users/user-notifications.component.ts
client/src/app/videos/+video-watch/comment/video-comments.component.html
client/src/app/videos/+video-watch/video-watch.component.html

index 29337d3a718add3ffcec687c483415f835b85230..493f03e3586e708771f667797d4f6194e7fc251e 100644 (file)
@@ -2,7 +2,6 @@ import { Injectable } from '@angular/core'
 import { environment } from '../../../environments/environment'
 import { UserNotification as UserNotificationServer } from '../../../../../shared'
 import { Subject } from 'rxjs'
-import * as io from 'socket.io-client'
 import { AuthService } from '../auth'
 
 export type NotificationEvent = 'new' | 'read' | 'read-all'
index 4ef3f0e89174df2de4d519678557241e77860408..a5ef43d42ab2ab817383ece6d0f1bf61f5d3b6bc 100644 (file)
@@ -1,6 +1,6 @@
 <div
   [ngbPopover]="popContent" autoClose="outside" placement="bottom-left" container="body" popoverClass="popover-notifications"
-  i18n-title title="View your notifications" class="notification-avatar" #popover="ngbPopover"
+  i18n-title title="View your notifications" class="notification-avatar" #popover="ngbPopover" (hidden)="onPopoverHidden()"
 >
   <div *ngIf="unreadNotifications > 0" class="unread-notifications">{{ unreadNotifications }}</div>
 
@@ -8,16 +8,25 @@
 </div>
 
 <ng-template #popContent>
-  <div class="notifications-header">
-    <div i18n>Notifications</div>
+  <div class="content" [ngClass]="{ loaded: loaded }">
+    <div class="notifications-header">
+      <div i18n>Notifications</div>
 
-    <a
-      i18n-title title="Update your notification preferences" class="glyphicon glyphicon-cog"
-      routerLink="/my-account/settings" fragment="notifications"
-    ></a>
-  </div>
+      <a
+        i18n-title title="Update your notification preferences" class="glyphicon glyphicon-cog"
+        routerLink="/my-account/settings" fragment="notifications"
+      ></a>
+    </div>
+
+    <div *ngIf="!loaded" class="loader">
+      <my-loader [loading]="!loaded"></my-loader>
+    </div>
 
-  <my-user-notifications [ignoreLoadingBar]="true" [infiniteScroll]="false" itemsPerPage="10"></my-user-notifications>
+    <my-user-notifications
+      [ignoreLoadingBar]="true" [infiniteScroll]="false" itemsPerPage="10"
+      (notificationsLoaded)="onNotificationLoaded()"
+    ></my-user-notifications>
 
-  <a class="all-notifications" routerLink="/my-account/notifications" i18n>See all your notifications</a>
+    <a *ngIf="loaded" class="all-notifications" routerLink="/my-account/notifications" i18n>See all your notifications</a>
+  </div>
 </ng-template>
index e785db7886ea537fd52c62d9858f19ac84d88cfe..201668b6e54ea28cd3416991a9e3da039dbe8414 100644 (file)
@@ -9,11 +9,27 @@
       padding: 0;
       font-size: 14px;
       font-family: $main-fonts;
-      overflow-y: auto;
-      max-height: 500px;
+      overflow-y: scroll;
       width: 400px;
       box-shadow: 0 6px 14px rgba(0, 0, 0, 0.30);
 
+      .loader {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+
+        padding: 5px 0;
+      }
+
+      .content {
+        max-height: 150px;
+        transition: max-height 0.15s ease-out;
+
+        &.loaded {
+          max-height: 500px;
+        }
+      }
+
       .notifications-header {
         display: flex;
         justify-content: space-between;
index 878c5c88c581b96947a8ecc0c2dee9b27b83c593..a77a001ca4255f083d68cc7badc2e63e2f39a42a 100644 (file)
@@ -17,6 +17,7 @@ export class AvatarNotificationComponent implements OnInit, OnDestroy {
   @Input() user: User
 
   unreadNotifications = 0
+  loaded = false
 
   private notificationSub: Subscription
   private routeSub: Subscription
@@ -54,6 +55,14 @@ export class AvatarNotificationComponent implements OnInit, OnDestroy {
     this.popover.close()
   }
 
+  onPopoverHidden () {
+    this.loaded = false
+  }
+
+  onNotificationLoaded () {
+    this.loaded = true
+  }
+
   private async subscribeToNotifications () {
     const obs = await this.userNotificationSocket.getMyNotificationsSocket()
 
index 38d06950ec200c8ea2377c4c38e06984d18a0273..b8b7ad343a667ff51baa05a044c2dec0ea1902fd 100644 (file)
@@ -1,3 +1,8 @@
-<div id="video-loading" *ngIf="loading">
-  <div class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></div>
+<div *ngIf="loading">
+  <div class="lds-ring">
+    <div></div>
+    <div></div>
+    <div></div>
+    <div></div>
+  </div>
 </div>
diff --git a/client/src/app/shared/misc/loader.component.scss b/client/src/app/shared/misc/loader.component.scss
new file mode 100644 (file)
index 0000000..ddb64f0
--- /dev/null
@@ -0,0 +1,45 @@
+@import '_variables';
+@import '_mixins';
+
+// Thanks to https://loading.io/css/ (CC0 License)
+
+.lds-ring {
+  display: inline-block;
+  position: relative;
+  width: 50px;
+  height: 50px;
+}
+
+.lds-ring div {
+  box-sizing: border-box;
+  display: block;
+  position: absolute;
+  width: 44px;
+  height: 44px;
+  margin: 6px;
+  border: 4px solid;
+  border-radius: 50%;
+  animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
+  border-color: #999999 transparent transparent transparent;
+}
+
+.lds-ring div:nth-child(1) {
+  animation-delay: -0.45s;
+}
+
+.lds-ring div:nth-child(2) {
+  animation-delay: -0.3s;
+}
+
+.lds-ring div:nth-child(3) {
+  animation-delay: -0.15s;
+}
+
+@keyframes lds-ring {
+  0% {
+    transform: rotate(0deg);
+  }
+  100% {
+    transform: rotate(360deg);
+  }
+}
index f37d70c855fbb05d7cac77c48374fc567e23e8a0..e3b1eea3a886b2eaec2ca2f4e3f6cd171b1c1087 100644 (file)
@@ -2,10 +2,9 @@ import { Component, Input } from '@angular/core'
 
 @Component({
   selector: 'my-loader',
-  styleUrls: [ ],
+  styleUrls: [ './loader.component.scss' ],
   templateUrl: './loader.component.html'
 })
-
 export class LoaderComponent {
   @Input() loading: boolean
 }
diff --git a/client/src/app/shared/misc/small-loader.component.html b/client/src/app/shared/misc/small-loader.component.html
new file mode 100644 (file)
index 0000000..5a7cea7
--- /dev/null
@@ -0,0 +1,3 @@
+<div *ngIf="loading">
+  <div class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></div>
+</div>
diff --git a/client/src/app/shared/misc/small-loader.component.ts b/client/src/app/shared/misc/small-loader.component.ts
new file mode 100644 (file)
index 0000000..191877f
--- /dev/null
@@ -0,0 +1,11 @@
+import { Component, Input } from '@angular/core'
+
+@Component({
+  selector: 'my-small-loader',
+  styleUrls: [ ],
+  templateUrl: './small-loader.component.html'
+})
+
+export class SmallLoaderComponent {
+  @Input() loading: boolean
+}
index 6f8625c7e926f83f8a5eaaf38d60cbb5afa889c7..1c4e3df1aa94f3c58200364bb8562ae8ef6dc356 100644 (file)
@@ -69,6 +69,7 @@ import { InstanceService } from '@app/shared/instance/instance.service'
 import { HtmlRendererService, LinkifierService, MarkdownService } from '@app/shared/renderer'
 import { ConfirmComponent } from '@app/shared/confirm/confirm.component'
 import { GlobalIconComponent } from '@app/shared/icons/global-icon.component'
+import { SmallLoaderComponent } from '@app/shared/misc/small-loader.component'
 
 @NgModule({
   imports: [
@@ -90,6 +91,7 @@ import { GlobalIconComponent } from '@app/shared/icons/global-icon.component'
 
   declarations: [
     LoaderComponent,
+    SmallLoaderComponent,
     VideoThumbnailComponent,
     VideoMiniatureComponent,
     FeedComponent,
@@ -135,6 +137,7 @@ import { GlobalIconComponent } from '@app/shared/icons/global-icon.component'
     KeysPipe,
 
     LoaderComponent,
+    SmallLoaderComponent,
     VideoThumbnailComponent,
     VideoMiniatureComponent,
     FeedComponent,
index b5f9fd3991ab81fa254b129426b63b6c585d1669..ce43b604a33a929abd25447310a5e2fb01f7efd3 100644 (file)
@@ -1,4 +1,4 @@
-import { Component, Input, OnInit } from '@angular/core'
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
 import { UserNotificationService } from '@app/shared/users/user-notification.service'
 import { UserNotificationType } from '../../../../../shared'
 import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model'
@@ -15,6 +15,8 @@ export class UserNotificationsComponent implements OnInit {
   @Input() infiniteScroll = true
   @Input() itemsPerPage = 20
 
+  @Output() notificationsLoaded = new EventEmitter()
+
   notifications: UserNotification[] = []
 
   // So we can access it in the template
@@ -43,6 +45,8 @@ export class UserNotificationsComponent implements OnInit {
           result => {
             this.notifications = this.notifications.concat(result.data)
             this.componentPagination.totalItems = result.total
+
+            this.notificationsLoaded.emit()
           },
 
           err => this.notifier.error(err.message)
index 44016d8ad05edc3ecc46072f29cab91d136435c5..7b941454a96672a6bf1b83cbe6a4390d4bb15ff1 100644 (file)
@@ -54,7 +54,7 @@
           <ng-container i18n>View all {{ comment.totalReplies }} replies</ng-container>
 
           <span *ngIf="!threadLoading[comment.id]" class="glyphicon glyphicon-menu-down"></span>
-          <my-loader class="comment-thread-loading" [loading]="threadLoading[comment.id]"></my-loader>
+          <my-small-loader class="comment-thread-loading" [loading]="threadLoading[comment.id]"></my-small-loader>
         </div>
       </div>
     </div>
index 6e18ab6a69724f7ccc62d4393398ab38244c79ee..fffcc1275e58d0132f849ab39bd6387e8b813fe6 100644 (file)
           <div class="video-info-description-more" *ngIf="completeDescriptionShown === false && video.description?.length >= 250" (click)="showMoreDescription()">
             <ng-container i18n>Show more</ng-container>
             <span *ngIf="descriptionLoading === false" class="glyphicon glyphicon-menu-down"></span>
-            <my-loader class="description-loading" [loading]="descriptionLoading"></my-loader>
+            <my-small-loader class="description-loading" [loading]="descriptionLoading"></my-small-loader>
           </div>
 
           <div *ngIf="completeDescriptionShown === true" (click)="showLessDescription()" class="video-info-description-more">