Compare commits
13 Commits
0.1.0
...
issue/7-th
| Author | SHA1 | Date | |
|---|---|---|---|
| 3da5e00361 | |||
| a19f1f4438 | |||
| 6e2228b835 | |||
| 15ee51b884 | |||
| 6ab2baeb4e | |||
| 33892f81aa | |||
| bb7862c6ac | |||
| c1ac0faf78 | |||
| 1d91b50c32 | |||
| 9248b51908 | |||
| 0e2ee19f8f | |||
| 6e357ee8b7 | |||
| 3df034d309 |
7
CHANGELOG.md
Normal file
7
CHANGELOG.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Changelog
|
||||
|
||||
## [X.X.X] - XXXX-XX-XX
|
||||
- Allow passing in a space-separated string to the `classes` option
|
||||
|
||||
## [1.0.0] - 2023-06-27
|
||||
- First major version release
|
||||
24
README.md
24
README.md
@@ -33,11 +33,12 @@ pcm_icon:
|
||||
fill-group-hover: 'group-hover:fill-red-800'
|
||||
stroke-group-hover: 'group-hover:stroke-red-800'
|
||||
```
|
||||
# @TODO default options
|
||||
|
||||
`default` - Override the default options provided to the bundle.
|
||||
|
||||
`directories` - Which directories to look in for icons.
|
||||
|
||||
`colours` - Custom colours to use when colouring icons. Because this extension relies on Tailwind classes for colouring we must specify all the classes. This is a bit awkward, but you can just copy this template replacing COLOUR as appropriate:
|
||||
`colours` - Custom colours to use when colouring icons. Because this extension relies on Tailwind classes for colouring we **must** explicitly list all the classes required for Tailwind to render them properly. You can just copy this template replacing COLOUR as appropriate:
|
||||
|
||||
```yaml
|
||||
COLOUR:
|
||||
@@ -51,26 +52,17 @@ COLOUR:
|
||||
|
||||
## Options
|
||||
|
||||
`icon (string)` **(REQUIRED)** Icon to use, without the `.svg` extension
|
||||
`icon (string)` **(REQUIRED)** Icon to use, without the `.svg` extension.
|
||||
|
||||
`title (string)` Optional text to show on hover
|
||||
`title (string)` Optional text to show on hover. This can be null, but not an empty string.
|
||||
|
||||
`size (int)` Size of the icon in pixels
|
||||
`size (int)` Size of the icon in pixels.
|
||||
|
||||
`colour (string)` Name of the colour to use. Defaults to `primary` as it assumes you have a Tailwind colour set up called `primary`. If however you are not using `primary` to set a Tailwind primary colour in your project, you can instead set the default colour of the icon by changing what colour classes the primary colour uses. EG:
|
||||
```yaml
|
||||
primary:
|
||||
fill: 'fill-purple-700'
|
||||
stroke: 'stroke-purple-700'
|
||||
fill-hover: 'hover:fill-purple-700'
|
||||
stroke-hover: 'hover:stroke-purple-700'
|
||||
fill-group-hover: 'group-hover:fill-purple-700'
|
||||
stroke-group-hover: 'group-hover:stroke-purple-700'
|
||||
```
|
||||
`colour (string)` Name of the colour to use. Defaults to `primary` as it assumes you have a Tailwind colour set up called `primary`. If you are not using `primary` to set a Tailwind primary colour in your project you can change the default colour in the `pcm_icon.yaml` file.
|
||||
|
||||
`hover (string)` Name of the colour to use when the icon is hovered over
|
||||
|
||||
`classes (string[])` Additional classes to add to the icon. This can cause Tailwind class collisions, so only use it as a last resort.
|
||||
`classes (string[]|string)` Additional classes to add to the icon as either an array of strings or a space-separated string. This can cause Tailwind class collisions, so it is not recommended to use.
|
||||
|
||||
## Reminders
|
||||
Remember to add `./config/packages/*.yaml` as a value in your Tailwind config content array if it does not already exist. This will ensure Tailwind classes inside of the config file get compiled.
|
||||
|
||||
@@ -5,8 +5,16 @@ services:
|
||||
|
||||
pcm_icon.icon_extension:
|
||||
public: true
|
||||
class: Pcm\IconBundle\Twig\Functions\IconExtension
|
||||
class: Pcm\IconBundle\Twig\Extension\IconExtension
|
||||
|
||||
Pcm\IconBundle\Twig\Functions\IconExtension:
|
||||
Pcm\IconBundle\Twig\Extension\IconExtension:
|
||||
public: false
|
||||
alias: pcm_icon.icon_extension
|
||||
|
||||
Pcm\IconBundle\Twig\Runtime\IconRuntime:
|
||||
tags:
|
||||
- { name: twig.runtime }
|
||||
arguments:
|
||||
$defaultOptions: '%pcm.icon_bundle.default_options%'
|
||||
$directories: '%pcm.icon_bundle.directories%'
|
||||
$colours: '%pcm.icon_bundle.colours%'
|
||||
|
||||
@@ -23,10 +23,8 @@ class PcmIconExtension extends Extension
|
||||
$configuration = new Configuration();
|
||||
$config = $this->processConfiguration($configuration, $configs);
|
||||
|
||||
$definition = $container->getDefinition('pcm_icon.icon_extension');
|
||||
|
||||
$definition->addArgument($config['default']);
|
||||
$definition->addArgument($config['directories']);
|
||||
$definition->addArgument($config['colours']);
|
||||
$container->setParameter('pcm.icon_bundle.default_options', $config['default']);
|
||||
$container->setParameter('pcm.icon_bundle.directories', $config['directories']);
|
||||
$container->setParameter('pcm.icon_bundle.colours', $config['colours']);
|
||||
}
|
||||
}
|
||||
|
||||
7
src/Exception/EmptyFileException.php
Normal file
7
src/Exception/EmptyFileException.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Pcm\IconBundle\Exception;
|
||||
|
||||
class EmptyFileException extends \Exception {};
|
||||
@@ -16,7 +16,7 @@ final class IconExtension extends AbstractExtension
|
||||
public function getFunctions(): array
|
||||
{
|
||||
return [
|
||||
new TwigFunction('pcm_icon', [IconRuntime::class, 'renderIcon'])
|
||||
new TwigFunction('pcm_icon', [IconRuntime::class, 'renderIcon'], ['is_safe' => ['html']])
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace Pcm\IconBundle\Twig\Runtime;
|
||||
|
||||
use Pcm\IconBundle\Exception\ColourNotFound;
|
||||
use Pcm\IconBundle\Exception\EmptyFileException;
|
||||
use Pcm\IconBundle\Exception\IconNotFound;
|
||||
use Twig\Extension\RuntimeExtensionInterface;
|
||||
|
||||
@@ -16,7 +17,7 @@ final class IconRuntime implements RuntimeExtensionInterface
|
||||
'size' => null,
|
||||
'colour' => null,
|
||||
'hover' => null,
|
||||
'classes' => [],
|
||||
'classes' => "",
|
||||
];
|
||||
|
||||
public function __construct(private array $defaultOptions, private array $directories, private array $colours)
|
||||
@@ -31,7 +32,8 @@ final class IconRuntime implements RuntimeExtensionInterface
|
||||
* 'size' => (int) Height and width in px
|
||||
* 'colour' => (string) Main colour
|
||||
* 'hover' => (?string) Hover colour
|
||||
* 'classes' => (array) Additional classes to add to the icon. Not recommended.
|
||||
* 'classes' => (string[]|string) Additional classes to add to the icon, given as
|
||||
* an array of strings or a space-separated string.
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
@@ -43,6 +45,10 @@ final class IconRuntime implements RuntimeExtensionInterface
|
||||
|
||||
$svg = $this->getSvg($options['icon']);
|
||||
|
||||
if (empty($svg)) {
|
||||
throw new EmptyFileException(\sprintf("The file %s.svg was found, but it was empty!", $options['icon']));
|
||||
}
|
||||
|
||||
$this->sanitiseSvg($svg);
|
||||
|
||||
$colourClasses = $this->getColourClasses($options['colour'], $options['hover']);
|
||||
@@ -60,9 +66,9 @@ final class IconRuntime implements RuntimeExtensionInterface
|
||||
return $svg;
|
||||
}
|
||||
|
||||
private function getExtraClasses(array $extraClasses): string
|
||||
private function getExtraClasses(array|string $extraClasses): string
|
||||
{
|
||||
return implode(' ', $extraClasses);
|
||||
return \is_array($extraClasses) ? implode(' ', $extraClasses) : $extraClasses;
|
||||
}
|
||||
|
||||
private function mergeWithDefaultOptions(array $userOptions): array
|
||||
@@ -103,6 +109,9 @@ final class IconRuntime implements RuntimeExtensionInterface
|
||||
$this->removeBlackFillAttributes($svg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IconNotFound when an svg file with the passed in name cannot be found
|
||||
*/
|
||||
private function findSvgFilepath(string $iconName): string
|
||||
{
|
||||
foreach ($this->directories as $directory) {
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace Pcm\IconBundle\Tests\Twig\Functions;
|
||||
|
||||
use Pcm\IconBundle\DependencyInjection\Configuration;
|
||||
use Pcm\IconBundle\Exception\ColourNotFound;
|
||||
use Pcm\IconBundle\Exception\EmptyFileException;
|
||||
use Pcm\IconBundle\Exception\IconNotFound;
|
||||
use Pcm\IconBundle\Twig\Runtime\IconRuntime;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
@@ -50,6 +51,12 @@ class IconRuntimeTest extends TestCase
|
||||
$this->icon->renderIcon(['icon' => random_bytes(8)]);
|
||||
}
|
||||
|
||||
public function testThrowsIfPassedInAnEmptyFile(): void
|
||||
{
|
||||
$this->expectException(EmptyFileException::class);
|
||||
$this->icon->renderIcon(['icon' => 'empty']);
|
||||
}
|
||||
|
||||
public function testNoTitleExistsIfNotPassedIn(): void
|
||||
{
|
||||
$content = $this->icon->renderIcon(['icon' => self::ICON]);
|
||||
@@ -225,19 +232,26 @@ class IconRuntimeTest extends TestCase
|
||||
$this->assertMatchesRegularExpression('/<svg.+class=".*group-hover:stroke-white.*".*>/', $contents);
|
||||
}
|
||||
|
||||
public function testExtraClassesThrowsIfNotAnArray(): void
|
||||
public function testExtraClassesThrowsIfNotAnArrayOrString(): void
|
||||
{
|
||||
$this->expectException(\TypeError::class);
|
||||
$this->icon->renderIcon(['icon' => self::ICON, 'classes' => 'string_value']);
|
||||
$this->icon->renderIcon(['icon' => self::ICON, 'classes' => 1]);
|
||||
}
|
||||
|
||||
public function testExtraClassesGetAdded(): void
|
||||
public function testExtraClassesGetAddedFromArray(): void
|
||||
{
|
||||
$contents = $this->icon->renderIcon(['icon' => self::ICON, 'classes' => ['abc', 'def']]);
|
||||
$this->assertMatchesRegularExpression('/<svg.+class=".*abc.*".*>/', $contents);
|
||||
$this->assertMatchesRegularExpression('/<svg.+class=".*def.*".*>/', $contents);
|
||||
}
|
||||
|
||||
public function testExtraClassesGetAddedFromString(): void
|
||||
{
|
||||
$contents = $this->icon->renderIcon(['icon' => self::ICON, 'classes' => 'ghi jkl']);
|
||||
$this->assertMatchesRegularExpression('/<svg.+class=".*ghi.*".*>/', $contents);
|
||||
$this->assertMatchesRegularExpression('/<svg.+class=".*jkl.*".*>/', $contents);
|
||||
}
|
||||
|
||||
public function testAddingExtraClassesDoesntStripAwayColourClasses(): void
|
||||
{
|
||||
$contents = $this->icon->renderIcon(['icon' => self::ICON, 'classes' => ['abc']]);
|
||||
|
||||
0
tests/icons/empty.svg
Normal file
0
tests/icons/empty.svg
Normal file
Reference in New Issue
Block a user