Add Dark Mode Support for Brand Accent Component

This commit is contained in:
copecone committed 2026-04-07 11:27:49 +09:00
1 parent 4dc35c5aac
commit f97e9592ad
1 file changed
+64 -10
+64 -10
View File
@@ -1,5 +1,15 @@
import { afterNextRender, Component, ElementRef, NgZone, OnDestroy, ViewChild } from '@angular/core';
import {
afterNextRender,
Component,
effect,
ElementRef,
inject,
NgZone,
OnDestroy,
ViewChild,
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { SettingsService } from '../../services/settings.service';
@Component({
selector: 'brand-accent',
@@ -12,6 +22,7 @@ export class BrandAccent implements OnDestroy {
@ViewChild('canvasElement') canvasRef!: ElementRef<HTMLCanvasElement>;
private ctx!: CanvasRenderingContext2D;
private resizeObserver?: ResizeObserver;
private settingsService = inject(SettingsService);
private canvasNativeSize: [number, number] = [0, 0];
private bgGradient!: CanvasGradient;
@@ -35,6 +46,14 @@ export class BrandAccent implements OnDestroy {
};
constructor(private ngZone: NgZone) {
effect(() => {
// Trigger cache refresh when dark mode changes
this.settingsService.darkMode();
if (this.ctx) {
this.cacheGradients();
}
});
afterNextRender(() => {
this.ctx = this.canvasRef.nativeElement.getContext('2d')!;
@@ -82,14 +101,24 @@ export class BrandAccent implements OnDestroy {
private cacheGradients() {
let w = this.canvasNativeSize[0];
let h = this.canvasNativeSize[1];
const isDark = this.settingsService.darkMode();
this.bgGradient = this.ctx.createLinearGradient(0, 0, w, h);
this.bgGradient.addColorStop(0, 'oklch(1 0 0 / 0.6)');
this.bgGradient.addColorStop(1, 'oklch(0.7938 0.1292 47.77 / 0.6)');
if (!isDark) {
this.bgGradient = this.ctx.createLinearGradient(0, 0, w, h);
this.bgGradient.addColorStop(0, 'oklch(1 0 0 / 0.6)');
this.bgGradient.addColorStop(1, 'oklch(0.7938 0.1292 47.77 / 0.6)');
}
this.gridGradient = this.ctx.createLinearGradient(0, 0, w, h);
this.gridGradient.addColorStop(0, 'rgba(0, 0, 0, 0)');
this.gridGradient.addColorStop(1, 'rgba(0, 0, 0, 0.2)');
if (isDark) {
// Dark mode: subtle light grid
this.gridGradient.addColorStop(0, 'rgba(255, 255, 255, 0)');
this.gridGradient.addColorStop(1, 'rgba(255, 255, 255, 0.4)');
} else {
// Light mode: dark grid
this.gridGradient.addColorStop(0, 'rgba(0, 0, 0, 0)');
this.gridGradient.addColorStop(1, 'rgba(0, 0, 0, 0.2)');
}
}
private animate = (currentTime: number) => {
@@ -117,12 +146,37 @@ export class BrandAccent implements OnDestroy {
private draw() {
this.ctx.clearRect(0, 0, this.canvasNativeSize[0], this.canvasNativeSize[1]);
this.ctx.globalCompositeOperation = 'source-over';
const isDark = this.settingsService.darkMode();
this.ctx.fillStyle = this.bgGradient;
this.ctx.fillRect(0, 0, this.canvasNativeSize[0], this.canvasNativeSize[1]);
if (!isDark) {
this.ctx.globalCompositeOperation = 'source-over';
this.ctx.fillStyle = this.bgGradient;
this.ctx.fillRect(0, 0, this.canvasNativeSize[0], this.canvasNativeSize[1]);
this.ctx.globalCompositeOperation = 'multiply';
} else {
this.ctx.globalCompositeOperation = 'source-over';
this.ctx.fillStyle = 'oklch(0.1776 0 0)';
this.ctx.fillRect(0, 0, this.canvasNativeSize[0], this.canvasNativeSize[1]);
this.ctx.globalCompositeOperation = 'multiply';
const ellipseDimension = [
Math.max(100, this.canvasNativeSize[0] * 0.9421875),
Math.max(200 / 3, this.canvasNativeSize[1] * (203 / 120)),
];
const ellipseX = this.canvasNativeSize[0] / 2;
const ellipseY = this.canvasNativeSize[1] * 0.5763888888 + ellipseDimension[1] / 2;
this.ctx.filter = `blur(${Math.min(780, Math.min(ellipseDimension[0], ellipseDimension[1]) * 0.6)}px)`;
this.ctx.beginPath();
this.ctx.ellipse(ellipseX, ellipseY, ellipseDimension[0] / 2, ellipseDimension[1] / 2, 0, 0, 2 * Math.PI);
this.ctx.fillStyle = 'oklch(0.2547 0.0913 29.02)';
this.ctx.fill();
this.ctx.filter = 'none';
this.ctx.globalCompositeOperation = 'screen';
}
this.ctx.beginPath();
this.ctx.lineWidth = 2;