Add support for darkmode

This commit is contained in:
Teriuihi 2025-06-22 23:15:06 +02:00
parent 5284d498f3
commit 9abd570b87
10 changed files with 300 additions and 147 deletions

View File

@ -1,46 +1,48 @@
<mat-card> <div class="card-div">
<mat-card-header> <mat-card>
<mat-card-title>Frames</mat-card-title> <mat-card-header>
</mat-card-header> <mat-card-title>Frames</mat-card-title>
<mat-card-content> </mat-card-header>
<div class="frames-container"> <mat-card-content>
<mat-tab-group [selectedIndex]="frames.indexOf(currentFrame)" <div class="frames-container">
(selectedIndexChange)="switchFrame(frames[$event])"> <mat-tab-group [selectedIndex]="frames.indexOf(currentFrame)"
<mat-tab *ngFor="let frameId of frames" [label]="frameId"> (selectedIndexChange)="switchFrame(frames[$event])">
<div class="frame-content"> <mat-tab *ngFor="let frameId of frames" [label]="frameId">
<h3>Particles in {{ frameId }}</h3> <div class="frame-content">
<div class="particles-list"> <h3>Particles in {{ frameId }}</h3>
<div *ngFor="let particle of particleData.frames[frameId]; let i = index" class="particle-item"> <div class="particles-list">
<div *ngFor="let particle of particleData.frames[frameId]; let i = index" class="particle-item">
<span class="particle-item-text"> <span class="particle-item-text">
Particle {{ i + 1 }}: ({{ particle.x.toFixed(2) }}, {{ particle.y.toFixed(2) }} Particle {{ i + 1 }}: ({{ particle.x.toFixed(2) }}, {{ particle.y.toFixed(2) }}
, {{ particle.z.toFixed(2) }}) , {{ particle.z.toFixed(2) }})
</span> </span>
<button mat-icon-button (click)="removeParticle(frameId, i)"> <button mat-icon-button (click)="removeParticle(frameId, i)">
<mat-icon>delete</mat-icon> <mat-icon>delete</mat-icon>
</button> </button>
<button mat-icon-button (click)="highlightParticle(frameId, i)"> <button mat-icon-button (click)="highlightParticle(frameId, i)">
<mat-icon>lightbulb</mat-icon> <mat-icon>lightbulb</mat-icon>
</button>
</div>
<div *ngIf="!particleData.frames[frameId] || particleData.frames[frameId].length === 0"
class="no-particles">
No particles in this frame. Click on the plane to add particles.
</div>
</div>
<div class="frame-actions">
<button mat-raised-button color="warn" (click)="removeFrame(frameId)"
[disabled]="frames.length <= 1">
Remove Frame
</button> </button>
</div> </div>
<div *ngIf="!particleData.frames[frameId] || particleData.frames[frameId].length === 0"
class="no-particles">
No particles in this frame. Click on the plane to add particles.
</div>
</div> </div>
<div class="frame-actions"> </mat-tab>
<button mat-raised-button color="warn" (click)="removeFrame(frameId)" </mat-tab-group>
[disabled]="frames.length <= 1"> <div class="add-frame">
Remove Frame <button mat-raised-button color="primary" (click)="addFrame()">
</button> Add New Frame
</div> </button>
</div> </div>
</mat-tab>
</mat-tab-group>
<div class="add-frame">
<button mat-raised-button color="primary" (click)="addFrame()">
Add New Frame
</button>
</div> </div>
</div> </mat-card-content>
</mat-card-content> </mat-card>
</mat-card> </div>

View File

@ -34,7 +34,7 @@
.no-particles { .no-particles {
padding: 20px; padding: 20px;
text-align: center; text-align: center;
color: #888; color: var(--color-primairy);
} }
.frame-actions { .frame-actions {
@ -48,3 +48,14 @@
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
.card-div {
mat-card {
background-color: var(--color-primary);
color: var(--font-color);
}
}
span {
color: var(--font-color);
}

View File

@ -1,11 +1,13 @@
<mat-card class="color-picker-card"> <div class="card-div">
<mat-card-header> <mat-card class="color-picker-card">
<mat-card-title>Particle Color</mat-card-title> <mat-card-header>
</mat-card-header> <mat-card-title>Particle Color</mat-card-title>
<mat-card-content> </mat-card-header>
<div class="color-picker"> <mat-card-content>
<input type="color" [(ngModel)]="selectedColor"> <div class="color-picker">
<span>Selected Color: {{ selectedColor }}</span> <input type="color" [(ngModel)]="selectedColor">
</div> <span>Selected Color: {{ selectedColor }}</span>
</mat-card-content> </div>
</mat-card> </mat-card-content>
</mat-card>
</div>

View File

@ -15,3 +15,14 @@
border-radius: 4px; border-radius: 4px;
cursor: pointer; cursor: pointer;
} }
.card-div {
mat-card {
background-color: var(--color-primary);
color: var(--font-color);
}
}
span {
color: var(--font-color);
}

