ooknet/outputs/lib/color/utils.nix

320 lines
8.5 KiB
Nix

{
math,
types,
translate,
}: let
# Base modification functions
modifyHSL = hexStr: modifications: let
hslSet = translate.hex.toHSL.set hexStr;
newHSL = types.hsl.set {
inherit (hslSet) h;
l = math.clamp 0.0 1.0 (hslSet.l + (modifications.l or 0.0));
s = math.clamp 0.0 1.0 (hslSet.s + (modifications.s or 0.0));
};
rgbSet = translate.hsl.toRGB.set newHSL;
in
translate.rgb.toHex.string rgbSet;
lighten = amount: hexStr:
modifyHSL hexStr {l = amount / 100.0;};
darken = amount: hexStr:
modifyHSL hexStr {l = (amount * -1) / 100.0;};
saturate = amount: hexStr:
modifyHSL hexStr {s = amount / 100.0;};
desaturate = amount: hexStr:
modifyHSL hexStr {s = (amount * -1) / 100.0;};
# opinionated scale generators for light/dark themes
# lighter/darker shades always desaturate
mkDarkColorScale = base: {
up4 = desaturate 24 (lighten 12 base);
up3 = desaturate 18 (lighten 9 base);
up2 = desaturate 12 (lighten 6 base);
up1 = desaturate 6 (lighten 3 base);
inherit base;
down1 = desaturate 6 (darken 3 base);
down2 = desaturate 12 (darken 6 base);
down3 = desaturate 18 (darken 9 base);
down4 = desaturate 24 (darken 12 base);
};
mkLightColorScale = base: {
down4 = desaturate 24 (lighten 12 base);
down3 = desaturate 18 (lighten 9 base);
down2 = desaturate 12 (lighten 6 base);
down1 = desaturate 6 (lighten 3 base);
inherit base;
up1 = desaturate 6 (darken 3 base);
up2 = desaturate 12 (darken 6 base);
up3 = desaturate 18 (darken 9 base);
up4 = desaturate 24 (darken 12 base);
};
# core color scheme generator
mkColorScheme = {
type ? "dark",
neutrals ? {},
primary,
red,
orange,
yellow,
olive,
green,
teal,
blue,
violet,
purple,
pink,
brown,
} @ args: let
# Select scale function based on theme type
colorScale =
if type == "dark"
then mkDarkColorScale
else mkLightColorScale;
# Generate color scales
colorScales = {
red = colorScale args.red;
orange = colorScale args.orange;
yellow = colorScale args.yellow;
olive = colorScale args.olive;
green = colorScale args.green;
teal = colorScale args.teal;
blue = colorScale args.blue;
violet = colorScale args.violet;
purple = colorScale args.purple;
pink = colorScale args.pink;
brown = colorScale args.brown;
};
# Theme-specific configurations
themeConfig =
if type == "dark"
then {
semantic = {
body = args.neutrals."700";
header = args.neutrals."800";
footer = args.neutrals."800";
menu = args.neutrals."800";
border = args.neutrals."150";
border-active = args.neutrals."150";
border-inactive = args.neutrals."600";
text = args.neutrals."150";
text-bright = args.neutrals."100";
subtext = args.neutrals."300";
};
secondary = {
up-4 = args.neutrals."400";
up-3 = args.neutrals."450";
up-2 = args.neutrals."500";
up-1 = args.neutrals."550";
base = args.neutrals."700";
down-1 = args.neutrals."750";
down-2 = args.neutrals."800";
down-3 = args.neutrals."850";
down-4 = args.neutrals."900";
};
base00 = args.neutrals."800";
base01 = args.neutrals."700";
base02 = args.neutrals."600";
base03 = args.neutrals."450";
base04 = args.neutrals."300";
base05 = args.neutrals."150";
base06 = args.neutrals."100";
base07 = args.neutrals."50";
base10 = args.neutrals."850";
base11 = args.neutrals."900";
}
else {
semantic = {
body = args.neutrals."50";
header = args.neutrals."150";
footer = args.neutrals."150";
menu = args.neutrals."150";
border = args.neutrals."800";
border-active = args.neutrals."800";
border-inactive = args.neutrals."300";
text = args.neutrals."800";
text-bright = args.neutrals."850";
subtext = args.neutrals."600";
};
secondary = {
up-4 = args.neutrals."400";
up-3 = args.neutrals."350";
up-2 = args.neutrals."300";
up-1 = args.neutrals."250";
base = args.neutrals."200";
down-1 = args.neutrals."150";
down-2 = args.neutrals."100";
down-3 = args.neutrals."50";
down-4 = args.neutrals."50";
};
base00 = args.neutrals."150";
base01 = args.neutrals."250";
base02 = args.neutrals."450";
base03 = args.neutrals."550";
base04 = args.neutrals."650";
base05 = args.neutrals."800";
base06 = args.neutrals."850";
base07 = args.neutrals."900";
base10 = args.neutrals."100";
base11 = args.neutrals."50";
};
in {
# Common structure for both themes
neutrals = {
inherit
(args.neutrals)
"50"
"100"
"150"
"200"
"250"
"300"
"350"
"400"
"450"
"500"
"550"
"600"
"650"
"700"
"750"
"800"
"850"
"900"
;
};
inherit
(colorScales)
red
orange
yellow
olive
green
teal
blue
violet
purple
pink
brown
;
primary = colorScale args.primary;
inherit (themeConfig) semantic secondary;
# Status colors (same structure for both themes)
error = {
bg = "${colorScales.red.base}";
bg-active = "${colorScales.red.down1}";
bg-hover = "${colorScales.red.down2}";
text = "${themeConfig.semantic.text-bright}";
border = "${colorScales.red.up2}";
};
success = {
bg = "${colorScales.green.base}";
bg-active = "${colorScales.green.down1}";
bg-hover = "${colorScales.green.down2}";
text = "${themeConfig.semantic.text-bright}";
border = "${colorScales.green.up2}";
};
warning = {
bg = "${colorScales.yellow.base}";
bg-active = "${colorScales.yellow.down1}";
bg-hover = "${colorScales.yellow.down2}";
text = "${themeConfig.semantic.text-bright}";
border = "${colorScales.yellow.up2}";
};
info = {
bg = "${colorScales.blue.base}";
bg-active = "${colorScales.blue.down1}";
bg-hover = "${colorScales.blue.down2}";
text = "${themeConfig.semantic.text-bright}";
border = "${colorScales.blue.up2}";
};
tip = {
bg = "${colorScales.teal.base}";
bg-active = "${colorScales.teal.down1}";
bg-hover = "${colorScales.teal.down2}";
text = "${themeConfig.semantic.text-bright}";
border = "${colorScales.teal.up2}";
};
# Syntax highlighting (same for both themes)
syntax = {
string = args.green;
number = args.purple;
float = args.purple;
boolean = args.purple;
type = args.yellow;
structure = args.orange;
statement = args.red;
label = args.orange;
operator = args.orange;
identifier = args.blue;
function = args.green;
storageClass = args.orange;
constant = args.teal;
exception = args.red;
preproc = args.purple;
include = args.purple;
define = args.purple;
macro = args.teal;
preCondit = args.purple;
special = args.yellow;
specialChar = args.yellow;
comment = "${themeConfig.semantic.subtext}";
todo = args.purple;
tag = args.teal;
};
# Base16/24 colors
inherit
(themeConfig)
base00
base01
base02
base03
base04
base05
base06
base07
base10
base11
;
# Generated base colors
base08 = args.red;
base09 = args.orange;
base0A = args.yellow;
base0B = args.green;
base0C = args.teal;
base0D = args.blue;
base0E = args.purple;
base0F = args.brown;
base12 = "${colorScales.red.up2}";
base13 = "${colorScales.yellow.up2}";
base14 = "${colorScales.green.up2}";
base15 = "${colorScales.teal.up2}";
base16 = "${colorScales.blue.up2}";
base17 = "${colorScales.purple.up2}";
};
# wrappers
mkDarkColorScheme = args: mkColorScheme (args // {type = "dark";});
mkLightColorScheme = args: mkColorScheme (args // {type = "light";});
in {
inherit lighten darken saturate desaturate;
inherit mkDarkColorScale mkLightColorScale;
inherit mkColorScheme mkDarkColorScheme mkLightColorScheme;
}