Warning, /firebird/firebird-ng/src/app/services/theme.service.ts is written in an unsupported language. File is not indexed.
0001 import { Injectable, Inject, PLATFORM_ID, signal } from '@angular/core';
0002 import { isPlatformBrowser } from '@angular/common';
0003 import { ThreeService } from './three.service';
0004 import * as THREE from 'three';
0005 import {UserConfigService} from "./user-config.service";
0006 import {ConfigProperty} from "../utils/config-property";
0007
0008 export type Theme = 'light' | 'dark' | 'system';
0009
0010 @Injectable({
0011 providedIn: 'root',
0012 })
0013 export class ThemeService {
0014
0015 /**
0016 * Signal holding the current theme.
0017 * Default is 'dark' when no theme is saved.
0018 */
0019 private _currentTheme = signal<Theme>('dark');
0020
0021 /**
0022 * Exposed read-only signal for the current theme.
0023 */
0024 public readonly currentTheme = this._currentTheme.asReadonly();
0025
0026 // Reference to the html element (if available)
0027 private _htmlElement?: HTMLHtmlElement;
0028
0029 // Colors for three.js background for dark and light themes
0030 private readonly threeDarkBackground = new THREE.Color(0x3f3f3f);
0031 private readonly threeLightBackground = new THREE.Color(0xf3f3f3);
0032
0033 // What user has in local storage
0034 private userSavedTheme: ConfigProperty<string>;
0035
0036 /**
0037 * Creates an instance of ThemeService.
0038 * @param platformId Angular platform identifier.
0039 * @param threeService ThreeService used to update three.js scene background.
0040 * @param userConfigService User configs saved in local storage service
0041 */
0042 constructor(
0043 @Inject(PLATFORM_ID) private platformId: Object,
0044 private threeService: ThreeService,
0045 private userConfigService: UserConfigService
0046 ) {
0047 if (isPlatformBrowser(this.platformId)) {
0048 this._htmlElement = document.documentElement as HTMLHtmlElement;
0049 }
0050
0051 this.userSavedTheme = this.userConfigService.uiSelectedTheme;
0052 this.initializeTheme();
0053
0054 }
0055
0056 /**
0057 * Determines the system's current theme using the browser's preference.
0058 * @returns 'light' or 'dark' based on the media query.
0059 */
0060 public getSystemTheme(): 'light' | 'dark' {
0061 return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
0062 }
0063
0064
0065
0066 /**
0067 * Initializes the theme on application startup.
0068 * If no saved theme is found, the default is 'dark'.
0069 */
0070 public initializeTheme(): void {
0071 if (!isPlatformBrowser(this.platformId)) return;
0072 const saved = this.userSavedTheme.value || 'dark';
0073 this.setTheme(saved as Theme);
0074 }
0075
0076 /**
0077 * Sets the application theme.
0078 * When 'system' is selected, the system's color scheme is used.
0079 * This method updates local storage, the html element's attributes,
0080 * the Angular signal, and the three.js scene background via ThreeService.
0081 *
0082 * @param theme The theme to set ('light', 'dark', or 'system').
0083 */
0084 public setTheme(theme: Theme): void {
0085 if (!isPlatformBrowser(this.platformId)) return;
0086
0087 this.userSavedTheme.value = theme;
0088
0089 // Update the signal.
0090 this._currentTheme.set(theme);
0091
0092 // Determine the applied theme (for 'system', use the current system preference).
0093 const appliedTheme: 'light' | 'dark' = theme === 'system' ? this.getSystemTheme() : theme;
0094
0095 // Set the html element's color-scheme attribute.
0096 this._htmlElement?.setAttribute('style', `color-scheme: ${appliedTheme};`);
0097
0098 // Toggle theme-specific classes on the html element.
0099 if (appliedTheme === 'dark') {
0100 this._htmlElement?.classList.add('dark-theme');
0101 this._htmlElement?.classList.remove('light-theme');
0102 } else {
0103 this._htmlElement?.classList.add('light-theme');
0104 this._htmlElement?.classList.remove('dark-theme');
0105 }
0106
0107 // Update the three.js scene background using ThreeService.
0108 if (this.threeService?.scene) {
0109 this.threeService.scene.background = appliedTheme === 'dark'
0110 ? this.threeDarkBackground
0111 : this.threeLightBackground;
0112 }
0113 }
0114
0115 /**
0116 * Convenience method to retrieve the current theme value.
0117 * This can be used by UI components to determine which icon to show on startup.
0118 *
0119 * @returns The current theme ('light', 'dark', or 'system').
0120 */
0121 public getCurrentTheme(): Theme {
0122 return this._currentTheme();
0123 }
0124 }