View File

@ -1,91 +1,93 @@
<mat-card> <div class="card-div">
<mat-card-header> <mat-card>
<mat-card-title>Particle Properties</mat-card-title> <mat-card-header>
</mat-card-header> <mat-card-title>Particle Properties</mat-card-title>
<mat-card-content> </mat-card-header>
<div class="form-row"> <mat-card-content>
<mat-form-field appearance="outline"> <div class="form-row">
<mat-label>Particle Name</mat-label> <mat-form-field appearance="outline">
<input matInput [(ngModel)]="particleData.particle_name" placeholder="Enter particle name"> <mat-label>Particle Name</mat-label>
</mat-form-field> <input matInput [(ngModel)]="particleData.particle_name" placeholder="Enter particle name">
</div> </mat-form-field>
</div>
<div class="form-row"> <div class="form-row">
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Display Name</mat-label> <mat-label>Display Name</mat-label>
<input matInput [(ngModel)]="particleData.display_name" placeholder="Enter display name"> <input matInput [(ngModel)]="particleData.display_name" placeholder="Enter display name">
</mat-form-field> </mat-form-field>
</div> </div>
<div class="form-row"> <div class="form-row">
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Particle Type</mat-label> <mat-label>Particle Type</mat-label>
<mat-select [(ngModel)]="particleData.particle_type"> <mat-select [(ngModel)]="particleData.particle_type">
<mat-option *ngFor="let type of particleTypes" [value]="type">{{ type }}</mat-option> <mat-option *ngFor="let type of particleTypes" [value]="type">{{ type }}</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="form-row"> <div class="form-row">
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Lore</mat-label> <mat-label>Lore</mat-label>
<textarea matInput [(ngModel)]="particleData.lore" placeholder="Enter lore"></textarea> <textarea matInput [(ngModel)]="particleData.lore" placeholder="Enter lore"></textarea>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="form-row"> <div class="form-row">
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Display Item</mat-label> <mat-label>Display Item</mat-label>
<input matInput [(ngModel)]="particleData.display_item" placeholder="Enter display item"> <input matInput [(ngModel)]="particleData.display_item" placeholder="Enter display item">
</mat-form-field> </mat-form-field>
</div> </div>
<div class="form-row"> <div class="form-row">
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Permission</mat-label> <mat-label>Permission</mat-label>
<input matInput [(ngModel)]="particleData.permission" placeholder="Enter permission"> <input matInput [(ngModel)]="particleData.permission" placeholder="Enter permission">
</mat-form-field> </mat-form-field>
</div> </div>
<div class="form-row"> <div class="form-row">
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Package Permission</mat-label> <mat-label>Package Permission</mat-label>
<input matInput [(ngModel)]="particleData.package_permission" placeholder="Enter package permission"> <input matInput [(ngModel)]="particleData.package_permission" placeholder="Enter package permission">
</mat-form-field> </mat-form-field>
</div> </div>
<div class="form-row"> <div class="form-row">
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Frame Delay</mat-label> <mat-label>Frame Delay</mat-label>
<input matInput type="number" [(ngModel)]="particleData.frame_delay" placeholder="Enter frame delay"> <input matInput type="number" [(ngModel)]="particleData.frame_delay" placeholder="Enter frame delay">
</mat-form-field> </mat-form-field>
</div> </div>
<div class="form-row"> <div class="form-row">
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Repeat</mat-label> <mat-label>Repeat</mat-label>
<input matInput type="number" [(ngModel)]="particleData.repeat" placeholder="Enter repeat count"> <input matInput type="number" [(ngModel)]="particleData.repeat" placeholder="Enter repeat count">
</mat-form-field> </mat-form-field>
</div> </div>
<div class="form-row"> <div class="form-row">
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Repeat Delay</mat-label> <mat-label>Repeat Delay</mat-label>
<input matInput type="number" [(ngModel)]="particleData.repeat_delay" <input matInput type="number" [(ngModel)]="particleData.repeat_delay"
placeholder="Enter repeat delay"> placeholder="Enter repeat delay">
</mat-form-field> </mat-form-field>
</div> </div>
<div class="form-row"> <div class="form-row">
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Random Offset</mat-label> <mat-label>Random Offset</mat-label>
<input matInput type="number" [(ngModel)]="particleData.random_offset" <input matInput type="number" [(ngModel)]="particleData.random_offset"
placeholder="Enter random offset"> placeholder="Enter random offset">
</mat-form-field> </mat-form-field>
</div> </div>
<div class="form-row"> <div class="form-row">
<mat-checkbox [(ngModel)]="particleData.stationary">Stationary</mat-checkbox> <mat-checkbox [(ngModel)]="particleData.stationary"><span>Stationary</span></mat-checkbox>
</div> </div>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>
</div>

