diff options
author | crupest <crupest@outlook.com> | 2021-05-06 20:57:18 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2021-05-06 20:57:18 +0800 |
commit | 9b567399b4da6a2ef787160667105907ecdea41d (patch) | |
tree | 29dfacb012f929424dc453f8ba04034f57d91296 /FrontEnd/src/app/palette.ts | |
parent | d7f32f764c28a923279a8d2133c471f2cf4afba1 (diff) | |
download | timeline-9b567399b4da6a2ef787160667105907ecdea41d.tar.gz timeline-9b567399b4da6a2ef787160667105907ecdea41d.tar.bz2 timeline-9b567399b4da6a2ef787160667105907ecdea41d.zip |
...
Diffstat (limited to 'FrontEnd/src/app/palette.ts')
-rw-r--r-- | FrontEnd/src/app/palette.ts | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/FrontEnd/src/app/palette.ts b/FrontEnd/src/app/palette.ts new file mode 100644 index 00000000..63a70c4e --- /dev/null +++ b/FrontEnd/src/app/palette.ts @@ -0,0 +1,111 @@ +import Color from "color"; +import { BehaviorSubject, Observable } from "rxjs"; + +function lightenBy(color: Color, ratio: number): Color { + const lightness = color.lightness(); + return color.lightness(lightness + (100 - lightness) * ratio); +} + +function darkenBy(color: Color, ratio: number): Color { + const lightness = color.lightness(); + return color.lightness(lightness - lightness * ratio); +} + +export interface PaletteColor { + color: string; + inactive: string; + lighter: string; + darker: string; + [key: string]: string; +} + +export interface Palette { + primary: PaletteColor; + primaryEnhance: PaletteColor; + secondary: PaletteColor; + textPrimary: PaletteColor; + textOnPrimary: PaletteColor; + danger: PaletteColor; + success: PaletteColor; + [key: string]: PaletteColor; +} + +export function generatePaletteColor(color: string): PaletteColor { + const c = Color(color); + return { + color: c.toString(), + inactive: (c.isLight() ? darkenBy(c, 0.2) : lightenBy(c, 0.2)).toString(), + lighter: lightenBy(c, 0.1).fade(0.1).toString(), + darker: darkenBy(c, 0.1).toString(), + }; +} + +export function generatePalette(options: { + primary: string; + primaryEnhance?: string; + secondary?: string; +}): Palette { + const { primary, primaryEnhance, secondary } = options; + const p = Color(primary); + const pe = + primaryEnhance == null + ? lightenBy(p, 0.3).saturate(0.3) + : Color(primaryEnhance); + const s = secondary == null ? p.rotate(90) : Color(secondary); + + return { + primary: generatePaletteColor(p.toString()), + primaryEnhance: generatePaletteColor(pe.toString()), + secondary: generatePaletteColor(s.toString()), + textPrimary: generatePaletteColor("#111111"), + textOnPrimary: generatePaletteColor(p.isLight() ? "black" : "white"), + danger: generatePaletteColor("red"), + success: generatePaletteColor("green"), + }; +} + +export function generatePaletteCSS(palette: Palette): string { + function toSnakeCase(s: string): string { + return s.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`); + } + + const colors: [string, string][] = []; + for (const paletteColorName in palette) { + const paletteColor = palette[paletteColorName]; + for (const variant in paletteColor) { + let key = `--tl-${toSnakeCase(paletteColorName)}`; + if (variant !== "color") key += `-${toSnakeCase(variant)}`; + key += "-color"; + colors.push([key, paletteColor[variant]]); + } + } + + return `:root {${colors + .map(([key, color]) => `${key} : ${color};`) + .join("")}}`; +} + +const paletteSubject: BehaviorSubject<Palette> = new BehaviorSubject<Palette>( + generatePalette({ primary: "#007bff" }) +); + +export const palette$: Observable<Palette> = paletteSubject.asObservable(); + +palette$.subscribe((palette) => { + let styleTag = document.getElementById("timeline-palette-css"); + if (styleTag == null) { + styleTag = document.createElement("style"); + document.head.append(styleTag); + } + styleTag.innerHTML = generatePaletteCSS(palette); +}); + +export function setPalette(palette: Palette): () => void { + const old = paletteSubject.value; + + paletteSubject.next(palette); + + return () => { + paletteSubject.next(old); + }; +} |