From 47587812b809fee2a95c76266d9d0e42fc4ac1ca Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 15 Jun 2021 14:14:28 +0800 Subject: ... --- FrontEnd/src/palette.ts | 116 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 FrontEnd/src/palette.ts (limited to 'FrontEnd/src/palette.ts') diff --git a/FrontEnd/src/palette.ts b/FrontEnd/src/palette.ts new file mode 100644 index 00000000..c4f4f4f9 --- /dev/null +++ b/FrontEnd/src/palette.ts @@ -0,0 +1,116 @@ +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.lightness() > 60 + ? darkenBy(c, 0.1) + : 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.lightness() > 60 ? "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 = new BehaviorSubject( + generatePalette({ primary: "#007bff" }) +); + +export const palette$: Observable = paletteSubject.asObservable(); + +palette$.subscribe((palette) => { + const styleTagId = "timeline-palette-css"; + let styleTag = document.getElementById(styleTagId); + if (styleTag == null) { + styleTag = document.createElement("style"); + styleTag.id = styleTagId; + 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); + }; +} -- cgit v1.2.3