Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f5453f755 | ||
|
|
f97e9592ad | ||
|
|
4dc35c5aac |
No files matched your search
@@ -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,15 +101,25 @@ export class BrandAccent implements OnDestroy {
|
||||
private cacheGradients() {
|
||||
let w = this.canvasNativeSize[0];
|
||||
let h = this.canvasNativeSize[1];
|
||||
const isDark = this.settingsService.darkMode();
|
||||
|
||||
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);
|
||||
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) => {
|
||||
this.animation.id = requestAnimationFrame(this.animate);
|
||||
@@ -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();
|
||||
|
||||
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]);
|
||||
|
||||
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;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
@use "styles/library" as library;
|
||||
|
||||
$off_bg: oklch(0.683 0 0); // #999999
|
||||
$off_dark_bg: oklch(0 0 0);
|
||||
|
||||
$dimension: (57px, 30px);
|
||||
$knob_dimension: (24px, 24px);
|
||||
@@ -17,15 +18,23 @@ $default_animation_duration: 0.2s;
|
||||
display: inline-block;
|
||||
width: list.nth($dimension, 1); height: list.nth($dimension, 2);
|
||||
border-radius: $border_radius;
|
||||
|
||||
background-color: $off_bg;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 0 0 1px $border_color inset;
|
||||
|
||||
--animation-duration: calc(#{$default_animation_duration} * var(--motion-duration-multiplier));
|
||||
transition: background-color var(--animation-duration) $animation_timing;
|
||||
|
||||
html.dark-theme & {
|
||||
background-color: $off_dark_bg;
|
||||
box-shadow: 0 0 0 1px oklch(1 0 0 / 40%) inset;
|
||||
transition: background-color var(--animation-duration) $animation_timing, box-shadow var(--animation-duration) $animation_timing;
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&:hover, &:focus-within {
|
||||
.switch-knob {
|
||||
will-change: transform;
|
||||
@@ -35,6 +44,11 @@ $default_animation_duration: 0.2s;
|
||||
&.active {
|
||||
background-color: list.nth(library.$brand_palette, 5);
|
||||
|
||||
html.dark-theme & {
|
||||
background-color: list.nth(library.$brand_palette, 9);
|
||||
box-shadow: 0 0 0 1px list.nth(library.$brand_palette, 10) inset;
|
||||
}
|
||||
|
||||
.switch-knob {
|
||||
transform: translate(
|
||||
list.nth($dimension, 1) - list.nth($knob_dimension, 1) - list.nth($internal_padding, 1) * 2,
|
||||
|
||||
@@ -13,6 +13,18 @@
|
||||
--motion-duration-multiplier: 0 !important;
|
||||
}
|
||||
|
||||
html.dark-theme {
|
||||
color: white;
|
||||
|
||||
& > body {
|
||||
background-color: oklch(0.1776 0 0);
|
||||
}
|
||||
|
||||
section.feature-block {
|
||||
background-color: oklch(0 0 0 / 60%);
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'NanumSquareNeo', 'Wanted Sans Variable', 'Pretendard JP', sans-serif;
|
||||
font-weight: 500;
|
||||
|
||||
Reference in new issue
Block a user