@muxima-ui/notification-center 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -0
- package/esm2020/index.mjs +2 -0
- package/esm2020/lib/notification-center/notification-center.component.mjs +202 -0
- package/esm2020/muxima-ui-notification-center.mjs +5 -0
- package/fesm2015/muxima-ui-notification-center.mjs +209 -0
- package/fesm2015/muxima-ui-notification-center.mjs.map +1 -0
- package/fesm2020/muxima-ui-notification-center.mjs +209 -0
- package/fesm2020/muxima-ui-notification-center.mjs.map +1 -0
- package/index.d.ts +1 -0
- package/lib/notification-center/notification-center.component.d.ts +53 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Notification Center
|
|
2
|
+
|
|
3
|
+
Centro de notificações com painel, toasts e gerenciamento completo.
|
|
4
|
+
|
|
5
|
+
## Instalação
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @muxima-ui/notification-center
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Uso
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { NotificationCenterComponent } from '@muxima-ui/notification-center';
|
|
15
|
+
|
|
16
|
+
@Component({
|
|
17
|
+
standalone: true,
|
|
18
|
+
imports: [NotificationCenterComponent],
|
|
19
|
+
template: `
|
|
20
|
+
<muxima-notification-center
|
|
21
|
+
[notifications]="notifications"
|
|
22
|
+
[position]="'top-right'"
|
|
23
|
+
(notificationRead)="onRead($event)">
|
|
24
|
+
</muxima-notification-center>
|
|
25
|
+
`
|
|
26
|
+
})
|
|
27
|
+
export class MyComponent {
|
|
28
|
+
notifications = [
|
|
29
|
+
{
|
|
30
|
+
id: '1',
|
|
31
|
+
type: 'success',
|
|
32
|
+
title: 'Sucesso!',
|
|
33
|
+
message: 'Operação concluída',
|
|
34
|
+
timestamp: new Date(),
|
|
35
|
+
read: false
|
|
36
|
+
}
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
onRead(id: string) {
|
|
40
|
+
console.log('Notification read:', id);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Licença
|
|
46
|
+
|
|
47
|
+
MIT
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export * from './lib/notification-center/notification-center.component';
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9vdmVybGF5L25vdGlmaWNhdGlvbi1jZW50ZXIvc3JjL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMseURBQXlELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgKiBmcm9tICcuL2xpYi9ub3RpZmljYXRpb24tY2VudGVyL25vdGlmaWNhdGlvbi1jZW50ZXIuY29tcG9uZW50JztcclxuIl19
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { trigger, transition, style, animate } from '@angular/animations';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
import * as i1 from "@angular/common";
|
|
6
|
+
export class NotificationCenterComponent {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.notifications = [];
|
|
9
|
+
this.position = 'top-right';
|
|
10
|
+
this.maxToasts = 3;
|
|
11
|
+
this.defaultDuration = 5000;
|
|
12
|
+
this.showBadge = true;
|
|
13
|
+
this.groupByCategory = false;
|
|
14
|
+
this.notificationRead = new EventEmitter();
|
|
15
|
+
this.notificationDismissed = new EventEmitter();
|
|
16
|
+
this.notificationAction = new EventEmitter();
|
|
17
|
+
this.allRead = new EventEmitter();
|
|
18
|
+
this.allCleared = new EventEmitter();
|
|
19
|
+
this.isOpen = false;
|
|
20
|
+
this.activeToasts = [];
|
|
21
|
+
this.autoCloseTimers = new Map();
|
|
22
|
+
}
|
|
23
|
+
ngOnDestroy() {
|
|
24
|
+
this.autoCloseTimers.forEach(timer => clearTimeout(timer));
|
|
25
|
+
}
|
|
26
|
+
togglePanel() {
|
|
27
|
+
this.isOpen = !this.isOpen;
|
|
28
|
+
}
|
|
29
|
+
closePanel() {
|
|
30
|
+
this.isOpen = false;
|
|
31
|
+
}
|
|
32
|
+
get unreadCount() {
|
|
33
|
+
return this.notifications.filter(n => !n.read).length;
|
|
34
|
+
}
|
|
35
|
+
get groupedNotifications() {
|
|
36
|
+
if (!this.groupByCategory) {
|
|
37
|
+
return [{ category: 'all', notifications: this.notifications }];
|
|
38
|
+
}
|
|
39
|
+
const groups = new Map();
|
|
40
|
+
this.notifications.forEach(notification => {
|
|
41
|
+
const category = notification.category || 'Outros';
|
|
42
|
+
if (!groups.has(category)) {
|
|
43
|
+
groups.set(category, []);
|
|
44
|
+
}
|
|
45
|
+
groups.get(category).push(notification);
|
|
46
|
+
});
|
|
47
|
+
return Array.from(groups.entries()).map(([category, notifications]) => ({
|
|
48
|
+
category,
|
|
49
|
+
notifications
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
showToast(notification) {
|
|
53
|
+
// Add to active toasts
|
|
54
|
+
if (this.activeToasts.length >= this.maxToasts) {
|
|
55
|
+
this.activeToasts.shift();
|
|
56
|
+
}
|
|
57
|
+
this.activeToasts.push(notification);
|
|
58
|
+
// Auto close if enabled
|
|
59
|
+
if (notification.autoClose !== false) {
|
|
60
|
+
const duration = notification.duration || this.defaultDuration;
|
|
61
|
+
const timer = setTimeout(() => {
|
|
62
|
+
this.dismissToast(notification.id);
|
|
63
|
+
}, duration);
|
|
64
|
+
this.autoCloseTimers.set(notification.id, timer);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
dismissToast(id) {
|
|
68
|
+
const index = this.activeToasts.findIndex(t => t.id === id);
|
|
69
|
+
if (index !== -1) {
|
|
70
|
+
this.activeToasts.splice(index, 1);
|
|
71
|
+
}
|
|
72
|
+
if (this.autoCloseTimers.has(id)) {
|
|
73
|
+
clearTimeout(this.autoCloseTimers.get(id));
|
|
74
|
+
this.autoCloseTimers.delete(id);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
markAsRead(notification) {
|
|
78
|
+
if (!notification.read) {
|
|
79
|
+
notification.read = true;
|
|
80
|
+
this.notificationRead.emit(notification.id);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
markAllAsRead() {
|
|
84
|
+
this.notifications.forEach(n => n.read = true);
|
|
85
|
+
this.allRead.emit();
|
|
86
|
+
}
|
|
87
|
+
dismissNotification(notification, event) {
|
|
88
|
+
event?.stopPropagation();
|
|
89
|
+
const index = this.notifications.indexOf(notification);
|
|
90
|
+
if (index !== -1) {
|
|
91
|
+
this.notifications.splice(index, 1);
|
|
92
|
+
this.notificationDismissed.emit(notification.id);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
clearAll() {
|
|
96
|
+
this.notifications.length = 0;
|
|
97
|
+
this.allCleared.emit();
|
|
98
|
+
}
|
|
99
|
+
executeAction(notification, event) {
|
|
100
|
+
event?.stopPropagation();
|
|
101
|
+
if (notification.actionCallback) {
|
|
102
|
+
notification.actionCallback();
|
|
103
|
+
}
|
|
104
|
+
this.notificationAction.emit(notification);
|
|
105
|
+
this.markAsRead(notification);
|
|
106
|
+
}
|
|
107
|
+
getIcon(type) {
|
|
108
|
+
const icons = {
|
|
109
|
+
success: '✅',
|
|
110
|
+
info: 'ℹ️',
|
|
111
|
+
warning: '⚠️',
|
|
112
|
+
error: '❌'
|
|
113
|
+
};
|
|
114
|
+
return icons[type];
|
|
115
|
+
}
|
|
116
|
+
formatTimestamp(date) {
|
|
117
|
+
const now = new Date();
|
|
118
|
+
const diff = now.getTime() - date.getTime();
|
|
119
|
+
const minutes = Math.floor(diff / 60000);
|
|
120
|
+
const hours = Math.floor(diff / 3600000);
|
|
121
|
+
const days = Math.floor(diff / 86400000);
|
|
122
|
+
if (minutes < 1)
|
|
123
|
+
return 'Agora';
|
|
124
|
+
if (minutes < 60)
|
|
125
|
+
return `${minutes}m atrás`;
|
|
126
|
+
if (hours < 24)
|
|
127
|
+
return `${hours}h atrás`;
|
|
128
|
+
if (days < 7)
|
|
129
|
+
return `${days}d atrás`;
|
|
130
|
+
return date.toLocaleDateString('pt-BR', { day: '2-digit', month: 'short' });
|
|
131
|
+
}
|
|
132
|
+
get positionClass() {
|
|
133
|
+
return `position-${this.position}`;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
NotificationCenterComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NotificationCenterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
137
|
+
NotificationCenterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: NotificationCenterComponent, isStandalone: true, selector: "muxima-notification-center", inputs: { notifications: "notifications", position: "position", maxToasts: "maxToasts", defaultDuration: "defaultDuration", showBadge: "showBadge", groupByCategory: "groupByCategory" }, outputs: { notificationRead: "notificationRead", notificationDismissed: "notificationDismissed", notificationAction: "notificationAction", allRead: "allRead", allCleared: "allCleared" }, ngImport: i0, template: "<!-- Notification Bell Icon -->\r\n<div class=\"notification-bell\" (click)=\"togglePanel()\">\r\n <span class=\"bell-icon\">\uD83D\uDD14</span>\r\n <span class=\"badge\" *ngIf=\"showBadge && unreadCount > 0\">{{ unreadCount > 99 ? '99+' : unreadCount }}</span>\r\n</div>\r\n\r\n<!-- Notification Panel -->\r\n<div class=\"notification-panel\" [class.open]=\"isOpen\" [@slideDown]>\r\n <div class=\"panel-header\">\r\n <h3>Notifica\u00E7\u00F5es</h3>\r\n <div class=\"header-actions\">\r\n <button class=\"action-btn\" (click)=\"markAllAsRead()\" *ngIf=\"unreadCount > 0\" title=\"Marcar todas como lidas\">\r\n <span>\u2713</span>\r\n </button>\r\n <button class=\"action-btn\" (click)=\"clearAll()\" *ngIf=\"notifications.length > 0\" title=\"Limpar todas\">\r\n <span>\uD83D\uDDD1\uFE0F</span>\r\n </button>\r\n <button class=\"action-btn close-btn\" (click)=\"closePanel()\" title=\"Fechar\">\r\n <span>\u2715</span>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"panel-body\">\r\n <div *ngIf=\"notifications.length === 0\" class=\"empty-state\">\r\n <div class=\"empty-icon\">\uD83D\uDD15</div>\r\n <p>Nenhuma notifica\u00E7\u00E3o</p>\r\n </div>\r\n\r\n <div *ngIf=\"notifications.length > 0\">\r\n <div *ngFor=\"let group of groupedNotifications\" class=\"notification-group\">\r\n <h4 class=\"group-title\" *ngIf=\"groupByCategory\">{{ group.category }}</h4>\r\n \r\n <div *ngFor=\"let notification of group.notifications\" \r\n class=\"notification-item\"\r\n [class.unread]=\"!notification.read\"\r\n [class.type-success]=\"notification.type === 'success'\"\r\n [class.type-info]=\"notification.type === 'info'\"\r\n [class.type-warning]=\"notification.type === 'warning'\"\r\n [class.type-error]=\"notification.type === 'error'\"\r\n (click)=\"markAsRead(notification)\">\r\n \r\n <div class=\"notification-icon\">\r\n <span>{{ getIcon(notification.type) }}</span>\r\n </div>\r\n\r\n <div class=\"notification-content\">\r\n <div class=\"notification-header\">\r\n <h5 class=\"notification-title\">{{ notification.title }}</h5>\r\n <span class=\"notification-time\">{{ formatTimestamp(notification.timestamp) }}</span>\r\n </div>\r\n <p class=\"notification-message\">{{ notification.message }}</p>\r\n \r\n <button *ngIf=\"notification.actionLabel\" \r\n class=\"notification-action\"\r\n (click)=\"executeAction(notification, $event)\">\r\n {{ notification.actionLabel }}\r\n </button>\r\n </div>\r\n\r\n <button class=\"dismiss-btn\" (click)=\"dismissNotification(notification, $event)\" title=\"Dispensar\">\r\n <span>\u2715</span>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Toast Notifications -->\r\n<div class=\"toast-container\" [class]=\"positionClass\">\r\n <div *ngFor=\"let toast of activeToasts\" \r\n class=\"toast-notification\"\r\n [class.type-success]=\"toast.type === 'success'\"\r\n [class.type-info]=\"toast.type === 'info'\"\r\n [class.type-warning]=\"toast.type === 'warning'\"\r\n [class.type-error]=\"toast.type === 'error'\"\r\n [@slideIn]>\r\n \r\n <div class=\"toast-icon\">\r\n <span>{{ getIcon(toast.type) }}</span>\r\n </div>\r\n\r\n <div class=\"toast-content\">\r\n <h5 class=\"toast-title\">{{ toast.title }}</h5>\r\n <p class=\"toast-message\">{{ toast.message }}</p>\r\n \r\n <button *ngIf=\"toast.actionLabel\" \r\n class=\"toast-action\"\r\n (click)=\"executeAction(toast, $event)\">\r\n {{ toast.actionLabel }}\r\n </button>\r\n </div>\r\n\r\n <button class=\"toast-close\" (click)=\"dismissToast(toast.id)\" title=\"Fechar\">\r\n <span>\u2715</span>\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<!-- Overlay -->\r\n<div class=\"overlay\" *ngIf=\"isOpen\" (click)=\"closePanel()\"></div>\r\n", styles: [".notification-bell{position:relative;display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);border-radius:50%;cursor:pointer;transition:all .3s ease;box-shadow:0 4px 8px #667eea4d}.notification-bell:hover{transform:scale(1.1);box-shadow:0 6px 12px #667eea66}.notification-bell:active{transform:scale(.95)}.notification-bell .bell-icon{font-size:1.5rem;animation:ring 2s ease-in-out infinite}.notification-bell .badge{position:absolute;top:-4px;right:-4px;min-width:20px;height:20px;padding:0 4px;background:#ef4444;color:#fff;font-size:.75rem;font-weight:700;border-radius:10px;display:flex;align-items:center;justify-content:center;border:2px solid white;animation:pulse 2s ease-in-out infinite}@keyframes ring{0%,to{transform:rotate(0)}10%,30%{transform:rotate(-10deg)}20%,40%{transform:rotate(10deg)}}@keyframes pulse{0%,to{transform:scale(1)}50%{transform:scale(1.1)}}.notification-panel{position:fixed;top:60px;right:20px;width:400px;max-height:600px;background:white;border-radius:12px;box-shadow:0 10px 25px #0003;transform:translateY(-20px);opacity:0;pointer-events:none;transition:all .3s ease;z-index:1000;display:flex;flex-direction:column}.notification-panel.open{transform:translateY(0);opacity:1;pointer-events:all}.panel-header{padding:1.25rem;border-bottom:1px solid #e5e7eb;display:flex;align-items:center;justify-content:space-between}.panel-header h3{font-size:1.25rem;font-weight:700;color:#111827;margin:0}.panel-header .header-actions{display:flex;gap:.5rem}.panel-header .action-btn{padding:.5rem;background:transparent;border:none;color:#6b7280;font-size:1rem;cursor:pointer;border-radius:6px;transition:all .2s ease;display:flex;align-items:center;justify-content:center}.panel-header .action-btn:hover{background:#f3f4f6;color:#667eea}.panel-header .action-btn.close-btn:hover{color:#ef4444}.panel-body{flex:1;overflow-y:auto;max-height:500px}.panel-body::-webkit-scrollbar{width:6px}.panel-body::-webkit-scrollbar-track{background:#f3f4f6}.panel-body::-webkit-scrollbar-thumb{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);border-radius:3px}.empty-state{padding:3rem 1.5rem;text-align:center}.empty-state .empty-icon{font-size:3rem;margin-bottom:1rem;opacity:.5}.empty-state p{color:#9ca3af;font-size:1rem}.notification-group .group-title{padding:.75rem 1.25rem;font-size:.875rem;font-weight:600;color:#667eea;text-transform:uppercase;letter-spacing:.05em;background:#f9fafb;border-bottom:1px solid #e5e7eb;margin:0}.notification-item{display:flex;gap:1rem;padding:1rem 1.25rem;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:all .2s ease;position:relative}.notification-item:last-child{border-bottom:none}.notification-item:hover{background:#f9fafb}.notification-item.unread{background:rgba(102,126,234,.05)}.notification-item.unread:before{content:\"\";position:absolute;left:0;top:0;bottom:0;width:4px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%)}.notification-item.type-success .notification-icon{color:#10b981}.notification-item.type-info .notification-icon{color:#3b82f6}.notification-item.type-warning .notification-icon{color:#f59e0b}.notification-item.type-error .notification-icon{color:#ef4444}.notification-item .notification-icon{font-size:1.5rem;flex-shrink:0}.notification-item .notification-content{flex:1;min-width:0}.notification-item .notification-header{display:flex;align-items:flex-start;justify-content:space-between;gap:.5rem;margin-bottom:.5rem}.notification-item .notification-title{font-size:.875rem;font-weight:600;color:#111827;margin:0}.notification-item .notification-time{font-size:.75rem;color:#9ca3af;white-space:nowrap}.notification-item .notification-message{font-size:.875rem;color:#6b7280;margin:0 0 .75rem;line-height:1.5}.notification-item .notification-action{padding:.375rem .75rem;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border:none;border-radius:6px;font-size:.75rem;font-weight:600;cursor:pointer;transition:all .2s ease}.notification-item .notification-action:hover{transform:translateY(-1px);box-shadow:0 4px 8px #667eea4d}.notification-item .dismiss-btn{padding:.25rem;background:transparent;border:none;color:#9ca3af;font-size:1rem;cursor:pointer;border-radius:4px;transition:all .2s ease;flex-shrink:0}.notification-item .dismiss-btn:hover{background:#f3f4f6;color:#ef4444}.toast-container{position:fixed;z-index:9999;display:flex;flex-direction:column;gap:1rem;pointer-events:none}.toast-container.position-top-right{top:20px;right:20px}.toast-container.position-top-left{top:20px;left:20px}.toast-container.position-bottom-right{bottom:20px;right:20px}.toast-container.position-bottom-left{bottom:20px;left:20px}.toast-container.position-top-center{top:20px;left:50%;transform:translate(-50%)}.toast-container.position-bottom-center{bottom:20px;left:50%;transform:translate(-50%)}.toast-notification{display:flex;align-items:flex-start;gap:1rem;min-width:350px;max-width:450px;padding:1rem 1.25rem;background:white;border-radius:12px;box-shadow:0 10px 25px #00000026;pointer-events:all;border-left:4px solid}.toast-notification.type-success{border-left-color:#10b981}.toast-notification.type-success .toast-icon{color:#10b981}.toast-notification.type-info{border-left-color:#3b82f6}.toast-notification.type-info .toast-icon{color:#3b82f6}.toast-notification.type-warning{border-left-color:#f59e0b}.toast-notification.type-warning .toast-icon{color:#f59e0b}.toast-notification.type-error{border-left-color:#ef4444}.toast-notification.type-error .toast-icon{color:#ef4444}.toast-notification .toast-icon{font-size:1.5rem;flex-shrink:0}.toast-notification .toast-content{flex:1;min-width:0}.toast-notification .toast-title{font-size:.875rem;font-weight:600;color:#111827;margin:0 0 .25rem}.toast-notification .toast-message{font-size:.875rem;color:#6b7280;margin:0 0 .75rem;line-height:1.5}.toast-notification .toast-action{padding:.375rem .75rem;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border:none;border-radius:6px;font-size:.75rem;font-weight:600;cursor:pointer;transition:all .2s ease}.toast-notification .toast-action:hover{transform:translateY(-1px);box-shadow:0 4px 8px #667eea4d}.toast-notification .toast-close{padding:.25rem;background:transparent;border:none;color:#9ca3af;font-size:1rem;cursor:pointer;border-radius:4px;transition:all .2s ease;flex-shrink:0}.toast-notification .toast-close:hover{background:#f3f4f6;color:#ef4444}.overlay{position:fixed;inset:0;background:rgba(0,0,0,.3);z-index:999;animation:fadeIn .3s ease}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@media (max-width: 768px){.notification-panel{right:10px;left:10px;width:auto}.toast-notification{min-width:300px;max-width:350px}.toast-container.position-top-right,.toast-container.position-top-left,.toast-container.position-top-center{top:10px;left:10px;right:10px;transform:none}.toast-container.position-bottom-right,.toast-container.position-bottom-left,.toast-container.position-bottom-center{bottom:10px;left:10px;right:10px;transform:none}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], animations: [
|
|
138
|
+
trigger('slideIn', [
|
|
139
|
+
transition(':enter', [
|
|
140
|
+
style({ transform: 'translateX(100%)', opacity: 0 }),
|
|
141
|
+
animate('300ms ease-out', style({ transform: 'translateX(0)', opacity: 1 }))
|
|
142
|
+
]),
|
|
143
|
+
transition(':leave', [
|
|
144
|
+
animate('300ms ease-in', style({ transform: 'translateX(100%)', opacity: 0 }))
|
|
145
|
+
])
|
|
146
|
+
]),
|
|
147
|
+
trigger('slideDown', [
|
|
148
|
+
transition(':enter', [
|
|
149
|
+
style({ height: 0, opacity: 0 }),
|
|
150
|
+
animate('200ms ease-out', style({ height: '*', opacity: 1 }))
|
|
151
|
+
]),
|
|
152
|
+
transition(':leave', [
|
|
153
|
+
animate('200ms ease-in', style({ height: 0, opacity: 0 }))
|
|
154
|
+
])
|
|
155
|
+
])
|
|
156
|
+
] });
|
|
157
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NotificationCenterComponent, decorators: [{
|
|
158
|
+
type: Component,
|
|
159
|
+
args: [{ selector: 'muxima-notification-center', standalone: true, imports: [CommonModule], animations: [
|
|
160
|
+
trigger('slideIn', [
|
|
161
|
+
transition(':enter', [
|
|
162
|
+
style({ transform: 'translateX(100%)', opacity: 0 }),
|
|
163
|
+
animate('300ms ease-out', style({ transform: 'translateX(0)', opacity: 1 }))
|
|
164
|
+
]),
|
|
165
|
+
transition(':leave', [
|
|
166
|
+
animate('300ms ease-in', style({ transform: 'translateX(100%)', opacity: 0 }))
|
|
167
|
+
])
|
|
168
|
+
]),
|
|
169
|
+
trigger('slideDown', [
|
|
170
|
+
transition(':enter', [
|
|
171
|
+
style({ height: 0, opacity: 0 }),
|
|
172
|
+
animate('200ms ease-out', style({ height: '*', opacity: 1 }))
|
|
173
|
+
]),
|
|
174
|
+
transition(':leave', [
|
|
175
|
+
animate('200ms ease-in', style({ height: 0, opacity: 0 }))
|
|
176
|
+
])
|
|
177
|
+
])
|
|
178
|
+
], template: "<!-- Notification Bell Icon -->\r\n<div class=\"notification-bell\" (click)=\"togglePanel()\">\r\n <span class=\"bell-icon\">\uD83D\uDD14</span>\r\n <span class=\"badge\" *ngIf=\"showBadge && unreadCount > 0\">{{ unreadCount > 99 ? '99+' : unreadCount }}</span>\r\n</div>\r\n\r\n<!-- Notification Panel -->\r\n<div class=\"notification-panel\" [class.open]=\"isOpen\" [@slideDown]>\r\n <div class=\"panel-header\">\r\n <h3>Notifica\u00E7\u00F5es</h3>\r\n <div class=\"header-actions\">\r\n <button class=\"action-btn\" (click)=\"markAllAsRead()\" *ngIf=\"unreadCount > 0\" title=\"Marcar todas como lidas\">\r\n <span>\u2713</span>\r\n </button>\r\n <button class=\"action-btn\" (click)=\"clearAll()\" *ngIf=\"notifications.length > 0\" title=\"Limpar todas\">\r\n <span>\uD83D\uDDD1\uFE0F</span>\r\n </button>\r\n <button class=\"action-btn close-btn\" (click)=\"closePanel()\" title=\"Fechar\">\r\n <span>\u2715</span>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"panel-body\">\r\n <div *ngIf=\"notifications.length === 0\" class=\"empty-state\">\r\n <div class=\"empty-icon\">\uD83D\uDD15</div>\r\n <p>Nenhuma notifica\u00E7\u00E3o</p>\r\n </div>\r\n\r\n <div *ngIf=\"notifications.length > 0\">\r\n <div *ngFor=\"let group of groupedNotifications\" class=\"notification-group\">\r\n <h4 class=\"group-title\" *ngIf=\"groupByCategory\">{{ group.category }}</h4>\r\n \r\n <div *ngFor=\"let notification of group.notifications\" \r\n class=\"notification-item\"\r\n [class.unread]=\"!notification.read\"\r\n [class.type-success]=\"notification.type === 'success'\"\r\n [class.type-info]=\"notification.type === 'info'\"\r\n [class.type-warning]=\"notification.type === 'warning'\"\r\n [class.type-error]=\"notification.type === 'error'\"\r\n (click)=\"markAsRead(notification)\">\r\n \r\n <div class=\"notification-icon\">\r\n <span>{{ getIcon(notification.type) }}</span>\r\n </div>\r\n\r\n <div class=\"notification-content\">\r\n <div class=\"notification-header\">\r\n <h5 class=\"notification-title\">{{ notification.title }}</h5>\r\n <span class=\"notification-time\">{{ formatTimestamp(notification.timestamp) }}</span>\r\n </div>\r\n <p class=\"notification-message\">{{ notification.message }}</p>\r\n \r\n <button *ngIf=\"notification.actionLabel\" \r\n class=\"notification-action\"\r\n (click)=\"executeAction(notification, $event)\">\r\n {{ notification.actionLabel }}\r\n </button>\r\n </div>\r\n\r\n <button class=\"dismiss-btn\" (click)=\"dismissNotification(notification, $event)\" title=\"Dispensar\">\r\n <span>\u2715</span>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Toast Notifications -->\r\n<div class=\"toast-container\" [class]=\"positionClass\">\r\n <div *ngFor=\"let toast of activeToasts\" \r\n class=\"toast-notification\"\r\n [class.type-success]=\"toast.type === 'success'\"\r\n [class.type-info]=\"toast.type === 'info'\"\r\n [class.type-warning]=\"toast.type === 'warning'\"\r\n [class.type-error]=\"toast.type === 'error'\"\r\n [@slideIn]>\r\n \r\n <div class=\"toast-icon\">\r\n <span>{{ getIcon(toast.type) }}</span>\r\n </div>\r\n\r\n <div class=\"toast-content\">\r\n <h5 class=\"toast-title\">{{ toast.title }}</h5>\r\n <p class=\"toast-message\">{{ toast.message }}</p>\r\n \r\n <button *ngIf=\"toast.actionLabel\" \r\n class=\"toast-action\"\r\n (click)=\"executeAction(toast, $event)\">\r\n {{ toast.actionLabel }}\r\n </button>\r\n </div>\r\n\r\n <button class=\"toast-close\" (click)=\"dismissToast(toast.id)\" title=\"Fechar\">\r\n <span>\u2715</span>\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<!-- Overlay -->\r\n<div class=\"overlay\" *ngIf=\"isOpen\" (click)=\"closePanel()\"></div>\r\n", styles: [".notification-bell{position:relative;display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);border-radius:50%;cursor:pointer;transition:all .3s ease;box-shadow:0 4px 8px #667eea4d}.notification-bell:hover{transform:scale(1.1);box-shadow:0 6px 12px #667eea66}.notification-bell:active{transform:scale(.95)}.notification-bell .bell-icon{font-size:1.5rem;animation:ring 2s ease-in-out infinite}.notification-bell .badge{position:absolute;top:-4px;right:-4px;min-width:20px;height:20px;padding:0 4px;background:#ef4444;color:#fff;font-size:.75rem;font-weight:700;border-radius:10px;display:flex;align-items:center;justify-content:center;border:2px solid white;animation:pulse 2s ease-in-out infinite}@keyframes ring{0%,to{transform:rotate(0)}10%,30%{transform:rotate(-10deg)}20%,40%{transform:rotate(10deg)}}@keyframes pulse{0%,to{transform:scale(1)}50%{transform:scale(1.1)}}.notification-panel{position:fixed;top:60px;right:20px;width:400px;max-height:600px;background:white;border-radius:12px;box-shadow:0 10px 25px #0003;transform:translateY(-20px);opacity:0;pointer-events:none;transition:all .3s ease;z-index:1000;display:flex;flex-direction:column}.notification-panel.open{transform:translateY(0);opacity:1;pointer-events:all}.panel-header{padding:1.25rem;border-bottom:1px solid #e5e7eb;display:flex;align-items:center;justify-content:space-between}.panel-header h3{font-size:1.25rem;font-weight:700;color:#111827;margin:0}.panel-header .header-actions{display:flex;gap:.5rem}.panel-header .action-btn{padding:.5rem;background:transparent;border:none;color:#6b7280;font-size:1rem;cursor:pointer;border-radius:6px;transition:all .2s ease;display:flex;align-items:center;justify-content:center}.panel-header .action-btn:hover{background:#f3f4f6;color:#667eea}.panel-header .action-btn.close-btn:hover{color:#ef4444}.panel-body{flex:1;overflow-y:auto;max-height:500px}.panel-body::-webkit-scrollbar{width:6px}.panel-body::-webkit-scrollbar-track{background:#f3f4f6}.panel-body::-webkit-scrollbar-thumb{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);border-radius:3px}.empty-state{padding:3rem 1.5rem;text-align:center}.empty-state .empty-icon{font-size:3rem;margin-bottom:1rem;opacity:.5}.empty-state p{color:#9ca3af;font-size:1rem}.notification-group .group-title{padding:.75rem 1.25rem;font-size:.875rem;font-weight:600;color:#667eea;text-transform:uppercase;letter-spacing:.05em;background:#f9fafb;border-bottom:1px solid #e5e7eb;margin:0}.notification-item{display:flex;gap:1rem;padding:1rem 1.25rem;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:all .2s ease;position:relative}.notification-item:last-child{border-bottom:none}.notification-item:hover{background:#f9fafb}.notification-item.unread{background:rgba(102,126,234,.05)}.notification-item.unread:before{content:\"\";position:absolute;left:0;top:0;bottom:0;width:4px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%)}.notification-item.type-success .notification-icon{color:#10b981}.notification-item.type-info .notification-icon{color:#3b82f6}.notification-item.type-warning .notification-icon{color:#f59e0b}.notification-item.type-error .notification-icon{color:#ef4444}.notification-item .notification-icon{font-size:1.5rem;flex-shrink:0}.notification-item .notification-content{flex:1;min-width:0}.notification-item .notification-header{display:flex;align-items:flex-start;justify-content:space-between;gap:.5rem;margin-bottom:.5rem}.notification-item .notification-title{font-size:.875rem;font-weight:600;color:#111827;margin:0}.notification-item .notification-time{font-size:.75rem;color:#9ca3af;white-space:nowrap}.notification-item .notification-message{font-size:.875rem;color:#6b7280;margin:0 0 .75rem;line-height:1.5}.notification-item .notification-action{padding:.375rem .75rem;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border:none;border-radius:6px;font-size:.75rem;font-weight:600;cursor:pointer;transition:all .2s ease}.notification-item .notification-action:hover{transform:translateY(-1px);box-shadow:0 4px 8px #667eea4d}.notification-item .dismiss-btn{padding:.25rem;background:transparent;border:none;color:#9ca3af;font-size:1rem;cursor:pointer;border-radius:4px;transition:all .2s ease;flex-shrink:0}.notification-item .dismiss-btn:hover{background:#f3f4f6;color:#ef4444}.toast-container{position:fixed;z-index:9999;display:flex;flex-direction:column;gap:1rem;pointer-events:none}.toast-container.position-top-right{top:20px;right:20px}.toast-container.position-top-left{top:20px;left:20px}.toast-container.position-bottom-right{bottom:20px;right:20px}.toast-container.position-bottom-left{bottom:20px;left:20px}.toast-container.position-top-center{top:20px;left:50%;transform:translate(-50%)}.toast-container.position-bottom-center{bottom:20px;left:50%;transform:translate(-50%)}.toast-notification{display:flex;align-items:flex-start;gap:1rem;min-width:350px;max-width:450px;padding:1rem 1.25rem;background:white;border-radius:12px;box-shadow:0 10px 25px #00000026;pointer-events:all;border-left:4px solid}.toast-notification.type-success{border-left-color:#10b981}.toast-notification.type-success .toast-icon{color:#10b981}.toast-notification.type-info{border-left-color:#3b82f6}.toast-notification.type-info .toast-icon{color:#3b82f6}.toast-notification.type-warning{border-left-color:#f59e0b}.toast-notification.type-warning .toast-icon{color:#f59e0b}.toast-notification.type-error{border-left-color:#ef4444}.toast-notification.type-error .toast-icon{color:#ef4444}.toast-notification .toast-icon{font-size:1.5rem;flex-shrink:0}.toast-notification .toast-content{flex:1;min-width:0}.toast-notification .toast-title{font-size:.875rem;font-weight:600;color:#111827;margin:0 0 .25rem}.toast-notification .toast-message{font-size:.875rem;color:#6b7280;margin:0 0 .75rem;line-height:1.5}.toast-notification .toast-action{padding:.375rem .75rem;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border:none;border-radius:6px;font-size:.75rem;font-weight:600;cursor:pointer;transition:all .2s ease}.toast-notification .toast-action:hover{transform:translateY(-1px);box-shadow:0 4px 8px #667eea4d}.toast-notification .toast-close{padding:.25rem;background:transparent;border:none;color:#9ca3af;font-size:1rem;cursor:pointer;border-radius:4px;transition:all .2s ease;flex-shrink:0}.toast-notification .toast-close:hover{background:#f3f4f6;color:#ef4444}.overlay{position:fixed;inset:0;background:rgba(0,0,0,.3);z-index:999;animation:fadeIn .3s ease}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@media (max-width: 768px){.notification-panel{right:10px;left:10px;width:auto}.toast-notification{min-width:300px;max-width:350px}.toast-container.position-top-right,.toast-container.position-top-left,.toast-container.position-top-center{top:10px;left:10px;right:10px;transform:none}.toast-container.position-bottom-right,.toast-container.position-bottom-left,.toast-container.position-bottom-center{bottom:10px;left:10px;right:10px;transform:none}}\n"] }]
|
|
179
|
+
}], propDecorators: { notifications: [{
|
|
180
|
+
type: Input
|
|
181
|
+
}], position: [{
|
|
182
|
+
type: Input
|
|
183
|
+
}], maxToasts: [{
|
|
184
|
+
type: Input
|
|
185
|
+
}], defaultDuration: [{
|
|
186
|
+
type: Input
|
|
187
|
+
}], showBadge: [{
|
|
188
|
+
type: Input
|
|
189
|
+
}], groupByCategory: [{
|
|
190
|
+
type: Input
|
|
191
|
+
}], notificationRead: [{
|
|
192
|
+
type: Output
|
|
193
|
+
}], notificationDismissed: [{
|
|
194
|
+
type: Output
|
|
195
|
+
}], notificationAction: [{
|
|
196
|
+
type: Output
|
|
197
|
+
}], allRead: [{
|
|
198
|
+
type: Output
|
|
199
|
+
}], allCleared: [{
|
|
200
|
+
type: Output
|
|
201
|
+
}] } });
|
|
202
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm90aWZpY2F0aW9uLWNlbnRlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9vdmVybGF5L25vdGlmaWNhdGlvbi1jZW50ZXIvc3JjL2xpYi9ub3RpZmljYXRpb24tY2VudGVyL25vdGlmaWNhdGlvbi1jZW50ZXIuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vb3ZlcmxheS9ub3RpZmljYXRpb24tY2VudGVyL3NyYy9saWIvbm90aWZpY2F0aW9uLWNlbnRlci9ub3RpZmljYXRpb24tY2VudGVyLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQWEsTUFBTSxlQUFlLENBQUM7QUFDbEYsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQVMsTUFBTSxxQkFBcUIsQ0FBQzs7O0FBOENqRixNQUFNLE9BQU8sMkJBQTJCO0lBM0J4QztRQTRCVyxrQkFBYSxHQUFtQixFQUFFLENBQUM7UUFDbkMsYUFBUSxHQUF5QixXQUFXLENBQUM7UUFDN0MsY0FBUyxHQUFXLENBQUMsQ0FBQztRQUN0QixvQkFBZSxHQUFXLElBQUksQ0FBQztRQUMvQixjQUFTLEdBQVksSUFBSSxDQUFDO1FBQzFCLG9CQUFlLEdBQVksS0FBSyxDQUFDO1FBRWhDLHFCQUFnQixHQUFHLElBQUksWUFBWSxFQUFVLENBQUM7UUFDOUMsMEJBQXFCLEdBQUcsSUFBSSxZQUFZLEVBQVUsQ0FBQztRQUNuRCx1QkFBa0IsR0FBRyxJQUFJLFlBQVksRUFBZ0IsQ0FBQztRQUN0RCxZQUFPLEdBQUcsSUFBSSxZQUFZLEVBQVEsQ0FBQztRQUNuQyxlQUFVLEdBQUcsSUFBSSxZQUFZLEVBQVEsQ0FBQztRQUVoRCxX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LE9BQU8sQ0FBQyxlQUFlLEVBQUUsS0FBSyxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsRUFBRSxPQUFPLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQzs2QkFDM0QsQ0FBQzt5QkFDSCxDQUFDO3FCQUNIOzhCQUdRLGFBQWE7c0JBQXJCLEtBQUs7Z0JBQ0csUUFBUTtzQkFBaEIsS0FBSztnQkFDRyxTQUFTO3NCQUFqQixLQUFLO2dCQUNHLGVBQWU7c0JBQXZCLEtBQUs7Z0JBQ0csU0FBUztzQkFBakIsS0FBSztnQkFDRyxlQUFlO3NCQUF2QixLQUFLO2dCQUVJLGdCQUFnQjtzQkFBekIsTUFBTTtnQkFDRyxxQkFBcUI7c0JBQTlCLE1BQU07Z0JBQ0csa0JBQWtCO3NCQUEzQixNQUFNO2dCQUNHLE9BQU87c0JBQWhCLE1BQU07Z0JBQ0csVUFBVTtzQkFBbkIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIE91dHB1dCwgRXZlbnRFbWl0dGVyLCBPbkRlc3Ryb3kgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcclxuaW1wb3J0IHsgdHJpZ2dlciwgdHJhbnNpdGlvbiwgc3R5bGUsIGFuaW1hdGUsIHN0YXRlIH0gZnJvbSAnQGFuZ3VsYXIvYW5pbWF0aW9ucyc7XHJcblxyXG5leHBvcnQgdHlwZSBOb3RpZmljYXRpb25UeXBlID0gJ3N1Y2Nlc3MnIHwgJ2luZm8nIHwgJ3dhcm5pbmcnIHwgJ2Vycm9yJztcclxuZXhwb3J0IHR5cGUgTm90aWZpY2F0aW9uUG9zaXRpb24gPSAndG9wLXJpZ2h0JyB8ICd0b3AtbGVmdCcgfCAnYm90dG9tLXJpZ2h0JyB8ICdib3R0b20tbGVmdCcgfCAndG9wLWNlbnRlcicgfCAnYm90dG9tLWNlbnRlcic7XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIE5vdGlmaWNhdGlvbiB7XHJcbiAgaWQ6IHN0cmluZztcclxuICB0eXBlOiBOb3RpZmljYXRpb25UeXBlO1xyXG4gIHRpdGxlOiBzdHJpbmc7XHJcbiAgbWVzc2FnZTogc3RyaW5nO1xyXG4gIHRpbWVzdGFtcDogRGF0ZTtcclxuICByZWFkOiBib29sZWFuO1xyXG4gIGNhdGVnb3J5Pzogc3RyaW5nO1xyXG4gIGFjdGlvbkxhYmVsPzogc3RyaW5nO1xyXG4gIGFjdGlvbkNhbGxiYWNrPzogKCkgPT4gdm9pZDtcclxuICBhdXRvQ2xvc2U/OiBib29sZWFuO1xyXG4gIGR1cmF0aW9uPzogbnVtYmVyO1xyXG59XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ211eGltYS1ub3RpZmljYXRpb24tY2VudGVyJyxcclxuICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGVdLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi9ub3RpZmljYXRpb24tY2VudGVyLmNvbXBvbmVudC5odG1sJyxcclxuICBzdHlsZVVybHM6IFsnLi9ub3RpZmljYXRpb24tY2VudGVyLmNvbXBvbmVudC5zY3NzJ10sXHJcbiAgYW5pbWF0aW9uczogW1xyXG4gICAgdHJpZ2dlcignc2xpZGVJbicsIFtcclxuICAgICAgdHJhbnNpdGlvbignOmVudGVyJywgW1xyXG4gICAgICAgIHN0eWxlKHsgdHJhbnNmb3JtOiAndHJhbnNsYXRlWCgxMDAlKScsIG9wYWNpdHk6IDAgfSksXHJcbiAgICAgICAgYW5pbWF0ZSgnMzAwbXMgZWFzZS1vdXQnLCBzdHlsZSh7IHRyYW5zZm9ybTogJ3RyYW5zbGF0ZVgoMCknLCBvcGFjaXR5OiAxIH0pKVxyXG4gICAgICBdKSxcclxuICAgICAgdHJhbnNpdGlvbignOmxlYXZlJywgW1xyXG4gICAgICAgIGFuaW1hdGUoJzMwMG1zIGVhc2UtaW4nLCBzdHlsZSh7IHRyYW5zZm9ybTogJ3RyYW5zbGF0ZVgoMTAwJSknLCBvcGFjaXR5OiAwIH0pKVxyXG4gICAgICBdKVxyXG4gICAgXSksXHJcbiAgICB0cmlnZ2VyKCdzbGlkZURvd24nLCBbXHJcbiAgICAgIHRyYW5zaXRpb24oJzplbnRlcicsIFtcclxuICAgICAgICBzdHlsZSh7IGhlaWdodDogMCwgb3BhY2l0eTogMCB9KSxcclxuICAgICAgICBhbmltYXRlKCcyMDBtcyBlYXNlLW91dCcsIHN0eWxlKHsgaGVpZ2h0OiAnKicsIG9wYWNpdHk6IDEgfSkpXHJcbiAgICAgIF0pLFxyXG4gICAgICB0cmFuc2l0aW9uKCc6bGVhdmUnLCBbXHJcbiAgICAgICAgYW5pbWF0ZSgnMjAwbXMgZWFzZS1pbicsIHN0eWxlKHsgaGVpZ2h0OiAwLCBvcGFjaXR5OiAwIH0pKVxyXG4gICAgICBdKVxyXG4gICAgXSlcclxuICBdXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBOb3RpZmljYXRpb25DZW50ZXJDb21wb25lbnQgaW1wbGVtZW50cyBPbkRlc3Ryb3kge1xyXG4gIEBJbnB1dCgpIG5vdGlmaWNhdGlvbnM6IE5vdGlmaWNhdGlvbltdID0gW107XHJcbiAgQElucHV0KCkgcG9zaXRpb246IE5vdGlmaWNhdGlvblBvc2l0aW9uID0gJ3RvcC1yaWdodCc7XHJcbiAgQElucHV0KCkgbWF4VG9hc3RzOiBudW1iZXIgPSAzO1xyXG4gIEBJbnB1dCgpIGRlZmF1bHREdXJhdGlvbjogbnVtYmVyID0gNTAwMDtcclxuICBASW5wdXQoKSBzaG93QmFkZ2U6IGJvb2xlYW4gPSB0cnVlO1xyXG4gIEBJbnB1dCgpIGdyb3VwQnlDYXRlZ29yeTogYm9vbGVhbiA9IGZhbHNlO1xyXG5cclxuICBAT3V0cHV0KCkgbm90aWZpY2F0aW9uUmVhZCA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xyXG4gIEBPdXRwdXQoKSBub3RpZmljYXRpb25EaXNtaXNzZWQgPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcclxuICBAT3V0cHV0KCkgbm90aWZpY2F0aW9uQWN0aW9uID0gbmV3IEV2ZW50RW1pdHRlcjxOb3RpZmljYXRpb24+KCk7XHJcbiAgQE91dHB1dCgpIGFsbFJlYWQgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XHJcbiAgQE91dHB1dCgpIGFsbENsZWFyZWQgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XHJcblxyXG4gIGlzT3BlbiA9IGZhbHNlO1xyXG4gIGFjdGl2ZVRvYXN0czogTm90aWZpY2F0aW9uW10gPSBbXTtcclxuICBwcml2YXRlIGF1dG9DbG9zZVRpbWVycyA9IG5ldyBNYXA8c3RyaW5nLCBhbnk+KCk7XHJcblxyXG4gIG5nT25EZXN0cm95KCkge1xyXG4gICAgdGhpcy5hdXRvQ2xvc2VUaW1lcnMuZm9yRWFjaCh0aW1lciA9PiBjbGVhclRpbWVvdXQodGltZXIpKTtcclxuICB9XHJcblxyXG4gIHRvZ2dsZVBhbmVsKCkge1xyXG4gICAgdGhpcy5pc09wZW4gPSAhdGhpcy5pc09wZW47XHJcbiAgfVxyXG5cclxuICBjbG9zZVBhbmVsKCkge1xyXG4gICAgdGhpcy5pc09wZW4gPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIGdldCB1bnJlYWRDb3VudCgpOiBudW1iZXIge1xyXG4gICAgcmV0dXJuIHRoaXMubm90aWZpY2F0aW9ucy5maWx0ZXIobiA9PiAhbi5yZWFkKS5sZW5ndGg7XHJcbiAgfVxyXG5cclxuICBnZXQgZ3JvdXBlZE5vdGlmaWNhdGlvbnMoKTogeyBjYXRlZ29yeTogc3RyaW5nOyBub3RpZmljYXRpb25zOiBOb3RpZmljYXRpb25bXSB9W10ge1xyXG4gICAgaWYgKCF0aGlzLmdyb3VwQnlDYXRlZ29yeSkge1xyXG4gICAgICByZXR1cm4gW3sgY2F0ZWdvcnk6ICdhbGwnLCBub3RpZmljYXRpb25zOiB0aGlzLm5vdGlmaWNhdGlvbnMgfV07XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgZ3JvdXBzID0gbmV3IE1hcDxzdHJpbmcsIE5vdGlmaWNhdGlvbltdPigpO1xyXG4gICAgXHJcbiAgICB0aGlzLm5vdGlmaWNhdGlvbnMuZm9yRWFjaChub3RpZmljYXRpb24gPT4ge1xyXG4gICAgICBjb25zdCBjYXRlZ29yeSA9IG5vdGlmaWNhdGlvbi5jYXRlZ29yeSB8fCAnT3V0cm9zJztcclxuICAgICAgaWYgKCFncm91cHMuaGFzKGNhdGVnb3J5KSkge1xyXG4gICAgICAgIGdyb3Vwcy5zZXQoY2F0ZWdvcnksIFtdKTtcclxuICAgICAgfVxyXG4gICAgICBncm91cHMuZ2V0KGNhdGVnb3J5KSEucHVzaChub3RpZmljYXRpb24pO1xyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIEFycmF5LmZyb20oZ3JvdXBzLmVudHJpZXMoKSkubWFwKChbY2F0ZWdvcnksIG5vdGlmaWNhdGlvbnNdKSA9PiAoe1xyXG4gICAgICBjYXRlZ29yeSxcclxuICAgICAgbm90aWZpY2F0aW9uc1xyXG4gICAgfSkpO1xyXG4gIH1cclxuXHJcbiAgc2hvd1RvYXN0KG5vdGlmaWNhdGlvbjogTm90aWZpY2F0aW9uKSB7XHJcbiAgICAvLyBBZGQgdG8gYWN0aXZlIHRvYXN0c1xyXG4gICAgaWYgKHRoaXMuYWN0aXZlVG9hc3RzLmxlbmd0aCA+PSB0aGlzLm1heFRvYXN0cykge1xyXG4gICAgICB0aGlzLmFjdGl2ZVRvYXN0cy5zaGlmdCgpO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICB0aGlzLmFjdGl2ZVRvYXN0cy5wdXNoKG5vdGlmaWNhdGlvbik7XHJcblxyXG4gICAgLy8gQXV0byBjbG9zZSBpZiBlbmFibGVkXHJcbiAgICBpZiAobm90aWZpY2F0aW9uLmF1dG9DbG9zZSAhPT0gZmFsc2UpIHtcclxuICAgICAgY29uc3QgZHVyYXRpb24gPSBub3RpZmljYXRpb24uZHVyYXRpb24gfHwgdGhpcy5kZWZhdWx0RHVyYXRpb247XHJcbiAgICAgIGNvbnN0IHRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgICAgdGhpcy5kaXNtaXNzVG9hc3Qobm90aWZpY2F0aW9uLmlkKTtcclxuICAgICAgfSwgZHVyYXRpb24pO1xyXG4gICAgICBcclxuICAgICAgdGhpcy5hdXRvQ2xvc2VUaW1lcnMuc2V0KG5vdGlmaWNhdGlvbi5pZCwgdGltZXIpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZGlzbWlzc1RvYXN0KGlkOiBzdHJpbmcpIHtcclxuICAgIGNvbnN0IGluZGV4ID0gdGhpcy5hY3RpdmVUb2FzdHMuZmluZEluZGV4KHQgPT4gdC5pZCA9PT0gaWQpO1xyXG4gICAgaWYgKGluZGV4ICE9PSAtMSkge1xyXG4gICAgICB0aGlzLmFjdGl2ZVRvYXN0cy5zcGxpY2UoaW5kZXgsIDEpO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICBpZiAodGhpcy5hdXRvQ2xvc2VUaW1lcnMuaGFzKGlkKSkge1xyXG4gICAgICBjbGVhclRpbWVvdXQodGhpcy5hdXRvQ2xvc2VUaW1lcnMuZ2V0KGlkKSk7XHJcbiAgICAgIHRoaXMuYXV0b0Nsb3NlVGltZXJzLmRlbGV0ZShpZCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBtYXJrQXNSZWFkKG5vdGlmaWNhdGlvbjogTm90aWZpY2F0aW9uKSB7XHJcbiAgICBpZiAoIW5vdGlmaWNhdGlvbi5yZWFkKSB7XHJcbiAgICAgIG5vdGlmaWNhdGlvbi5yZWFkID0gdHJ1ZTtcclxuICAgICAgdGhpcy5ub3RpZmljYXRpb25SZWFkLmVtaXQobm90aWZpY2F0aW9uLmlkKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIG1hcmtBbGxBc1JlYWQoKSB7XHJcbiAgICB0aGlzLm5vdGlmaWNhdGlvbnMuZm9yRWFjaChuID0+IG4ucmVhZCA9IHRydWUpO1xyXG4gICAgdGhpcy5hbGxSZWFkLmVtaXQoKTtcclxuICB9XHJcblxyXG4gIGRpc21pc3NOb3RpZmljYXRpb24obm90aWZpY2F0aW9uOiBOb3RpZmljYXRpb24sIGV2ZW50PzogRXZlbnQpIHtcclxuICAgIGV2ZW50Py5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgIGNvbnN0IGluZGV4ID0gdGhpcy5ub3RpZmljYXRpb25zLmluZGV4T2Yobm90aWZpY2F0aW9uKTtcclxuICAgIGlmIChpbmRleCAhPT0gLTEpIHtcclxuICAgICAgdGhpcy5ub3RpZmljYXRpb25zLnNwbGljZShpbmRleCwgMSk7XHJcbiAgICAgIHRoaXMubm90aWZpY2F0aW9uRGlzbWlzc2VkLmVtaXQobm90aWZpY2F0aW9uLmlkKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGNsZWFyQWxsKCkge1xyXG4gICAgdGhpcy5ub3RpZmljYXRpb25zLmxlbmd0aCA9IDA7XHJcbiAgICB0aGlzLmFsbENsZWFyZWQuZW1pdCgpO1xyXG4gIH1cclxuXHJcbiAgZXhlY3V0ZUFjdGlvbihub3RpZmljYXRpb246IE5vdGlmaWNhdGlvbiwgZXZlbnQ/OiBFdmVudCkge1xyXG4gICAgZXZlbnQ/LnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgXHJcbiAgICBpZiAobm90aWZpY2F0aW9uLmFjdGlvbkNhbGxiYWNrKSB7XHJcbiAgICAgIG5vdGlmaWNhdGlvbi5hY3Rpb25DYWxsYmFjaygpO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICB0aGlzLm5vdGlmaWNhdGlvbkFjdGlvbi5lbWl0KG5vdGlmaWNhdGlvbik7XHJcbiAgICB0aGlzLm1hcmtBc1JlYWQobm90aWZpY2F0aW9uKTtcclxuICB9XHJcblxyXG4gIGdldEljb24odHlwZTogTm90aWZpY2F0aW9uVHlwZSk6IHN0cmluZyB7XHJcbiAgICBjb25zdCBpY29ucyA9IHtcclxuICAgICAgc3VjY2VzczogJ+KchScsXHJcbiAgICAgIGluZm86ICfihLnvuI8nLFxyXG4gICAgICB3YXJuaW5nOiAn4pqg77iPJyxcclxuICAgICAgZXJyb3I6ICfinYwnXHJcbiAgICB9O1xyXG4gICAgcmV0dXJuIGljb25zW3R5cGVdO1xyXG4gIH1cclxuXHJcbiAgZm9ybWF0VGltZXN0YW1wKGRhdGU6IERhdGUpOiBzdHJpbmcge1xyXG4gICAgY29uc3Qgbm93ID0gbmV3IERhdGUoKTtcclxuICAgIGNvbnN0IGRpZmYgPSBub3cuZ2V0VGltZSgpIC0gZGF0ZS5nZXRUaW1lKCk7XHJcbiAgICBcclxuICAgIGNvbnN0IG1pbnV0ZXMgPSBNYXRoLmZsb29yKGRpZmYgLyA2MDAwMCk7XHJcbiAgICBjb25zdCBob3VycyA9IE1hdGguZmxvb3IoZGlmZiAvIDM2MDAwMDApO1xyXG4gICAgY29uc3QgZGF5cyA9IE1hdGguZmxvb3IoZGlmZiAvIDg2NDAwMDAwKTtcclxuICAgIFxyXG4gICAgaWYgKG1pbnV0ZXMgPCAxKSByZXR1cm4gJ0Fnb3JhJztcclxuICAgIGlmIChtaW51dGVzIDwgNjApIHJldHVybiBgJHttaW51dGVzfW0gYXRyw6FzYDtcclxuICAgIGlmIChob3VycyA8IDI0KSByZXR1cm4gYCR7aG91cnN9aCBhdHLDoXNgO1xyXG4gICAgaWYgKGRheXMgPCA3KSByZXR1cm4gYCR7ZGF5c31kIGF0csOhc2A7XHJcbiAgICBcclxuICAgIHJldHVybiBkYXRlLnRvTG9jYWxlRGF0ZVN0cmluZygncHQtQlInLCB7IGRheTogJzItZGlnaXQnLCBtb250aDogJ3Nob3J0JyB9KTtcclxuICB9XHJcblxyXG4gIGdldCBwb3NpdGlvbkNsYXNzKCk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gYHBvc2l0aW9uLSR7dGhpcy5wb3NpdGlvbn1gO1xyXG4gIH1cclxufVxyXG4iLCI8IS0tIE5vdGlmaWNhdGlvbiBCZWxsIEljb24gLS0+XHJcbjxkaXYgY2xhc3M9XCJub3RpZmljYXRpb24tYmVsbFwiIChjbGljayk9XCJ0b2dnbGVQYW5lbCgpXCI+XHJcbiAgPHNwYW4gY2xhc3M9XCJiZWxsLWljb25cIj7wn5SUPC9zcGFuPlxyXG4gIDxzcGFuIGNsYXNzPVwiYmFkZ2VcIiAqbmdJZj1cInNob3dCYWRnZSAmJiB1bnJlYWRDb3VudCA+IDBcIj57eyB1bnJlYWRDb3VudCA+IDk5ID8gJzk5KycgOiB1bnJlYWRDb3VudCB9fTwvc3Bhbj5cclxuPC9kaXY+XHJcblxyXG48IS0tIE5vdGlmaWNhdGlvbiBQYW5lbCAtLT5cclxuPGRpdiBjbGFzcz1cIm5vdGlmaWNhdGlvbi1wYW5lbFwiIFtjbGFzcy5vcGVuXT1cImlzT3BlblwiIFtAc2xpZGVEb3duXT5cclxuICA8ZGl2IGNsYXNzPVwicGFuZWwtaGVhZGVyXCI+XHJcbiAgICA8aDM+Tm90aWZpY2HDp8O1ZXM8L2gzPlxyXG4gICAgPGRpdiBjbGFzcz1cImhlYWRlci1hY3Rpb25zXCI+XHJcbiAgICAgIDxidXR0b24gY2xhc3M9XCJhY3Rpb24tYnRuXCIgKGNsaWNrKT1cIm1hcmtBbGxBc1JlYWQoKVwiICpuZ0lmPVwidW5yZWFkQ291bnQgPiAwXCIgdGl0bGU9XCJNYXJjYXIgdG9kYXMgY29tbyBsaWRhc1wiPlxyXG4gICAgICAgIDxzcGFuPuKckzwvc3Bhbj5cclxuICAgICAgPC9idXR0b24+XHJcbiAgICAgIDxidXR0b24gY2xhc3M9XCJhY3Rpb24tYnRuXCIgKGNsaWNrKT1cImNsZWFyQWxsKClcIiAqbmdJZj1cIm5vdGlmaWNhdGlvbnMubGVuZ3RoID4gMFwiIHRpdGxlPVwiTGltcGFyIHRvZGFzXCI+XHJcbiAgICAgICAgPHNwYW4+8J+Xke+4jzwvc3Bhbj5cclxuICAgICAgPC9idXR0b24+XHJcbiAgICAgIDxidXR0b24gY2xhc3M9XCJhY3Rpb24tYnRuIGNsb3NlLWJ0blwiIChjbGljayk9XCJjbG9zZVBhbmVsKClcIiB0aXRsZT1cIkZlY2hhclwiPlxyXG4gICAgICAgIDxzcGFuPuKclTwvc3Bhbj5cclxuICAgICAgPC9idXR0b24+XHJcbiAgICA8L2Rpdj5cclxuICA8L2Rpdj5cclxuXHJcbiAgPGRpdiBjbGFzcz1cInBhbmVsLWJvZHlcIj5cclxuICAgIDxkaXYgKm5nSWY9XCJub3RpZmljYXRpb25zLmxlbmd0aCA9PT0gMFwiIGNsYXNzPVwiZW1wdHktc3RhdGVcIj5cclxuICAgICAgPGRpdiBjbGFzcz1cImVtcHR5LWljb25cIj7wn5SVPC9kaXY+XHJcbiAgICAgIDxwPk5lbmh1bWEgbm90aWZpY2HDp8OjbzwvcD5cclxuICAgIDwvZGl2PlxyXG5cclxuICAgIDxkaXYgKm5nSWY9XCJub3RpZmljYXRpb25zLmxlbmd0aCA+IDBcIj5cclxuICAgICAgPGRpdiAqbmdGb3I9XCJsZXQgZ3JvdXAgb2YgZ3JvdXBlZE5vdGlmaWNhdGlvbnNcIiBjbGFzcz1cIm5vdGlmaWNhdGlvbi1ncm91cFwiPlxyXG4gICAgICAgIDxoNCBjbGFzcz1cImdyb3VwLXRpdGxlXCIgKm5nSWY9XCJncm91cEJ5Q2F0ZWdvcnlcIj57eyBncm91cC5jYXRlZ29yeSB9fTwvaDQ+XHJcbiAgICAgICAgXHJcbiAgICAgICAgPGRpdiAqbmdGb3I9XCJsZXQgbm90aWZpY2F0aW9uIG9mIGdyb3VwLm5vdGlmaWNhdGlvbnNcIiBcclxuICAgICAgICAgICAgIGNsYXNzPVwibm90aWZpY2F0aW9uLWl0ZW1cIlxyXG4gICAgICAgICAgICAgW2NsYXNzLnVucmVhZF09XCIhbm90aWZpY2F0aW9uLnJlYWRcIlxyXG4gICAgICAgICAgICAgW2NsYXNzLnR5cGUtc3VjY2Vzc109XCJub3RpZmljYXRpb24udHlwZSA9PT0gJ3N1Y2Nlc3MnXCJcclxuICAgICAgICAgICAgIFtjbGFzcy50eXBlLWluZm9dPVwibm90aWZpY2F0aW9uLnR5cGUgPT09ICdpbmZvJ1wiXHJcbiAgICAgICAgICAgICBbY2xhc3MudHlwZS13YXJuaW5nXT1cIm5vdGlmaWNhdGlvbi50eXBlID09PSAnd2FybmluZydcIlxyXG4gICAgICAgICAgICAgW2NsYXNzLnR5cGUtZXJyb3JdPVwibm90aWZpY2F0aW9uLnR5cGUgPT09ICdlcnJvcidcIlxyXG4gICAgICAgICAgICAgKGNsaWNrKT1cIm1hcmtBc1JlYWQobm90aWZpY2F0aW9uKVwiPlxyXG4gICAgICAgICAgXHJcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwibm90aWZpY2F0aW9uLWljb25cIj5cclxuICAgICAgICAgICAgPHNwYW4+e3sgZ2V0SWNvbihub3RpZmljYXRpb24udHlwZSkgfX08L3NwYW4+XHJcbiAgICAgICAgICA8L2Rpdj5cclxuXHJcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwibm90aWZpY2F0aW9uLWNvbnRlbnRcIj5cclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm5vdGlmaWNhdGlvbi1oZWFkZXJcIj5cclxuICAgICAgICAgICAgICA8aDUgY2xhc3M9XCJub3RpZmljYXRpb24tdGl0bGVcIj57eyBub3RpZmljYXRpb24udGl0bGUgfX08L2g1PlxyXG4gICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibm90aWZpY2F0aW9uLXRpbWVcIj57eyBmb3JtYXRUaW1lc3RhbXAobm90aWZpY2F0aW9uLnRpbWVzdGFtcCkgfX08L3NwYW4+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICA8cCBjbGFzcz1cIm5vdGlmaWNhdGlvbi1tZXNzYWdlXCI+e3sgbm90aWZpY2F0aW9uLm1lc3NhZ2UgfX08L3A+XHJcbiAgICAgICAgICAgIFxyXG4gICAgICAgICAgICA8YnV0dG9uICpuZ0lmPVwibm90aWZpY2F0aW9uLmFjdGlvbkxhYmVsXCIgXHJcbiAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJub3RpZmljYXRpb24tYWN0aW9uXCJcclxuICAgICAgICAgICAgICAgICAgICAoY2xpY2spPVwiZXhlY3V0ZUFjdGlvbihub3RpZmljYXRpb24sICRldmVudClcIj5cclxuICAgICAgICAgICAgICB7eyBub3RpZmljYXRpb24uYWN0aW9uTGFiZWwgfX1cclxuICAgICAgICAgICAgPC9idXR0b24+XHJcbiAgICAgICAgICA8L2Rpdj5cclxuXHJcbiAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwiZGlzbWlzcy1idG5cIiAoY2xpY2spPVwiZGlzbWlzc05vdGlmaWNhdGlvbihub3RpZmljYXRpb24sICRldmVudClcIiB0aXRsZT1cIkRpc3BlbnNhclwiPlxyXG4gICAgICAgICAgICA8c3Bhbj7inJU8L3NwYW4+XHJcbiAgICAgICAgICA8L2J1dHRvbj5cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgPC9kaXY+XHJcbiAgICA8L2Rpdj5cclxuICA8L2Rpdj5cclxuPC9kaXY+XHJcblxyXG48IS0tIFRvYXN0IE5vdGlmaWNhdGlvbnMgLS0+XHJcbjxkaXYgY2xhc3M9XCJ0b2FzdC1jb250YWluZXJcIiBbY2xhc3NdPVwicG9zaXRpb25DbGFzc1wiPlxyXG4gIDxkaXYgKm5nRm9yPVwibGV0IHRvYXN0IG9mIGFjdGl2ZVRvYXN0c1wiIFxyXG4gICAgICAgY2xhc3M9XCJ0b2FzdC1ub3RpZmljYXRpb25cIlxyXG4gICAgICAgW2NsYXNzLnR5cGUtc3VjY2Vzc109XCJ0b2FzdC50eXBlID09PSAnc3VjY2VzcydcIlxyXG4gICAgICAgW2NsYXNzLnR5cGUtaW5mb109XCJ0b2FzdC50eXBlID09PSAnaW5mbydcIlxyXG4gICAgICAgW2NsYXNzLnR5cGUtd2FybmluZ109XCJ0b2FzdC50eXBlID09PSAnd2FybmluZydcIlxyXG4gICAgICAgW2NsYXNzLnR5cGUtZXJyb3JdPVwidG9hc3QudHlwZSA9PT0gJ2Vycm9yJ1wiXHJcbiAgICAgICBbQHNsaWRlSW5dPlxyXG4gICAgXHJcbiAgICA8ZGl2IGNsYXNzPVwidG9hc3QtaWNvblwiPlxyXG4gICAgICA8c3Bhbj57eyBnZXRJY29uKHRvYXN0LnR5cGUpIH19PC9zcGFuPlxyXG4gICAgPC9kaXY+XHJcblxyXG4gICAgPGRpdiBjbGFzcz1cInRvYXN0LWNvbnRlbnRcIj5cclxuICAgICAgPGg1IGNsYXNzPVwidG9hc3QtdGl0bGVcIj57eyB0b2FzdC50aXRsZSB9fTwvaDU+XHJcbiAgICAgIDxwIGNsYXNzPVwidG9hc3QtbWVzc2FnZVwiPnt7IHRvYXN0Lm1lc3NhZ2UgfX08L3A+XHJcbiAgICAgIFxyXG4gICAgICA8YnV0dG9uICpuZ0lmPVwidG9hc3QuYWN0aW9uTGFiZWxcIiBcclxuICAgICAgICAgICAgICBjbGFzcz1cInRvYXN0LWFjdGlvblwiXHJcbiAgICAgICAgICAgICAgKGNsaWNrKT1cImV4ZWN1dGVBY3Rpb24odG9hc3QsICRldmVudClcIj5cclxuICAgICAgICB7eyB0b2FzdC5hY3Rpb25MYWJlbCB9fVxyXG4gICAgICA8L2J1dHRvbj5cclxuICAgIDwvZGl2PlxyXG5cclxuICAgIDxidXR0b24gY2xhc3M9XCJ0b2FzdC1jbG9zZVwiIChjbGljayk9XCJkaXNtaXNzVG9hc3QodG9hc3QuaWQpXCIgdGl0bGU9XCJGZWNoYXJcIj5cclxuICAgICAgPHNwYW4+4pyVPC9zcGFuPlxyXG4gICAgPC9idXR0b24+XHJcbiAgPC9kaXY+XHJcbjwvZGl2PlxyXG5cclxuPCEtLSBPdmVybGF5IC0tPlxyXG48ZGl2IGNsYXNzPVwib3ZlcmxheVwiICpuZ0lmPVwiaXNPcGVuXCIgKGNsaWNrKT1cImNsb3NlUGFuZWwoKVwiPjwvZGl2PlxyXG4iXX0=
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated bundle index. Do not edit.
|
|
3
|
+
*/
|
|
4
|
+
export * from './index';
|
|
5
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibXV4aW1hLXVpLW5vdGlmaWNhdGlvbi1jZW50ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9vdmVybGF5L25vdGlmaWNhdGlvbi1jZW50ZXIvc3JjL211eGltYS11aS1ub3RpZmljYXRpb24tY2VudGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxTQUFTLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEdlbmVyYXRlZCBidW5kbGUgaW5kZXguIERvIG5vdCBlZGl0LlxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vaW5kZXgnO1xuIl19
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { EventEmitter, Component, Input, Output } from '@angular/core';
|
|
3
|
+
import * as i1 from '@angular/common';
|
|
4
|
+
import { CommonModule } from '@angular/common';
|
|
5
|
+
import { trigger, transition, style, animate } from '@angular/animations';
|
|
6
|
+
|
|
7
|
+
class NotificationCenterComponent {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.notifications = [];
|
|
10
|
+
this.position = 'top-right';
|
|
11
|
+
this.maxToasts = 3;
|
|
12
|
+
this.defaultDuration = 5000;
|
|
13
|
+
this.showBadge = true;
|
|
14
|
+
this.groupByCategory = false;
|
|
15
|
+
this.notificationRead = new EventEmitter();
|
|
16
|
+
this.notificationDismissed = new EventEmitter();
|
|
17
|
+
this.notificationAction = new EventEmitter();
|
|
18
|
+
this.allRead = new EventEmitter();
|
|
19
|
+
this.allCleared = new EventEmitter();
|
|
20
|
+
this.isOpen = false;
|
|
21
|
+
this.activeToasts = [];
|
|
22
|
+
this.autoCloseTimers = new Map();
|
|
23
|
+
}
|
|
24
|
+
ngOnDestroy() {
|
|
25
|
+
this.autoCloseTimers.forEach(timer => clearTimeout(timer));
|
|
26
|
+
}
|
|
27
|
+
togglePanel() {
|
|
28
|
+
this.isOpen = !this.isOpen;
|
|
29
|
+
}
|
|
30
|
+
closePanel() {
|
|
31
|
+
this.isOpen = false;
|
|
32
|
+
}
|
|
33
|
+
get unreadCount() {
|
|
34
|
+
return this.notifications.filter(n => !n.read).length;
|
|
35
|
+
}
|
|
36
|
+
get groupedNotifications() {
|
|
37
|
+
if (!this.groupByCategory) {
|
|
38
|
+
return [{ category: 'all', notifications: this.notifications }];
|
|
39
|
+
}
|
|
40
|
+
const groups = new Map();
|
|
41
|
+
this.notifications.forEach(notification => {
|
|
42
|
+
const category = notification.category || 'Outros';
|
|
43
|
+
if (!groups.has(category)) {
|
|
44
|
+
groups.set(category, []);
|
|
45
|
+
}
|
|
46
|
+
groups.get(category).push(notification);
|
|
47
|
+
});
|
|
48
|
+
return Array.from(groups.entries()).map(([category, notifications]) => ({
|
|
49
|
+
category,
|
|
50
|
+
notifications
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
showToast(notification) {
|
|
54
|
+
// Add to active toasts
|
|
55
|
+
if (this.activeToasts.length >= this.maxToasts) {
|
|
56
|
+
this.activeToasts.shift();
|
|
57
|
+
}
|
|
58
|
+
this.activeToasts.push(notification);
|
|
59
|
+
// Auto close if enabled
|
|
60
|
+
if (notification.autoClose !== false) {
|
|
61
|
+
const duration = notification.duration || this.defaultDuration;
|
|
62
|
+
const timer = setTimeout(() => {
|
|
63
|
+
this.dismissToast(notification.id);
|
|
64
|
+
}, duration);
|
|
65
|
+
this.autoCloseTimers.set(notification.id, timer);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
dismissToast(id) {
|
|
69
|
+
const index = this.activeToasts.findIndex(t => t.id === id);
|
|
70
|
+
if (index !== -1) {
|
|
71
|
+
this.activeToasts.splice(index, 1);
|
|
72
|
+
}
|
|
73
|
+
if (this.autoCloseTimers.has(id)) {
|
|
74
|
+
clearTimeout(this.autoCloseTimers.get(id));
|
|
75
|
+
this.autoCloseTimers.delete(id);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
markAsRead(notification) {
|
|
79
|
+
if (!notification.read) {
|
|
80
|
+
notification.read = true;
|
|
81
|
+
this.notificationRead.emit(notification.id);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
markAllAsRead() {
|
|
85
|
+
this.notifications.forEach(n => n.read = true);
|
|
86
|
+
this.allRead.emit();
|
|
87
|
+
}
|
|
88
|
+
dismissNotification(notification, event) {
|
|
89
|
+
event === null || event === void 0 ? void 0 : event.stopPropagation();
|
|
90
|
+
const index = this.notifications.indexOf(notification);
|
|
91
|
+
if (index !== -1) {
|
|
92
|
+
this.notifications.splice(index, 1);
|
|
93
|
+
this.notificationDismissed.emit(notification.id);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
clearAll() {
|
|
97
|
+
this.notifications.length = 0;
|
|
98
|
+
this.allCleared.emit();
|
|
99
|
+
}
|
|
100
|
+
executeAction(notification, event) {
|
|
101
|
+
event === null || event === void 0 ? void 0 : event.stopPropagation();
|
|
102
|
+
if (notification.actionCallback) {
|
|
103
|
+
notification.actionCallback();
|
|
104
|
+
}
|
|
105
|
+
this.notificationAction.emit(notification);
|
|
106
|
+
this.markAsRead(notification);
|
|
107
|
+
}
|
|
108
|
+
getIcon(type) {
|
|
109
|
+
const icons = {
|
|
110
|
+
success: '✅',
|
|
111
|
+
info: 'ℹ️',
|
|
112
|
+
warning: '⚠️',
|
|
113
|
+
error: '❌'
|
|
114
|
+
};
|
|
115
|
+
return icons[type];
|
|
116
|
+
}
|
|
117
|
+
formatTimestamp(date) {
|
|
118
|
+
const now = new Date();
|
|
119
|
+
const diff = now.getTime() - date.getTime();
|
|
120
|
+
const minutes = Math.floor(diff / 60000);
|
|
121
|
+
const hours = Math.floor(diff / 3600000);
|
|
122
|
+
const days = Math.floor(diff / 86400000);
|
|
123
|
+
if (minutes < 1)
|
|
124
|
+
return 'Agora';
|
|
125
|
+
if (minutes < 60)
|
|
126
|
+
return `${minutes}m atrás`;
|
|
127
|
+
if (hours < 24)
|
|
128
|
+
return `${hours}h atrás`;
|
|
129
|
+
if (days < 7)
|
|
130
|
+
return `${days}d atrás`;
|
|
131
|
+
return date.toLocaleDateString('pt-BR', { day: '2-digit', month: 'short' });
|
|
132
|
+
}
|
|
133
|
+
get positionClass() {
|
|
134
|
+
return `position-${this.position}`;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
NotificationCenterComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NotificationCenterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
138
|
+
NotificationCenterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: NotificationCenterComponent, isStandalone: true, selector: "muxima-notification-center", inputs: { notifications: "notifications", position: "position", maxToasts: "maxToasts", defaultDuration: "defaultDuration", showBadge: "showBadge", groupByCategory: "groupByCategory" }, outputs: { notificationRead: "notificationRead", notificationDismissed: "notificationDismissed", notificationAction: "notificationAction", allRead: "allRead", allCleared: "allCleared" }, ngImport: i0, template: "<!-- Notification Bell Icon -->\r\n<div class=\"notification-bell\" (click)=\"togglePanel()\">\r\n <span class=\"bell-icon\">\uD83D\uDD14</span>\r\n <span class=\"badge\" *ngIf=\"showBadge && unreadCount > 0\">{{ unreadCount > 99 ? '99+' : unreadCount }}</span>\r\n</div>\r\n\r\n<!-- Notification Panel -->\r\n<div class=\"notification-panel\" [class.open]=\"isOpen\" [@slideDown]>\r\n <div class=\"panel-header\">\r\n <h3>Notifica\u00E7\u00F5es</h3>\r\n <div class=\"header-actions\">\r\n <button class=\"action-btn\" (click)=\"markAllAsRead()\" *ngIf=\"unreadCount > 0\" title=\"Marcar todas como lidas\">\r\n <span>\u2713</span>\r\n </button>\r\n <button class=\"action-btn\" (click)=\"clearAll()\" *ngIf=\"notifications.length > 0\" title=\"Limpar todas\">\r\n <span>\uD83D\uDDD1\uFE0F</span>\r\n </button>\r\n <button class=\"action-btn close-btn\" (click)=\"closePanel()\" title=\"Fechar\">\r\n <span>\u2715</span>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"panel-body\">\r\n <div *ngIf=\"notifications.length === 0\" class=\"empty-state\">\r\n <div class=\"empty-icon\">\uD83D\uDD15</div>\r\n <p>Nenhuma notifica\u00E7\u00E3o</p>\r\n </div>\r\n\r\n <div *ngIf=\"notifications.length > 0\">\r\n <div *ngFor=\"let group of groupedNotifications\" class=\"notification-group\">\r\n <h4 class=\"group-title\" *ngIf=\"groupByCategory\">{{ group.category }}</h4>\r\n \r\n <div *ngFor=\"let notification of group.notifications\" \r\n class=\"notification-item\"\r\n [class.unread]=\"!notification.read\"\r\n [class.type-success]=\"notification.type === 'success'\"\r\n [class.type-info]=\"notification.type === 'info'\"\r\n [class.type-warning]=\"notification.type === 'warning'\"\r\n [class.type-error]=\"notification.type === 'error'\"\r\n (click)=\"markAsRead(notification)\">\r\n \r\n <div class=\"notification-icon\">\r\n <span>{{ getIcon(notification.type) }}</span>\r\n </div>\r\n\r\n <div class=\"notification-content\">\r\n <div class=\"notification-header\">\r\n <h5 class=\"notification-title\">{{ notification.title }}</h5>\r\n <span class=\"notification-time\">{{ formatTimestamp(notification.timestamp) }}</span>\r\n </div>\r\n <p class=\"notification-message\">{{ notification.message }}</p>\r\n \r\n <button *ngIf=\"notification.actionLabel\" \r\n class=\"notification-action\"\r\n (click)=\"executeAction(notification, $event)\">\r\n {{ notification.actionLabel }}\r\n </button>\r\n </div>\r\n\r\n <button class=\"dismiss-btn\" (click)=\"dismissNotification(notification, $event)\" title=\"Dispensar\">\r\n <span>\u2715</span>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Toast Notifications -->\r\n<div class=\"toast-container\" [class]=\"positionClass\">\r\n <div *ngFor=\"let toast of activeToasts\" \r\n class=\"toast-notification\"\r\n [class.type-success]=\"toast.type === 'success'\"\r\n [class.type-info]=\"toast.type === 'info'\"\r\n [class.type-warning]=\"toast.type === 'warning'\"\r\n [class.type-error]=\"toast.type === 'error'\"\r\n [@slideIn]>\r\n \r\n <div class=\"toast-icon\">\r\n <span>{{ getIcon(toast.type) }}</span>\r\n </div>\r\n\r\n <div class=\"toast-content\">\r\n <h5 class=\"toast-title\">{{ toast.title }}</h5>\r\n <p class=\"toast-message\">{{ toast.message }}</p>\r\n \r\n <button *ngIf=\"toast.actionLabel\" \r\n class=\"toast-action\"\r\n (click)=\"executeAction(toast, $event)\">\r\n {{ toast.actionLabel }}\r\n </button>\r\n </div>\r\n\r\n <button class=\"toast-close\" (click)=\"dismissToast(toast.id)\" title=\"Fechar\">\r\n <span>\u2715</span>\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<!-- Overlay -->\r\n<div class=\"overlay\" *ngIf=\"isOpen\" (click)=\"closePanel()\"></div>\r\n", styles: [".notification-bell{position:relative;display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);border-radius:50%;cursor:pointer;transition:all .3s ease;box-shadow:0 4px 8px #667eea4d}.notification-bell:hover{transform:scale(1.1);box-shadow:0 6px 12px #667eea66}.notification-bell:active{transform:scale(.95)}.notification-bell .bell-icon{font-size:1.5rem;animation:ring 2s ease-in-out infinite}.notification-bell .badge{position:absolute;top:-4px;right:-4px;min-width:20px;height:20px;padding:0 4px;background:#ef4444;color:#fff;font-size:.75rem;font-weight:700;border-radius:10px;display:flex;align-items:center;justify-content:center;border:2px solid white;animation:pulse 2s ease-in-out infinite}@keyframes ring{0%,to{transform:rotate(0)}10%,30%{transform:rotate(-10deg)}20%,40%{transform:rotate(10deg)}}@keyframes pulse{0%,to{transform:scale(1)}50%{transform:scale(1.1)}}.notification-panel{position:fixed;top:60px;right:20px;width:400px;max-height:600px;background:white;border-radius:12px;box-shadow:0 10px 25px #0003;transform:translateY(-20px);opacity:0;pointer-events:none;transition:all .3s ease;z-index:1000;display:flex;flex-direction:column}.notification-panel.open{transform:translateY(0);opacity:1;pointer-events:all}.panel-header{padding:1.25rem;border-bottom:1px solid #e5e7eb;display:flex;align-items:center;justify-content:space-between}.panel-header h3{font-size:1.25rem;font-weight:700;color:#111827;margin:0}.panel-header .header-actions{display:flex;gap:.5rem}.panel-header .action-btn{padding:.5rem;background:transparent;border:none;color:#6b7280;font-size:1rem;cursor:pointer;border-radius:6px;transition:all .2s ease;display:flex;align-items:center;justify-content:center}.panel-header .action-btn:hover{background:#f3f4f6;color:#667eea}.panel-header .action-btn.close-btn:hover{color:#ef4444}.panel-body{flex:1;overflow-y:auto;max-height:500px}.panel-body::-webkit-scrollbar{width:6px}.panel-body::-webkit-scrollbar-track{background:#f3f4f6}.panel-body::-webkit-scrollbar-thumb{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);border-radius:3px}.empty-state{padding:3rem 1.5rem;text-align:center}.empty-state .empty-icon{font-size:3rem;margin-bottom:1rem;opacity:.5}.empty-state p{color:#9ca3af;font-size:1rem}.notification-group .group-title{padding:.75rem 1.25rem;font-size:.875rem;font-weight:600;color:#667eea;text-transform:uppercase;letter-spacing:.05em;background:#f9fafb;border-bottom:1px solid #e5e7eb;margin:0}.notification-item{display:flex;gap:1rem;padding:1rem 1.25rem;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:all .2s ease;position:relative}.notification-item:last-child{border-bottom:none}.notification-item:hover{background:#f9fafb}.notification-item.unread{background:rgba(102,126,234,.05)}.notification-item.unread:before{content:\"\";position:absolute;left:0;top:0;bottom:0;width:4px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%)}.notification-item.type-success .notification-icon{color:#10b981}.notification-item.type-info .notification-icon{color:#3b82f6}.notification-item.type-warning .notification-icon{color:#f59e0b}.notification-item.type-error .notification-icon{color:#ef4444}.notification-item .notification-icon{font-size:1.5rem;flex-shrink:0}.notification-item .notification-content{flex:1;min-width:0}.notification-item .notification-header{display:flex;align-items:flex-start;justify-content:space-between;gap:.5rem;margin-bottom:.5rem}.notification-item .notification-title{font-size:.875rem;font-weight:600;color:#111827;margin:0}.notification-item .notification-time{font-size:.75rem;color:#9ca3af;white-space:nowrap}.notification-item .notification-message{font-size:.875rem;color:#6b7280;margin:0 0 .75rem;line-height:1.5}.notification-item .notification-action{padding:.375rem .75rem;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border:none;border-radius:6px;font-size:.75rem;font-weight:600;cursor:pointer;transition:all .2s ease}.notification-item .notification-action:hover{transform:translateY(-1px);box-shadow:0 4px 8px #667eea4d}.notification-item .dismiss-btn{padding:.25rem;background:transparent;border:none;color:#9ca3af;font-size:1rem;cursor:pointer;border-radius:4px;transition:all .2s ease;flex-shrink:0}.notification-item .dismiss-btn:hover{background:#f3f4f6;color:#ef4444}.toast-container{position:fixed;z-index:9999;display:flex;flex-direction:column;gap:1rem;pointer-events:none}.toast-container.position-top-right{top:20px;right:20px}.toast-container.position-top-left{top:20px;left:20px}.toast-container.position-bottom-right{bottom:20px;right:20px}.toast-container.position-bottom-left{bottom:20px;left:20px}.toast-container.position-top-center{top:20px;left:50%;transform:translate(-50%)}.toast-container.position-bottom-center{bottom:20px;left:50%;transform:translate(-50%)}.toast-notification{display:flex;align-items:flex-start;gap:1rem;min-width:350px;max-width:450px;padding:1rem 1.25rem;background:white;border-radius:12px;box-shadow:0 10px 25px #00000026;pointer-events:all;border-left:4px solid}.toast-notification.type-success{border-left-color:#10b981}.toast-notification.type-success .toast-icon{color:#10b981}.toast-notification.type-info{border-left-color:#3b82f6}.toast-notification.type-info .toast-icon{color:#3b82f6}.toast-notification.type-warning{border-left-color:#f59e0b}.toast-notification.type-warning .toast-icon{color:#f59e0b}.toast-notification.type-error{border-left-color:#ef4444}.toast-notification.type-error .toast-icon{color:#ef4444}.toast-notification .toast-icon{font-size:1.5rem;flex-shrink:0}.toast-notification .toast-content{flex:1;min-width:0}.toast-notification .toast-title{font-size:.875rem;font-weight:600;color:#111827;margin:0 0 .25rem}.toast-notification .toast-message{font-size:.875rem;color:#6b7280;margin:0 0 .75rem;line-height:1.5}.toast-notification .toast-action{padding:.375rem .75rem;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border:none;border-radius:6px;font-size:.75rem;font-weight:600;cursor:pointer;transition:all .2s ease}.toast-notification .toast-action:hover{transform:translateY(-1px);box-shadow:0 4px 8px #667eea4d}.toast-notification .toast-close{padding:.25rem;background:transparent;border:none;color:#9ca3af;font-size:1rem;cursor:pointer;border-radius:4px;transition:all .2s ease;flex-shrink:0}.toast-notification .toast-close:hover{background:#f3f4f6;color:#ef4444}.overlay{position:fixed;inset:0;background:rgba(0,0,0,.3);z-index:999;animation:fadeIn .3s ease}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@media (max-width: 768px){.notification-panel{right:10px;left:10px;width:auto}.toast-notification{min-width:300px;max-width:350px}.toast-container.position-top-right,.toast-container.position-top-left,.toast-container.position-top-center{top:10px;left:10px;right:10px;transform:none}.toast-container.position-bottom-right,.toast-container.position-bottom-left,.toast-container.position-bottom-center{bottom:10px;left:10px;right:10px;transform:none}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], animations: [
|
|
139
|
+
trigger('slideIn', [
|
|
140
|
+
transition(':enter', [
|
|
141
|
+
style({ transform: 'translateX(100%)', opacity: 0 }),
|
|
142
|
+
animate('300ms ease-out', style({ transform: 'translateX(0)', opacity: 1 }))
|
|
143
|
+
]),
|
|
144
|
+
transition(':leave', [
|
|
145
|
+
animate('300ms ease-in', style({ transform: 'translateX(100%)', opacity: 0 }))
|
|
146
|
+
])
|
|
147
|
+
]),
|
|
148
|
+
trigger('slideDown', [
|
|
149
|
+
transition(':enter', [
|
|
150
|
+
style({ height: 0, opacity: 0 }),
|
|
151
|
+
animate('200ms ease-out', style({ height: '*', opacity: 1 }))
|
|
152
|
+
]),
|
|
153
|
+
transition(':leave', [
|
|
154
|
+
animate('200ms ease-in', style({ height: 0, opacity: 0 }))
|
|
155
|
+
])
|
|
156
|
+
])
|
|
157
|
+
] });
|
|
158
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NotificationCenterComponent, decorators: [{
|
|
159
|
+
type: Component,
|
|
160
|
+
args: [{ selector: 'muxima-notification-center', standalone: true, imports: [CommonModule], animations: [
|
|
161
|
+
trigger('slideIn', [
|
|
162
|
+
transition(':enter', [
|
|
163
|
+
style({ transform: 'translateX(100%)', opacity: 0 }),
|
|
164
|
+
animate('300ms ease-out', style({ transform: 'translateX(0)', opacity: 1 }))
|
|
165
|
+
]),
|
|
166
|
+
transition(':leave', [
|
|
167
|
+
animate('300ms ease-in', style({ transform: 'translateX(100%)', opacity: 0 }))
|
|
168
|
+
])
|
|
169
|
+
]),
|
|
170
|
+
trigger('slideDown', [
|
|
171
|
+
transition(':enter', [
|
|
172
|
+
style({ height: 0, opacity: 0 }),
|
|
173
|
+
animate('200ms ease-out', style({ height: '*', opacity: 1 }))
|
|
174
|
+
]),
|
|
175
|
+
transition(':leave', [
|
|
176
|
+
animate('200ms ease-in', style({ height: 0, opacity: 0 }))
|
|
177
|
+
])
|
|
178
|
+
])
|
|
179
|
+
], template: "<!-- Notification Bell Icon -->\r\n<div class=\"notification-bell\" (click)=\"togglePanel()\">\r\n <span class=\"bell-icon\">\uD83D\uDD14</span>\r\n <span class=\"badge\" *ngIf=\"showBadge && unreadCount > 0\">{{ unreadCount > 99 ? '99+' : unreadCount }}</span>\r\n</div>\r\n\r\n<!-- Notification Panel -->\r\n<div class=\"notification-panel\" [class.open]=\"isOpen\" [@slideDown]>\r\n <div class=\"panel-header\">\r\n <h3>Notifica\u00E7\u00F5es</h3>\r\n <div class=\"header-actions\">\r\n <button class=\"action-btn\" (click)=\"markAllAsRead()\" *ngIf=\"unreadCount > 0\" title=\"Marcar todas como lidas\">\r\n <span>\u2713</span>\r\n </button>\r\n <button class=\"action-btn\" (click)=\"clearAll()\" *ngIf=\"notifications.length > 0\" title=\"Limpar todas\">\r\n <span>\uD83D\uDDD1\uFE0F</span>\r\n </button>\r\n <button class=\"action-btn close-btn\" (click)=\"closePanel()\" title=\"Fechar\">\r\n <span>\u2715</span>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"panel-body\">\r\n <div *ngIf=\"notifications.length === 0\" class=\"empty-state\">\r\n <div class=\"empty-icon\">\uD83D\uDD15</div>\r\n <p>Nenhuma notifica\u00E7\u00E3o</p>\r\n </div>\r\n\r\n <div *ngIf=\"notifications.length > 0\">\r\n <div *ngFor=\"let group of groupedNotifications\" class=\"notification-group\">\r\n <h4 class=\"group-title\" *ngIf=\"groupByCategory\">{{ group.category }}</h4>\r\n \r\n <div *ngFor=\"let notification of group.notifications\" \r\n class=\"notification-item\"\r\n [class.unread]=\"!notification.read\"\r\n [class.type-success]=\"notification.type === 'success'\"\r\n [class.type-info]=\"notification.type === 'info'\"\r\n [class.type-warning]=\"notification.type === 'warning'\"\r\n [class.type-error]=\"notification.type === 'error'\"\r\n (click)=\"markAsRead(notification)\">\r\n \r\n <div class=\"notification-icon\">\r\n <span>{{ getIcon(notification.type) }}</span>\r\n </div>\r\n\r\n <div class=\"notification-content\">\r\n <div class=\"notification-header\">\r\n <h5 class=\"notification-title\">{{ notification.title }}</h5>\r\n <span class=\"notification-time\">{{ formatTimestamp(notification.timestamp) }}</span>\r\n </div>\r\n <p class=\"notification-message\">{{ notification.message }}</p>\r\n \r\n <button *ngIf=\"notification.actionLabel\" \r\n class=\"notification-action\"\r\n (click)=\"executeAction(notification, $event)\">\r\n {{ notification.actionLabel }}\r\n </button>\r\n </div>\r\n\r\n <button class=\"dismiss-btn\" (click)=\"dismissNotification(notification, $event)\" title=\"Dispensar\">\r\n <span>\u2715</span>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Toast Notifications -->\r\n<div class=\"toast-container\" [class]=\"positionClass\">\r\n <div *ngFor=\"let toast of activeToasts\" \r\n class=\"toast-notification\"\r\n [class.type-success]=\"toast.type === 'success'\"\r\n [class.type-info]=\"toast.type === 'info'\"\r\n [class.type-warning]=\"toast.type === 'warning'\"\r\n [class.type-error]=\"toast.type === 'error'\"\r\n [@slideIn]>\r\n \r\n <div class=\"toast-icon\">\r\n <span>{{ getIcon(toast.type) }}</span>\r\n </div>\r\n\r\n <div class=\"toast-content\">\r\n <h5 class=\"toast-title\">{{ toast.title }}</h5>\r\n <p class=\"toast-message\">{{ toast.message }}</p>\r\n \r\n <button *ngIf=\"toast.actionLabel\" \r\n class=\"toast-action\"\r\n (click)=\"executeAction(toast, $event)\">\r\n {{ toast.actionLabel }}\r\n </button>\r\n </div>\r\n\r\n <button class=\"toast-close\" (click)=\"dismissToast(toast.id)\" title=\"Fechar\">\r\n <span>\u2715</span>\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<!-- Overlay -->\r\n<div class=\"overlay\" *ngIf=\"isOpen\" (click)=\"closePanel()\"></div>\r\n", styles: [".notification-bell{position:relative;display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);border-radius:50%;cursor:pointer;transition:all .3s ease;box-shadow:0 4px 8px #667eea4d}.notification-bell:hover{transform:scale(1.1);box-shadow:0 6px 12px #667eea66}.notification-bell:active{transform:scale(.95)}.notification-bell .bell-icon{font-size:1.5rem;animation:ring 2s ease-in-out infinite}.notification-bell .badge{position:absolute;top:-4px;right:-4px;min-width:20px;height:20px;padding:0 4px;background:#ef4444;color:#fff;font-size:.75rem;font-weight:700;border-radius:10px;display:flex;align-items:center;justify-content:center;border:2px solid white;animation:pulse 2s ease-in-out infinite}@keyframes ring{0%,to{transform:rotate(0)}10%,30%{transform:rotate(-10deg)}20%,40%{transform:rotate(10deg)}}@keyframes pulse{0%,to{transform:scale(1)}50%{transform:scale(1.1)}}.notification-panel{position:fixed;top:60px;right:20px;width:400px;max-height:600px;background:white;border-radius:12px;box-shadow:0 10px 25px #0003;transform:translateY(-20px);opacity:0;pointer-events:none;transition:all .3s ease;z-index:1000;display:flex;flex-direction:column}.notification-panel.open{transform:translateY(0);opacity:1;pointer-events:all}.panel-header{padding:1.25rem;border-bottom:1px solid #e5e7eb;display:flex;align-items:center;justify-content:space-between}.panel-header h3{font-size:1.25rem;font-weight:700;color:#111827;margin:0}.panel-header .header-actions{display:flex;gap:.5rem}.panel-header .action-btn{padding:.5rem;background:transparent;border:none;color:#6b7280;font-size:1rem;cursor:pointer;border-radius:6px;transition:all .2s ease;display:flex;align-items:center;justify-content:center}.panel-header .action-btn:hover{background:#f3f4f6;color:#667eea}.panel-header .action-btn.close-btn:hover{color:#ef4444}.panel-body{flex:1;overflow-y:auto;max-height:500px}.panel-body::-webkit-scrollbar{width:6px}.panel-body::-webkit-scrollbar-track{background:#f3f4f6}.panel-body::-webkit-scrollbar-thumb{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);border-radius:3px}.empty-state{padding:3rem 1.5rem;text-align:center}.empty-state .empty-icon{font-size:3rem;margin-bottom:1rem;opacity:.5}.empty-state p{color:#9ca3af;font-size:1rem}.notification-group .group-title{padding:.75rem 1.25rem;font-size:.875rem;font-weight:600;color:#667eea;text-transform:uppercase;letter-spacing:.05em;background:#f9fafb;border-bottom:1px solid #e5e7eb;margin:0}.notification-item{display:flex;gap:1rem;padding:1rem 1.25rem;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:all .2s ease;position:relative}.notification-item:last-child{border-bottom:none}.notification-item:hover{background:#f9fafb}.notification-item.unread{background:rgba(102,126,234,.05)}.notification-item.unread:before{content:\"\";position:absolute;left:0;top:0;bottom:0;width:4px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%)}.notification-item.type-success .notification-icon{color:#10b981}.notification-item.type-info .notification-icon{color:#3b82f6}.notification-item.type-warning .notification-icon{color:#f59e0b}.notification-item.type-error .notification-icon{color:#ef4444}.notification-item .notification-icon{font-size:1.5rem;flex-shrink:0}.notification-item .notification-content{flex:1;min-width:0}.notification-item .notification-header{display:flex;align-items:flex-start;justify-content:space-between;gap:.5rem;margin-bottom:.5rem}.notification-item .notification-title{font-size:.875rem;font-weight:600;color:#111827;margin:0}.notification-item .notification-time{font-size:.75rem;color:#9ca3af;white-space:nowrap}.notification-item .notification-message{font-size:.875rem;color:#6b7280;margin:0 0 .75rem;line-height:1.5}.notification-item .notification-action{padding:.375rem .75rem;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border:none;border-radius:6px;font-size:.75rem;font-weight:600;cursor:pointer;transition:all .2s ease}.notification-item .notification-action:hover{transform:translateY(-1px);box-shadow:0 4px 8px #667eea4d}.notification-item .dismiss-btn{padding:.25rem;background:transparent;border:none;color:#9ca3af;font-size:1rem;cursor:pointer;border-radius:4px;transition:all .2s ease;flex-shrink:0}.notification-item .dismiss-btn:hover{background:#f3f4f6;color:#ef4444}.toast-container{position:fixed;z-index:9999;display:flex;flex-direction:column;gap:1rem;pointer-events:none}.toast-container.position-top-right{top:20px;right:20px}.toast-container.position-top-left{top:20px;left:20px}.toast-container.position-bottom-right{bottom:20px;right:20px}.toast-container.position-bottom-left{bottom:20px;left:20px}.toast-container.position-top-center{top:20px;left:50%;transform:translate(-50%)}.toast-container.position-bottom-center{bottom:20px;left:50%;transform:translate(-50%)}.toast-notification{display:flex;align-items:flex-start;gap:1rem;min-width:350px;max-width:450px;padding:1rem 1.25rem;background:white;border-radius:12px;box-shadow:0 10px 25px #00000026;pointer-events:all;border-left:4px solid}.toast-notification.type-success{border-left-color:#10b981}.toast-notification.type-success .toast-icon{color:#10b981}.toast-notification.type-info{border-left-color:#3b82f6}.toast-notification.type-info .toast-icon{color:#3b82f6}.toast-notification.type-warning{border-left-color:#f59e0b}.toast-notification.type-warning .toast-icon{color:#f59e0b}.toast-notification.type-error{border-left-color:#ef4444}.toast-notification.type-error .toast-icon{color:#ef4444}.toast-notification .toast-icon{font-size:1.5rem;flex-shrink:0}.toast-notification .toast-content{flex:1;min-width:0}.toast-notification .toast-title{font-size:.875rem;font-weight:600;color:#111827;margin:0 0 .25rem}.toast-notification .toast-message{font-size:.875rem;color:#6b7280;margin:0 0 .75rem;line-height:1.5}.toast-notification .toast-action{padding:.375rem .75rem;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border:none;border-radius:6px;font-size:.75rem;font-weight:600;cursor:pointer;transition:all .2s ease}.toast-notification .toast-action:hover{transform:translateY(-1px);box-shadow:0 4px 8px #667eea4d}.toast-notification .toast-close{padding:.25rem;background:transparent;border:none;color:#9ca3af;font-size:1rem;cursor:pointer;border-radius:4px;transition:all .2s ease;flex-shrink:0}.toast-notification .toast-close:hover{background:#f3f4f6;color:#ef4444}.overlay{position:fixed;inset:0;background:rgba(0,0,0,.3);z-index:999;animation:fadeIn .3s ease}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@media (max-width: 768px){.notification-panel{right:10px;left:10px;width:auto}.toast-notification{min-width:300px;max-width:350px}.toast-container.position-top-right,.toast-container.position-top-left,.toast-container.position-top-center{top:10px;left:10px;right:10px;transform:none}.toast-container.position-bottom-right,.toast-container.position-bottom-left,.toast-container.position-bottom-center{bottom:10px;left:10px;right:10px;transform:none}}\n"] }]
|
|
180
|
+
}], propDecorators: { notifications: [{
|
|
181
|
+
type: Input
|
|
182
|
+
}], position: [{
|
|
183
|
+
type: Input
|
|
184
|
+
}], maxToasts: [{
|
|
185
|
+
type: Input
|
|
186
|
+
}], defaultDuration: [{
|
|
187
|
+
type: Input
|
|
188
|
+
}], showBadge: [{
|
|
189
|
+
type: Input
|
|
190
|
+
}], groupByCategory: [{
|
|
191
|
+
type: Input
|
|
192
|
+
}], notificationRead: [{
|
|
193
|
+
type: Output
|
|
194
|
+
}], notificationDismissed: [{
|
|
195
|
+
type: Output
|
|
196
|
+
}], notificationAction: [{
|
|
197
|
+
type: Output
|
|
198
|
+
}], allRead: [{
|
|
199
|
+
type: Output
|
|
200
|
+
}], allCleared: [{
|
|
201
|
+
type: Output
|
|
202
|
+
}] } });
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Generated bundle index. Do not edit.
|
|
206
|
+
*/
|
|
207
|
+
|
|
208
|
+
export { NotificationCenterComponent };
|
|
209
|
+
//# sourceMappingURL=muxima-ui-notification-center.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"muxima-ui-notification-center.mjs","sources":["../../../../overlay/notification-center/src/lib/notification-center/notification-center.component.ts","../../../../overlay/notification-center/src/lib/notification-center/notification-center.component.html","../../../../overlay/notification-center/src/muxima-ui-notification-center.ts"],"sourcesContent":["import { Component, Input, Output, EventEmitter, OnDestroy } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { trigger, transition, style, animate, state } from '@angular/animations';\r\n\r\nexport type NotificationType = 'success' | 'info' | 'warning' | 'error';\r\nexport type NotificationPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'top-center' | 'bottom-center';\r\n\r\nexport interface Notification {\r\n id: string;\r\n type: NotificationType;\r\n title: string;\r\n message: string;\r\n timestamp: Date;\r\n read: boolean;\r\n category?: string;\r\n actionLabel?: string;\r\n actionCallback?: () => void;\r\n autoClose?: boolean;\r\n duration?: number;\r\n}\r\n\r\n@Component({\r\n selector: 'muxima-notification-center',\r\n standalone: true,\r\n imports: [CommonModule],\r\n templateUrl: './notification-center.component.html',\r\n styleUrls: ['./notification-center.component.scss'],\r\n animations: [\r\n trigger('slideIn', [\r\n transition(':enter', [\r\n style({ transform: 'translateX(100%)', opacity: 0 }),\r\n animate('300ms ease-out', style({ transform: 'translateX(0)', opacity: 1 }))\r\n ]),\r\n transition(':leave', [\r\n animate('300ms ease-in', style({ transform: 'translateX(100%)', opacity: 0 }))\r\n ])\r\n ]),\r\n trigger('slideDown', [\r\n transition(':enter', [\r\n style({ height: 0, opacity: 0 }),\r\n animate('200ms ease-out', style({ height: '*', opacity: 1 }))\r\n ]),\r\n transition(':leave', [\r\n animate('200ms ease-in', style({ height: 0, opacity: 0 }))\r\n ])\r\n ])\r\n ]\r\n})\r\nexport class NotificationCenterComponent implements OnDestroy {\r\n @Input() notifications: Notification[] = [];\r\n @Input() position: NotificationPosition = 'top-right';\r\n @Input() maxToasts: number = 3;\r\n @Input() defaultDuration: number = 5000;\r\n @Input() showBadge: boolean = true;\r\n @Input() groupByCategory: boolean = false;\r\n\r\n @Output() notificationRead = new EventEmitter<string>();\r\n @Output() notificationDismissed = new EventEmitter<string>();\r\n @Output() notificationAction = new EventEmitter<Notification>();\r\n @Output() allRead = new EventEmitter<void>();\r\n @Output() allCleared = new EventEmitter<void>();\r\n\r\n isOpen = false;\r\n activeToasts: Notification[] = [];\r\n private autoCloseTimers = new Map<string, any>();\r\n\r\n ngOnDestroy() {\r\n this.autoCloseTimers.forEach(timer => clearTimeout(timer));\r\n }\r\n\r\n togglePanel() {\r\n this.isOpen = !this.isOpen;\r\n }\r\n\r\n closePanel() {\r\n this.isOpen = false;\r\n }\r\n\r\n get unreadCount(): number {\r\n return this.notifications.filter(n => !n.read).length;\r\n }\r\n\r\n get groupedNotifications(): { category: string; notifications: Notification[] }[] {\r\n if (!this.groupByCategory) {\r\n return [{ category: 'all', notifications: this.notifications }];\r\n }\r\n\r\n const groups = new Map<string, Notification[]>();\r\n \r\n this.notifications.forEach(notification => {\r\n const category = notification.category || 'Outros';\r\n if (!groups.has(category)) {\r\n groups.set(category, []);\r\n }\r\n groups.get(category)!.push(notification);\r\n });\r\n\r\n return Array.from(groups.entries()).map(([category, notifications]) => ({\r\n category,\r\n notifications\r\n }));\r\n }\r\n\r\n showToast(notification: Notification) {\r\n // Add to active toasts\r\n if (this.activeToasts.length >= this.maxToasts) {\r\n this.activeToasts.shift();\r\n }\r\n \r\n this.activeToasts.push(notification);\r\n\r\n // Auto close if enabled\r\n if (notification.autoClose !== false) {\r\n const duration = notification.duration || this.defaultDuration;\r\n const timer = setTimeout(() => {\r\n this.dismissToast(notification.id);\r\n }, duration);\r\n \r\n this.autoCloseTimers.set(notification.id, timer);\r\n }\r\n }\r\n\r\n dismissToast(id: string) {\r\n const index = this.activeToasts.findIndex(t => t.id === id);\r\n if (index !== -1) {\r\n this.activeToasts.splice(index, 1);\r\n }\r\n \r\n if (this.autoCloseTimers.has(id)) {\r\n clearTimeout(this.autoCloseTimers.get(id));\r\n this.autoCloseTimers.delete(id);\r\n }\r\n }\r\n\r\n markAsRead(notification: Notification) {\r\n if (!notification.read) {\r\n notification.read = true;\r\n this.notificationRead.emit(notification.id);\r\n }\r\n }\r\n\r\n markAllAsRead() {\r\n this.notifications.forEach(n => n.read = true);\r\n this.allRead.emit();\r\n }\r\n\r\n dismissNotification(notification: Notification, event?: Event) {\r\n event?.stopPropagation();\r\n const index = this.notifications.indexOf(notification);\r\n if (index !== -1) {\r\n this.notifications.splice(index, 1);\r\n this.notificationDismissed.emit(notification.id);\r\n }\r\n }\r\n\r\n clearAll() {\r\n this.notifications.length = 0;\r\n this.allCleared.emit();\r\n }\r\n\r\n executeAction(notification: Notification, event?: Event) {\r\n event?.stopPropagation();\r\n \r\n if (notification.actionCallback) {\r\n notification.actionCallback();\r\n }\r\n \r\n this.notificationAction.emit(notification);\r\n this.markAsRead(notification);\r\n }\r\n\r\n getIcon(type: NotificationType): string {\r\n const icons = {\r\n success: '✅',\r\n info: 'ℹ️',\r\n warning: '⚠️',\r\n error: '❌'\r\n };\r\n return icons[type];\r\n }\r\n\r\n formatTimestamp(date: Date): string {\r\n const now = new Date();\r\n const diff = now.getTime() - date.getTime();\r\n \r\n const minutes = Math.floor(diff / 60000);\r\n const hours = Math.floor(diff / 3600000);\r\n const days = Math.floor(diff / 86400000);\r\n \r\n if (minutes < 1) return 'Agora';\r\n if (minutes < 60) return `${minutes}m atrás`;\r\n if (hours < 24) return `${hours}h atrás`;\r\n if (days < 7) return `${days}d atrás`;\r\n \r\n return date.toLocaleDateString('pt-BR', { day: '2-digit', month: 'short' });\r\n }\r\n\r\n get positionClass(): string {\r\n return `position-${this.position}`;\r\n }\r\n}\r\n","<!-- Notification Bell Icon -->\r\n<div class=\"notification-bell\" (click)=\"togglePanel()\">\r\n <span class=\"bell-icon\">🔔</span>\r\n <span class=\"badge\" *ngIf=\"showBadge && unreadCount > 0\">{{ unreadCount > 99 ? '99+' : unreadCount }}</span>\r\n</div>\r\n\r\n<!-- Notification Panel -->\r\n<div class=\"notification-panel\" [class.open]=\"isOpen\" [@slideDown]>\r\n <div class=\"panel-header\">\r\n <h3>Notificações</h3>\r\n <div class=\"header-actions\">\r\n <button class=\"action-btn\" (click)=\"markAllAsRead()\" *ngIf=\"unreadCount > 0\" title=\"Marcar todas como lidas\">\r\n <span>✓</span>\r\n </button>\r\n <button class=\"action-btn\" (click)=\"clearAll()\" *ngIf=\"notifications.length > 0\" title=\"Limpar todas\">\r\n <span>🗑️</span>\r\n </button>\r\n <button class=\"action-btn close-btn\" (click)=\"closePanel()\" title=\"Fechar\">\r\n <span>✕</span>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"panel-body\">\r\n <div *ngIf=\"notifications.length === 0\" class=\"empty-state\">\r\n <div class=\"empty-icon\">🔕</div>\r\n <p>Nenhuma notificação</p>\r\n </div>\r\n\r\n <div *ngIf=\"notifications.length > 0\">\r\n <div *ngFor=\"let group of groupedNotifications\" class=\"notification-group\">\r\n <h4 class=\"group-title\" *ngIf=\"groupByCategory\">{{ group.category }}</h4>\r\n \r\n <div *ngFor=\"let notification of group.notifications\" \r\n class=\"notification-item\"\r\n [class.unread]=\"!notification.read\"\r\n [class.type-success]=\"notification.type === 'success'\"\r\n [class.type-info]=\"notification.type === 'info'\"\r\n [class.type-warning]=\"notification.type === 'warning'\"\r\n [class.type-error]=\"notification.type === 'error'\"\r\n (click)=\"markAsRead(notification)\">\r\n \r\n <div class=\"notification-icon\">\r\n <span>{{ getIcon(notification.type) }}</span>\r\n </div>\r\n\r\n <div class=\"notification-content\">\r\n <div class=\"notification-header\">\r\n <h5 class=\"notification-title\">{{ notification.title }}</h5>\r\n <span class=\"notification-time\">{{ formatTimestamp(notification.timestamp) }}</span>\r\n </div>\r\n <p class=\"notification-message\">{{ notification.message }}</p>\r\n \r\n <button *ngIf=\"notification.actionLabel\" \r\n class=\"notification-action\"\r\n (click)=\"executeAction(notification, $event)\">\r\n {{ notification.actionLabel }}\r\n </button>\r\n </div>\r\n\r\n <button class=\"dismiss-btn\" (click)=\"dismissNotification(notification, $event)\" title=\"Dispensar\">\r\n <span>✕</span>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Toast Notifications -->\r\n<div class=\"toast-container\" [class]=\"positionClass\">\r\n <div *ngFor=\"let toast of activeToasts\" \r\n class=\"toast-notification\"\r\n [class.type-success]=\"toast.type === 'success'\"\r\n [class.type-info]=\"toast.type === 'info'\"\r\n [class.type-warning]=\"toast.type === 'warning'\"\r\n [class.type-error]=\"toast.type === 'error'\"\r\n [@slideIn]>\r\n \r\n <div class=\"toast-icon\">\r\n <span>{{ getIcon(toast.type) }}</span>\r\n </div>\r\n\r\n <div class=\"toast-content\">\r\n <h5 class=\"toast-title\">{{ toast.title }}</h5>\r\n <p class=\"toast-message\">{{ toast.message }}</p>\r\n \r\n <button *ngIf=\"toast.actionLabel\" \r\n class=\"toast-action\"\r\n (click)=\"executeAction(toast, $event)\">\r\n {{ toast.actionLabel }}\r\n </button>\r\n </div>\r\n\r\n <button class=\"toast-close\" (click)=\"dismissToast(toast.id)\" title=\"Fechar\">\r\n <span>✕</span>\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<!-- Overlay -->\r\n<div class=\"overlay\" *ngIf=\"isOpen\" (click)=\"closePanel()\"></div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { EventEmitter, Component, Input, Output } from '@angular/core';
|
|
3
|
+
import * as i1 from '@angular/common';
|
|
4
|
+
import { CommonModule } from '@angular/common';
|
|
5
|
+
import { trigger, transition, style, animate } from '@angular/animations';
|
|
6
|
+
|
|
7
|
+
class NotificationCenterComponent {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.notifications = [];
|
|
10
|
+
this.position = 'top-right';
|
|
11
|
+
this.maxToasts = 3;
|
|
12
|
+
this.defaultDuration = 5000;
|
|
13
|
+
this.showBadge = true;
|
|
14
|
+
this.groupByCategory = false;
|
|
15
|
+
this.notificationRead = new EventEmitter();
|
|
16
|
+
this.notificationDismissed = new EventEmitter();
|
|
17
|
+
this.notificationAction = new EventEmitter();
|
|
18
|
+
this.allRead = new EventEmitter();
|
|
19
|
+
this.allCleared = new EventEmitter();
|
|
20
|
+
this.isOpen = false;
|
|
21
|
+
this.activeToasts = [];
|
|
22
|
+
this.autoCloseTimers = new Map();
|
|
23
|
+
}
|
|
24
|
+
ngOnDestroy() {
|
|
25
|
+
this.autoCloseTimers.forEach(timer => clearTimeout(timer));
|
|
26
|
+
}
|
|
27
|
+
togglePanel() {
|
|
28
|
+
this.isOpen = !this.isOpen;
|
|
29
|
+
}
|
|
30
|
+
closePanel() {
|
|
31
|
+
this.isOpen = false;
|
|
32
|
+
}
|
|
33
|
+
get unreadCount() {
|
|
34
|
+
return this.notifications.filter(n => !n.read).length;
|
|
35
|
+
}
|
|
36
|
+
get groupedNotifications() {
|
|
37
|
+
if (!this.groupByCategory) {
|
|
38
|
+
return [{ category: 'all', notifications: this.notifications }];
|
|
39
|
+
}
|
|
40
|
+
const groups = new Map();
|
|
41
|
+
this.notifications.forEach(notification => {
|
|
42
|
+
const category = notification.category || 'Outros';
|
|
43
|
+
if (!groups.has(category)) {
|
|
44
|
+
groups.set(category, []);
|
|
45
|
+
}
|
|
46
|
+
groups.get(category).push(notification);
|
|
47
|
+
});
|
|
48
|
+
return Array.from(groups.entries()).map(([category, notifications]) => ({
|
|
49
|
+
category,
|
|
50
|
+
notifications
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
showToast(notification) {
|
|
54
|
+
// Add to active toasts
|
|
55
|
+
if (this.activeToasts.length >= this.maxToasts) {
|
|
56
|
+
this.activeToasts.shift();
|
|
57
|
+
}
|
|
58
|
+
this.activeToasts.push(notification);
|
|
59
|
+
// Auto close if enabled
|
|
60
|
+
if (notification.autoClose !== false) {
|
|
61
|
+
const duration = notification.duration || this.defaultDuration;
|
|
62
|
+
const timer = setTimeout(() => {
|
|
63
|
+
this.dismissToast(notification.id);
|
|
64
|
+
}, duration);
|
|
65
|
+
this.autoCloseTimers.set(notification.id, timer);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
dismissToast(id) {
|
|
69
|
+
const index = this.activeToasts.findIndex(t => t.id === id);
|
|
70
|
+
if (index !== -1) {
|
|
71
|
+
this.activeToasts.splice(index, 1);
|
|
72
|
+
}
|
|
73
|
+
if (this.autoCloseTimers.has(id)) {
|
|
74
|
+
clearTimeout(this.autoCloseTimers.get(id));
|
|
75
|
+
this.autoCloseTimers.delete(id);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
markAsRead(notification) {
|
|
79
|
+
if (!notification.read) {
|
|
80
|
+
notification.read = true;
|
|
81
|
+
this.notificationRead.emit(notification.id);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
markAllAsRead() {
|
|
85
|
+
this.notifications.forEach(n => n.read = true);
|
|
86
|
+
this.allRead.emit();
|
|
87
|
+
}
|
|
88
|
+
dismissNotification(notification, event) {
|
|
89
|
+
event?.stopPropagation();
|
|
90
|
+
const index = this.notifications.indexOf(notification);
|
|
91
|
+
if (index !== -1) {
|
|
92
|
+
this.notifications.splice(index, 1);
|
|
93
|
+
this.notificationDismissed.emit(notification.id);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
clearAll() {
|
|
97
|
+
this.notifications.length = 0;
|
|
98
|
+
this.allCleared.emit();
|
|
99
|
+
}
|
|
100
|
+
executeAction(notification, event) {
|
|
101
|
+
event?.stopPropagation();
|
|
102
|
+
if (notification.actionCallback) {
|
|
103
|
+
notification.actionCallback();
|
|
104
|
+
}
|
|
105
|
+
this.notificationAction.emit(notification);
|
|
106
|
+
this.markAsRead(notification);
|
|
107
|
+
}
|
|
108
|
+
getIcon(type) {
|
|
109
|
+
const icons = {
|
|
110
|
+
success: '✅',
|
|
111
|
+
info: 'ℹ️',
|
|
112
|
+
warning: '⚠️',
|
|
113
|
+
error: '❌'
|
|
114
|
+
};
|
|
115
|
+
return icons[type];
|
|
116
|
+
}
|
|
117
|
+
formatTimestamp(date) {
|
|
118
|
+
const now = new Date();
|
|
119
|
+
const diff = now.getTime() - date.getTime();
|
|
120
|
+
const minutes = Math.floor(diff / 60000);
|
|
121
|
+
const hours = Math.floor(diff / 3600000);
|
|
122
|
+
const days = Math.floor(diff / 86400000);
|
|
123
|
+
if (minutes < 1)
|
|
124
|
+
return 'Agora';
|
|
125
|
+
if (minutes < 60)
|
|
126
|
+
return `${minutes}m atrás`;
|
|
127
|
+
if (hours < 24)
|
|
128
|
+
return `${hours}h atrás`;
|
|
129
|
+
if (days < 7)
|
|
130
|
+
return `${days}d atrás`;
|
|
131
|
+
return date.toLocaleDateString('pt-BR', { day: '2-digit', month: 'short' });
|
|
132
|
+
}
|
|
133
|
+
get positionClass() {
|
|
134
|
+
return `position-${this.position}`;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
NotificationCenterComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NotificationCenterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
138
|
+
NotificationCenterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: NotificationCenterComponent, isStandalone: true, selector: "muxima-notification-center", inputs: { notifications: "notifications", position: "position", maxToasts: "maxToasts", defaultDuration: "defaultDuration", showBadge: "showBadge", groupByCategory: "groupByCategory" }, outputs: { notificationRead: "notificationRead", notificationDismissed: "notificationDismissed", notificationAction: "notificationAction", allRead: "allRead", allCleared: "allCleared" }, ngImport: i0, template: "<!-- Notification Bell Icon -->\r\n<div class=\"notification-bell\" (click)=\"togglePanel()\">\r\n <span class=\"bell-icon\">\uD83D\uDD14</span>\r\n <span class=\"badge\" *ngIf=\"showBadge && unreadCount > 0\">{{ unreadCount > 99 ? '99+' : unreadCount }}</span>\r\n</div>\r\n\r\n<!-- Notification Panel -->\r\n<div class=\"notification-panel\" [class.open]=\"isOpen\" [@slideDown]>\r\n <div class=\"panel-header\">\r\n <h3>Notifica\u00E7\u00F5es</h3>\r\n <div class=\"header-actions\">\r\n <button class=\"action-btn\" (click)=\"markAllAsRead()\" *ngIf=\"unreadCount > 0\" title=\"Marcar todas como lidas\">\r\n <span>\u2713</span>\r\n </button>\r\n <button class=\"action-btn\" (click)=\"clearAll()\" *ngIf=\"notifications.length > 0\" title=\"Limpar todas\">\r\n <span>\uD83D\uDDD1\uFE0F</span>\r\n </button>\r\n <button class=\"action-btn close-btn\" (click)=\"closePanel()\" title=\"Fechar\">\r\n <span>\u2715</span>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"panel-body\">\r\n <div *ngIf=\"notifications.length === 0\" class=\"empty-state\">\r\n <div class=\"empty-icon\">\uD83D\uDD15</div>\r\n <p>Nenhuma notifica\u00E7\u00E3o</p>\r\n </div>\r\n\r\n <div *ngIf=\"notifications.length > 0\">\r\n <div *ngFor=\"let group of groupedNotifications\" class=\"notification-group\">\r\n <h4 class=\"group-title\" *ngIf=\"groupByCategory\">{{ group.category }}</h4>\r\n \r\n <div *ngFor=\"let notification of group.notifications\" \r\n class=\"notification-item\"\r\n [class.unread]=\"!notification.read\"\r\n [class.type-success]=\"notification.type === 'success'\"\r\n [class.type-info]=\"notification.type === 'info'\"\r\n [class.type-warning]=\"notification.type === 'warning'\"\r\n [class.type-error]=\"notification.type === 'error'\"\r\n (click)=\"markAsRead(notification)\">\r\n \r\n <div class=\"notification-icon\">\r\n <span>{{ getIcon(notification.type) }}</span>\r\n </div>\r\n\r\n <div class=\"notification-content\">\r\n <div class=\"notification-header\">\r\n <h5 class=\"notification-title\">{{ notification.title }}</h5>\r\n <span class=\"notification-time\">{{ formatTimestamp(notification.timestamp) }}</span>\r\n </div>\r\n <p class=\"notification-message\">{{ notification.message }}</p>\r\n \r\n <button *ngIf=\"notification.actionLabel\" \r\n class=\"notification-action\"\r\n (click)=\"executeAction(notification, $event)\">\r\n {{ notification.actionLabel }}\r\n </button>\r\n </div>\r\n\r\n <button class=\"dismiss-btn\" (click)=\"dismissNotification(notification, $event)\" title=\"Dispensar\">\r\n <span>\u2715</span>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Toast Notifications -->\r\n<div class=\"toast-container\" [class]=\"positionClass\">\r\n <div *ngFor=\"let toast of activeToasts\" \r\n class=\"toast-notification\"\r\n [class.type-success]=\"toast.type === 'success'\"\r\n [class.type-info]=\"toast.type === 'info'\"\r\n [class.type-warning]=\"toast.type === 'warning'\"\r\n [class.type-error]=\"toast.type === 'error'\"\r\n [@slideIn]>\r\n \r\n <div class=\"toast-icon\">\r\n <span>{{ getIcon(toast.type) }}</span>\r\n </div>\r\n\r\n <div class=\"toast-content\">\r\n <h5 class=\"toast-title\">{{ toast.title }}</h5>\r\n <p class=\"toast-message\">{{ toast.message }}</p>\r\n \r\n <button *ngIf=\"toast.actionLabel\" \r\n class=\"toast-action\"\r\n (click)=\"executeAction(toast, $event)\">\r\n {{ toast.actionLabel }}\r\n </button>\r\n </div>\r\n\r\n <button class=\"toast-close\" (click)=\"dismissToast(toast.id)\" title=\"Fechar\">\r\n <span>\u2715</span>\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<!-- Overlay -->\r\n<div class=\"overlay\" *ngIf=\"isOpen\" (click)=\"closePanel()\"></div>\r\n", styles: [".notification-bell{position:relative;display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);border-radius:50%;cursor:pointer;transition:all .3s ease;box-shadow:0 4px 8px #667eea4d}.notification-bell:hover{transform:scale(1.1);box-shadow:0 6px 12px #667eea66}.notification-bell:active{transform:scale(.95)}.notification-bell .bell-icon{font-size:1.5rem;animation:ring 2s ease-in-out infinite}.notification-bell .badge{position:absolute;top:-4px;right:-4px;min-width:20px;height:20px;padding:0 4px;background:#ef4444;color:#fff;font-size:.75rem;font-weight:700;border-radius:10px;display:flex;align-items:center;justify-content:center;border:2px solid white;animation:pulse 2s ease-in-out infinite}@keyframes ring{0%,to{transform:rotate(0)}10%,30%{transform:rotate(-10deg)}20%,40%{transform:rotate(10deg)}}@keyframes pulse{0%,to{transform:scale(1)}50%{transform:scale(1.1)}}.notification-panel{position:fixed;top:60px;right:20px;width:400px;max-height:600px;background:white;border-radius:12px;box-shadow:0 10px 25px #0003;transform:translateY(-20px);opacity:0;pointer-events:none;transition:all .3s ease;z-index:1000;display:flex;flex-direction:column}.notification-panel.open{transform:translateY(0);opacity:1;pointer-events:all}.panel-header{padding:1.25rem;border-bottom:1px solid #e5e7eb;display:flex;align-items:center;justify-content:space-between}.panel-header h3{font-size:1.25rem;font-weight:700;color:#111827;margin:0}.panel-header .header-actions{display:flex;gap:.5rem}.panel-header .action-btn{padding:.5rem;background:transparent;border:none;color:#6b7280;font-size:1rem;cursor:pointer;border-radius:6px;transition:all .2s ease;display:flex;align-items:center;justify-content:center}.panel-header .action-btn:hover{background:#f3f4f6;color:#667eea}.panel-header .action-btn.close-btn:hover{color:#ef4444}.panel-body{flex:1;overflow-y:auto;max-height:500px}.panel-body::-webkit-scrollbar{width:6px}.panel-body::-webkit-scrollbar-track{background:#f3f4f6}.panel-body::-webkit-scrollbar-thumb{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);border-radius:3px}.empty-state{padding:3rem 1.5rem;text-align:center}.empty-state .empty-icon{font-size:3rem;margin-bottom:1rem;opacity:.5}.empty-state p{color:#9ca3af;font-size:1rem}.notification-group .group-title{padding:.75rem 1.25rem;font-size:.875rem;font-weight:600;color:#667eea;text-transform:uppercase;letter-spacing:.05em;background:#f9fafb;border-bottom:1px solid #e5e7eb;margin:0}.notification-item{display:flex;gap:1rem;padding:1rem 1.25rem;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:all .2s ease;position:relative}.notification-item:last-child{border-bottom:none}.notification-item:hover{background:#f9fafb}.notification-item.unread{background:rgba(102,126,234,.05)}.notification-item.unread:before{content:\"\";position:absolute;left:0;top:0;bottom:0;width:4px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%)}.notification-item.type-success .notification-icon{color:#10b981}.notification-item.type-info .notification-icon{color:#3b82f6}.notification-item.type-warning .notification-icon{color:#f59e0b}.notification-item.type-error .notification-icon{color:#ef4444}.notification-item .notification-icon{font-size:1.5rem;flex-shrink:0}.notification-item .notification-content{flex:1;min-width:0}.notification-item .notification-header{display:flex;align-items:flex-start;justify-content:space-between;gap:.5rem;margin-bottom:.5rem}.notification-item .notification-title{font-size:.875rem;font-weight:600;color:#111827;margin:0}.notification-item .notification-time{font-size:.75rem;color:#9ca3af;white-space:nowrap}.notification-item .notification-message{font-size:.875rem;color:#6b7280;margin:0 0 .75rem;line-height:1.5}.notification-item .notification-action{padding:.375rem .75rem;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border:none;border-radius:6px;font-size:.75rem;font-weight:600;cursor:pointer;transition:all .2s ease}.notification-item .notification-action:hover{transform:translateY(-1px);box-shadow:0 4px 8px #667eea4d}.notification-item .dismiss-btn{padding:.25rem;background:transparent;border:none;color:#9ca3af;font-size:1rem;cursor:pointer;border-radius:4px;transition:all .2s ease;flex-shrink:0}.notification-item .dismiss-btn:hover{background:#f3f4f6;color:#ef4444}.toast-container{position:fixed;z-index:9999;display:flex;flex-direction:column;gap:1rem;pointer-events:none}.toast-container.position-top-right{top:20px;right:20px}.toast-container.position-top-left{top:20px;left:20px}.toast-container.position-bottom-right{bottom:20px;right:20px}.toast-container.position-bottom-left{bottom:20px;left:20px}.toast-container.position-top-center{top:20px;left:50%;transform:translate(-50%)}.toast-container.position-bottom-center{bottom:20px;left:50%;transform:translate(-50%)}.toast-notification{display:flex;align-items:flex-start;gap:1rem;min-width:350px;max-width:450px;padding:1rem 1.25rem;background:white;border-radius:12px;box-shadow:0 10px 25px #00000026;pointer-events:all;border-left:4px solid}.toast-notification.type-success{border-left-color:#10b981}.toast-notification.type-success .toast-icon{color:#10b981}.toast-notification.type-info{border-left-color:#3b82f6}.toast-notification.type-info .toast-icon{color:#3b82f6}.toast-notification.type-warning{border-left-color:#f59e0b}.toast-notification.type-warning .toast-icon{color:#f59e0b}.toast-notification.type-error{border-left-color:#ef4444}.toast-notification.type-error .toast-icon{color:#ef4444}.toast-notification .toast-icon{font-size:1.5rem;flex-shrink:0}.toast-notification .toast-content{flex:1;min-width:0}.toast-notification .toast-title{font-size:.875rem;font-weight:600;color:#111827;margin:0 0 .25rem}.toast-notification .toast-message{font-size:.875rem;color:#6b7280;margin:0 0 .75rem;line-height:1.5}.toast-notification .toast-action{padding:.375rem .75rem;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border:none;border-radius:6px;font-size:.75rem;font-weight:600;cursor:pointer;transition:all .2s ease}.toast-notification .toast-action:hover{transform:translateY(-1px);box-shadow:0 4px 8px #667eea4d}.toast-notification .toast-close{padding:.25rem;background:transparent;border:none;color:#9ca3af;font-size:1rem;cursor:pointer;border-radius:4px;transition:all .2s ease;flex-shrink:0}.toast-notification .toast-close:hover{background:#f3f4f6;color:#ef4444}.overlay{position:fixed;inset:0;background:rgba(0,0,0,.3);z-index:999;animation:fadeIn .3s ease}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@media (max-width: 768px){.notification-panel{right:10px;left:10px;width:auto}.toast-notification{min-width:300px;max-width:350px}.toast-container.position-top-right,.toast-container.position-top-left,.toast-container.position-top-center{top:10px;left:10px;right:10px;transform:none}.toast-container.position-bottom-right,.toast-container.position-bottom-left,.toast-container.position-bottom-center{bottom:10px;left:10px;right:10px;transform:none}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], animations: [
|
|
139
|
+
trigger('slideIn', [
|
|
140
|
+
transition(':enter', [
|
|
141
|
+
style({ transform: 'translateX(100%)', opacity: 0 }),
|
|
142
|
+
animate('300ms ease-out', style({ transform: 'translateX(0)', opacity: 1 }))
|
|
143
|
+
]),
|
|
144
|
+
transition(':leave', [
|
|
145
|
+
animate('300ms ease-in', style({ transform: 'translateX(100%)', opacity: 0 }))
|
|
146
|
+
])
|
|
147
|
+
]),
|
|
148
|
+
trigger('slideDown', [
|
|
149
|
+
transition(':enter', [
|
|
150
|
+
style({ height: 0, opacity: 0 }),
|
|
151
|
+
animate('200ms ease-out', style({ height: '*', opacity: 1 }))
|
|
152
|
+
]),
|
|
153
|
+
transition(':leave', [
|
|
154
|
+
animate('200ms ease-in', style({ height: 0, opacity: 0 }))
|
|
155
|
+
])
|
|
156
|
+
])
|
|
157
|
+
] });
|
|
158
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NotificationCenterComponent, decorators: [{
|
|
159
|
+
type: Component,
|
|
160
|
+
args: [{ selector: 'muxima-notification-center', standalone: true, imports: [CommonModule], animations: [
|
|
161
|
+
trigger('slideIn', [
|
|
162
|
+
transition(':enter', [
|
|
163
|
+
style({ transform: 'translateX(100%)', opacity: 0 }),
|
|
164
|
+
animate('300ms ease-out', style({ transform: 'translateX(0)', opacity: 1 }))
|
|
165
|
+
]),
|
|
166
|
+
transition(':leave', [
|
|
167
|
+
animate('300ms ease-in', style({ transform: 'translateX(100%)', opacity: 0 }))
|
|
168
|
+
])
|
|
169
|
+
]),
|
|
170
|
+
trigger('slideDown', [
|
|
171
|
+
transition(':enter', [
|
|
172
|
+
style({ height: 0, opacity: 0 }),
|
|
173
|
+
animate('200ms ease-out', style({ height: '*', opacity: 1 }))
|
|
174
|
+
]),
|
|
175
|
+
transition(':leave', [
|
|
176
|
+
animate('200ms ease-in', style({ height: 0, opacity: 0 }))
|
|
177
|
+
])
|
|
178
|
+
])
|
|
179
|
+
], template: "<!-- Notification Bell Icon -->\r\n<div class=\"notification-bell\" (click)=\"togglePanel()\">\r\n <span class=\"bell-icon\">\uD83D\uDD14</span>\r\n <span class=\"badge\" *ngIf=\"showBadge && unreadCount > 0\">{{ unreadCount > 99 ? '99+' : unreadCount }}</span>\r\n</div>\r\n\r\n<!-- Notification Panel -->\r\n<div class=\"notification-panel\" [class.open]=\"isOpen\" [@slideDown]>\r\n <div class=\"panel-header\">\r\n <h3>Notifica\u00E7\u00F5es</h3>\r\n <div class=\"header-actions\">\r\n <button class=\"action-btn\" (click)=\"markAllAsRead()\" *ngIf=\"unreadCount > 0\" title=\"Marcar todas como lidas\">\r\n <span>\u2713</span>\r\n </button>\r\n <button class=\"action-btn\" (click)=\"clearAll()\" *ngIf=\"notifications.length > 0\" title=\"Limpar todas\">\r\n <span>\uD83D\uDDD1\uFE0F</span>\r\n </button>\r\n <button class=\"action-btn close-btn\" (click)=\"closePanel()\" title=\"Fechar\">\r\n <span>\u2715</span>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"panel-body\">\r\n <div *ngIf=\"notifications.length === 0\" class=\"empty-state\">\r\n <div class=\"empty-icon\">\uD83D\uDD15</div>\r\n <p>Nenhuma notifica\u00E7\u00E3o</p>\r\n </div>\r\n\r\n <div *ngIf=\"notifications.length > 0\">\r\n <div *ngFor=\"let group of groupedNotifications\" class=\"notification-group\">\r\n <h4 class=\"group-title\" *ngIf=\"groupByCategory\">{{ group.category }}</h4>\r\n \r\n <div *ngFor=\"let notification of group.notifications\" \r\n class=\"notification-item\"\r\n [class.unread]=\"!notification.read\"\r\n [class.type-success]=\"notification.type === 'success'\"\r\n [class.type-info]=\"notification.type === 'info'\"\r\n [class.type-warning]=\"notification.type === 'warning'\"\r\n [class.type-error]=\"notification.type === 'error'\"\r\n (click)=\"markAsRead(notification)\">\r\n \r\n <div class=\"notification-icon\">\r\n <span>{{ getIcon(notification.type) }}</span>\r\n </div>\r\n\r\n <div class=\"notification-content\">\r\n <div class=\"notification-header\">\r\n <h5 class=\"notification-title\">{{ notification.title }}</h5>\r\n <span class=\"notification-time\">{{ formatTimestamp(notification.timestamp) }}</span>\r\n </div>\r\n <p class=\"notification-message\">{{ notification.message }}</p>\r\n \r\n <button *ngIf=\"notification.actionLabel\" \r\n class=\"notification-action\"\r\n (click)=\"executeAction(notification, $event)\">\r\n {{ notification.actionLabel }}\r\n </button>\r\n </div>\r\n\r\n <button class=\"dismiss-btn\" (click)=\"dismissNotification(notification, $event)\" title=\"Dispensar\">\r\n <span>\u2715</span>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Toast Notifications -->\r\n<div class=\"toast-container\" [class]=\"positionClass\">\r\n <div *ngFor=\"let toast of activeToasts\" \r\n class=\"toast-notification\"\r\n [class.type-success]=\"toast.type === 'success'\"\r\n [class.type-info]=\"toast.type === 'info'\"\r\n [class.type-warning]=\"toast.type === 'warning'\"\r\n [class.type-error]=\"toast.type === 'error'\"\r\n [@slideIn]>\r\n \r\n <div class=\"toast-icon\">\r\n <span>{{ getIcon(toast.type) }}</span>\r\n </div>\r\n\r\n <div class=\"toast-content\">\r\n <h5 class=\"toast-title\">{{ toast.title }}</h5>\r\n <p class=\"toast-message\">{{ toast.message }}</p>\r\n \r\n <button *ngIf=\"toast.actionLabel\" \r\n class=\"toast-action\"\r\n (click)=\"executeAction(toast, $event)\">\r\n {{ toast.actionLabel }}\r\n </button>\r\n </div>\r\n\r\n <button class=\"toast-close\" (click)=\"dismissToast(toast.id)\" title=\"Fechar\">\r\n <span>\u2715</span>\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<!-- Overlay -->\r\n<div class=\"overlay\" *ngIf=\"isOpen\" (click)=\"closePanel()\"></div>\r\n", styles: [".notification-bell{position:relative;display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);border-radius:50%;cursor:pointer;transition:all .3s ease;box-shadow:0 4px 8px #667eea4d}.notification-bell:hover{transform:scale(1.1);box-shadow:0 6px 12px #667eea66}.notification-bell:active{transform:scale(.95)}.notification-bell .bell-icon{font-size:1.5rem;animation:ring 2s ease-in-out infinite}.notification-bell .badge{position:absolute;top:-4px;right:-4px;min-width:20px;height:20px;padding:0 4px;background:#ef4444;color:#fff;font-size:.75rem;font-weight:700;border-radius:10px;display:flex;align-items:center;justify-content:center;border:2px solid white;animation:pulse 2s ease-in-out infinite}@keyframes ring{0%,to{transform:rotate(0)}10%,30%{transform:rotate(-10deg)}20%,40%{transform:rotate(10deg)}}@keyframes pulse{0%,to{transform:scale(1)}50%{transform:scale(1.1)}}.notification-panel{position:fixed;top:60px;right:20px;width:400px;max-height:600px;background:white;border-radius:12px;box-shadow:0 10px 25px #0003;transform:translateY(-20px);opacity:0;pointer-events:none;transition:all .3s ease;z-index:1000;display:flex;flex-direction:column}.notification-panel.open{transform:translateY(0);opacity:1;pointer-events:all}.panel-header{padding:1.25rem;border-bottom:1px solid #e5e7eb;display:flex;align-items:center;justify-content:space-between}.panel-header h3{font-size:1.25rem;font-weight:700;color:#111827;margin:0}.panel-header .header-actions{display:flex;gap:.5rem}.panel-header .action-btn{padding:.5rem;background:transparent;border:none;color:#6b7280;font-size:1rem;cursor:pointer;border-radius:6px;transition:all .2s ease;display:flex;align-items:center;justify-content:center}.panel-header .action-btn:hover{background:#f3f4f6;color:#667eea}.panel-header .action-btn.close-btn:hover{color:#ef4444}.panel-body{flex:1;overflow-y:auto;max-height:500px}.panel-body::-webkit-scrollbar{width:6px}.panel-body::-webkit-scrollbar-track{background:#f3f4f6}.panel-body::-webkit-scrollbar-thumb{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);border-radius:3px}.empty-state{padding:3rem 1.5rem;text-align:center}.empty-state .empty-icon{font-size:3rem;margin-bottom:1rem;opacity:.5}.empty-state p{color:#9ca3af;font-size:1rem}.notification-group .group-title{padding:.75rem 1.25rem;font-size:.875rem;font-weight:600;color:#667eea;text-transform:uppercase;letter-spacing:.05em;background:#f9fafb;border-bottom:1px solid #e5e7eb;margin:0}.notification-item{display:flex;gap:1rem;padding:1rem 1.25rem;border-bottom:1px solid #e5e7eb;cursor:pointer;transition:all .2s ease;position:relative}.notification-item:last-child{border-bottom:none}.notification-item:hover{background:#f9fafb}.notification-item.unread{background:rgba(102,126,234,.05)}.notification-item.unread:before{content:\"\";position:absolute;left:0;top:0;bottom:0;width:4px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%)}.notification-item.type-success .notification-icon{color:#10b981}.notification-item.type-info .notification-icon{color:#3b82f6}.notification-item.type-warning .notification-icon{color:#f59e0b}.notification-item.type-error .notification-icon{color:#ef4444}.notification-item .notification-icon{font-size:1.5rem;flex-shrink:0}.notification-item .notification-content{flex:1;min-width:0}.notification-item .notification-header{display:flex;align-items:flex-start;justify-content:space-between;gap:.5rem;margin-bottom:.5rem}.notification-item .notification-title{font-size:.875rem;font-weight:600;color:#111827;margin:0}.notification-item .notification-time{font-size:.75rem;color:#9ca3af;white-space:nowrap}.notification-item .notification-message{font-size:.875rem;color:#6b7280;margin:0 0 .75rem;line-height:1.5}.notification-item .notification-action{padding:.375rem .75rem;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border:none;border-radius:6px;font-size:.75rem;font-weight:600;cursor:pointer;transition:all .2s ease}.notification-item .notification-action:hover{transform:translateY(-1px);box-shadow:0 4px 8px #667eea4d}.notification-item .dismiss-btn{padding:.25rem;background:transparent;border:none;color:#9ca3af;font-size:1rem;cursor:pointer;border-radius:4px;transition:all .2s ease;flex-shrink:0}.notification-item .dismiss-btn:hover{background:#f3f4f6;color:#ef4444}.toast-container{position:fixed;z-index:9999;display:flex;flex-direction:column;gap:1rem;pointer-events:none}.toast-container.position-top-right{top:20px;right:20px}.toast-container.position-top-left{top:20px;left:20px}.toast-container.position-bottom-right{bottom:20px;right:20px}.toast-container.position-bottom-left{bottom:20px;left:20px}.toast-container.position-top-center{top:20px;left:50%;transform:translate(-50%)}.toast-container.position-bottom-center{bottom:20px;left:50%;transform:translate(-50%)}.toast-notification{display:flex;align-items:flex-start;gap:1rem;min-width:350px;max-width:450px;padding:1rem 1.25rem;background:white;border-radius:12px;box-shadow:0 10px 25px #00000026;pointer-events:all;border-left:4px solid}.toast-notification.type-success{border-left-color:#10b981}.toast-notification.type-success .toast-icon{color:#10b981}.toast-notification.type-info{border-left-color:#3b82f6}.toast-notification.type-info .toast-icon{color:#3b82f6}.toast-notification.type-warning{border-left-color:#f59e0b}.toast-notification.type-warning .toast-icon{color:#f59e0b}.toast-notification.type-error{border-left-color:#ef4444}.toast-notification.type-error .toast-icon{color:#ef4444}.toast-notification .toast-icon{font-size:1.5rem;flex-shrink:0}.toast-notification .toast-content{flex:1;min-width:0}.toast-notification .toast-title{font-size:.875rem;font-weight:600;color:#111827;margin:0 0 .25rem}.toast-notification .toast-message{font-size:.875rem;color:#6b7280;margin:0 0 .75rem;line-height:1.5}.toast-notification .toast-action{padding:.375rem .75rem;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border:none;border-radius:6px;font-size:.75rem;font-weight:600;cursor:pointer;transition:all .2s ease}.toast-notification .toast-action:hover{transform:translateY(-1px);box-shadow:0 4px 8px #667eea4d}.toast-notification .toast-close{padding:.25rem;background:transparent;border:none;color:#9ca3af;font-size:1rem;cursor:pointer;border-radius:4px;transition:all .2s ease;flex-shrink:0}.toast-notification .toast-close:hover{background:#f3f4f6;color:#ef4444}.overlay{position:fixed;inset:0;background:rgba(0,0,0,.3);z-index:999;animation:fadeIn .3s ease}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@media (max-width: 768px){.notification-panel{right:10px;left:10px;width:auto}.toast-notification{min-width:300px;max-width:350px}.toast-container.position-top-right,.toast-container.position-top-left,.toast-container.position-top-center{top:10px;left:10px;right:10px;transform:none}.toast-container.position-bottom-right,.toast-container.position-bottom-left,.toast-container.position-bottom-center{bottom:10px;left:10px;right:10px;transform:none}}\n"] }]
|
|
180
|
+
}], propDecorators: { notifications: [{
|
|
181
|
+
type: Input
|
|
182
|
+
}], position: [{
|
|
183
|
+
type: Input
|
|
184
|
+
}], maxToasts: [{
|
|
185
|
+
type: Input
|
|
186
|
+
}], defaultDuration: [{
|
|
187
|
+
type: Input
|
|
188
|
+
}], showBadge: [{
|
|
189
|
+
type: Input
|
|
190
|
+
}], groupByCategory: [{
|
|
191
|
+
type: Input
|
|
192
|
+
}], notificationRead: [{
|
|
193
|
+
type: Output
|
|
194
|
+
}], notificationDismissed: [{
|
|
195
|
+
type: Output
|
|
196
|
+
}], notificationAction: [{
|
|
197
|
+
type: Output
|
|
198
|
+
}], allRead: [{
|
|
199
|
+
type: Output
|
|
200
|
+
}], allCleared: [{
|
|
201
|
+
type: Output
|
|
202
|
+
}] } });
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Generated bundle index. Do not edit.
|
|
206
|
+
*/
|
|
207
|
+
|
|
208
|
+
export { NotificationCenterComponent };
|
|
209
|
+
//# sourceMappingURL=muxima-ui-notification-center.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"muxima-ui-notification-center.mjs","sources":["../../../../overlay/notification-center/src/lib/notification-center/notification-center.component.ts","../../../../overlay/notification-center/src/lib/notification-center/notification-center.component.html","../../../../overlay/notification-center/src/muxima-ui-notification-center.ts"],"sourcesContent":["import { Component, Input, Output, EventEmitter, OnDestroy } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { trigger, transition, style, animate, state } from '@angular/animations';\r\n\r\nexport type NotificationType = 'success' | 'info' | 'warning' | 'error';\r\nexport type NotificationPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'top-center' | 'bottom-center';\r\n\r\nexport interface Notification {\r\n id: string;\r\n type: NotificationType;\r\n title: string;\r\n message: string;\r\n timestamp: Date;\r\n read: boolean;\r\n category?: string;\r\n actionLabel?: string;\r\n actionCallback?: () => void;\r\n autoClose?: boolean;\r\n duration?: number;\r\n}\r\n\r\n@Component({\r\n selector: 'muxima-notification-center',\r\n standalone: true,\r\n imports: [CommonModule],\r\n templateUrl: './notification-center.component.html',\r\n styleUrls: ['./notification-center.component.scss'],\r\n animations: [\r\n trigger('slideIn', [\r\n transition(':enter', [\r\n style({ transform: 'translateX(100%)', opacity: 0 }),\r\n animate('300ms ease-out', style({ transform: 'translateX(0)', opacity: 1 }))\r\n ]),\r\n transition(':leave', [\r\n animate('300ms ease-in', style({ transform: 'translateX(100%)', opacity: 0 }))\r\n ])\r\n ]),\r\n trigger('slideDown', [\r\n transition(':enter', [\r\n style({ height: 0, opacity: 0 }),\r\n animate('200ms ease-out', style({ height: '*', opacity: 1 }))\r\n ]),\r\n transition(':leave', [\r\n animate('200ms ease-in', style({ height: 0, opacity: 0 }))\r\n ])\r\n ])\r\n ]\r\n})\r\nexport class NotificationCenterComponent implements OnDestroy {\r\n @Input() notifications: Notification[] = [];\r\n @Input() position: NotificationPosition = 'top-right';\r\n @Input() maxToasts: number = 3;\r\n @Input() defaultDuration: number = 5000;\r\n @Input() showBadge: boolean = true;\r\n @Input() groupByCategory: boolean = false;\r\n\r\n @Output() notificationRead = new EventEmitter<string>();\r\n @Output() notificationDismissed = new EventEmitter<string>();\r\n @Output() notificationAction = new EventEmitter<Notification>();\r\n @Output() allRead = new EventEmitter<void>();\r\n @Output() allCleared = new EventEmitter<void>();\r\n\r\n isOpen = false;\r\n activeToasts: Notification[] = [];\r\n private autoCloseTimers = new Map<string, any>();\r\n\r\n ngOnDestroy() {\r\n this.autoCloseTimers.forEach(timer => clearTimeout(timer));\r\n }\r\n\r\n togglePanel() {\r\n this.isOpen = !this.isOpen;\r\n }\r\n\r\n closePanel() {\r\n this.isOpen = false;\r\n }\r\n\r\n get unreadCount(): number {\r\n return this.notifications.filter(n => !n.read).length;\r\n }\r\n\r\n get groupedNotifications(): { category: string; notifications: Notification[] }[] {\r\n if (!this.groupByCategory) {\r\n return [{ category: 'all', notifications: this.notifications }];\r\n }\r\n\r\n const groups = new Map<string, Notification[]>();\r\n \r\n this.notifications.forEach(notification => {\r\n const category = notification.category || 'Outros';\r\n if (!groups.has(category)) {\r\n groups.set(category, []);\r\n }\r\n groups.get(category)!.push(notification);\r\n });\r\n\r\n return Array.from(groups.entries()).map(([category, notifications]) => ({\r\n category,\r\n notifications\r\n }));\r\n }\r\n\r\n showToast(notification: Notification) {\r\n // Add to active toasts\r\n if (this.activeToasts.length >= this.maxToasts) {\r\n this.activeToasts.shift();\r\n }\r\n \r\n this.activeToasts.push(notification);\r\n\r\n // Auto close if enabled\r\n if (notification.autoClose !== false) {\r\n const duration = notification.duration || this.defaultDuration;\r\n const timer = setTimeout(() => {\r\n this.dismissToast(notification.id);\r\n }, duration);\r\n \r\n this.autoCloseTimers.set(notification.id, timer);\r\n }\r\n }\r\n\r\n dismissToast(id: string) {\r\n const index = this.activeToasts.findIndex(t => t.id === id);\r\n if (index !== -1) {\r\n this.activeToasts.splice(index, 1);\r\n }\r\n \r\n if (this.autoCloseTimers.has(id)) {\r\n clearTimeout(this.autoCloseTimers.get(id));\r\n this.autoCloseTimers.delete(id);\r\n }\r\n }\r\n\r\n markAsRead(notification: Notification) {\r\n if (!notification.read) {\r\n notification.read = true;\r\n this.notificationRead.emit(notification.id);\r\n }\r\n }\r\n\r\n markAllAsRead() {\r\n this.notifications.forEach(n => n.read = true);\r\n this.allRead.emit();\r\n }\r\n\r\n dismissNotification(notification: Notification, event?: Event) {\r\n event?.stopPropagation();\r\n const index = this.notifications.indexOf(notification);\r\n if (index !== -1) {\r\n this.notifications.splice(index, 1);\r\n this.notificationDismissed.emit(notification.id);\r\n }\r\n }\r\n\r\n clearAll() {\r\n this.notifications.length = 0;\r\n this.allCleared.emit();\r\n }\r\n\r\n executeAction(notification: Notification, event?: Event) {\r\n event?.stopPropagation();\r\n \r\n if (notification.actionCallback) {\r\n notification.actionCallback();\r\n }\r\n \r\n this.notificationAction.emit(notification);\r\n this.markAsRead(notification);\r\n }\r\n\r\n getIcon(type: NotificationType): string {\r\n const icons = {\r\n success: '✅',\r\n info: 'ℹ️',\r\n warning: '⚠️',\r\n error: '❌'\r\n };\r\n return icons[type];\r\n }\r\n\r\n formatTimestamp(date: Date): string {\r\n const now = new Date();\r\n const diff = now.getTime() - date.getTime();\r\n \r\n const minutes = Math.floor(diff / 60000);\r\n const hours = Math.floor(diff / 3600000);\r\n const days = Math.floor(diff / 86400000);\r\n \r\n if (minutes < 1) return 'Agora';\r\n if (minutes < 60) return `${minutes}m atrás`;\r\n if (hours < 24) return `${hours}h atrás`;\r\n if (days < 7) return `${days}d atrás`;\r\n \r\n return date.toLocaleDateString('pt-BR', { day: '2-digit', month: 'short' });\r\n }\r\n\r\n get positionClass(): string {\r\n return `position-${this.position}`;\r\n }\r\n}\r\n","<!-- Notification Bell Icon -->\r\n<div class=\"notification-bell\" (click)=\"togglePanel()\">\r\n <span class=\"bell-icon\">🔔</span>\r\n <span class=\"badge\" *ngIf=\"showBadge && unreadCount > 0\">{{ unreadCount > 99 ? '99+' : unreadCount }}</span>\r\n</div>\r\n\r\n<!-- Notification Panel -->\r\n<div class=\"notification-panel\" [class.open]=\"isOpen\" [@slideDown]>\r\n <div class=\"panel-header\">\r\n <h3>Notificações</h3>\r\n <div class=\"header-actions\">\r\n <button class=\"action-btn\" (click)=\"markAllAsRead()\" *ngIf=\"unreadCount > 0\" title=\"Marcar todas como lidas\">\r\n <span>✓</span>\r\n </button>\r\n <button class=\"action-btn\" (click)=\"clearAll()\" *ngIf=\"notifications.length > 0\" title=\"Limpar todas\">\r\n <span>🗑️</span>\r\n </button>\r\n <button class=\"action-btn close-btn\" (click)=\"closePanel()\" title=\"Fechar\">\r\n <span>✕</span>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"panel-body\">\r\n <div *ngIf=\"notifications.length === 0\" class=\"empty-state\">\r\n <div class=\"empty-icon\">🔕</div>\r\n <p>Nenhuma notificação</p>\r\n </div>\r\n\r\n <div *ngIf=\"notifications.length > 0\">\r\n <div *ngFor=\"let group of groupedNotifications\" class=\"notification-group\">\r\n <h4 class=\"group-title\" *ngIf=\"groupByCategory\">{{ group.category }}</h4>\r\n \r\n <div *ngFor=\"let notification of group.notifications\" \r\n class=\"notification-item\"\r\n [class.unread]=\"!notification.read\"\r\n [class.type-success]=\"notification.type === 'success'\"\r\n [class.type-info]=\"notification.type === 'info'\"\r\n [class.type-warning]=\"notification.type === 'warning'\"\r\n [class.type-error]=\"notification.type === 'error'\"\r\n (click)=\"markAsRead(notification)\">\r\n \r\n <div class=\"notification-icon\">\r\n <span>{{ getIcon(notification.type) }}</span>\r\n </div>\r\n\r\n <div class=\"notification-content\">\r\n <div class=\"notification-header\">\r\n <h5 class=\"notification-title\">{{ notification.title }}</h5>\r\n <span class=\"notification-time\">{{ formatTimestamp(notification.timestamp) }}</span>\r\n </div>\r\n <p class=\"notification-message\">{{ notification.message }}</p>\r\n \r\n <button *ngIf=\"notification.actionLabel\" \r\n class=\"notification-action\"\r\n (click)=\"executeAction(notification, $event)\">\r\n {{ notification.actionLabel }}\r\n </button>\r\n </div>\r\n\r\n <button class=\"dismiss-btn\" (click)=\"dismissNotification(notification, $event)\" title=\"Dispensar\">\r\n <span>✕</span>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Toast Notifications -->\r\n<div class=\"toast-container\" [class]=\"positionClass\">\r\n <div *ngFor=\"let toast of activeToasts\" \r\n class=\"toast-notification\"\r\n [class.type-success]=\"toast.type === 'success'\"\r\n [class.type-info]=\"toast.type === 'info'\"\r\n [class.type-warning]=\"toast.type === 'warning'\"\r\n [class.type-error]=\"toast.type === 'error'\"\r\n [@slideIn]>\r\n \r\n <div class=\"toast-icon\">\r\n <span>{{ getIcon(toast.type) }}</span>\r\n </div>\r\n\r\n <div class=\"toast-content\">\r\n <h5 class=\"toast-title\">{{ toast.title }}</h5>\r\n <p class=\"toast-message\">{{ toast.message }}</p>\r\n \r\n <button *ngIf=\"toast.actionLabel\" \r\n class=\"toast-action\"\r\n (click)=\"executeAction(toast, $event)\">\r\n {{ toast.actionLabel }}\r\n </button>\r\n </div>\r\n\r\n <button class=\"toast-close\" (click)=\"dismissToast(toast.id)\" title=\"Fechar\">\r\n <span>✕</span>\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<!-- Overlay -->\r\n<div class=\"overlay\" *ngIf=\"isOpen\" (click)=\"closePanel()\"></div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './lib/notification-center/notification-center.component';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { EventEmitter, OnDestroy } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export type NotificationType = 'success' | 'info' | 'warning' | 'error';
|
|
4
|
+
export type NotificationPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'top-center' | 'bottom-center';
|
|
5
|
+
export interface Notification {
|
|
6
|
+
id: string;
|
|
7
|
+
type: NotificationType;
|
|
8
|
+
title: string;
|
|
9
|
+
message: string;
|
|
10
|
+
timestamp: Date;
|
|
11
|
+
read: boolean;
|
|
12
|
+
category?: string;
|
|
13
|
+
actionLabel?: string;
|
|
14
|
+
actionCallback?: () => void;
|
|
15
|
+
autoClose?: boolean;
|
|
16
|
+
duration?: number;
|
|
17
|
+
}
|
|
18
|
+
export declare class NotificationCenterComponent implements OnDestroy {
|
|
19
|
+
notifications: Notification[];
|
|
20
|
+
position: NotificationPosition;
|
|
21
|
+
maxToasts: number;
|
|
22
|
+
defaultDuration: number;
|
|
23
|
+
showBadge: boolean;
|
|
24
|
+
groupByCategory: boolean;
|
|
25
|
+
notificationRead: EventEmitter<string>;
|
|
26
|
+
notificationDismissed: EventEmitter<string>;
|
|
27
|
+
notificationAction: EventEmitter<Notification>;
|
|
28
|
+
allRead: EventEmitter<void>;
|
|
29
|
+
allCleared: EventEmitter<void>;
|
|
30
|
+
isOpen: boolean;
|
|
31
|
+
activeToasts: Notification[];
|
|
32
|
+
private autoCloseTimers;
|
|
33
|
+
ngOnDestroy(): void;
|
|
34
|
+
togglePanel(): void;
|
|
35
|
+
closePanel(): void;
|
|
36
|
+
get unreadCount(): number;
|
|
37
|
+
get groupedNotifications(): {
|
|
38
|
+
category: string;
|
|
39
|
+
notifications: Notification[];
|
|
40
|
+
}[];
|
|
41
|
+
showToast(notification: Notification): void;
|
|
42
|
+
dismissToast(id: string): void;
|
|
43
|
+
markAsRead(notification: Notification): void;
|
|
44
|
+
markAllAsRead(): void;
|
|
45
|
+
dismissNotification(notification: Notification, event?: Event): void;
|
|
46
|
+
clearAll(): void;
|
|
47
|
+
executeAction(notification: Notification, event?: Event): void;
|
|
48
|
+
getIcon(type: NotificationType): string;
|
|
49
|
+
formatTimestamp(date: Date): string;
|
|
50
|
+
get positionClass(): string;
|
|
51
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<NotificationCenterComponent, never>;
|
|
52
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<NotificationCenterComponent, "muxima-notification-center", never, { "notifications": "notifications"; "position": "position"; "maxToasts": "maxToasts"; "defaultDuration": "defaultDuration"; "showBadge": "showBadge"; "groupByCategory": "groupByCategory"; }, { "notificationRead": "notificationRead"; "notificationDismissed": "notificationDismissed"; "notificationAction": "notificationAction"; "allRead": "allRead"; "allCleared": "allCleared"; }, never, never, true, never>;
|
|
53
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@muxima-ui/notification-center",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Notification center component for Angular 18+ - Muxima UI",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"angular",
|
|
7
|
+
"notification",
|
|
8
|
+
"notification-center",
|
|
9
|
+
"alerts",
|
|
10
|
+
"inbox",
|
|
11
|
+
"muxima-ui"
|
|
12
|
+
],
|
|
13
|
+
"author": "Muxima UI Team (jokerscript)",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/Aldemiro20/muxima-ui.git",
|
|
18
|
+
"directory": "packages/overlay/notification-center"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://muxima-ui.vercel.app/components/notification-center",
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/Aldemiro20/muxima-ui/issues"
|
|
23
|
+
},
|
|
24
|
+
"documentation": "https://muxima-ui.vercel.app",
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"@angular/animations": "^18.0.0",
|
|
30
|
+
"@angular/common": "^18.0.0",
|
|
31
|
+
"@angular/core": "^18.0.0"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"tslib": "^2.3.0"
|
|
35
|
+
},
|
|
36
|
+
"sideEffects": false,
|
|
37
|
+
"module": "fesm2015/muxima-ui-notification-center.mjs",
|
|
38
|
+
"es2020": "fesm2020/muxima-ui-notification-center.mjs",
|
|
39
|
+
"esm2020": "esm2020/muxima-ui-notification-center.mjs",
|
|
40
|
+
"fesm2020": "fesm2020/muxima-ui-notification-center.mjs",
|
|
41
|
+
"fesm2015": "fesm2015/muxima-ui-notification-center.mjs",
|
|
42
|
+
"typings": "index.d.ts",
|
|
43
|
+
"exports": {
|
|
44
|
+
"./package.json": {
|
|
45
|
+
"default": "./package.json"
|
|
46
|
+
},
|
|
47
|
+
".": {
|
|
48
|
+
"types": "./index.d.ts",
|
|
49
|
+
"esm2020": "./esm2020/muxima-ui-notification-center.mjs",
|
|
50
|
+
"es2020": "./fesm2020/muxima-ui-notification-center.mjs",
|
|
51
|
+
"es2015": "./fesm2015/muxima-ui-notification-center.mjs",
|
|
52
|
+
"node": "./fesm2015/muxima-ui-notification-center.mjs",
|
|
53
|
+
"default": "./fesm2020/muxima-ui-notification-center.mjs"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|