Back to home page

EIC code displayed by LXR

 
 

    


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 {ConfigService} from "./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(0xFFFFFF);
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: ConfigService
0046   ) {
0047     if (isPlatformBrowser(this.platformId)) {
0048       this._htmlElement = document.documentElement as HTMLHtmlElement;
0049     }
0050 
0051     this.userSavedTheme = this.userConfigService.getConfig<string>('uiSelectedTheme')
0052       ?? this.userConfigService.createConfig('uiSelectedTheme', 'dark');
0053     this.initializeTheme();
0054 
0055   }
0056 
0057   /**
0058    * Determines the system's current theme using the browser's preference.
0059    * @returns 'light' or 'dark' based on the media query.
0060    */
0061   public getSystemTheme(): 'light' | 'dark' {
0062     return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
0063   }
0064 
0065 
0066 
0067   /**
0068    * Initializes the theme on application startup.
0069    * If no saved theme is found, the default is 'dark'.
0070    */
0071   public initializeTheme(): void {
0072     if (!isPlatformBrowser(this.platformId)) return;
0073     const saved = this.userSavedTheme.value || 'dark';
0074     this.setTheme(saved as Theme);
0075   }
0076 
0077   /**
0078    * Sets the application theme.
0079    * When 'system' is selected, the system's color scheme is used.
0080    * This method updates local storage, the html element's attributes,
0081    * the Angular signal, and the three.js scene background via ThreeService.
0082    *
0083    * @param theme The theme to set ('light', 'dark', or 'system').
0084    */
0085   public setTheme(theme: Theme): void {
0086     if (!isPlatformBrowser(this.platformId)) return;
0087 
0088     this.userSavedTheme.value = theme;
0089 
0090     // Update the signal.
0091     this._currentTheme.set(theme);
0092 
0093     // Determine the applied theme (for 'system', use the current system preference).
0094     const appliedTheme: 'light' | 'dark' = theme === 'system' ? this.getSystemTheme() : theme;
0095 
0096     // Set the html element's color-scheme attribute.
0097     this._htmlElement?.setAttribute('style', `color-scheme: ${appliedTheme};`);
0098 
0099     // Toggle theme-specific classes on the html element.
0100     if (appliedTheme === 'dark') {
0101       this._htmlElement?.classList.add('dark-theme');
0102       this._htmlElement?.classList.remove('light-theme');
0103     } else {
0104       this._htmlElement?.classList.add('light-theme');
0105       this._htmlElement?.classList.remove('dark-theme');
0106     }
0107 
0108     // Update the three.js scene background using ThreeService.
0109     if (this.threeService?.scene) {
0110       this.threeService.scene.background = appliedTheme === 'dark'
0111         ? this.threeDarkBackground
0112         : this.threeLightBackground;
0113     }
0114   }
0115 
0116   /**
0117    * Convenience method to retrieve the current theme value.
0118    * This can be used by UI components to determine which icon to show on startup.
0119    *
0120    * @returns The current theme ('light', 'dark', or 'system').
0121    */
0122   public getCurrentTheme(): Theme {
0123     return this._currentTheme();
0124   }
0125 }