Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f82317cf99 | ||
|
|
03212310fd | ||
|
|
eb2bea62a7 | ||
|
|
b28a6f69f9 | ||
|
|
9ef5d58a8a |
58
README.md
58
README.md
@@ -1,22 +1,60 @@
|
||||
# PCM Icon Bundle
|
||||
|
||||
# WIP DON'T USE YET
|
||||
Use icons inside of Twig templates with ease!
|
||||
|
||||
```php
|
||||
{{ icon({ icon: 'person' }) }}
|
||||
```
|
||||
|
||||
## Config
|
||||
Example config:
|
||||
```yml
|
||||
```yaml
|
||||
# config/packages/pcm_icon.yaml
|
||||
pcm_icon:
|
||||
directories:
|
||||
- '%kernel.project_dir%/public/icons'
|
||||
palletes:
|
||||
primary:
|
||||
stroke: 'stroke-primary'
|
||||
fill: 'fill-primary'
|
||||
white:
|
||||
stroke: 'stroke-white'
|
||||
fill: 'fill-white'
|
||||
fill: 'fill-primary'
|
||||
stroke: 'stroke-primary'
|
||||
fill-hover: 'hover:fill-primary'
|
||||
stroke-hover: 'hover:stroke-primary'
|
||||
fill-group-hover: 'group-hover:fill-primary'
|
||||
stroke-group-hover: 'group-hover:stroke-primary'
|
||||
red:
|
||||
stroke: 'stroke-red-400'
|
||||
fill: 'fill-red-400'
|
||||
fill: 'fill-red-800'
|
||||
stroke: 'stroke-red-800'
|
||||
fill-hover: 'hover:fill-red-800'
|
||||
stroke-hover: 'hover:stroke-red-800'
|
||||
fill-group-hover: 'group-hover:fill-red-800'
|
||||
stroke-group-hover: 'group-hover:stroke-red-800'
|
||||
```
|
||||
|
||||
Remember to add './config/packages/*.yaml' as a value in your Tailwind config content array.
|
||||
`directories` - Which directories to look in for icons.
|
||||
|
||||
`palletes` - Custom colour palletes to use when colouring icons. Because this extension relies on Tailwind classes for colouring we must specify all the classes. This is annoyingly verbose, but you can just copy this template:
|
||||
|
||||
```yaml
|
||||
PALLETE_NAME:
|
||||
fill: 'fill-COLOUR'
|
||||
stroke: 'stroke-COLOUR'
|
||||
fill-hover: 'hover:fill-COLOUR'
|
||||
stroke-hover: 'hover:stroke-COLOUR'
|
||||
fill-group-hover: 'group-hover:fill-COLOUR'
|
||||
stroke-group-hover: 'group-hover:stroke-COLOUR'
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
`icon (string)` **(REQUIRED)** Icon to use, without the `.svg` extension
|
||||
|
||||
`title (string)` Optional text to show on hover
|
||||
|
||||
`size (int)` Size of the icon in pixels
|
||||
|
||||
`colour (string)` Name of the main colour pallete to use. Defaults to `"primary"`, assuming that a pallete with the project's primary colour will exist
|
||||
|
||||
`hover (string)` Name of the colour pallete to use when the icon is hovered over
|
||||
|
||||
## Reminders
|
||||
Remember to add `./config/packages/*.yaml` as a value in your Tailwind config content array if it does not already exist.
|
||||
|
||||
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace Pcm\IconBundle\Twig\Functions;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFunction;
|
||||
|
||||
@@ -23,7 +22,7 @@ final class IconExtension extends AbstractExtension
|
||||
public function __construct(private array $directories, private array $palletes)
|
||||
{
|
||||
if (empty($this->directories))
|
||||
throw new InvalidArgumentException('Directories array must contain at least one path!');
|
||||
throw new \InvalidArgumentException('Directories array must contain at least one path!');
|
||||
|
||||
$dirsContainNonString = array_reduce($this->directories,
|
||||
fn($notString, $path) => $notString || !is_string($path));
|
||||
@@ -32,7 +31,7 @@ final class IconExtension extends AbstractExtension
|
||||
throw new \TypeError('Directories array must only contain strings!');
|
||||
|
||||
if (empty($this->palletes))
|
||||
throw new InvalidArgumentException('Palletes array must contain at least one pallet!');
|
||||
throw new \InvalidArgumentException('Palletes array must contain at least one pallet!');
|
||||
|
||||
$pelletesContainNonarray = array_reduce($this->palletes,
|
||||
fn($notArray, $path) => $notArray || !is_array($path));
|
||||
@@ -41,7 +40,14 @@ final class IconExtension extends AbstractExtension
|
||||
throw new \TypeError('Palletes array must only contain arrays!');
|
||||
|
||||
foreach ($this->palletes as $pallete) {
|
||||
if (!(array_key_exists('stroke', $pallete) && array_key_exists('fill', $pallete))) {
|
||||
if (!(
|
||||
array_key_exists('stroke', $pallete) &&
|
||||
array_key_exists('fill', $pallete) &&
|
||||
array_key_exists('fill-hover', $pallete) &&
|
||||
array_key_exists('stroke-hover', $pallete) &&
|
||||
array_key_exists('fill-group-hover', $pallete) &&
|
||||
array_key_exists('stroke-group-hover', $pallete))
|
||||
) {
|
||||
throw new \Exception('Palletes must contain a "stroke" and "fill" key!');
|
||||
}
|
||||
}
|
||||
@@ -75,13 +81,14 @@ final class IconExtension extends AbstractExtension
|
||||
{
|
||||
$options = $this->mergeUserOptionsWithDefaults($userOptions);
|
||||
|
||||
$this->throwIfUnrecognisedOptionExists($options);
|
||||
|
||||
$iconFilepath = $this->findSvgFilepath($options['icon']);
|
||||
$rawSvgMarkup = $this->getSvgMarkup($iconFilepath);
|
||||
$cleanSvgMarkup = $this->cleanSvgMarkup($rawSvgMarkup);
|
||||
|
||||
$mainPallete = $this->getPallete($options['colour']);
|
||||
|
||||
|
||||
$colourClasses = "{$mainPallete['stroke']} {$mainPallete['fill']}";
|
||||
|
||||
if (null !== $options['hover']) {
|
||||
@@ -114,6 +121,14 @@ final class IconExtension extends AbstractExtension
|
||||
return array_merge(self::DEFAULT_OPTIONS, $userOptions);
|
||||
}
|
||||
|
||||
private function throwIfUnrecognisedOptionExists(array $options): void
|
||||
{
|
||||
foreach (array_keys($options) as $key) {
|
||||
if (!key_exists($key, self::DEFAULT_OPTIONS))
|
||||
throw new \InvalidArgumentException("Unrecognised option '{$key}'!");
|
||||
}
|
||||
}
|
||||
|
||||
private function findSvgFilepath(string $iconName): string
|
||||
{
|
||||
foreach ($this->directories as $directory) {
|
||||
|
||||
@@ -15,12 +15,20 @@ class IconExtensionTest extends TestCase
|
||||
|
||||
private const PALLETES = [
|
||||
'primary' => [
|
||||
'fill' => 'fill-primary',
|
||||
'stroke' => 'stroke-primary',
|
||||
'fill' => 'fill-primary'
|
||||
'fill-hover' => 'hover:fill-primary',
|
||||
'stroke-hover' => 'hover:stroke-primary',
|
||||
'fill-group-hover' => 'group-hover:fill-primary',
|
||||
'stroke-group-hover' => 'group-hover:stroke-primary',
|
||||
],
|
||||
'white' => [
|
||||
'fill' => 'fill-white',
|
||||
'stroke' => 'stroke-white',
|
||||
'fill' => 'fill-white'
|
||||
'fill-hover' => 'hover:fill-white',
|
||||
'stroke-hover' => 'hover:stroke-white',
|
||||
'fill-group-hover' => 'group-hover:fill-white',
|
||||
'stroke-group-hover' => 'group-hover:stroke-white',
|
||||
]
|
||||
];
|
||||
|
||||
@@ -182,13 +190,37 @@ class IconExtensionTest extends TestCase
|
||||
public function testThrowsIfChildArrayDoesntContainStrokeKey(): void
|
||||
{
|
||||
$this->expectException(\Exception::class);
|
||||
new IconExtension(['/'], [['fill' => '']]);
|
||||
new IconExtension(['/'], [['fill' => '', 'fill-hover' => '', 'stroke-hover' => '', 'fill-group-hover' => '', 'stroke-group-hover' => '']]);
|
||||
}
|
||||
|
||||
public function testThrowsIfChildArrayDoesntContainFillKey(): void
|
||||
{
|
||||
$this->expectException(\Exception::class);
|
||||
new IconExtension(['/'], [['stroke' => '']]);
|
||||
new IconExtension(['/'], [['stroke' => '', 'fill-hover' => '', 'stroke-hover' => '', 'fill-group-hover' => '', 'stroke-group-hover' => '']]);
|
||||
}
|
||||
|
||||
public function testThrowsIfChildArrayDoesntContainFillHoverKey(): void
|
||||
{
|
||||
$this->expectException(\Exception::class);
|
||||
new IconExtension(['/'], [['fill' => '', 'stroke' => '', 'stroke-hover' => '', 'fill-group-hover' => '', 'stroke-group-hover' => '']]);
|
||||
}
|
||||
|
||||
public function testThrowsIfChildArrayDoesntContainStrokeHoverKey(): void
|
||||
{
|
||||
$this->expectException(\Exception::class);
|
||||
new IconExtension(['/'], [['fill' => '', 'stroke' => '', 'fill-hover' => '', 'fill-group-hover' => '', 'stroke-group-hover' => '']]);
|
||||
}
|
||||
|
||||
public function testThrowsIfChildArrayDoesntContainFillGroupHoverKey(): void
|
||||
{
|
||||
$this->expectException(\Exception::class);
|
||||
new IconExtension(['/'], [['fill' => '', 'stroke' => '', 'fill-hover' => '', 'stroke-hover' => '', 'stroke-group-hover' => '']]);
|
||||
}
|
||||
|
||||
public function testThrowsIfChildArrayDoesntContainStrokeGroupHoverKey(): void
|
||||
{
|
||||
$this->expectException(\Exception::class);
|
||||
new IconExtension(['/'], [['fill' => '', 'stroke' => '', 'fill-hover' => '', 'stroke-hover' => '', 'fill-group-hover' => '']]);
|
||||
}
|
||||
|
||||
public function testBlackStrokeAttributeValuesAreRemoved(): void
|
||||
@@ -267,4 +299,11 @@ class IconExtensionTest extends TestCase
|
||||
$this->assertMatchesRegularExpression('/<svg.+class=".*group-hover:fill-white.*".*>/', $contents);
|
||||
$this->assertMatchesRegularExpression('/<svg.+class=".*group-hover:stroke-white.*".*>/', $contents);
|
||||
}
|
||||
|
||||
public function testThrowsIfInvalidOptionPassed(): void
|
||||
{
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
$this->icon->renderIcon(['icon' => self::ICON, 'fake-key-should-throw' => null]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user