Add user notification animation
This commit is contained in:
parent
28c8e63e55
commit
b28e4e5e08
|
@ -2,7 +2,6 @@ import { Injectable } from '@angular/core'
|
||||||
import { environment } from '../../../environments/environment'
|
import { environment } from '../../../environments/environment'
|
||||||
import { UserNotification as UserNotificationServer } from '../../../../../shared'
|
import { UserNotification as UserNotificationServer } from '../../../../../shared'
|
||||||
import { Subject } from 'rxjs'
|
import { Subject } from 'rxjs'
|
||||||
import * as io from 'socket.io-client'
|
|
||||||
import { AuthService } from '../auth'
|
import { AuthService } from '../auth'
|
||||||
|
|
||||||
export type NotificationEvent = 'new' | 'read' | 'read-all'
|
export type NotificationEvent = 'new' | 'read' | 'read-all'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<div
|
<div
|
||||||
[ngbPopover]="popContent" autoClose="outside" placement="bottom-left" container="body" popoverClass="popover-notifications"
|
[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>
|
<div *ngIf="unreadNotifications > 0" class="unread-notifications">{{ unreadNotifications }}</div>
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ng-template #popContent>
|
<ng-template #popContent>
|
||||||
|
<div class="content" [ngClass]="{ loaded: loaded }">
|
||||||
<div class="notifications-header">
|
<div class="notifications-header">
|
||||||
<div i18n>Notifications</div>
|
<div i18n>Notifications</div>
|
||||||
|
|
||||||
|
@ -17,7 +18,15 @@
|
||||||
></a>
|
></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<my-user-notifications [ignoreLoadingBar]="true" [infiniteScroll]="false" itemsPerPage="10"></my-user-notifications>
|
<div *ngIf="!loaded" class="loader">
|
||||||
|
<my-loader [loading]="!loaded"></my-loader>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a class="all-notifications" routerLink="/my-account/notifications" i18n>See all your notifications</a>
|
<my-user-notifications
|
||||||
|
[ignoreLoadingBar]="true" [infiniteScroll]="false" itemsPerPage="10"
|
||||||
|
(notificationsLoaded)="onNotificationLoaded()"
|
||||||
|
></my-user-notifications>
|
||||||
|
|
||||||
|
<a *ngIf="loaded" class="all-notifications" routerLink="/my-account/notifications" i18n>See all your notifications</a>
|
||||||
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
|
@ -9,11 +9,27 @@
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: $main-fonts;
|
font-family: $main-fonts;
|
||||||
overflow-y: auto;
|
overflow-y: scroll;
|
||||||
max-height: 500px;
|
|
||||||
width: 400px;
|
width: 400px;
|
||||||
box-shadow: 0 6px 14px rgba(0, 0, 0, 0.30);
|
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 {
|
.notifications-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
|
@ -17,6 +17,7 @@ export class AvatarNotificationComponent implements OnInit, OnDestroy {
|
||||||
@Input() user: User
|
@Input() user: User
|
||||||
|
|
||||||
unreadNotifications = 0
|
unreadNotifications = 0
|
||||||
|
loaded = false
|
||||||
|
|
||||||
private notificationSub: Subscription
|
private notificationSub: Subscription
|
||||||
private routeSub: Subscription
|
private routeSub: Subscription
|
||||||
|
@ -54,6 +55,14 @@ export class AvatarNotificationComponent implements OnInit, OnDestroy {
|
||||||
this.popover.close()
|
this.popover.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onPopoverHidden () {
|
||||||
|
this.loaded = false
|
||||||
|
}
|
||||||
|
|
||||||
|
onNotificationLoaded () {
|
||||||
|
this.loaded = true
|
||||||
|
}
|
||||||
|
|
||||||
private async subscribeToNotifications () {
|
private async subscribeToNotifications () {
|
||||||
const obs = await this.userNotificationSocket.getMyNotificationsSocket()
|
const obs = await this.userNotificationSocket.getMyNotificationsSocket()
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
<div id="video-loading" *ngIf="loading">
|
<div *ngIf="loading">
|
||||||
<div class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></div>
|
<div class="lds-ring">
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,10 +2,9 @@ import { Component, Input } from '@angular/core'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-loader',
|
selector: 'my-loader',
|
||||||
styleUrls: [ ],
|
styleUrls: [ './loader.component.scss' ],
|
||||||
templateUrl: './loader.component.html'
|
templateUrl: './loader.component.html'
|
||||||
})
|
})
|
||||||
|
|
||||||
export class LoaderComponent {
|
export class LoaderComponent {
|
||||||
@Input() loading: boolean
|
@Input() loading: boolean
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
<div *ngIf="loading">
|
||||||
|
<div class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></div>
|
||||||
|
</div>
|
|
@ -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
|
||||||
|
}
|
|
@ -69,6 +69,7 @@ import { InstanceService } from '@app/shared/instance/instance.service'
|
||||||
import { HtmlRendererService, LinkifierService, MarkdownService } from '@app/shared/renderer'
|
import { HtmlRendererService, LinkifierService, MarkdownService } from '@app/shared/renderer'
|
||||||
import { ConfirmComponent } from '@app/shared/confirm/confirm.component'
|
import { ConfirmComponent } from '@app/shared/confirm/confirm.component'
|
||||||
import { GlobalIconComponent } from '@app/shared/icons/global-icon.component'
|
import { GlobalIconComponent } from '@app/shared/icons/global-icon.component'
|
||||||
|
import { SmallLoaderComponent } from '@app/shared/misc/small-loader.component'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -90,6 +91,7 @@ import { GlobalIconComponent } from '@app/shared/icons/global-icon.component'
|
||||||
|
|
||||||
declarations: [
|
declarations: [
|
||||||
LoaderComponent,
|
LoaderComponent,
|
||||||
|
SmallLoaderComponent,
|
||||||
VideoThumbnailComponent,
|
VideoThumbnailComponent,
|
||||||
VideoMiniatureComponent,
|
VideoMiniatureComponent,
|
||||||
FeedComponent,
|
FeedComponent,
|
||||||
|
@ -135,6 +137,7 @@ import { GlobalIconComponent } from '@app/shared/icons/global-icon.component'
|
||||||
KeysPipe,
|
KeysPipe,
|
||||||
|
|
||||||
LoaderComponent,
|
LoaderComponent,
|
||||||
|
SmallLoaderComponent,
|
||||||
VideoThumbnailComponent,
|
VideoThumbnailComponent,
|
||||||
VideoMiniatureComponent,
|
VideoMiniatureComponent,
|
||||||
FeedComponent,
|
FeedComponent,
|
||||||
|
|
|
@ -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 { UserNotificationService } from '@app/shared/users/user-notification.service'
|
||||||
import { UserNotificationType } from '../../../../../shared'
|
import { UserNotificationType } from '../../../../../shared'
|
||||||
import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model'
|
import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model'
|
||||||
|
@ -15,6 +15,8 @@ export class UserNotificationsComponent implements OnInit {
|
||||||
@Input() infiniteScroll = true
|
@Input() infiniteScroll = true
|
||||||
@Input() itemsPerPage = 20
|
@Input() itemsPerPage = 20
|
||||||
|
|
||||||
|
@Output() notificationsLoaded = new EventEmitter()
|
||||||
|
|
||||||
notifications: UserNotification[] = []
|
notifications: UserNotification[] = []
|
||||||
|
|
||||||
// So we can access it in the template
|
// So we can access it in the template
|
||||||
|
@ -43,6 +45,8 @@ export class UserNotificationsComponent implements OnInit {
|
||||||
result => {
|
result => {
|
||||||
this.notifications = this.notifications.concat(result.data)
|
this.notifications = this.notifications.concat(result.data)
|
||||||
this.componentPagination.totalItems = result.total
|
this.componentPagination.totalItems = result.total
|
||||||
|
|
||||||
|
this.notificationsLoaded.emit()
|
||||||
},
|
},
|
||||||
|
|
||||||
err => this.notifier.error(err.message)
|
err => this.notifier.error(err.message)
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
<ng-container i18n>View all {{ comment.totalReplies }} replies</ng-container>
|
<ng-container i18n>View all {{ comment.totalReplies }} replies</ng-container>
|
||||||
|
|
||||||
<span *ngIf="!threadLoading[comment.id]" class="glyphicon glyphicon-menu-down"></span>
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -146,7 +146,7 @@
|
||||||
<div class="video-info-description-more" *ngIf="completeDescriptionShown === false && video.description?.length >= 250" (click)="showMoreDescription()">
|
<div class="video-info-description-more" *ngIf="completeDescriptionShown === false && video.description?.length >= 250" (click)="showMoreDescription()">
|
||||||
<ng-container i18n>Show more</ng-container>
|
<ng-container i18n>Show more</ng-container>
|
||||||
<span *ngIf="descriptionLoading === false" class="glyphicon glyphicon-menu-down"></span>
|
<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>
|
||||||
|
|
||||||
<div *ngIf="completeDescriptionShown === true" (click)="showLessDescription()" class="video-info-description-more">
|
<div *ngIf="completeDescriptionShown === true" (click)="showLessDescription()" class="video-info-description-more">
|
||||||
|
|
Loading…
Reference in New Issue