From f485a52d9aad83d3c0c9c4bcd1cfaf60e2a4504c Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 21 Jan 2022 16:08:32 +0100 Subject: [PATCH] feat(console): apply text color, fallback to zitadel themes if colors not adequate (#3087) * feat: fallback to real themes if colors not adequate * lint --- console/src/app/app.component.ts | 49 +++++++++++++++++-- console/src/app/services/theme.service.ts | 23 +++++++-- console/src/styles.scss | 59 ++++++++++++----------- 3 files changed, 94 insertions(+), 37 deletions(-) diff --git a/console/src/app/app.component.ts b/console/src/app/app.component.ts index 467badae9..65e40c857 100644 --- a/console/src/app/app.component.ts +++ b/console/src/app/app.component.ts @@ -235,6 +235,9 @@ export class AppComponent implements OnDestroy { const darkBackground = '#212224'; const lightBackground = '#fafafa'; + const darkText = '#ffffff'; + const lightText = '#000000'; + this.themeService.savePrimaryColor(darkPrimary, true); this.themeService.savePrimaryColor(lightPrimary, false); @@ -243,6 +246,9 @@ export class AppComponent implements OnDestroy { this.themeService.saveBackgroundColor(darkBackground, true); this.themeService.saveBackgroundColor(lightBackground, false); + + this.themeService.saveTextColor(darkText, true); + this.themeService.saveTextColor(lightText, false); }; setDefaultColors(); @@ -251,14 +257,20 @@ export class AppComponent implements OnDestroy { if (labelpolicy.policy) { this.labelpolicy = labelpolicy.policy; + const isDark = (color: string) => this.themeService.isDark(color); + const isLight = (color: string) => this.themeService.isLight(color); + const darkPrimary = this.labelpolicy?.primaryColorDark || '#5282c1'; const lightPrimary = this.labelpolicy?.primaryColor || '#5282c1'; const darkWarn = this.labelpolicy?.warnColorDark || '#cd3d56'; const lightWarn = this.labelpolicy?.warnColor || '#cd3d56'; - const darkBackground = this.labelpolicy?.backgroundColorDark || '#212224'; - const lightBackground = this.labelpolicy?.backgroundColor || '#fafafa'; + let darkBackground = this.labelpolicy?.backgroundColorDark; + let lightBackground = this.labelpolicy?.backgroundColor; + + let darkText = this.labelpolicy.fontColorDark; + let lightText = this.labelpolicy.fontColor; this.themeService.savePrimaryColor(darkPrimary, true); this.themeService.savePrimaryColor(lightPrimary, false); @@ -266,8 +278,37 @@ export class AppComponent implements OnDestroy { this.themeService.saveWarnColor(darkWarn, true); this.themeService.saveWarnColor(lightWarn, false); - this.themeService.saveBackgroundColor(darkBackground, true); - this.themeService.saveBackgroundColor(lightBackground, false); + if (darkBackground && !isDark(darkBackground)) { + console.info( + `Background (${darkBackground}) is not dark enough for a dark theme. Falling back to zitadel background`, + ); + darkBackground = '#212224'; + } + this.themeService.saveBackgroundColor(darkBackground || '#212224', true); + + if (lightBackground && !isLight(lightBackground)) { + console.info( + `Background (${lightBackground}) is not light enough for a light theme. Falling back to zitadel background`, + ); + lightBackground = '#fafafa'; + } + this.themeService.saveBackgroundColor(lightBackground || '#fafafa', false); + + if (darkText && !isLight(darkText)) { + console.info( + `Text color (${darkText}) is not light enough for a dark theme. Falling back to zitadel's text color`, + ); + darkText = '#ffffff'; + } + this.themeService.saveTextColor(darkText || '#ffffff', true); + + if (lightText && !isDark(lightText)) { + console.info( + `Text color (${lightText}) is not dark enough for a light theme. Falling back to zitadel's text color`, + ); + lightText = '#000000'; + } + this.themeService.saveTextColor(lightText || '#000000', false); } }); } diff --git a/console/src/app/services/theme.service.ts b/console/src/app/services/theme.service.ts index 656d79ceb..992f65db2 100644 --- a/console/src/app/services/theme.service.ts +++ b/console/src/app/services/theme.service.ts @@ -23,11 +23,8 @@ export class ThemeService { } public updateTheme(colors: Color[], type: string, theme: string): void { - colors.forEach(color => { - document.documentElement.style.setProperty( - `--theme-${theme}-${type}-${color.name}`, - color.hex, - ); + colors.forEach((color) => { + document.documentElement.style.setProperty(`--theme-${theme}-${type}-${color.name}`, color.hex); document.documentElement.style.setProperty( `--theme-${theme}-${type}-contrast-${color.name}`, color.darkContrast ? 'hsla(0, 0%, 0%, 0.87)' : '#ffffff', @@ -50,6 +47,12 @@ export class ThemeService { this.updateTheme(this.backgroundColorPalette, 'background', isDark ? 'dark' : 'light'); } + public saveTextColor(colorHex: string, isDark: boolean): void { + this.primaryColorPalette = this.computeColors(colorHex); + const theme = isDark ? 'dark' : 'light'; + document.documentElement.style.setProperty(`--theme-${theme}-${'text'}`, colorHex); + } + private computeColors(hex: string): Color[] { return [ this.getColorObject(tinycolor(hex).lighten(52), '50'), @@ -77,4 +80,14 @@ export class ThemeService { darkContrast: c.isLight(), }; } + + public isLight(hex: string): boolean { + const color = tinycolor(hex); + return color.isLight(); + } + + public isDark(hex: string): boolean { + const color = tinycolor(hex); + return color.isDark(); + } } diff --git a/console/src/styles.scss b/console/src/styles.scss index ef6b5ceaf..876b9512f 100644 --- a/console/src/styles.scss +++ b/console/src/styles.scss @@ -221,14 +221,17 @@ $caos-light-warn: ( ), ); +$caos-dark-theme-text: var(--theme-dark-text); +$caos-light-theme-text: var(--theme-light-text); + $caos-dark-theme-background: ( status-bar: map_get($caos-dark-background, 300), app-bar: map_get($caos-dark-background, 500), background: map_get($caos-dark-background, 500), - hover: rgba(black, .04), + hover: rgba(black, 0.04), card: map_get($caos-dark-background, 400), dialog: map_get($caos-dark-background, 500), - disabled-button: rgba(black, .12), + disabled-button: rgba(black, 0.12), raised-button: white, focused-button: $dark-focused, selected-button: map_get($caos-dark-background, 300), @@ -246,10 +249,10 @@ $caos-light-theme-background: ( status-bar: map_get($caos-light-background, 300), app-bar: map_get($caos-light-background, 100), background: map_get($caos-light-background, 500), - hover: rgba(black, .04), + hover: rgba(black, 0.04), card: map_get($caos-light-background, 400), dialog: map_get($caos-light-background, 500), - disabled-button: rgba(black, .12), + disabled-button: rgba(black, 0.12), raised-button: white, focused-button: $light-focused, selected-button: map_get($caos-light-background, 300), @@ -268,17 +271,17 @@ $caos-dark-theme-foreground: ( divider: $light-dividers, dividers: $light-dividers, disabled: $light-disabled-text, - disabled-button: rgba(white, .26), + disabled-button: rgba(white, 0.26), disabled-text: $light-disabled-text, elevation: black, hint-text: $light-disabled-text, secondary-text: $light-secondary-text, - icon: rgba(white, .54), - icons: rgba(white, .54), - text: rgba(white, .87), - slider-min: rgba(white, .87), - slider-off: rgba(white, .26), - slider-off-active: rgba(white, .38), + icon: rgba(white, 0.54), + icons: rgba(white, 0.54), + text: $caos-dark-theme-text, + slider-min: rgba(white, 0.87), + slider-off: rgba(white, 0.26), + slider-off-active: rgba(white, 0.38), infosection: #f0f0f0, warninfosection: #ffc1c1, successinfosection: #cbf4c9, @@ -289,17 +292,17 @@ $caos-light-theme-foreground: ( divider: $dark-dividers, dividers: $dark-dividers, disabled: $dark-disabled-text, - disabled-button: rgba(black, .26), + disabled-button: rgba(black, 0.26), disabled-text: $dark-disabled-text, elevation: black, hint-text: $dark-disabled-text, secondary-text: $dark-secondary-text, - icon: rgba(black, .54), - icons: rgba(black, .54), - text: rgba(black, .87), - slider-min: rgba(black, .87), - slider-off: rgba(black, .26), - slider-off-active: rgba(black, .38), + icon: rgba(black, 0.54), + icons: rgba(black, 0.54), + text: $caos-light-theme-text, + slider-min: rgba(black, 0.87), + slider-off: rgba(black, 0.26), + slider-off-active: rgba(black, 0.38), infosection: #4a4a4a, warninfosection: #620e0e, successinfosection: #0e6245, @@ -357,12 +360,12 @@ $custom-typography: .main-container, .mat-dialog-container { background-color: map-get($background, background); - transition: background-color .3s cubic-bezier(.645, .045, .355, 1); + transition: background-color 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); } ::-webkit-scrollbar-track { - -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .1); - box-shadow: inset 0 0 6px rgba(0, 0, 0, .1); + -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1); background-color: map-get($background, background); border-radius: 8px; } @@ -397,29 +400,29 @@ $custom-typography: .main-container, .mat-dialog-container { background-color: map-get($background, background); - transition: background-color .3s cubic-bezier(.645, .045, .355, 1); + transition: background-color 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); } ::-webkit-scrollbar-track { - -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3); - box-shadow: inset 0 0 6px rgba(0, 0, 0, .3); + -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); + box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); background-color: map-get($background, background); border-radius: 8px; - transition: all .3s cubic-bezier(.645, .045, .355, 1) !important; + transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1) !important; } ::-webkit-scrollbar { width: 6px; height: 6px; background-color: map-get($background, background); - transition: all .3s cubic-bezier(.645, .045, .355, 1) !important; + transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1) !important; } ::-webkit-scrollbar-thumb { background-color: #737c8870; border-radius: 8px; cursor: pointer; - transition: all .3s cubic-bezier(.645, .045, .355, 1) !important; + transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1) !important; } .root-header { @@ -502,5 +505,5 @@ i { } .mat-checkbox-inner-container.mat-checkbox-inner-container-no-side-margin { - margin-right: .5rem !important; + margin-right: 0.5rem !important; }