mirror of
https://github.com/foo-dogsquared/nixos-config.git
synced 2025-01-31 04:58:01 +00:00
bahaghari/lib: implement basic HSL color namespace
This commit is contained in:
parent
a170fd8344
commit
2576ef4e43
135
subprojects/bahaghari/lib/colors/hsl.nix
Normal file
135
subprojects/bahaghari/lib/colors/hsl.nix
Normal file
@ -0,0 +1,135 @@
|
||||
# Similar to RGB, we're also going to base our implementation from looking
|
||||
# after the W3 CSS Color Module Level 4 specification simply because it is the
|
||||
# most common one.
|
||||
{ pkgs, lib, self }:
|
||||
|
||||
let inherit (self.colors) rgb;
|
||||
in rec {
|
||||
valueHueMin = 0.0;
|
||||
valueHueMax = 360.0;
|
||||
valueParamMin = 0.0;
|
||||
valueParamMax = 100.0;
|
||||
|
||||
/* Generates an HSL colorspace object to be generated with its method for
|
||||
convenience.
|
||||
|
||||
Type: HSL :: Attrs -> Attrs
|
||||
|
||||
Example:
|
||||
HSL { h = 242.0; s = 25; l = 50; }
|
||||
=> {
|
||||
# The individual hue, saturation, and luminance levels.
|
||||
|
||||
# And several methods.
|
||||
methods = {
|
||||
toRgb = <function>;
|
||||
lighten = <function>;
|
||||
};
|
||||
}
|
||||
*/
|
||||
HSL = { h, s, l, ... }@color:
|
||||
assert lib.assertMsg (isHsl color)
|
||||
"bahaghariLib.colors.hsl.HSL: given color does not have valid HSL value";
|
||||
{
|
||||
inherit h s l;
|
||||
} // lib.optionalAttrs (color ? a) { inherit (color) a; };
|
||||
|
||||
/* Returns a boolean if the object is a valid HSL Nix object.
|
||||
|
||||
Type: isHsl :: Attrs -> Bool
|
||||
|
||||
Example:
|
||||
isHsl { h = 43; s = 89; l = 79; }
|
||||
=> true
|
||||
|
||||
# The hue value is over 360 so it isn't valid.
|
||||
isHsl { h = 467; s = 78; l = 50; }
|
||||
=> false
|
||||
|
||||
# The lightness is over 100 so not valid either.
|
||||
isHsl { h = 360; s = 86; l = 120; }
|
||||
=> false
|
||||
*/
|
||||
isHsl = { h, s, l, ... }@color:
|
||||
let
|
||||
isValidHue = self.math.isWithinRange valueHueMin valueHueMax;
|
||||
isValidPercentage = self.math.isWithinRange valueParamMin valueParamMax;
|
||||
in
|
||||
isValidHue h && isValidPercentage s && isValidPercentage l;
|
||||
|
||||
/* Converts an HSL object to RGB instance.
|
||||
|
||||
Formula is directly taken from the following resource:
|
||||
https://www.rapidtables.com/convert/color/hsl-to-rgb.html
|
||||
|
||||
Type: toRgb :: Attrs -> Attrs
|
||||
|
||||
Example:
|
||||
toRgb { h = 234; s = 65; l = 73; }
|
||||
=> { r = 43; g = 52; b = 56 }
|
||||
*/
|
||||
toRgb = { h, s, l, ... }@color:
|
||||
let
|
||||
inherit (self.colors.rgb) RGB valueMax;
|
||||
inherit (self.math) abs sub mod';
|
||||
|
||||
l' = l / valueParamMax;
|
||||
s' = s / valueParamMax;
|
||||
|
||||
# This may as well turn into Scheme code.
|
||||
C = (1 - (abs ((2 * l') - 1))) * s';
|
||||
X = C * (1 - (abs (sub (mod' (h / 60.0) 2) 1)));
|
||||
m = l' - (C / 2);
|
||||
|
||||
isHueWithin = min: max:
|
||||
(h >= min) && (h < max);
|
||||
rgb' =
|
||||
if (isHueWithin 0 60) then
|
||||
{ r = C; g = X; b = 0; }
|
||||
else if (isHueWithin 60 120) then
|
||||
{ r = X; g = C; b = 0; }
|
||||
else if (isHueWithin 120 180) then
|
||||
{ r = 0; g = C; b = X; }
|
||||
else if (isHueWithin 180 240) then
|
||||
{ r = 0; g = X; b = C; }
|
||||
else if (isHueWithin 240 300) then
|
||||
{ r = X; g = 0; b = C; }
|
||||
else if (isHueWithin 300 360) then
|
||||
{ r = C; g = 0; b = X; }
|
||||
else throw "WHAT IN THE HELL";
|
||||
|
||||
scaleValue = x: self.math.round ((x + m) * valueMax);
|
||||
in
|
||||
RGB {
|
||||
r = scaleValue rgb'.r;
|
||||
g = scaleValue rgb'.g;
|
||||
b = scaleValue rgb'.b;
|
||||
};
|
||||
|
||||
/* Converts an HSL object into an RGB hex string.
|
||||
|
||||
Type: toHex :: Attrs -> String
|
||||
|
||||
Example:
|
||||
toHex { h = 34; s = 76; l = 100; }
|
||||
=> "FFFFFF"
|
||||
*/
|
||||
toHex = color: rgb.toHex (toRgb color);
|
||||
|
||||
/* Converts an HSL object into an RGBA hex string.
|
||||
|
||||
Type: toHex :: Attrs -> String
|
||||
|
||||
Example:
|
||||
toHex { h = 34; s = 76; l = 100; }
|
||||
=> "FFFFFF"
|
||||
*/
|
||||
toHex' = color: rgb.toHex' (toRgb color);
|
||||
|
||||
lighten = { h, s, l, ... }:
|
||||
percentage:
|
||||
HSL {
|
||||
inherit h s;
|
||||
l = l + percentage;
|
||||
};
|
||||
}
|
@ -34,6 +34,7 @@ pkgs.lib.makeExtensible
|
||||
# some unbeknownst and probably irrational reason.
|
||||
colors = {
|
||||
rgb = callLibs ./colors/rgb.nix;
|
||||
hsl = callLibs ./colors/hsl.nix;
|
||||
};
|
||||
|
||||
# Dedicated module sets are not supposed to have any of its functions as a
|
||||
|
@ -13,4 +13,5 @@ in
|
||||
trivial = callLib ./trivial;
|
||||
tinted-theming = callLib ./tinted-theming;
|
||||
rgb = callLib ./rgb.nix;
|
||||
hsl = callLib ./hsl.nix;
|
||||
}
|
||||
|
59
subprojects/bahaghari/tests/lib/hsl.nix
Normal file
59
subprojects/bahaghari/tests/lib/hsl.nix
Normal file
@ -0,0 +1,59 @@
|
||||
{ pkgs, lib, self }:
|
||||
|
||||
let
|
||||
inherit (self.colors.rgb) RGB;
|
||||
inherit (self.colors.hsl) HSL;
|
||||
|
||||
hslSample = HSL {
|
||||
h = 254;
|
||||
s = 100;
|
||||
l = 45;
|
||||
};
|
||||
in lib.runTests {
|
||||
testsBasicHsl = {
|
||||
expr = HSL {
|
||||
h = 245;
|
||||
s = 16;
|
||||
l = 60;
|
||||
};
|
||||
expected = {
|
||||
h = 245;
|
||||
s = 16;
|
||||
l = 60;
|
||||
};
|
||||
};
|
||||
|
||||
testsBasicHsl2 = {
|
||||
expr = HSL {
|
||||
h = 350;
|
||||
s = 16;
|
||||
l = 60;
|
||||
a = 100;
|
||||
};
|
||||
expected = {
|
||||
h = 350;
|
||||
s = 16;
|
||||
l = 60;
|
||||
a = 100;
|
||||
};
|
||||
};
|
||||
|
||||
testsToRgb = {
|
||||
expr = self.colors.hsl.toRgb hslSample;
|
||||
expected = RGB {
|
||||
r = 54;
|
||||
g = 0;
|
||||
b = 230;
|
||||
};
|
||||
};
|
||||
|
||||
testsToHex = {
|
||||
expr = self.colors.hsl.toHex hslSample;
|
||||
expected = "3600E6";
|
||||
};
|
||||
|
||||
testsToHex' = {
|
||||
expr = self.colors.hsl.toHex' hslSample;
|
||||
expected = "3600E6FF";
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user