Back to home page

EIC code displayed by LXR

 
 

    


Warning, /firebird/packages/firebird-ng/display/src/lib/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 { ConfigProperty, ConfigService } from '@dexvis/app-features';
0006 
0007 export type Theme = 'light' | 'dark' | 'system';
0008 
0009 @Injectable({
0010   providedIn: 'root',
0011 })
0012 export class ThemeService {
0013 
0014   /**
0015    * Signal holding the current theme.
0016    * Default is 'dark' when no theme is saved.
0017    */
0018   private _currentTheme = signal<Theme>('dark');
0019 
0020   /**
0021    * Exposed read-only signal for the current theme.
0022    */
0023   public readonly currentTheme = this._currentTheme.asReadonly();
0024 
0025   // Reference to the html element (if available)
0026   private _htmlElement?: HTMLHtmlElement;
0027 
0028   // Colors for three.js background for dark and light themes
0029   private readonly threeDarkBackground = new THREE.Color(0x3f3f3f);
0030   private readonly threeLightBackground = new THREE.Color(0xFFFFFF);
0031 
0032   // What user has in local storage
0033   private userSavedTheme: ConfigProperty<string>;
0034 
0035   /**
0036    * Creates an instance of ThemeService.
0037    * @param platformId Angular platform identifier.
0038    * @param threeService ThreeService used to update three.js scene background.
0039    * @param userConfigService User configs saved in local storage service
0040    */
0041   constructor(
0042     @Inject(PLATFORM_ID) private platformId: Object,
0043     private threeService: ThreeService,
0044     private userConfigService: ConfigService
0045   ) {
0046     if (isPlatformBrowser(this.platformId)) {
0047       this._htmlElement = document.documentElement as HTMLHtmlElement;
0048     }
0049 
0050     this.userSavedTheme = this.userConfigService.getConfig<string>('uiSelectedTheme')
0051       ?? this.userConfigService.createConfig('uiSelectedTheme', 'dark');
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     // The canvas background follows the theme. ThreeService keeps the color
0108     // when its scene does not exist yet (the theme applies at startup, before
0109     // the display page creates the scene) and schedules a render otherwise.
0110     this.threeService.setBackground(appliedTheme === 'dark'
0111       ? this.threeDarkBackground
0112       : this.threeLightBackground);
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 }