diff --git a/src/app/layout/app/app.component.html b/src/app/layout/app/app.component.html index 862ddd2..0278604 100644 --- a/src/app/layout/app/app.component.html +++ b/src/app/layout/app/app.component.html @@ -1,6 +1,6 @@ + - -
+
diff --git a/src/app/layout/app/app.component.ts b/src/app/layout/app/app.component.ts index 5a5aef1..28073f5 100644 --- a/src/app/layout/app/app.component.ts +++ b/src/app/layout/app/app.component.ts @@ -2,12 +2,13 @@ import { Component } from '@angular/core'; import { RouterOutlet } from '@angular/router'; import {TopbarComponent} from '../topbar/topbar.component'; import {TranslatePipe} from '@ngx-translate/core'; +import {ParticleBackgroundComponent} from '../../shared/components/particles-background/particles-background.component'; @Component({ selector: 'app-root', standalone: true, - imports: [RouterOutlet, TopbarComponent, TranslatePipe], + imports: [RouterOutlet, TopbarComponent, TranslatePipe, ParticleBackgroundComponent], templateUrl: './app.component.html', styleUrl: './app.component.scss' }) diff --git a/src/app/shared/components/particles-background/particles-background.component.html b/src/app/shared/components/particles-background/particles-background.component.html new file mode 100644 index 0000000..c2e2ad0 --- /dev/null +++ b/src/app/shared/components/particles-background/particles-background.component.html @@ -0,0 +1 @@ + diff --git a/src/app/shared/components/particles-background/particles-background.component.scss b/src/app/shared/components/particles-background/particles-background.component.scss new file mode 100644 index 0000000..1024a3c --- /dev/null +++ b/src/app/shared/components/particles-background/particles-background.component.scss @@ -0,0 +1,14 @@ +:host { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + z-index: -1; + pointer-events: none; +} +canvas { + display: block; + width: 100%; + height: 100%; +} diff --git a/src/app/shared/components/particles-background/particles-background.component.ts b/src/app/shared/components/particles-background/particles-background.component.ts new file mode 100644 index 0000000..3ba1f74 --- /dev/null +++ b/src/app/shared/components/particles-background/particles-background.component.ts @@ -0,0 +1,102 @@ +import {AfterViewInit, Component, ElementRef, HostListener, NgZone, OnDestroy, ViewChild} from '@angular/core'; + +@Component({ + selector: 'app-particles-background', + imports: [], + templateUrl: './particles-background.component.html', + styleUrl: './particles-background.component.scss', +}) +export class ParticleBackgroundComponent implements AfterViewInit, OnDestroy { + @ViewChild('canvas', { static: true }) canvasRef!: ElementRef; + + private ctx!: CanvasRenderingContext2D; + private particles: any[] = []; + private animationFrameId: number = 0; + + // --- Configuration --- + private readonly numParticles = 80; + private readonly maxDistance = 150; + private readonly particleSpeed = 0.8; + + constructor(private ngZone: NgZone) {} + + ngAfterViewInit(): void { + const canvas = this.canvasRef.nativeElement; + this.ctx = canvas.getContext('2d')!; + + this.resizeCanvas(); + this.initParticles(); + + this.ngZone.runOutsideAngular(() => { + this.animate(); + }); + } + + ngOnDestroy(): void { + cancelAnimationFrame(this.animationFrameId); + } + + @HostListener('window:resize') + resizeCanvas(): void { + const canvas = this.canvasRef.nativeElement; + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + } + + private initParticles(): void { + this.particles = []; + const canvas = this.canvasRef.nativeElement; + + for (let i = 0; i < this.numParticles; i++) { + this.particles.push({ + x: Math.random() * canvas.width, + y: Math.random() * canvas.height, + vx: (Math.random() - 0.5) * this.particleSpeed, + vy: (Math.random() - 0.5) * this.particleSpeed, + radius: Math.random() * 1.5 + 0.5 + }); + } + } + + private animate = (): void => { + const canvas = this.canvasRef.nativeElement; + + this.ctx.clearRect(0, 0, canvas.width, canvas.height); + + for (let i = 0; i < this.numParticles; i++) { + let p = this.particles[i]; + + p.x += p.vx; + p.y += p.vy; + + if (p.x < 0 || p.x > canvas.width) p.vx *= -1; + if (p.y < 0 || p.y > canvas.height) p.vy *= -1; + + this.ctx.beginPath(); + this.ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2); + this.ctx.fillStyle = 'rgba(120, 150, 170, 0.4)'; + this.ctx.fill(); + + for (let j = i + 1; j < this.numParticles; j++) { + let p2 = this.particles[j]; + + let dx = p.x - p2.x; + let dy = p.y - p2.y; + let distance = Math.sqrt(dx * dx + dy * dy); + + if (distance < this.maxDistance) { + this.ctx.beginPath(); + this.ctx.moveTo(p.x, p.y); + this.ctx.lineTo(p2.x, p2.y); + + let opacity = (1 - (distance / this.maxDistance)) * 0.5; + this.ctx.strokeStyle = `rgba(120, 150, 170, ${opacity})`; + this.ctx.lineWidth = 1; + this.ctx.stroke(); + } + } + } + + this.animationFrameId = requestAnimationFrame(this.animate); + }; +} diff --git a/src/app/shared/components/particles-background/particles-background.html b/src/app/shared/components/particles-background/particles-background.html deleted file mode 100644 index 39134d1..0000000 --- a/src/app/shared/components/particles-background/particles-background.html +++ /dev/null @@ -1 +0,0 @@ -

particles-background works!

diff --git a/src/app/shared/components/particles-background/particles-background.scss b/src/app/shared/components/particles-background/particles-background.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/shared/components/particles-background/particles-background.ts b/src/app/shared/components/particles-background/particles-background.ts deleted file mode 100644 index 4d2d3d7..0000000 --- a/src/app/shared/components/particles-background/particles-background.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-particles-background', - imports: [], - templateUrl: './particles-background.html', - styleUrl: './particles-background.scss', -}) -export class ParticlesBackground { - -} diff --git a/src/styles.scss b/src/styles.scss index febb19c..d4a918e 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -407,9 +407,15 @@ app-root { min-height: 100vh; } +.app-container { + width: 100%; + max-width: var(--app-maxWidth); + margin: 1rem auto; + +} + .app-surface { flex-grow: 1; - background: var(--app-bg); color: var(--app-fg); transition: background-color 220ms ease, color 220ms ease; }