metube/ui/src/app/toasts.component.ts

88 lines
2.7 KiB
TypeScript

import { Component } from '@angular/core';
import { faCheckCircle, faTimesCircle } from '@fortawesome/free-regular-svg-icons';
import { Toast, ToastService } from './toast.service';
@Component({
selector: 'app-toasts',
standalone: false,
template: `
<div class="toasts" aria-live="polite">
<div *ngFor="let toast of toastService.toasts" class="toast" [class.err]="toast.error">
<fa-icon [icon]="toast.error ? faTimesCircle : faCheckCircle" class="t-icon"></fa-icon>
<span class="t-msg">{{ toast.message }}</span>
<button *ngIf="toast.actionLabel" type="button" class="t-act" (click)="toastService.runAction(toast)">
{{ toast.actionLabel }}
</button>
<button type="button" class="t-close" (click)="toastService.dismiss(toast.id)" aria-label="关闭">
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
</button>
</div>
</div>
`,
styles: [`
:host { display: block; }
.toasts {
position: fixed;
right: 20px;
bottom: 20px;
display: flex;
flex-direction: column;
gap: 8px;
z-index: 60;
}
.toast {
display: flex;
align-items: center;
gap: 10px;
background: var(--surface);
border: 1px solid var(--border);
border-left: 3px solid var(--accent);
border-radius: 8px;
padding: 11px 14px;
font-size: 13px;
color: var(--fg);
box-shadow: 0 8px 24px oklch(30% 0.02 240 / 0.14);
min-width: 260px;
max-width: min(420px, calc(100vw - 40px));
animation: toast-in 0.25s ease;
}
.toast.err { border-left-color: var(--danger); }
.t-icon { flex: none; color: var(--accent-strong); }
.toast.err .t-icon { color: var(--danger); }
.t-msg { flex: 1; }
.t-act {
flex: none;
border: none;
background: none;
color: var(--accent-strong);
font-size: 12.5px;
font-weight: 550;
padding: 2px 4px;
border-radius: 4px;
white-space: nowrap;
}
.t-act:hover { background: var(--accent-tint); }
.t-close {
flex: none;
width: 20px;
height: 20px;
display: grid;
place-items: center;
border: none;
background: none;
color: var(--muted);
border-radius: 4px;
}
.t-close:hover { background: var(--bg); color: var(--fg); }
@keyframes toast-in {
from { opacity: 0; transform: translateY(8px); }
}
`]
})
export class ToastsComponent {
faCheckCircle = faCheckCircle;
faTimesCircle = faTimesCircle;
constructor(public toastService: ToastService) {}
}