View File

@ -0,0 +1,14 @@
.form-row {
margin-bottom: 15px;
}
.card-div {
mat-card {
background-color: var(--color-primary);
color: var(--font-color);
}
}
span {
color: var(--font-color);
}

View File

@ -1,14 +1,16 @@
<div #rendererContainer class="renderer-container"> <div #rendererContainer class="renderer-container">
<div class="plane-controls-overlay"> <div class="plane-controls-overlay">
<button mat-mini-fab color="primary" (click)="resetCamera()" <div class="button-row">
matTooltip="Reset camera"> <button mat-mini-fab color="primary" (click)="resetCamera()"
<mat-icon>location_searching</mat-icon> matTooltip="Reset camera">
</button> <mat-icon>location_searching</mat-icon>
</button>
<button mat-mini-fab color="primary" (click)="togglePlaneLock()" <button mat-mini-fab color="primary" (click)="togglePlaneLock()"
[matTooltip]="isPlaneLocked ? 'Unlock Plane' : 'Lock Plane'"> [matTooltip]="isPlaneLocked ? 'Unlock Plane' : 'Lock Plane'">
<mat-icon>{{ isPlaneLocked ? 'lock' : 'lock_open' }}</mat-icon> <mat-icon>{{ isPlaneLocked ? 'lock' : 'lock_open' }}</mat-icon>
</button> </button>
</div>
<div *ngIf="isPlaneLocked" class="plane-orientation-buttons"> <div *ngIf="isPlaneLocked" class="plane-orientation-buttons">
<button mat-mini-fab color="warn" (click)="setPlaneOrientation(planeOrientations.VERTICAL_ABOVE)" <button mat-mini-fab color="warn" (click)="setPlaneOrientation(planeOrientations.VERTICAL_ABOVE)"

View File

