generated from spatie/package-skeleton-laravel
-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #26 from wsssoftware/colors
Colors helper
- Loading branch information
Showing
8 changed files
with
535 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?php | ||
|
||
namespace LaravelToolkit\Colors; | ||
|
||
enum ColorFormat | ||
{ | ||
case HEX; | ||
case HSL; | ||
case RGB; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<?php | ||
|
||
namespace LaravelToolkit\Colors; | ||
|
||
enum ColorStep: int | ||
{ | ||
case STEP_50 = 50; | ||
case STEP_100 = 100; | ||
case STEP_200 = 200; | ||
case STEP_300 = 300; | ||
case STEP_400 = 400; | ||
case STEP_500 = 500; | ||
case STEP_600 = 600; | ||
case STEP_700 = 700; | ||
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
<?php | ||
|
||
namespace LaravelToolkit\Colors; | ||
|
||
use Exception; | ||
|
||
/** | ||
* @see \LaravelToolkit\Facades\Colors | ||
*/ | ||
class Colors | ||
{ | ||
/** | ||
* @return array{0: float, 1: float, 2: float} | ||
* | ||
* @throws \Exception | ||
*/ | ||
public function hexToHsl(string $hex): array | ||
{ | ||
return $this->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 hslToHex(int $h, int $s, int $l): string | ||
{ | ||
return $this->rgbToHex(...$this->hslToRgb($h, $s, $l)); | ||
} | ||
|
||
/** | ||
* @return array{0: int, 1: int, 2: int} | ||
*/ | ||
public function hslToRgb(int $h, int $s, int $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, | ||
}; | ||
} | ||
|
||
/** | ||
* @throws \Exception | ||
*/ | ||
public function palette( | ||
?string $hex = null, | ||
?array $rgb = null, | ||
?array $hsl = null, | ||
ColorStep $baseStep = ColorStep::STEP_500, | ||
ColorFormat $outputFormat = ColorFormat::HEX, | ||
float $thresholdLightest = 5, | ||
float $thresholdDarkest = 6, | ||
): array { | ||
[$h, $s, $l] = match (true) { | ||
! empty($hex) => $this->hexToHsl($hex), | ||
! empty($rgb) => $this->rgbToHsl(...$rgb), | ||
! empty($hsl) => $hsl, | ||
default => throw new Exception('You must provide one color format.'), | ||
}; | ||
|
||
return (new PaletteGenerator($h, $s, $l, $baseStep, $outputFormat, $thresholdLightest, $thresholdDarkest))(); | ||
} | ||
|
||
public function randHex(): string | ||
{ | ||
return $this->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); | ||
} | ||
|
||
/** | ||
* @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 [ | ||
intval(round($h * 360)), | ||
intval(round($s * 100)), | ||
intval(round($l * 100)), | ||
]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
<?php | ||
|
||
namespace LaravelToolkit\Colors; | ||
|
||
use LaravelToolkit\Facades\Colors; | ||
|
||
class PaletteGenerator | ||
{ | ||
public function __construct( | ||
protected readonly int $h, | ||
protected readonly int $s, | ||
protected readonly int $l, | ||
protected readonly ColorStep $baseStep, | ||
protected readonly ColorFormat $outputFormat, | ||
protected readonly float $thresholdLightest, | ||
protected readonly float $thresholdDarkest, | ||
) { | ||
// | ||
} | ||
|
||
public function __invoke(): array | ||
{ | ||
$palette = collect(); | ||
|
||
$lighterSteps = $this->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(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?php | ||
|
||
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 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() | ||
* @method static string rgbToHex(int $r, int $g, int $b) | ||
* @method static int[] rgbToHsl(int $r, int $g, int $b) | ||
* | ||
* @see \LaravelToolkit\Colors\Colors | ||
*/ | ||
class Colors extends Facade | ||
{ | ||
protected static function getFacadeAccessor(): string | ||
{ | ||
return \LaravelToolkit\Colors\Colors::class; | ||
} | ||
} |
Oops, something went wrong.