Add comprehensive toast notification component to feedback category
- Create new toast component with full TypeScript implementation - Add SCSS styling using semantic design tokens exclusively - Implement size variants (sm, md, lg) and color variants (primary, success, warning, danger, info) - Include interactive features: auto-dismiss, manual dismiss, progress bar, hover pause/resume - Add comprehensive accessibility support with ARIA attributes and keyboard navigation - Create engaging demo component with interactive examples and live statistics - Integrate toast into feedback category menu and routing system - Follow established component patterns and design system conventions 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ToastComponent } from '../../../../../../../ui-essentials/src/lib/components/feedback/toast/toast.component';
|
||||
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||
import { faPlay, faStop, faRedo } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
@Component({
|
||||
selector: 'ui-toast-demo',
|
||||
standalone: true,
|
||||
imports: [CommonModule, ToastComponent, FontAwesomeModule],
|
||||
template: `
|
||||
<div class="demo-container">
|
||||
<h2>Toast Demo</h2>
|
||||
<p>Toast notifications provide contextual feedback messages for user actions.</p>
|
||||
|
||||
<!-- Size Variants -->
|
||||
<section class="demo-section">
|
||||
<h3>Sizes</h3>
|
||||
<div class="demo-row">
|
||||
@for (size of sizes; track size) {
|
||||
<div class="toast-wrapper">
|
||||
<ui-toast [size]="size" [autoDismiss]="false" title="Toast notification">
|
||||
This is a {{ size }} toast message.
|
||||
</ui-toast>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Color Variants -->
|
||||
<section class="demo-section">
|
||||
<h3>Variants</h3>
|
||||
<div class="demo-row">
|
||||
@for (variant of variants; track variant) {
|
||||
<div class="toast-wrapper">
|
||||
<ui-toast
|
||||
[variant]="variant"
|
||||
[autoDismiss]="false"
|
||||
[title]="getVariantTitle(variant)">
|
||||
{{ getVariantMessage(variant) }}
|
||||
</ui-toast>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- States -->
|
||||
<section class="demo-section">
|
||||
<h3>Configuration Options</h3>
|
||||
<div class="demo-row">
|
||||
<div class="toast-wrapper">
|
||||
<ui-toast
|
||||
variant="success"
|
||||
[autoDismiss]="false"
|
||||
[dismissible]="false"
|
||||
title="Non-dismissible">
|
||||
This toast cannot be manually dismissed.
|
||||
</ui-toast>
|
||||
</div>
|
||||
|
||||
<div class="toast-wrapper">
|
||||
<ui-toast
|
||||
variant="info"
|
||||
[autoDismiss]="false"
|
||||
[showIcon]="false"
|
||||
title="No icon">
|
||||
This toast has no icon displayed.
|
||||
</ui-toast>
|
||||
</div>
|
||||
|
||||
<div class="toast-wrapper">
|
||||
<ui-toast
|
||||
variant="warning"
|
||||
[autoDismiss]="false"
|
||||
[showProgress]="true"
|
||||
title="With progress"
|
||||
[boldTitle]="true">
|
||||
This toast shows a progress indicator.
|
||||
</ui-toast>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Interactive Examples -->
|
||||
<section class="demo-section">
|
||||
<h3>Interactive Examples</h3>
|
||||
|
||||
<div class="controls-section">
|
||||
<h4>Toast Controls</h4>
|
||||
<div class="button-group">
|
||||
<button
|
||||
class="demo-button demo-button--primary"
|
||||
(click)="showToast('success', 'Success!', 'Your action was completed successfully.')">
|
||||
<fa-icon [icon]="faPlay"></fa-icon>
|
||||
Show Success Toast
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="demo-button demo-button--warning"
|
||||
(click)="showToast('warning', 'Warning!', 'Please review your input before proceeding.')">
|
||||
<fa-icon [icon]="faPlay"></fa-icon>
|
||||
Show Warning Toast
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="demo-button demo-button--danger"
|
||||
(click)="showToast('danger', 'Error!', 'Something went wrong. Please try again.')">
|
||||
<fa-icon [icon]="faPlay"></fa-icon>
|
||||
Show Error Toast
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="demo-button demo-button--secondary"
|
||||
(click)="clearToasts()">
|
||||
<fa-icon [icon]="faStop"></fa-icon>
|
||||
Clear All
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast Container -->
|
||||
<div class="toast-container">
|
||||
@for (toast of activeToasts; track toast.id) {
|
||||
<ui-toast
|
||||
[variant]="toast.variant"
|
||||
[title]="toast.title"
|
||||
[size]="toast.size"
|
||||
[duration]="toast.duration"
|
||||
[autoDismiss]="toast.autoDismiss"
|
||||
[showProgress]="toast.showProgress"
|
||||
(dismissed)="removeToast(toast.id)"
|
||||
(expired)="removeToast(toast.id)">
|
||||
{{ toast.message }}
|
||||
</ui-toast>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Statistics -->
|
||||
<div class="stats-section">
|
||||
<h4>Demo Statistics</h4>
|
||||
<div class="stats-grid">
|
||||
<div class="stat-item">
|
||||
<span class="stat-label">Toasts Shown:</span>
|
||||
<span class="stat-value">{{ toastCount }}</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="stat-label">Currently Active:</span>
|
||||
<span class="stat-value">{{ activeToasts.length }}</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="stat-label">Auto Dismissed:</span>
|
||||
<span class="stat-value">{{ expiredCount }}</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span class="stat-label">Manually Dismissed:</span>
|
||||
<span class="stat-value">{{ dismissedCount }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="demo-button demo-button--secondary"
|
||||
(click)="resetStats()">
|
||||
<fa-icon [icon]="faRedo"></fa-icon>
|
||||
Reset Statistics
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
`,
|
||||
styleUrl: './toast-demo.component.scss'
|
||||
})
|
||||
export class ToastDemoComponent {
|
||||
sizes = ['sm', 'md', 'lg'] as const;
|
||||
variants = ['primary', 'success', 'warning', 'danger', 'info'] as const;
|
||||
|
||||
// Icons
|
||||
readonly faPlay = faPlay;
|
||||
readonly faStop = faStop;
|
||||
readonly faRedo = faRedo;
|
||||
|
||||
// Toast management
|
||||
activeToasts: any[] = [];
|
||||
private nextToastId = 1;
|
||||
|
||||
// Statistics
|
||||
toastCount = 0;
|
||||
expiredCount = 0;
|
||||
dismissedCount = 0;
|
||||
|
||||
getVariantTitle(variant: string): string {
|
||||
const titles = {
|
||||
primary: 'Primary Toast',
|
||||
success: 'Success Toast',
|
||||
warning: 'Warning Toast',
|
||||
danger: 'Error Toast',
|
||||
info: 'Information Toast'
|
||||
};
|
||||
return titles[variant as keyof typeof titles] || 'Toast';
|
||||
}
|
||||
|
||||
getVariantMessage(variant: string): string {
|
||||
const messages = {
|
||||
primary: 'This is a primary notification message.',
|
||||
success: 'Operation completed successfully!',
|
||||
warning: 'Please review your input carefully.',
|
||||
danger: 'An error occurred during processing.',
|
||||
info: 'Here is some helpful information.'
|
||||
};
|
||||
return messages[variant as keyof typeof messages] || 'Toast message';
|
||||
}
|
||||
|
||||
showToast(variant: any, title: string, message: string): void {
|
||||
const toast = {
|
||||
id: this.nextToastId++,
|
||||
variant,
|
||||
title,
|
||||
message,
|
||||
size: 'md' as const,
|
||||
duration: 4000,
|
||||
autoDismiss: true,
|
||||
showProgress: true
|
||||
};
|
||||
|
||||
this.activeToasts.push(toast);
|
||||
this.toastCount++;
|
||||
}
|
||||
|
||||
removeToast(id: number): void {
|
||||
const index = this.activeToasts.findIndex(toast => toast.id === id);
|
||||
if (index > -1) {
|
||||
this.activeToasts.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
clearToasts(): void {
|
||||
this.dismissedCount += this.activeToasts.length;
|
||||
this.activeToasts = [];
|
||||
}
|
||||
|
||||
resetStats(): void {
|
||||
this.toastCount = 0;
|
||||
this.expiredCount = 0;
|
||||
this.dismissedCount = 0;
|
||||
this.activeToasts = [];
|
||||
this.nextToastId = 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user