Skip to content

Instantly share code, notes, and snippets.

@nartc
Created Jan 20, 2021
Embed
What would you like to do?
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