From 8553010c8417cb934898528c0e76e9b8d432d068 Mon Sep 17 00:00:00 2001 From: Allan Mariucci Carvalho Date: Wed, 6 Nov 2024 12:58:11 -0300 Subject: [PATCH 1/6] created base classes --- src/Colors/Color.php | 14 +++++ src/Colors/Colors.php | 133 +++++++++++++++++++++++++++++++++++++++++ src/Facades/Colors.php | 23 +++++++ 3 files changed, 170 insertions(+) create mode 100644 src/Colors/Color.php create mode 100644 src/Colors/Colors.php create mode 100644 src/Facades/Colors.php diff --git a/src/Colors/Color.php b/src/Colors/Color.php new file mode 100644 index 0000000..19d2889 --- /dev/null +++ b/src/Colors/Color.php @@ -0,0 +1,14 @@ +rgbToHsl(...$this->hexToRgb($hex)); + } + + /** + * @return array{0: int, 1: int, 2: int} + * + * @throws \Exception + */ + public function hexToRgb(string $hex): array + { + $hex = ltrim($hex, '#'); + if (strlen($hex) === 6) { + return [ + hexdec(substr($hex, 0, 2)), + hexdec(substr($hex, 2, 2)), + hexdec(substr($hex, 4, 2)), + ]; + } elseif (strlen($hex) === 3) { + return [ + hexdec(str_repeat(substr($hex, 0, 1), 2)), + hexdec(str_repeat(substr($hex, 1, 1), 2)), + hexdec(str_repeat(substr($hex, 2, 1), 2)), + ]; + } else { + throw new Exception('Invalid hex string'); + } + } + + public function hlsToHex(float $h, float $s, float $l): string + { + return $this->rgbToHex(...$this->hlsToRgb($h, $s, $l)); + } + + /** + * @return array{0: int, 1: int, 2: int} + */ + public function hlsToRgb(float $h, float $s, float $l): array + { + $h /= 360; + $s /= 100; + $l /= 100; + if ($s == 0) { + $r = $g = $b = $l; + } else { + $q = $l < 0.5 ? $l * (1 + $s) : $l + $s - $l * $s; + $p = 2 * $l - $q; + + $r = $this->hueToRgb($p, $q, $h + 1 / 3); + $g = $this->hueToRgb($p, $q, $h); + $b = $this->hueToRgb($p, $q, $h - 1 / 3); + } + + return [ + intval(round($r * 255)), + intval(round($g * 255)), + intval(round($b * 255)), + ]; + } + + protected function hueToRgb(float $p, float $q, float $t): float + { + $t = match (true) { + $t < 0 => $t + 1, + $t > 1 => $t - 1, + default => $t, + }; + + return match (true) { + $t < 1 / 6 => $p + ($q - $p) * 6 * $t, + $t < 1 / 2 => $q, + $t < 2 / 3 => $p + ($q - $p) * (2 / 3 - $t) * 6, + default => $p, + }; + } + + public function rgbToHex(int $r, int $g, int $b): string + { + return sprintf('#%02X%02X%02X', $r, $g, $b); + } + + /** + * @return array{0: float, 1: float, 2: float} + */ + public function rgbToHsl(int $r, int $g, int $b): array + { + $r /= 255; + $g /= 255; + $b /= 255; + + $max = max($r, $g, $b); + $min = min($r, $g, $b); + + $h = $s = 0; + $l = ($max + $min) / 2; + + if ($max !== $min) { + $delta = $max - $min; + $s = $l > 0.5 ? $delta / (2.0 - $max - $min) : $delta / ($max + $min); + + $h = match (true) { + $max == $r => ($g - $b) / $delta + ($g < $b ? 6 : 0), + $max == $g => ($b - $r) / $delta + 2, + default => ($r - $g) / $delta + 4 + }; + + $h /= 6; + } + + return [ + round($h * 360), + round($s * 100), + round($l * 100), + ]; + } +} diff --git a/src/Facades/Colors.php b/src/Facades/Colors.php new file mode 100644 index 0000000..b478212 --- /dev/null +++ b/src/Facades/Colors.php @@ -0,0 +1,23 @@ + Date: Wed, 6 Nov 2024 13:52:04 -0300 Subject: [PATCH 2/6] tests --- src/Colors/Color.php | 14 -------------- src/Colors/Colors.php | 12 ++++++------ src/Facades/Colors.php | 8 ++++---- tests/ColorsTest.php | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 24 deletions(-) delete mode 100644 src/Colors/Color.php create mode 100644 tests/ColorsTest.php diff --git a/src/Colors/Color.php b/src/Colors/Color.php deleted file mode 100644 index 19d2889..0000000 --- a/src/Colors/Color.php +++ /dev/null @@ -1,14 +0,0 @@ -rgbToHex(...$this->hlsToRgb($h, $s, $l)); + return $this->rgbToHex(...$this->hslToRgb($h, $s, $l)); } /** * @return array{0: int, 1: int, 2: int} */ - public function hlsToRgb(float $h, float $s, float $l): array + public function hslToRgb(int $h, int $s, int $l): array { $h /= 360; $s /= 100; @@ -125,9 +125,9 @@ public function rgbToHsl(int $r, int $g, int $b): array } return [ - round($h * 360), - round($s * 100), - round($l * 100), + intval(round($h * 360)), + intval(round($s * 100)), + intval(round($l * 100)), ]; } } diff --git a/src/Facades/Colors.php b/src/Facades/Colors.php index b478212..24a64ab 100644 --- a/src/Facades/Colors.php +++ b/src/Facades/Colors.php @@ -5,12 +5,12 @@ use Illuminate\Support\Facades\Facade; /** - * @method static float[] hexToHsl(string $hex) + * @method static int[] hexToHsl(string $hex) * @method static int[] hexToRgb(string $hex) - * @method static string hlsToHex(float $h, float $s, float $l) - * @method static array hlsToRgb(float $h, float $s, float $l) + * @method static string hslToHex(int $h, int $s, int $l) + * @method static array hslToRgb(int $h, int $s, int $l) * @method static string rgbToHex(int $r, int $g, int $b) - * @method static float[] rgbToHsl(int $r, int $g, int $b) + * @method static int[] rgbToHsl(int $r, int $g, int $b) * * @see \LaravelToolkit\Colors\Colors */ diff --git a/tests/ColorsTest.php b/tests/ColorsTest.php new file mode 100644 index 0000000..31d3af2 --- /dev/null +++ b/tests/ColorsTest.php @@ -0,0 +1,37 @@ +toBeArray()->toBe($rgb)->each->toBeInt() + ->and(Colors::hexToHsl($hex)) + ->toBeArray()->toBe($hsl)->each->toBeInt() + ->and(Colors::hslToHex(...$hsl)) + ->toBeString()->toBe($hexFromHsl) + ->and(Colors::hslToRgb(...$hsl)) + ->toBeArray()->toBe($rgbFromHsl)->each->toBeInt() + ->and(Colors::rgbToHex(...$rgb)) + ->toBeString()->toBe(strlen($hex) === 7 ? $hex : '#CCCCCC') + ->and(Colors::rgbToHsl(...$rgb)) + ->toBeArray()->toBe($hsl)->each->toBeInt(); +})->with([ + ['hex' => '#CCCCCC', 'rgb' => [204, 204, 204], 'hsl' => [0, 0, 80], 'hexFromHsl' => '#CCCCCC', 'rgbFromHsl' => [204, 204, 204]], + ['hex' => '#CCC', 'rgb' => [204, 204, 204], 'hsl' => [0, 0, 80], 'hexFromHsl' => '#CCCCCC', 'rgbFromHsl' => [204, 204, 204]], + ['hex' => '#D3F6DB', 'rgb' => [211, 246, 219], 'hsl' => [134, 66, 90], 'hexFromHsl' => '#D5F6DD', 'rgbFromHsl' => [213, 246, 221]], + ['hex' => '#772D8B', 'rgb' => [119, 45, 139], 'hsl' => [287, 51, 36], 'hexFromHsl' => '#762D8B', 'rgbFromHsl' => [118, 45, 139]], + ['hex' => '#8C1C13', 'rgb' => [140, 28, 19], 'hsl' => [4, 76, 31], 'hexFromHsl' => '#8B1B13', 'rgbFromHsl' => [139, 27, 19]], + ['hex' => '#604D53', 'rgb' => [96, 77, 83], 'hsl' => [341, 11, 34], 'hexFromHsl' => '#604D53', 'rgbFromHsl' => [96, 77, 83]], + ['hex' => '#9DA3A4', 'rgb' => [157, 163, 164], 'hsl' => [189, 4, 63], 'hexFromHsl' => '#9DA3A4', 'rgbFromHsl' => [157, 163, 164]], + ['hex' => '#FFDBDA', 'rgb' => [255, 219, 218], 'hsl' => [2, 100, 93], 'hexFromHsl' => '#FFDCDB', 'rgbFromHsl' => [255, 220, 219]], + ['hex' => '#17BEBB', 'rgb' => [23, 190, 187], 'hsl' => [179, 78, 42], 'hexFromHsl' => '#18BFBC', 'rgbFromHsl' => [24, 191, 188]], + ['hex' => '#76B041', 'rgb' => [118, 176, 65], 'hsl' => [91, 46, 47], 'hexFromHsl' => '#76AF41', 'rgbFromHsl' => [118, 175, 65]], + ['hex' => '#FFC914', 'rgb' => [255, 201, 20], 'hsl' => [46, 100, 54], 'hexFromHsl' => '#FFC814', 'rgbFromHsl' => [255, 200, 20]], + ['hex' => '#E4572E', 'rgb' => [228, 87, 46], 'hsl' => [14, 77, 54], 'hexFromHsl' => '#E45A2F', 'rgbFromHsl' => [228, 90, 47]], + ['hex' => '#DFF3E4', 'rgb' => [223, 243, 228], 'hsl' => [135, 45, 91], 'hexFromHsl' => '#DEF2E3', 'rgbFromHsl' => [222, 242, 227]], + ['hex' => '#2E1760', 'rgb' => [46, 23, 96], 'hsl' => [259, 61, 23], 'hexFromHsl' => '#2E175E', 'rgbFromHsl' => [46, 23, 94]], + ['hex' => '#66C3FF', 'rgb' => [102, 195, 255], 'hsl' => [204, 100, 70], 'hexFromHsl' => '#66C2FF', 'rgbFromHsl' => [102, 194, 255]], + ['hex' => '#444444', 'rgb' => [68, 68, 68], 'hsl' => [0, 0, 27], 'hexFromHsl' => '#454545', 'rgbFromHsl' => [69, 69, 69]], + ['hex' => '#000000', 'rgb' => [0, 0, 0], 'hsl' => [0, 0, 0], 'hexFromHsl' => '#000000', 'rgbFromHsl' => [0, 0, 0]], + ['hex' => '#FFFFFF', 'rgb' => [255, 255, 255], 'hsl' => [0, 0, 100], 'hexFromHsl' => '#FFFFFF', 'rgbFromHsl' => [255, 255, 255]], +]); From c7bd439ddabb0e8222a8895ff08e3772343ba824 Mon Sep 17 00:00:00 2001 From: Allan Mariucci Carvalho Date: Wed, 6 Nov 2024 14:11:03 -0300 Subject: [PATCH 3/6] rand colors --- src/Colors/ColorFormat.php | 10 ++++++++++ src/Colors/ColorStep.php | 18 ++++++++++++++++++ src/Colors/Colors.php | 29 +++++++++++++++++++++++++++++ src/Facades/Colors.php | 6 ++++++ 4 files changed, 63 insertions(+) create mode 100644 src/Colors/ColorFormat.php create mode 100644 src/Colors/ColorStep.php diff --git a/src/Colors/ColorFormat.php b/src/Colors/ColorFormat.php new file mode 100644 index 0000000..376aaec --- /dev/null +++ b/src/Colors/ColorFormat.php @@ -0,0 +1,10 @@ +rgbToHex(...$this->randRgb()); + } + + public function randHsl(): array + { + return $this->rgbToHsl(...$this->randRgb()); + } + + public function randRgb(): array + { + return [ + rand(0, 255), + rand(0, 255), + rand(0, 255), + ]; + } + public function rgbToHex(int $r, int $g, int $b): string { return sprintf('#%02X%02X%02X', $r, $g, $b); diff --git a/src/Facades/Colors.php b/src/Facades/Colors.php index 24a64ab..367b30f 100644 --- a/src/Facades/Colors.php +++ b/src/Facades/Colors.php @@ -3,12 +3,18 @@ namespace LaravelToolkit\Facades; use Illuminate\Support\Facades\Facade; +use LaravelToolkit\Colors\ColorFormat; +use LaravelToolkit\Colors\ColorStep; /** * @method static int[] hexToHsl(string $hex) * @method static int[] hexToRgb(string $hex) * @method static string hslToHex(int $h, int $s, int $l) * @method static array hslToRgb(int $h, int $s, int $l) + * @method static array palete(null|string $hex = null, null|array $rbg = null, null|array $hsl = null, ColorStep $baseStep = ColorStep::STEP_500, ColorFormat $outputFormat = ColorFormat::HEX) + * @method static string randHex() + * @method static array randHsl() + * @method static array randRgb() * @method static string rgbToHex(int $r, int $g, int $b) * @method static int[] rgbToHsl(int $r, int $g, int $b) * From 95010d52d6ee9484f22ae47c1ed05dc3e0634502 Mon Sep 17 00:00:00 2001 From: Allan Mariucci Carvalho Date: Wed, 6 Nov 2024 16:18:48 -0300 Subject: [PATCH 4/6] wip com palette --- src/Colors/ColorStep.php | 32 +++++++++++ src/Colors/Colors.php | 16 +++++- src/Colors/PaletteGenerator.php | 58 ++++++++++++++++++++ src/Facades/Colors.php | 2 +- tests/ColorsTest.php | 97 +++++++++++++++++++++++++++------ 5 files changed, 185 insertions(+), 20 deletions(-) create mode 100644 src/Colors/PaletteGenerator.php diff --git a/src/Colors/ColorStep.php b/src/Colors/ColorStep.php index c8649ec..69cc760 100644 --- a/src/Colors/ColorStep.php +++ b/src/Colors/ColorStep.php @@ -15,4 +15,36 @@ enum ColorStep: int case STEP_800 = 800; case STEP_900 = 900; case STEP_950 = 950; + + /** + * @return \LaravelToolkit\Colors\ColorStep[] + */ + public function afterSteps(): array + { + $items = []; + foreach (self::cases() as $case) { + if ($case->value <= $this->value) { + continue; + } + $items[] = $case; + } + + return $items; + } + + /** + * @return \LaravelToolkit\Colors\ColorStep[] + */ + public function beforeSteps(): array + { + $items = []; + foreach (self::cases() as $case) { + if ($case === $this) { + break; + } + $items[] = $case; + } + + return $items; + } } diff --git a/src/Colors/Colors.php b/src/Colors/Colors.php index 15338dc..200a0c6 100644 --- a/src/Colors/Colors.php +++ b/src/Colors/Colors.php @@ -91,14 +91,26 @@ protected function hueToRgb(float $p, float $q, float $t): float }; } - public function palete( + /** + * @throws \Exception + */ + public function palette( ?string $hex = null, ?array $rbg = null, ?array $hsl = null, ColorStep $baseStep = ColorStep::STEP_500, ColorFormat $outputFormat = ColorFormat::HEX, + float $thresholdLightest = 5, + float $thresholdDarkest = 6, ): array { - return []; + [$h, $s, $l] = match (true) { + ! empty($hex) => $this->hexToHsl($hex), + ! empty($rbg) => $this->rgbToHsl(...$rbg), + ! empty($hsl) => $hsl, + default => throw new Exception('You must provide at lest one color'), + }; + + return (new PaletteGenerator($h, $s, $l, $baseStep, $outputFormat, $thresholdLightest, $thresholdDarkest))(); } public function randHex(): string diff --git a/src/Colors/PaletteGenerator.php b/src/Colors/PaletteGenerator.php new file mode 100644 index 0000000..b7b9954 --- /dev/null +++ b/src/Colors/PaletteGenerator.php @@ -0,0 +1,58 @@ +baseStep->beforeSteps(); + $lighterRangeStep = (100 - $this->thresholdLightest - $this->l) / count($lighterSteps); + foreach ($lighterSteps as $index => $step) { + $level = $step->value; + $baseLevel = $this->baseStep->value; + $palette->put($level, [ + $this->h, + round(max(0, $this->s - ($this->s * (($baseLevel - $level) / $baseLevel) * 0.5))), + round($this->l + ($lighterRangeStep * (count($lighterSteps) - $index))), + ]); + } + + $palette->put($this->baseStep->value, [$this->h, $this->s, $this->l]); + + $darkerSteps = $this->baseStep->afterSteps(); + $darkerRangeStep = ($this->l - $this->thresholdDarkest) / count($darkerSteps); + foreach ($darkerSteps as $index => $step) { + $level = $step->value; + $baseLevel = $this->baseStep->value; + $palette->put($step->value, [ + $this->h, + round(min(100, $this->s + ($this->s * (($level - $baseLevel) / $baseLevel) * 0.4))), + round($this->l - ($darkerRangeStep * ($index + 1))), + ]); + } + + return $palette + ->map(fn (array $hsl) => match ($this->outputFormat) { + ColorFormat::HEX => Colors::hslToHex(...$hsl), + ColorFormat::RGB => Colors::hslToRgb(...$hsl), + default => $hsl + })->toArray(); + } +} diff --git a/src/Facades/Colors.php b/src/Facades/Colors.php index 367b30f..8f6a64d 100644 --- a/src/Facades/Colors.php +++ b/src/Facades/Colors.php @@ -11,7 +11,7 @@ * @method static int[] hexToRgb(string $hex) * @method static string hslToHex(int $h, int $s, int $l) * @method static array hslToRgb(int $h, int $s, int $l) - * @method static array palete(null|string $hex = null, null|array $rbg = null, null|array $hsl = null, ColorStep $baseStep = ColorStep::STEP_500, ColorFormat $outputFormat = ColorFormat::HEX) + * @method static array palette(null|string $hex = null, null|array $rbg = null, null|array $hsl = null, ColorStep $baseStep = ColorStep::STEP_500, ColorFormat $outputFormat = ColorFormat::HEX, float $thresholdLightest = 0.9, float $thresholdDarkest = 0.1) * @method static string randHex() * @method static array randHsl() * @method static array randRgb() diff --git a/tests/ColorsTest.php b/tests/ColorsTest.php index 31d3af2..d660626 100644 --- a/tests/ColorsTest.php +++ b/tests/ColorsTest.php @@ -16,22 +16,85 @@ ->and(Colors::rgbToHsl(...$rgb)) ->toBeArray()->toBe($hsl)->each->toBeInt(); })->with([ - ['hex' => '#CCCCCC', 'rgb' => [204, 204, 204], 'hsl' => [0, 0, 80], 'hexFromHsl' => '#CCCCCC', 'rgbFromHsl' => [204, 204, 204]], - ['hex' => '#CCC', 'rgb' => [204, 204, 204], 'hsl' => [0, 0, 80], 'hexFromHsl' => '#CCCCCC', 'rgbFromHsl' => [204, 204, 204]], - ['hex' => '#D3F6DB', 'rgb' => [211, 246, 219], 'hsl' => [134, 66, 90], 'hexFromHsl' => '#D5F6DD', 'rgbFromHsl' => [213, 246, 221]], - ['hex' => '#772D8B', 'rgb' => [119, 45, 139], 'hsl' => [287, 51, 36], 'hexFromHsl' => '#762D8B', 'rgbFromHsl' => [118, 45, 139]], - ['hex' => '#8C1C13', 'rgb' => [140, 28, 19], 'hsl' => [4, 76, 31], 'hexFromHsl' => '#8B1B13', 'rgbFromHsl' => [139, 27, 19]], - ['hex' => '#604D53', 'rgb' => [96, 77, 83], 'hsl' => [341, 11, 34], 'hexFromHsl' => '#604D53', 'rgbFromHsl' => [96, 77, 83]], - ['hex' => '#9DA3A4', 'rgb' => [157, 163, 164], 'hsl' => [189, 4, 63], 'hexFromHsl' => '#9DA3A4', 'rgbFromHsl' => [157, 163, 164]], - ['hex' => '#FFDBDA', 'rgb' => [255, 219, 218], 'hsl' => [2, 100, 93], 'hexFromHsl' => '#FFDCDB', 'rgbFromHsl' => [255, 220, 219]], - ['hex' => '#17BEBB', 'rgb' => [23, 190, 187], 'hsl' => [179, 78, 42], 'hexFromHsl' => '#18BFBC', 'rgbFromHsl' => [24, 191, 188]], - ['hex' => '#76B041', 'rgb' => [118, 176, 65], 'hsl' => [91, 46, 47], 'hexFromHsl' => '#76AF41', 'rgbFromHsl' => [118, 175, 65]], - ['hex' => '#FFC914', 'rgb' => [255, 201, 20], 'hsl' => [46, 100, 54], 'hexFromHsl' => '#FFC814', 'rgbFromHsl' => [255, 200, 20]], - ['hex' => '#E4572E', 'rgb' => [228, 87, 46], 'hsl' => [14, 77, 54], 'hexFromHsl' => '#E45A2F', 'rgbFromHsl' => [228, 90, 47]], - ['hex' => '#DFF3E4', 'rgb' => [223, 243, 228], 'hsl' => [135, 45, 91], 'hexFromHsl' => '#DEF2E3', 'rgbFromHsl' => [222, 242, 227]], - ['hex' => '#2E1760', 'rgb' => [46, 23, 96], 'hsl' => [259, 61, 23], 'hexFromHsl' => '#2E175E', 'rgbFromHsl' => [46, 23, 94]], - ['hex' => '#66C3FF', 'rgb' => [102, 195, 255], 'hsl' => [204, 100, 70], 'hexFromHsl' => '#66C2FF', 'rgbFromHsl' => [102, 194, 255]], - ['hex' => '#444444', 'rgb' => [68, 68, 68], 'hsl' => [0, 0, 27], 'hexFromHsl' => '#454545', 'rgbFromHsl' => [69, 69, 69]], + [ + 'hex' => '#CCCCCC', 'rgb' => [204, 204, 204], 'hsl' => [0, 0, 80], 'hexFromHsl' => '#CCCCCC', + 'rgbFromHsl' => [204, 204, 204], + ], + [ + 'hex' => '#CCC', 'rgb' => [204, 204, 204], 'hsl' => [0, 0, 80], 'hexFromHsl' => '#CCCCCC', + 'rgbFromHsl' => [204, 204, 204], + ], + [ + 'hex' => '#D3F6DB', 'rgb' => [211, 246, 219], 'hsl' => [134, 66, 90], 'hexFromHsl' => '#D5F6DD', + 'rgbFromHsl' => [213, 246, 221], + ], + [ + 'hex' => '#772D8B', 'rgb' => [119, 45, 139], 'hsl' => [287, 51, 36], 'hexFromHsl' => '#762D8B', + 'rgbFromHsl' => [118, 45, 139], + ], + [ + 'hex' => '#8C1C13', 'rgb' => [140, 28, 19], 'hsl' => [4, 76, 31], 'hexFromHsl' => '#8B1B13', + 'rgbFromHsl' => [139, 27, 19], + ], + [ + 'hex' => '#604D53', 'rgb' => [96, 77, 83], 'hsl' => [341, 11, 34], 'hexFromHsl' => '#604D53', + 'rgbFromHsl' => [96, 77, 83], + ], + [ + 'hex' => '#9DA3A4', 'rgb' => [157, 163, 164], 'hsl' => [189, 4, 63], 'hexFromHsl' => '#9DA3A4', + 'rgbFromHsl' => [157, 163, 164], + ], + [ + 'hex' => '#FFDBDA', 'rgb' => [255, 219, 218], 'hsl' => [2, 100, 93], 'hexFromHsl' => '#FFDCDB', + 'rgbFromHsl' => [255, 220, 219], + ], + [ + 'hex' => '#17BEBB', 'rgb' => [23, 190, 187], 'hsl' => [179, 78, 42], 'hexFromHsl' => '#18BFBC', + 'rgbFromHsl' => [24, 191, 188], + ], + [ + 'hex' => '#76B041', 'rgb' => [118, 176, 65], 'hsl' => [91, 46, 47], 'hexFromHsl' => '#76AF41', + 'rgbFromHsl' => [118, 175, 65], + ], + [ + 'hex' => '#FFC914', 'rgb' => [255, 201, 20], 'hsl' => [46, 100, 54], 'hexFromHsl' => '#FFC814', + 'rgbFromHsl' => [255, 200, 20], + ], + [ + 'hex' => '#E4572E', 'rgb' => [228, 87, 46], 'hsl' => [14, 77, 54], 'hexFromHsl' => '#E45A2F', + 'rgbFromHsl' => [228, 90, 47], + ], + [ + 'hex' => '#DFF3E4', 'rgb' => [223, 243, 228], 'hsl' => [135, 45, 91], 'hexFromHsl' => '#DEF2E3', + 'rgbFromHsl' => [222, 242, 227], + ], + [ + 'hex' => '#2E1760', 'rgb' => [46, 23, 96], 'hsl' => [259, 61, 23], 'hexFromHsl' => '#2E175E', + 'rgbFromHsl' => [46, 23, 94], + ], + [ + 'hex' => '#66C3FF', 'rgb' => [102, 195, 255], 'hsl' => [204, 100, 70], 'hexFromHsl' => '#66C2FF', + 'rgbFromHsl' => [102, 194, 255], + ], + [ + 'hex' => '#444444', 'rgb' => [68, 68, 68], 'hsl' => [0, 0, 27], 'hexFromHsl' => '#454545', + 'rgbFromHsl' => [69, 69, 69], + ], ['hex' => '#000000', 'rgb' => [0, 0, 0], 'hsl' => [0, 0, 0], 'hexFromHsl' => '#000000', 'rgbFromHsl' => [0, 0, 0]], - ['hex' => '#FFFFFF', 'rgb' => [255, 255, 255], 'hsl' => [0, 0, 100], 'hexFromHsl' => '#FFFFFF', 'rgbFromHsl' => [255, 255, 255]], + [ + 'hex' => '#FFFFFF', 'rgb' => [255, 255, 255], 'hsl' => [0, 0, 100], 'hexFromHsl' => '#FFFFFF', + 'rgbFromHsl' => [255, 255, 255], + ], ]); + +it('rand colors', function () { + expect(Colors::randHex()) + ->toBeString() + ->toStartWith('#') + ->and(Colors::randHsl()) + ->toBeArray() + ->toHaveCount(3) + ->and(Colors::randRgb()) + ->toBeArray() + ->toHaveCount(3); +})->repeat(5); From 072fa197f731fdd39868b1a1b286157b9f3018d9 Mon Sep 17 00:00:00 2001 From: Allan Mariucci Carvalho Date: Wed, 6 Nov 2024 16:36:43 -0300 Subject: [PATCH 5/6] finished --- src/Colors/Colors.php | 6 ++--- src/Facades/Colors.php | 2 +- tests/ColorsTest.php | 60 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/Colors/Colors.php b/src/Colors/Colors.php index 200a0c6..27508b2 100644 --- a/src/Colors/Colors.php +++ b/src/Colors/Colors.php @@ -96,7 +96,7 @@ protected function hueToRgb(float $p, float $q, float $t): float */ public function palette( ?string $hex = null, - ?array $rbg = null, + ?array $rgb = null, ?array $hsl = null, ColorStep $baseStep = ColorStep::STEP_500, ColorFormat $outputFormat = ColorFormat::HEX, @@ -105,9 +105,9 @@ public function palette( ): array { [$h, $s, $l] = match (true) { ! empty($hex) => $this->hexToHsl($hex), - ! empty($rbg) => $this->rgbToHsl(...$rbg), + ! empty($rgb) => $this->rgbToHsl(...$rgb), ! empty($hsl) => $hsl, - default => throw new Exception('You must provide at lest one color'), + default => throw new Exception('You must provide one color format.'), }; return (new PaletteGenerator($h, $s, $l, $baseStep, $outputFormat, $thresholdLightest, $thresholdDarkest))(); diff --git a/src/Facades/Colors.php b/src/Facades/Colors.php index 8f6a64d..6e1f9d1 100644 --- a/src/Facades/Colors.php +++ b/src/Facades/Colors.php @@ -11,7 +11,7 @@ * @method static int[] hexToRgb(string $hex) * @method static string hslToHex(int $h, int $s, int $l) * @method static array hslToRgb(int $h, int $s, int $l) - * @method static array palette(null|string $hex = null, null|array $rbg = null, null|array $hsl = null, ColorStep $baseStep = ColorStep::STEP_500, ColorFormat $outputFormat = ColorFormat::HEX, float $thresholdLightest = 0.9, float $thresholdDarkest = 0.1) + * @method static array palette(null|string $hex = null, null|array $rgb = null, null|array $hsl = null, ColorStep $baseStep = ColorStep::STEP_500, ColorFormat $outputFormat = ColorFormat::HEX, float $thresholdLightest = 5, float $thresholdDarkest = 6) * @method static string randHex() * @method static array randHsl() * @method static array randRgb() diff --git a/tests/ColorsTest.php b/tests/ColorsTest.php index d660626..790f3d4 100644 --- a/tests/ColorsTest.php +++ b/tests/ColorsTest.php @@ -1,5 +1,7 @@ Colors::hexToRgb('#CC')) + ->toThrow('Invalid hex string'); +}); + +it('can generate rand colors', function () { expect(Colors::randHex()) ->toBeString() ->toStartWith('#') @@ -98,3 +105,54 @@ ->toBeArray() ->toHaveCount(3); })->repeat(5); + +it('test color step enum', function () { + $enum = ColorStep::STEP_200; + expect($enum->beforeSteps()) + ->toBeArray() + ->toHaveCount(2) + ->each + ->toBeInstanceOf(ColorStep::class) + ->and($enum->afterSteps()) + ->toBeArray() + ->toHaveCount(8) + ->each + ->toBeInstanceOf(ColorStep::class); + + $enum = ColorStep::STEP_400; + expect($enum->beforeSteps()) + ->toBeArray() + ->toHaveCount(4) + ->each + ->toBeInstanceOf(ColorStep::class) + ->and($enum->afterSteps()) + ->toBeArray() + ->toHaveCount(6) + ->each + ->toBeInstanceOf(ColorStep::class); +}); + +it('can generate a palette', function () { + expect(Colors::palette('#b2d600')) + ->toBeArray() + ->toHaveCount(11) + ->toHaveKeys([50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950]) + ->each + ->toBeString() + ->and(Colors::palette(rgb: [211, 246, 219], outputFormat: ColorFormat::RGB)) + ->toBeArray() + ->toHaveCount(11) + ->toHaveKeys([50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950]) + ->each + ->toBeArray() + ->toHaveKeys([0, 1, 2]) + ->and(Colors::palette(hsl: [134, 66, 89], outputFormat: ColorFormat::HSL)) + ->toBeArray() + ->toHaveCount(11) + ->toHaveKeys([50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950]) + ->each + ->toBeArray() + ->toHaveKeys([0, 1, 2]) + ->and(fn () => Colors::palette()) + ->toThrow('You must provide one color format.'); +}); From d635c74a5a4ef63c370b10883a4cb7b68bd69b66 Mon Sep 17 00:00:00 2001 From: Allan Mariucci Carvalho Date: Wed, 6 Nov 2024 16:47:31 -0300 Subject: [PATCH 6/6] docs --- README.md | 3 +++ docs/COLORS.md | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 docs/COLORS.md diff --git a/README.md b/README.md index 3bba31d..6383c79 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,9 @@ To Laravel Toolkit be able to compile its tailwind you must add this line on tai ### [ACL](docs/ACL.md) A minimalist implementation of an access control level +### [Colors](docs/COLORS.md) +A toolset of helpers for colors. + ### [Flash](docs/FLASH.md) Simple flash messages from backend to front end. diff --git a/docs/COLORS.md b/docs/COLORS.md new file mode 100644 index 0000000..872e225 --- /dev/null +++ b/docs/COLORS.md @@ -0,0 +1,53 @@ +## Colors + +A toolset of helpers for colors. + +### Converting +You can use the following methods of `Facade` to convert between colors format: +```php +use LaravelToolkit\Facades\Colors; + +[$r, $g, $b] = Colors::hexToRgb('#e4572e'); +[$h, $s, $l] = Colors::hexToHsl('#e4572e'); + +$hex = Colors::hslToHex(14, 77, 54); +[$r, $g, $b] = Colors::hslToRgb(14, 77, 54); + +$hex = Colors::rgbToHex(228, 87, 46); +[$h, $s, $l] = Colors::rgbToHsl(228, 87, 46); + +``` + +### Random colors +If you want to generate a random color use: +```php +use LaravelToolkit\Facades\Colors; + +$hex = Colors::randHex(); +[$r, $g, $b] = Colors::randRgb(); +[$h, $s, $l] = Colors::randHsl(); + +``` + +### Tailwind palette +If you have a base color and want to generate a palette: +```php +use LaravelToolkit\Facades\Colors; +use LaravelToolkit\Colors\ColorStep; +use LaravelToolkit\Colors\ColorFormat; + +// from hex +$palette = Colors::palette('#e4572e'); +// from rgb +$palette = Colors::palette(rgb: [228, 87, 46]); +// from hsl +$palette = Colors::palette(hsl: [14, 77, 54]); + +// changing base color +$palette = Colors::palette('#e4572e', baseStep: ColorStep::STEP_400); +// choosing output format +$palette = Colors::palette('#e4572e', outputFormat: ColorFormat::RGB); +// with custom threshold +$palette = Colors::palette('#e4572e', thresholdLightest: 10, thresholdDarkest: 10); + +``` \ No newline at end of file