import { Injectable } from '@angular/core'; import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; import { AppConfiguration } from '.'; import { AuthUser, ThemeDataType } from './models'; import { Color } from './models/customer/theme/color.interface'; import { convertLighten, getColorFromMaps, hexToRgb, hexToRgbString, ThemeColorType } from './utils'; export interface Theme { colors: {[colorId: string]: string}; headerUrl?: SafeResourceUrl; footerUrl?: SafeResourceUrl; portalUrl?: SafeResourceUrl; portalMessage: string; portalTitle: string; } @Injectable({ providedIn: 'root' }) export class ThemeService { public get defaultTheme(): Theme { return this._defaultTheme; } public set defaultTheme(theme: Theme) { this._defaultTheme = theme; } constructor( private domSanitizer: DomSanitizer, ) { } private baseColors: {[colorId in ThemeColorType]?: string} = { [ThemeColorType.VITAMUI_PRIMARY]: 'Couleur principale', [ThemeColorType.VITAMUI_SECONDARY]: 'Couleur secondaire', [ThemeColorType.VITAMUI_TERTIARY]: 'Couleur tertiaire', [ThemeColorType.VITAMUI_HEADER_FOOTER]: 'Couleur header/footer', [ThemeColorType.VITAMUI_BACKGROUND]: 'Couleur background' }; // tslint:disable-next-line: variable-name private _defaultTheme: Theme = { colors: {}, headerUrl: '', footerUrl: '', portalUrl: '', portalMessage: '', portalTitle: '' }; // Default theme defaultMap: {[colordId in ThemeColorType]: string} = { [ThemeColorType.VITAMUI_PRIMARY]: '#604379', [ThemeColorType.VITAMUI_PRIMARY_LIGHT]: '', [ThemeColorType.VITAMUI_PRIMARY_LIGHT_20]: '', [ThemeColorType.VITAMUI_PRIMARY_DARK]: '', [ThemeColorType.VITAMUI_SECONDARY]: '#65B2E4', [ThemeColorType.VITAMUI_SECONDARY_LIGHT]: '', [ThemeColorType.VITAMUI_SECONDARY_LIGHT_8]: '', [ThemeColorType.VITAMUI_SECONDARY_DARK_5]: '', [ThemeColorType.VITAMUI_TERTIARY]: '#E7304D', [ThemeColorType.VITAMUI_HEADER_FOOTER]: '#604379', [ThemeColorType.VITAMUI_BACKGROUND]: '#F5F5F5', [ThemeColorType.VITAMUI_GREY]: '#9E9E9E' }; // Theme for current app configuration applicationColorMap: {[colorId: string]: string}; // tslint:disable-next-line: variable-name private _backgroundChoice: Color[] = [ {class: 'Foncé', value: '#0F0D2D'}, {class: 'Blanc', value: '#FFFFFF'}, {class: 'Clair', value: '#F5F5F5'}, ]; public get backgroundChoice(): Color[] { return this._backgroundChoice; } public getBaseColors(): {[colorId in ThemeColorType]?: string} { return this.baseColors; } public getVariationColorsNames(baseName: string): string[] { return Object.keys(this.defaultMap).filter((colorName) => colorName.startsWith(baseName)); } public init(conf: AppConfiguration, customerColorMap: {[colorId: string]: string}): void { this.applicationColorMap = conf.THEME_COLORS; this.overrideTheme(customerColorMap); if (conf) { this.defaultTheme = { colors: conf.THEME_COLORS, portalMessage: conf.PORTAL_MESSAGE, portalTitle: conf.PORTAL_TITLE, headerUrl: this.domSanitizer.bypassSecurityTrustUrl('data:image/*;base64,' + conf.HEADER_LOGO), footerUrl: this.domSanitizer.bypassSecurityTrustUrl('data:image/*;base64,' + conf.FOOTER_LOGO), portalUrl: this.domSanitizer.bypassSecurityTrustUrl('data:image/*;base64,' + conf.PORTAL_LOGO), }; // init default background const defaultBackground = this.backgroundChoice .find((color: Color) => color.value === conf.THEME_COLORS[ThemeColorType.VITAMUI_BACKGROUND]); if (defaultBackground) { defaultBackground.isDefault = true; } } } public overloadLocalTheme(colors: {[colorId: string]: string}, selectorToOver: string): void { const selector: HTMLElement = document.querySelector(selectorToOver); for (const key in colors) { if (colors.hasOwnProperty(key) && selector != null) { selector.style.setProperty('--' + key, colors[key]); } } } public getData(authUser: AuthUser, type: string): string | SafeResourceUrl { const userAuthGraphicIdentity = authUser && authUser.basicCustomer && authUser.basicCustomer.graphicIdentity ? authUser.basicCustomer.graphicIdentity : null; switch (type) { case ThemeDataType.PORTAL_MESSAGE: return userAuthGraphicIdentity && userAuthGraphicIdentity.portalMessage && userAuthGraphicIdentity.hasCustomGraphicIdentity ? userAuthGraphicIdentity.portalMessage : this.defaultTheme.portalMessage; break; case ThemeDataType.PORTAL_TITLE: return userAuthGraphicIdentity && userAuthGraphicIdentity.portalTitle && userAuthGraphicIdentity.hasCustomGraphicIdentity ? userAuthGraphicIdentity.portalTitle : this.defaultTheme.portalTitle; break; case ThemeDataType.PORTAL_LOGO: return userAuthGraphicIdentity && userAuthGraphicIdentity.portalDataBase64 && userAuthGraphicIdentity.hasCustomGraphicIdentity ? this.domSanitizer.bypassSecurityTrustUrl('data:image/*;base64,' + userAuthGraphicIdentity.portalDataBase64) : this.defaultTheme.portalUrl; break; case ThemeDataType.HEADER_LOGO: return userAuthGraphicIdentity && userAuthGraphicIdentity.headerDataBase64 && userAuthGraphicIdentity.hasCustomGraphicIdentity ? this.domSanitizer.bypassSecurityTrustUrl('data:image/*;base64,' + userAuthGraphicIdentity.headerDataBase64) : this.defaultTheme.headerUrl; break; case ThemeDataType.FOOTER_LOGO: return userAuthGraphicIdentity && userAuthGraphicIdentity.footerDataBase64 && userAuthGraphicIdentity.hasCustomGraphicIdentity ? this.domSanitizer.bypassSecurityTrustUrl('data:image/*;base64,' + userAuthGraphicIdentity.footerDataBase64) : this.defaultTheme.footerUrl; break; default: return; } } private calculateFontColor(color: string): string { const rgbColor = hexToRgb(color); if ((rgbColor.r * 0.299 + rgbColor.g * 0.587 + rgbColor.b * 0.114) > 186) { return '#000000'; } else { return '#ffffff'; } } private add10Declinations(key: string, colors: {}, customerColors: {[colorId: string]: string}): void { // tslint:disable-next-line: variable-name const map = {...this.defaultMap, ...this.applicationColorMap, ...customerColors}; const rgbValue = hexToRgb(map[key]); // consider hs-L from color key as 500 colors[key + '-900'] = convertLighten(rgbValue, -32); colors[key + '-800'] = convertLighten(rgbValue, -24); colors[key + '-700'] = convertLighten(rgbValue, -16); colors[key + '-600'] = convertLighten(rgbValue, -8); colors[key + '-400'] = convertLighten(rgbValue, 8); colors[key + '-300'] = convertLighten(rgbValue, 16); colors[key + '-200'] = convertLighten(rgbValue, 24); colors[key + '-100'] = convertLighten(rgbValue, 32); colors[key + '-50'] = convertLighten(rgbValue, 40); colors[key + '-900-font'] = this.calculateFontColor(colors[key + '-900']); colors[key + '-800-font'] = this.calculateFontColor(colors[key + '-800']); colors[key + '-700-font'] = this.calculateFontColor(colors[key + '-700']); colors[key + '-600-font'] = this.calculateFontColor(colors[key + '-600']); colors[key + '-font'] = this.calculateFontColor(map[key]); // primary/secondary/tertiary colors[key + '-400-font'] = this.calculateFontColor(colors[key + '-400']); colors[key + '-300-font'] = this.calculateFontColor(colors[key + '-300']); colors[key + '-200-font'] = this.calculateFontColor(colors[key + '-200']); colors[key + '-100-font'] = this.calculateFontColor(colors[key + '-100']); colors[key + '-50-font'] = this.calculateFontColor(colors[key + '-50']); } /** * Gives complete color theme from current app config and any given customization. * Setting base colors (primary, secondary) will return updated variations (primary-light etc..) * @param customerColors Entries to override */ public getThemeColors(customerColors: {[colorId: string]: string} = null): {[colorId: string]: string} { const colors = {}; for (const key in this.defaultMap) { if (this.defaultMap.hasOwnProperty(key)) { if (([ThemeColorType.VITAMUI_PRIMARY, ThemeColorType.VITAMUI_SECONDARY, ThemeColorType.VITAMUI_GREY] as string[]).includes(key)) { this.add10Declinations(key, colors, customerColors); } colors[key] = getColorFromMaps(key, this.defaultMap, this.applicationColorMap, customerColors); } } return colors; } public overrideTheme(customerThemeMap, selector= 'body'): void { const element: HTMLElement = document.querySelector(selector); const themeColors = this.getThemeColors(customerThemeMap); for (const key in themeColors) { if (themeColors.hasOwnProperty(key)) { element.style.setProperty('--' + key, themeColors[key]); element.style.setProperty('--' + key + '-rgb', hexToRgbString(themeColors[key])); } } } }