1import type { NotificationOptions } from '../types/app.js';
2
3export class NotificationService {
4 private zoomNotification: HTMLElement | null = null;
5 private generalNotification: HTMLElement | null = null;
6
7 showZoom(message: string, duration = 2000): void {
8 // Create or update zoom notification
9 if (!this.zoomNotification) {
10 this.zoomNotification = this.createNotificationElement('zoom-notification', {
11 top: '20px',
12 right: '20px',
13 background: 'rgba(0, 0, 0, 0.8)',
14 color: 'white'
15 });
16 }
17
18 this.updateNotification(this.zoomNotification, message, duration);
19 }
20
21 show(message: string, type: NotificationOptions['type'] = 'info', duration = 3000): void {
22 // Create or update general notification
23 if (!this.generalNotification) {
24 this.generalNotification = this.createNotificationElement('general-notification', {
25 top: '60px',
26 right: '20px'
27 });
28 }
29
30 // Set colors based on type
31 const colors = this.getNotificationColors(type);
32 this.generalNotification.style.background = colors.background;
33 this.generalNotification.style.color = colors.color;
34
35 this.updateNotification(this.generalNotification, message, duration);
36 }
37
38 private createNotificationElement(id: string, baseStyles: Record<string, string>): HTMLElement {
39 const notification = document.createElement('div');
40 notification.id = id;
41
42 const styles = {
43 position: 'fixed',
44 padding: '10px 15px',
45 borderRadius: '5px',
46 fontSize: '14px',
47 zIndex: '10000',
48 transition: 'opacity 0.3s',
49 opacity: '0',
50 ...baseStyles
51 };
52
53 notification.style.cssText = Object.entries(styles)
54 .map(([key, value]) => `${this.camelToKebab(key)}: ${value}`)
55 .join('; ');
56
57 document.body.appendChild(notification);
58 return notification;
59 }
60
61 private updateNotification(element: HTMLElement, message: string, duration: number): void {
62 element.textContent = message;
63 element.style.opacity = '1';
64
65 // Clear any existing timeout
66 const existingTimeout = (element as any).timeout;
67 if (existingTimeout) {
68 clearTimeout(existingTimeout);
69 }
70
71 // Hide after duration
72 (element as any).timeout = setTimeout(() => {
73 element.style.opacity = '0';
74 }, duration);
75 }
76
77 private getNotificationColors(type: NotificationOptions['type']): { background: string; color: string } {
78 switch (type) {
79 case 'error':
80 return { background: 'rgba(220, 53, 69, 0.9)', color: 'white' };
81 case 'success':
82 return { background: 'rgba(25, 135, 84, 0.9)', color: 'white' };
83 default:
84 return { background: 'rgba(13, 110, 253, 0.9)', color: 'white' };
85 }
86 }
87
88 private camelToKebab(str: string): string {
89 return str.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`);
90 }
91}