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