diff options
Diffstat (limited to 'src/pybind/mgr/dashboard/frontend/src/app/shared/services/favicon.service.ts')
-rw-r--r-- | src/pybind/mgr/dashboard/frontend/src/app/shared/services/favicon.service.ts | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/favicon.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/favicon.service.ts new file mode 100644 index 000000000..87ce8fcad --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/favicon.service.ts @@ -0,0 +1,79 @@ +import { DOCUMENT } from '@angular/common'; +import { Inject, Injectable, OnDestroy } from '@angular/core'; + +import { Subscription } from 'rxjs'; + +import { CssHelper } from '~/app/shared/classes/css-helper'; +import { HealthColor } from '~/app/shared/enum/health-color.enum'; +import { SummaryService } from './summary.service'; + +@Injectable() +export class FaviconService implements OnDestroy { + sub: Subscription; + oldStatus: string; + url: string; + + constructor( + @Inject(DOCUMENT) private document: HTMLDocument, + private summaryService: SummaryService, + private cssHelper: CssHelper + ) {} + + init() { + this.url = this.document.getElementById('cdFavicon')?.getAttribute('href'); + + this.sub = this.summaryService.subscribe((summary) => { + this.changeIcon(summary.health_status); + }); + } + + changeIcon(status?: string) { + if (status === this.oldStatus) { + return; + } + + this.oldStatus = status; + + const favicon = this.document.getElementById('cdFavicon'); + const faviconSize = 16; + const radius = faviconSize / 4; + + const canvas = this.document.createElement('canvas'); + canvas.width = faviconSize; + canvas.height = faviconSize; + + const context = canvas.getContext('2d'); + const img = this.document.createElement('img'); + img.src = this.url; + + img.onload = () => { + // Draw Original Favicon as Background + context.drawImage(img, 0, 0, faviconSize, faviconSize); + + if (Object.keys(HealthColor).includes(status as HealthColor)) { + // Cut notification circle area + context.save(); + context.globalCompositeOperation = 'destination-out'; + context.beginPath(); + context.arc(canvas.width - radius, radius, radius + 2, 0, 2 * Math.PI); + context.fill(); + context.restore(); + + // Draw Notification Circle + context.beginPath(); + context.arc(canvas.width - radius, radius, radius, 0, 2 * Math.PI); + + context.fillStyle = this.cssHelper.propertyValue(HealthColor[status]); + context.fill(); + } + + // Replace favicon + favicon.setAttribute('href', canvas.toDataURL('image/png')); + }; + } + + ngOnDestroy() { + this.changeIcon(); + this.sub?.unsubscribe(); + } +} |