You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
85 lines
2.1 KiB
85 lines
2.1 KiB
import colors from "./colors.json";
|
|
import { hslToHex, hexToHsl, contrastRatio } from "./colors";
|
|
import { clamp } from "./math";
|
|
|
|
type Pallette = {
|
|
bg: string;
|
|
fg: string;
|
|
red: string;
|
|
green: string;
|
|
shade1: string;
|
|
shade2: string;
|
|
shade3: string;
|
|
shade4: string;
|
|
};
|
|
|
|
const MIN_CONTRAST = 3.0;
|
|
const FALLBACK_WHITE = "#ffffff";
|
|
|
|
const bg = colors.bg ?? "#0f0f10";
|
|
const fg = colors.fg ?? "#e6e6e6";
|
|
const redHue = colors.accentRedHue ?? 0;
|
|
const greenHue = colors.accentGreenHue ?? 140;
|
|
const sat = colors.accentSaturation ?? 65;
|
|
const light = colors.accentLightness ?? 60;
|
|
const steps = colors.shadeSteps ?? 4;
|
|
|
|
// generate accents
|
|
// ensure reasonable contrast with bg; if too low, nudge lightness
|
|
const fixContrast = (
|
|
ref: string,
|
|
hue: number,
|
|
sat: number,
|
|
lightness: number,
|
|
) => {
|
|
let cur = hslToHex(hue, sat, lightness);
|
|
let ctr = contrastRatio(cur, ref);
|
|
let l = lightness;
|
|
let tries = 0;
|
|
while (ctr < MIN_CONTRAST && tries < 10) {
|
|
l = clamp(l + 6, 0, 100); // make lighter
|
|
cur = hslToHex(hue, sat, l);
|
|
ctr = contrastRatio(cur, ref);
|
|
tries++;
|
|
}
|
|
return cur;
|
|
};
|
|
|
|
const red = fixContrast(bg, redHue, sat, light);
|
|
const green = fixContrast(bg, greenHue, sat, light);
|
|
|
|
// generate 4 darker shades from fg towards bg by lightness interpolation
|
|
const { h: fgH, s: fgS, l: fgL } = hexToHsl(fg);
|
|
const { s: bgS, l: bgL } = hexToHsl(bg);
|
|
const shades: string[] = [];
|
|
for (let i = 1; i <= steps; i++) {
|
|
const t = i / (steps + 1); // fraction towards bg
|
|
const l = fgL + (bgL - fgL) * t;
|
|
const s = fgS + (bgS - fgS) * t;
|
|
const h = fgH; // keep fg hue
|
|
shades.push(hslToHex(h, s, l));
|
|
}
|
|
|
|
const pallette: Pallette = {
|
|
bg,
|
|
fg,
|
|
red,
|
|
green,
|
|
shade1: shades[0] ?? FALLBACK_WHITE,
|
|
shade2: shades[1] ?? FALLBACK_WHITE,
|
|
shade3: shades[2] ?? FALLBACK_WHITE,
|
|
shade4: shades[3] ?? FALLBACK_WHITE,
|
|
};
|
|
|
|
function* createPalletteGenerator() {
|
|
const keys = Object.keys(pallette) as (keyof Pallette)[];
|
|
for (let key of keys) {
|
|
yield [key, pallette[key]];
|
|
}
|
|
}
|
|
|
|
const palletteGenerator = createPalletteGenerator();
|
|
|
|
export { pallette, palletteGenerator };
|
|
export type { Pallette };
|