-
-
Save nartc/f6757f6ad9037436270cb93734c196ac to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { DOCUMENT } from '@angular/common'; | |
import { Inject, Injectable } from '@angular/core'; | |
import { Observable } from 'rxjs'; | |
import * as tinycolor from 'tinycolor2'; | |
import { StateSubject } from '../extensions/state-subject'; | |
export interface Theme { | |
primary: string; | |
accent: string; | |
warn: string; | |
} | |
interface Color { | |
name: string; | |
hex: string; | |
isDarkContrast: boolean; | |
} | |
@Injectable({ | |
providedIn: 'root', | |
}) | |
export class ThemeService { | |
private readonly defaultTheme: Theme = { | |
primary: '#2c7be5', | |
accent: '#05d27a', | |
warn: '#e63757', | |
}; | |
private readonly $currentTheme = new StateSubject<Theme>(this.defaultTheme); | |
constructor(@Inject(DOCUMENT) private readonly document: Document) {} | |
get currentTheme$(): Observable<Theme> { | |
return this.$currentTheme.asObservable(); | |
} | |
get currentTheme(): Theme { | |
return this.$currentTheme.getValue(); | |
} | |
setTheme(theme: Theme) { | |
this.$currentTheme.setState(theme); | |
this._updateThemeVariables(theme); | |
} | |
private _updateThemeVariables(theme: Theme) { | |
for (const [name, color] of Object.entries(theme)) { | |
const palette = computeColors(color); | |
for (const variant of palette) { | |
this.document.documentElement.style.setProperty(`--${name}-${variant.name}`, variant.hex); | |
this.document.documentElement.style.setProperty( | |
`--${name}-contrast-${variant.name}`, | |
variant.isDarkContrast ? '#000' : '#fff', | |
); | |
} | |
} | |
} | |
} | |
function computeColors(hex: string): Color[] { | |
return [ | |
getColorObject(tinycolor(hex).lighten(52), '50'), | |
getColorObject(tinycolor(hex).lighten(37), '100'), | |
getColorObject(tinycolor(hex).lighten(26), '200'), | |
getColorObject(tinycolor(hex).lighten(12), '300'), | |
getColorObject(tinycolor(hex).lighten(6), '400'), | |
getColorObject(tinycolor(hex), '500'), | |
getColorObject(tinycolor(hex).darken(6), '600'), | |
getColorObject(tinycolor(hex).darken(12), '700'), | |
getColorObject(tinycolor(hex).darken(18), '800'), | |
getColorObject(tinycolor(hex).darken(24), '900'), | |
getColorObject(tinycolor(hex).lighten(50).saturate(30), 'a100'), | |
getColorObject(tinycolor(hex).lighten(30).saturate(30), 'a200'), | |
getColorObject(tinycolor(hex).lighten(10).saturate(15), 'a400'), | |
getColorObject(tinycolor(hex).lighten(5).saturate(5), 'a700'), | |
]; | |
} | |
function getColorObject(value: tinycolor.Instance, name: string): Color { | |
const c = tinycolor(value); | |
return { | |
name, | |
hex: c.toHexString(), | |
isDarkContrast: c.isLight(), | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment