feat: implement tenant branding system and global toast notification service
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
<div class="toast-container position-fixed top-0 end-0 p-3">
|
||||
@for (toast of toasts(); track toast.id) {
|
||||
<div
|
||||
class="toast show align-items-center border-0 shadow-sm"
|
||||
[ngClass]="getToastBgClass(toast.type)"
|
||||
role="alert"
|
||||
aria-live="assertive"
|
||||
aria-atomic="true"
|
||||
>
|
||||
<div class="d-flex p-2">
|
||||
<div class="toast-body d-flex align-items-center flex-grow-1">
|
||||
<i [class]="getToastIconClass(toast.type)" class="me-2 fs-5"></i>
|
||||
<span>{{ toast.message }}</span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close btn-close-white me-2 m-auto"
|
||||
aria-label="Cerrar"
|
||||
(click)="dismiss(toast.id)"
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@@ -0,0 +1,28 @@
|
||||
.toast-container {
|
||||
z-index: 1500;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
pointer-events: none;
|
||||
|
||||
.toast {
|
||||
pointer-events: auto;
|
||||
min-width: 300px;
|
||||
max-width: 450px;
|
||||
border-radius: 8px;
|
||||
animation: toast-slide-in 0.3s cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.15), 0 4px 6px -4px rgba(0, 0, 0, 0.15) !important;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes toast-slide-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-20px) scale(0.95);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
|
||||
import { NgClass } from '@angular/common';
|
||||
import { ToastService, Toast } from '../../../core/services/toast.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-toast-container',
|
||||
imports: [NgClass],
|
||||
templateUrl: './toast-container.component.html',
|
||||
styleUrl: './toast-container.component.scss',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class ToastContainerComponent {
|
||||
private readonly toastService = inject(ToastService);
|
||||
|
||||
readonly toasts = this.toastService.toasts;
|
||||
|
||||
dismiss(id: string): void {
|
||||
this.toastService.dismiss(id);
|
||||
}
|
||||
|
||||
getToastIconClass(type: Toast['type']): string {
|
||||
const icons: Record<Toast['type'], string> = {
|
||||
success: 'fa-solid fa-circle-check',
|
||||
danger: 'fa-solid fa-circle-exclamation',
|
||||
info: 'fa-solid fa-circle-info'
|
||||
};
|
||||
return icons[type] || 'fa-solid fa-bell';
|
||||
}
|
||||
|
||||
getToastBgClass(type: Toast['type']): string {
|
||||
const classes: Record<Toast['type'], string> = {
|
||||
success: 'text-bg-success',
|
||||
danger: 'text-bg-danger',
|
||||
info: 'text-bg-primary'
|
||||
};
|
||||
return classes[type] || 'text-bg-primary';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user