@ -3,7 +3,7 @@
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 4px; border-radius: 4px;
overflow: hidden; overflow: hidden;
background-color: #f0f0f0; background-color: var(--color-primairy);
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
@ -21,6 +21,13 @@
z-index: 10; z-index: 10;
} }
.button-row {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
margin-top: 10px;
}
.plane-orientation-buttons { .plane-orientation-buttons {
display: grid; display: grid;
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
@ -42,5 +49,5 @@
.plane-orientation-buttons button.active { .plane-orientation-buttons button.active {
opacity: 1; opacity: 1;
transform: scale(1.1); transform: scale(1.1);
box-shadow: 0 0 10px rgba(255, 255, 255, 0.5); box-shadow: 0 0 10px var(--color-tertiary);
} }

View File

@ -16,10 +16,14 @@
gap: 20px; gap: 20px;
} }
label, span {
color: var(--font-color);
}
.plane-controls { .plane-controls {
margin-top: 10px; margin-top: 10px;
padding: 10px; padding: 10px;
background-color: #f5f5f5; background-color: var(--color-primairy);
border-radius: 4px; border-radius: 4px;
display: flex; display: flex;
align-items: center; align-items: center;
@ -30,10 +34,92 @@
flex: 1; flex: 1;
} }
.form-row { :host ::ng-deep {
margin-bottom: 15px; .mdc-text-field--outlined {
background-color: var(--color-primary);
}
.mdc-text-field--outlined .mdc-floating-label,
.mdc-text-field--outlined .mdc-text-field__input,
.mat-mdc-form-field-label,
.mat-mdc-select-value-text,
.mat-mdc-select-arrow,
.mat-mdc-checkbox-label,
.mat-mdc-card-header,
.mat-mdc-card-title,
.mat-mdc-card-content {
color: var(--font-color) !important;
}
.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__leading,
.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__notch,
.mdc-text-field--outlined .mdc-notched-outline .mdc-notched-outline__trailing {
border-color: var(--font-color) !important;
}
// Fix for dropdown menu
.mat-mdc-select-panel {
background-color: var(--color-primary) !important;
}
.mat-mdc-option {
color: var(--font-color) !important;
}
.mat-mdc-option:hover:not(.mdc-list-item--disabled) {
background-color: rgba(255, 255, 255, 0.1) !important;
}
.mat-mdc-option.mat-mdc-option-active {
background-color: rgba(255, 255, 255, 0.2) !important;
}
.mat-mdc-select-panel {
background-color: var(--color-primary) !important;
}
.mat-mdc-option {
color: var(--font-color) !important;
}
.mat-mdc-option:hover:not(.mdc-list-item--disabled) {
background-color: rgba(255, 255, 255, 0.1) !important;
}
.mat-mdc-option.mat-mdc-option-active {
background-color: rgba(255, 255, 255, 0.2) !important;
}
.mat-mdc-tab {
color: var(--font-color) !important;
}
.mat-mdc-tab-header {
background-color: var(--color-primary);
}
.mat-mdc-tab-label-container {
background-color: var(--color-primary);
}
.mdc-tab__content .mdc-tab__text-label {
color: var(--font-color) !important;
}
.mat-mdc-tab-label, .mat-mdc-tab-link {
color: var(--font-color) !important;
}
.mat-mdc-tab-group.mat-primary .mat-mdc-tab:not(.mat-mdc-tab-disabled) .mdc-tab-indicator__content--underline {
border-color: var(--font-color) !important;
}
.mat-mdc-tab-body-content {
background-color: var(--color-primary);
}
.mat-icon {
color: var(--font-color);
}
} }
mat-form-field {
width: 100%;
}

View File

@ -1,6 +1,8 @@
import {ElementRef, Injectable} from '@angular/core'; import {ElementRef, Injectable} from '@angular/core';
import * as THREE from 'three'; import * as THREE from 'three';
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js'; import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js';
import {ThemeService} from '../../theme/theme.service';
import {THEME_MODE} from '../../constant';
/** /**
* Service responsible for managing the Three.js rendering environment * Service responsible for managing the Three.js rendering environment
@ -13,6 +15,16 @@ export class RendererService {
camera!: THREE.PerspectiveCamera; camera!: THREE.PerspectiveCamera;
renderer!: THREE.WebGLRenderer; renderer!: THREE.WebGLRenderer;
controls!: OrbitControls; controls!: OrbitControls;
private currentTheme: THEME_MODE = THEME_MODE.LIGHT;
constructor(private themeService: ThemeService) {
this.themeService.theme$.subscribe(theme => {
this.currentTheme = theme;
if (this.scene) {
this.setBackgroundColor(theme);
}
})
}
/** /**
* Initializes the Three.js scene, camera, renderer, and controls * Initializes the Three.js scene, camera, renderer, and controls
@ -20,7 +32,7 @@ export class RendererService {
initializeRenderer(container: ElementRef): void { initializeRenderer(container: ElementRef): void {
// Create scene // Create scene
this.scene = new THREE.Scene(); this.scene = new THREE.Scene();
this.scene.background = new THREE.Color(0xf0f0f0); this.setBackgroundColor(this.currentTheme);
// Get container dimensions // Get container dimensions
const containerWidth = container.nativeElement.clientWidth; const containerWidth = container.nativeElement.clientWidth;
@ -54,6 +66,10 @@ export class RendererService {
this.addLights(); this.addLights();
} }
private setBackgroundColor(theme: THEME_MODE) {
this.scene.background = new THREE.Color(this.currentTheme === THEME_MODE.DARK ? 0x242526 : 0xFBFBFE);
}
/** /**
* Resets the camera to its default position and orientation. * Resets the camera to its default position and orientation.
*/ */