Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9195df9028 | ||
|
|
f82317cf99 | ||
|
|
03212310fd | ||
|
|
eb2bea62a7 | ||
|
|
b28a6f69f9 | ||
|
|
9ef5d58a8a | ||
|
|
a4344687d4 | ||
|
|
4ec6224b25 | ||
|
|
7a3366c2da | ||
|
|
78a321137e | ||
|
|
5e3756773e | ||
|
|
6553d0d32f | ||
|
|
92eee8fa04 | ||
|
|
e12eceed26 | ||
|
|
27dfa0af2e | ||
|
|
3e4b948569 | ||
|
|
e72ce28af4 | ||
|
|
4329780c39 | ||
|
|
f7efd93cec | ||
|
|
bac02c285f |
59
README.md
59
README.md
@@ -1,3 +1,60 @@
|
|||||||
# PCM Icon Bundle
|
# PCM Icon Bundle
|
||||||
|
|
||||||
# WIP DON'T USE YET
|
Use icons inside of Twig templates with ease!
|
||||||
|
|
||||||
|
```php
|
||||||
|
{{ icon({ icon: 'person' }) }}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Config
|
||||||
|
Example config:
|
||||||
|
```yaml
|
||||||
|
# config/packages/pcm_icon.yaml
|
||||||
|
pcm_icon:
|
||||||
|
directories:
|
||||||
|
- '%kernel.project_dir%/public/icons'
|
||||||
|
palletes:
|
||||||
|
primary:
|
||||||
|
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:
|
||||||
|
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'
|
||||||
|
```
|
||||||
|
|
||||||
|
`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.
|
||||||
|
|||||||
@@ -6,16 +6,6 @@ services:
|
|||||||
pcm_icon.icon_extension:
|
pcm_icon.icon_extension:
|
||||||
public: true
|
public: true
|
||||||
class: Pcm\IconBundle\Twig\Functions\IconExtension
|
class: Pcm\IconBundle\Twig\Functions\IconExtension
|
||||||
args:
|
|
||||||
directories:
|
|
||||||
- '%kernel.project_dir%/public/icons'
|
|
||||||
palletes:
|
|
||||||
- primary:
|
|
||||||
stroke: stroke-primary,
|
|
||||||
fill: fill-primary
|
|
||||||
- white:
|
|
||||||
stroke: stroke-white,
|
|
||||||
fill: fill-white
|
|
||||||
|
|
||||||
Pcm\IconBundle\Twig\Functions\IconExtension:
|
Pcm\IconBundle\Twig\Functions\IconExtension:
|
||||||
public: false
|
public: false
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Pcm\IconBundle\Twig\Functions;
|
namespace Pcm\IconBundle\Twig\Functions;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
|
||||||
use Twig\Extension\AbstractExtension;
|
use Twig\Extension\AbstractExtension;
|
||||||
use Twig\TwigFunction;
|
use Twig\TwigFunction;
|
||||||
|
|
||||||
@@ -16,13 +15,14 @@ final class IconExtension extends AbstractExtension
|
|||||||
'icon' => null,
|
'icon' => null,
|
||||||
'title' => null,
|
'title' => null,
|
||||||
'size' => self::DEFAULT_SIZE,
|
'size' => self::DEFAULT_SIZE,
|
||||||
'colour' => 'primary'
|
'colour' => 'primary',
|
||||||
|
'hover' => null
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct(private array $directories, private array $palletes)
|
public function __construct(private array $directories, private array $palletes)
|
||||||
{
|
{
|
||||||
if (empty($this->directories))
|
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,
|
$dirsContainNonString = array_reduce($this->directories,
|
||||||
fn($notString, $path) => $notString || !is_string($path));
|
fn($notString, $path) => $notString || !is_string($path));
|
||||||
@@ -31,7 +31,7 @@ final class IconExtension extends AbstractExtension
|
|||||||
throw new \TypeError('Directories array must only contain strings!');
|
throw new \TypeError('Directories array must only contain strings!');
|
||||||
|
|
||||||
if (empty($this->palletes))
|
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,
|
$pelletesContainNonarray = array_reduce($this->palletes,
|
||||||
fn($notArray, $path) => $notArray || !is_array($path));
|
fn($notArray, $path) => $notArray || !is_array($path));
|
||||||
@@ -40,7 +40,14 @@ final class IconExtension extends AbstractExtension
|
|||||||
throw new \TypeError('Palletes array must only contain arrays!');
|
throw new \TypeError('Palletes array must only contain arrays!');
|
||||||
|
|
||||||
foreach ($this->palletes as $pallete) {
|
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!');
|
throw new \Exception('Palletes must contain a "stroke" and "fill" key!');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,41 +69,30 @@ final class IconExtension extends AbstractExtension
|
|||||||
* @param array $options
|
* @param array $options
|
||||||
* ```
|
* ```
|
||||||
* $options = [
|
* $options = [
|
||||||
* 'icon' => (string) Which icon to use
|
* 'icon' => (string) Which icon to use
|
||||||
* 'title' => (?string) Text to appear on mouse hover
|
* 'title' => (?string) Text to appear on mouse hover
|
||||||
* 'size' => (int) Height and width in px
|
* 'size' => (int) Height and width in px
|
||||||
* 'colour' => (string) Main colour pallete
|
* 'colour' => (string) Main colour pallete
|
||||||
|
* 'hover' => (?string) Hover colour pallete
|
||||||
* ]
|
* ]
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
public function renderIcon(array $userOptions): string
|
public function renderIcon(array $userOptions): string
|
||||||
{
|
{
|
||||||
$options = $this->mergeUserOptionsWithDefaults($userOptions);
|
$options = $this->getMergedOptions($userOptions);
|
||||||
|
$svg = $this->getSanitisedIconSvg($options['icon']);
|
||||||
|
$colourClasses = $this->getColourClasses($options['colour'], $options['hover']);
|
||||||
|
$svg = $this->addClassesToSvg($svg, $colourClasses);
|
||||||
|
$svg = $this->addTitleToSvgIfNotNull($svg, $options['title']);
|
||||||
|
$svg = $this->setSvgHeightAndWidth($svg, $options['size']);
|
||||||
|
|
||||||
$iconFilepath = $this->findSvgFilepath($options['icon']);
|
return $svg;
|
||||||
$rawSvgMarkup = $this->getSvgMarkup($iconFilepath);
|
}
|
||||||
$cleanSvgMarkup = $this->cleanSvgMarkup($rawSvgMarkup);
|
|
||||||
|
|
||||||
$mainPallete = $this->getMainPallete($options['colour']);
|
private function getMergedOptions(array $userOptions): array
|
||||||
|
{
|
||||||
$xml = new \SimpleXMLElement($cleanSvgMarkup);
|
$this->throwIfUnrecognisedOptionExists($userOptions);
|
||||||
$xml = $this->addAttributeToXmlElement($xml, 'class', $mainPallete['stroke'] . ' ' . $mainPallete['fill']);
|
return $this->mergeUserOptionsWithDefaults($userOptions);
|
||||||
$markup = $this->removeXMLDeclaration($xml->saveXML());
|
|
||||||
|
|
||||||
if ($this->isNonEmptyString($options['title']))
|
|
||||||
$markup = $this->addTitleToMarkup($markup, $options['title']);
|
|
||||||
|
|
||||||
if ($options['size'] < 0)
|
|
||||||
throw new \InvalidArgumentException('Size must not be negative');
|
|
||||||
|
|
||||||
if (!is_int($options['size']))
|
|
||||||
throw new \TypeError('Size value must be an integer');
|
|
||||||
|
|
||||||
$markup = $this->setSize($markup, $options['size']);
|
|
||||||
$markup = $this->removeBlackStrokeAttributes($markup);
|
|
||||||
$markup = $this->removeBlackFillAttributes($markup);
|
|
||||||
|
|
||||||
return $markup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function mergeUserOptionsWithDefaults(array $userOptions): array
|
private function mergeUserOptionsWithDefaults(array $userOptions): array
|
||||||
@@ -104,6 +100,23 @@ final class IconExtension extends AbstractExtension
|
|||||||
return array_merge(self::DEFAULT_OPTIONS, $userOptions);
|
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 getSanitisedIconSvg(string $iconName): string
|
||||||
|
{
|
||||||
|
$iconFilepath = $this->findSvgFilepath($iconName);
|
||||||
|
$rawSvgMarkup = $this->getSvgMarkup($iconFilepath);
|
||||||
|
$cleanSvgMarkup = $this->removeExistingTitleElement($rawSvgMarkup);
|
||||||
|
$cleanSvgMarkup = $this->removeBlackStrokeAttributes($cleanSvgMarkup);
|
||||||
|
return $this->removeBlackFillAttributes($cleanSvgMarkup);
|
||||||
|
}
|
||||||
|
|
||||||
private function findSvgFilepath(string $iconName): string
|
private function findSvgFilepath(string $iconName): string
|
||||||
{
|
{
|
||||||
foreach ($this->directories as $directory) {
|
foreach ($this->directories as $directory) {
|
||||||
@@ -121,12 +134,35 @@ final class IconExtension extends AbstractExtension
|
|||||||
return file_get_contents($filepath);
|
return file_get_contents($filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function cleanSvgMarkup(string $markup): string
|
private function removeExistingTitleElement(string $svg): string
|
||||||
{
|
{
|
||||||
return preg_replace('/<title>.*<\/title>/', '', $markup);
|
return preg_replace('/<title>.*<\/title>/', '', $svg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getMainPallete(string $palleteName): array
|
private function removeBlackStrokeAttributes(string $content): string
|
||||||
|
{
|
||||||
|
return preg_replace('/stroke(=|:)"?\s*(#0{6}|#000|rgb\(\s*0,\s*0,\s*0\s*\)|black)\s*"?/', '', $content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function removeBlackFillAttributes(string $content): string
|
||||||
|
{
|
||||||
|
return preg_replace('/fill(=|:)"?\s*(#0{6}|#000|rgb\(\s*0,\s*0,\s*0\s*\)|black)\s*"?/', '', $content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getColourClasses(string $primaryColour, ?string $hoverColour): string
|
||||||
|
{
|
||||||
|
$mainPallete = $this->getPallete($primaryColour);
|
||||||
|
$colourClasses = "{$mainPallete['stroke']} {$mainPallete['fill']}";
|
||||||
|
|
||||||
|
if (null !== $hoverColour) {
|
||||||
|
$hoverPallete = $this->getPallete($hoverColour);
|
||||||
|
$colourClasses .= " cursor-pointer {$hoverPallete['stroke-hover']} {$hoverPallete['fill-hover']} {$hoverPallete['stroke-group-hover']} {$hoverPallete['fill-group-hover']}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $colourClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getPallete(string $palleteName): array
|
||||||
{
|
{
|
||||||
if (array_key_exists($palleteName, $this->palletes))
|
if (array_key_exists($palleteName, $this->palletes))
|
||||||
return $this->palletes[$palleteName];
|
return $this->palletes[$palleteName];
|
||||||
@@ -134,36 +170,19 @@ final class IconExtension extends AbstractExtension
|
|||||||
throw new PalleteNotFound("The pallete '$palleteName' was not found!");
|
throw new PalleteNotFound("The pallete '$palleteName' was not found!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private function isNonEmptyString(mixed $title): bool
|
private function addClassesToSvg(string $svg, string $classes): string
|
||||||
{
|
{
|
||||||
if (!is_string($title) && null !== $title)
|
$xml = new \SimpleXMLElement($svg);
|
||||||
throw new \TypeError('Title must be a string!');
|
$xml = $this->addAttributeToXmlElement($xml, 'class', $classes);
|
||||||
|
return $this->removeXMLDeclaration($xml->saveXML());
|
||||||
if ('' === $title)
|
|
||||||
throw new \InvalidArgumentException('Title string must not be empty!');
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function addTitleToMarkup(string $markup, ?string $title): string
|
private function addTitleToSvgIfNotNull(string $svg, ?string $title): string
|
||||||
{
|
{
|
||||||
if (null === $title)
|
if (null === $title) return $svg;
|
||||||
return $markup;
|
$this->throwIfTitleIsEmpty($title);
|
||||||
|
|
||||||
return preg_replace('/(<svg(.|\n)*?>\n?)/', "$1<title>$title</title>", $markup);
|
return preg_replace('/(<svg(.|\n)*?>\n?)/', "$1<title>$title</title>", $svg);
|
||||||
}
|
|
||||||
|
|
||||||
private function setSize(string $content, int $size): string
|
|
||||||
{
|
|
||||||
$svgAsXmlElement = new \SimpleXMLElement($content);
|
|
||||||
$svgAsXmlElement = $this->addAttributeToXmlElement($svgAsXmlElement, 'width', $size);
|
|
||||||
$svgAsXmlElement = $this->addAttributeToXmlElement($svgAsXmlElement, 'height', $size);
|
|
||||||
return $this->removeXMLDeclaration($svgAsXmlElement->saveXML());
|
|
||||||
}
|
|
||||||
|
|
||||||
private function removeXMLDeclaration(string $content): string
|
|
||||||
{
|
|
||||||
return trim(preg_replace('/<\?xml.*\?>/', '', $content));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function addAttributeToXmlElement(\SimpleXMLElement $xml, string $attrName, mixed $attrValue): \SimpleXMLElement
|
private function addAttributeToXmlElement(\SimpleXMLElement $xml, string $attrName, mixed $attrValue): \SimpleXMLElement
|
||||||
@@ -177,27 +196,33 @@ final class IconExtension extends AbstractExtension
|
|||||||
return $xml;
|
return $xml;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function removeBlackStrokeAttributes(string $content): string
|
private function removeXMLDeclaration(string $content): string
|
||||||
{
|
{
|
||||||
return preg_replace('/stroke="\s*(#0{6}|#000|rgb\(\s*0,\s*0,\s*0\s*\)|black)\s*"/', '', $content);
|
return trim(preg_replace('/<\?xml.*\?>/', '', $content));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function removeBlackFillAttributes(string $content): string
|
private function throwIfTitleIsEmpty(string $title): void
|
||||||
{
|
{
|
||||||
return preg_replace('/fill="\s*(#0{6}|#000|rgb\(\s*0,\s*0,\s*0\s*\)|black)\s*"/', '', $content);
|
if ('' === $title)
|
||||||
|
throw new \InvalidArgumentException('Title string must not be empty!');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setSvgHeightAndWidth(string $content, int $size): string
|
||||||
|
{
|
||||||
|
$this->throwIfSizeIsNegative($size);
|
||||||
|
$svgAsXmlElement = new \SimpleXMLElement($content);
|
||||||
|
$svgAsXmlElement = $this->addAttributeToXmlElement($svgAsXmlElement, 'width', $size);
|
||||||
|
$svgAsXmlElement = $this->addAttributeToXmlElement($svgAsXmlElement, 'height', $size);
|
||||||
|
return $this->removeXMLDeclaration($svgAsXmlElement->saveXML());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function throwIfSizeIsNegative(int $size): void
|
||||||
|
{
|
||||||
|
if ($size < 0)
|
||||||
|
throw new \InvalidArgumentException('Size must not be negative');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class IconNotFound extends \Exception {};
|
class IconNotFound extends \Exception {};
|
||||||
|
|
||||||
class PalleteNotFound extends \Exception {};
|
class PalleteNotFound extends \Exception {};
|
||||||
|
|
||||||
// class="stroke-neutral-400 fill-neutral-400"
|
|
||||||
|
|
||||||
// hover:stroke-ses-highlight
|
|
||||||
// group-hover:stroke-ses-highlight
|
|
||||||
|
|
||||||
// hover:fill-ses-highlight
|
|
||||||
// group-hover:fill-ses-highlight
|
|
||||||
|
|
||||||
// cursor-pointer
|
|
||||||
|
|||||||
@@ -15,12 +15,20 @@ class IconExtensionTest extends TestCase
|
|||||||
|
|
||||||
private const PALLETES = [
|
private const PALLETES = [
|
||||||
'primary' => [
|
'primary' => [
|
||||||
|
'fill' => 'fill-primary',
|
||||||
'stroke' => 'stroke-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' => [
|
'white' => [
|
||||||
|
'fill' => 'fill-white',
|
||||||
'stroke' => 'stroke-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
|
public function testThrowsIfChildArrayDoesntContainStrokeKey(): void
|
||||||
{
|
{
|
||||||
$this->expectException(\Exception::class);
|
$this->expectException(\Exception::class);
|
||||||
new IconExtension(['/'], [['fill' => '']]);
|
new IconExtension(['/'], [['fill' => '', 'fill-hover' => '', 'stroke-hover' => '', 'fill-group-hover' => '', 'stroke-group-hover' => '']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testThrowsIfChildArrayDoesntContainFillKey(): void
|
public function testThrowsIfChildArrayDoesntContainFillKey(): void
|
||||||
{
|
{
|
||||||
$this->expectException(\Exception::class);
|
$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
|
public function testBlackStrokeAttributeValuesAreRemoved(): void
|
||||||
@@ -200,6 +232,15 @@ class IconExtensionTest extends TestCase
|
|||||||
$this->assertDoesNotMatchRegularExpression('/stroke="\s*rgb\(0,\s*0,\s*0\)\s*"/', $content);
|
$this->assertDoesNotMatchRegularExpression('/stroke="\s*rgb\(0,\s*0,\s*0\)\s*"/', $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testBlackStrokeStylesAreRemoved(): void
|
||||||
|
{
|
||||||
|
$content = $this->icon->renderIcon(['icon' => self::ICON]);
|
||||||
|
$this->assertDoesNotMatchRegularExpression('/stroke:\s*#000\s*/', $content);
|
||||||
|
$this->assertDoesNotMatchRegularExpression('/stroke:\s*#000000\s*/', $content);
|
||||||
|
$this->assertDoesNotMatchRegularExpression('/stroke:\s*black\s*/', $content);
|
||||||
|
$this->assertDoesNotMatchRegularExpression('/stroke:\s*rgb\(0,\s*0,\s*0\)\s*/', $content);
|
||||||
|
}
|
||||||
|
|
||||||
public function testBlackFillAttributeValuesAreRemoved(): void
|
public function testBlackFillAttributeValuesAreRemoved(): void
|
||||||
{
|
{
|
||||||
$content = $this->icon->renderIcon(['icon' => self::ICON]);
|
$content = $this->icon->renderIcon(['icon' => self::ICON]);
|
||||||
@@ -209,7 +250,16 @@ class IconExtensionTest extends TestCase
|
|||||||
$this->assertDoesNotMatchRegularExpression('/fill="\s*rgb\(0,\s*0,\s*0\)\s*"/', $content);
|
$this->assertDoesNotMatchRegularExpression('/fill="\s*rgb\(0,\s*0,\s*0\)\s*"/', $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testThrowsIfPalleteIsNotFound(): void
|
public function testBlackFillStylesAreRemoved(): void
|
||||||
|
{
|
||||||
|
$content = $this->icon->renderIcon(['icon' => self::ICON]);
|
||||||
|
$this->assertDoesNotMatchRegularExpression('/fill:\s*#000\s*/', $content);
|
||||||
|
$this->assertDoesNotMatchRegularExpression('/fill:\s*#000000\s*/', $content);
|
||||||
|
$this->assertDoesNotMatchRegularExpression('/fill:\s*black\s*/', $content);
|
||||||
|
$this->assertDoesNotMatchRegularExpression('/fill:\s*rgb\(0,\s*0,\s*0\)\s*/', $content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testThrowsIfColourPalleteIsNotFound(): void
|
||||||
{
|
{
|
||||||
$this->expectException(PalleteNotFound::class);
|
$this->expectException(PalleteNotFound::class);
|
||||||
$this->icon->renderIcon(['icon' => self::ICON, 'colour' => 'red']);
|
$this->icon->renderIcon(['icon' => self::ICON, 'colour' => 'red']);
|
||||||
@@ -222,5 +272,38 @@ class IconExtensionTest extends TestCase
|
|||||||
$this->assertMatchesRegularExpression('/<svg.*?class=".*?stroke-white?.*>/', $contents);
|
$this->assertMatchesRegularExpression('/<svg.*?class=".*?stroke-white?.*>/', $contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testThrowsIfHoverPalleteIsNotFound(): void
|
||||||
|
{
|
||||||
|
$this->expectException(PalleteNotFound::class);
|
||||||
|
$this->icon->renderIcon(['icon' => self::ICON, 'hover' => 'red']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSvgClassContainsHoverPalleteClasses(): void
|
||||||
|
{
|
||||||
|
$contents = $this->icon->renderIcon(['icon' => self::ICON, 'hover' => 'white']);
|
||||||
|
$this->assertMatchesRegularExpression('/<svg.+class=".*cursor-pointer.*".*>/', $contents);
|
||||||
|
$this->assertMatchesRegularExpression('/<svg.+class=".*hover:fill-white.*".*>/', $contents);
|
||||||
|
$this->assertMatchesRegularExpression('/<svg.+class=".*hover:stroke-white.*".*>/', $contents);
|
||||||
|
$this->assertMatchesRegularExpression('/<svg.+class=".*group-hover:fill-white.*".*>/', $contents);
|
||||||
|
$this->assertMatchesRegularExpression('/<svg.+class=".*group-hover:stroke-white.*".*>/', $contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSvgClassContainsHoverAndColourPalleteClasses(): void
|
||||||
|
{
|
||||||
|
$contents = $this->icon->renderIcon(['icon' => self::ICON, 'hover' => 'white', 'colour' => 'primary']);
|
||||||
|
$this->assertMatchesRegularExpression('/<svg.+class=".*fill-primary.*".*>/', $contents);
|
||||||
|
$this->assertMatchesRegularExpression('/<svg.+class=".*stroke-primary.*".*>/', $contents);
|
||||||
|
$this->assertMatchesRegularExpression('/<svg.+class=".*cursor-pointer.*".*>/', $contents);
|
||||||
|
$this->assertMatchesRegularExpression('/<svg.+class=".*hover:fill-white.*".*>/', $contents);
|
||||||
|
$this->assertMatchesRegularExpression('/<svg.+class=".*hover:stroke-white.*".*>/', $contents);
|
||||||
|
$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]);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,4 +6,5 @@
|
|||||||
<line fill="black"></line>
|
<line fill="black"></line>
|
||||||
<line x1="256" y1="112" x2="256" y2="400" width="101" height="101" style="fill: none; stroke: rgb(0,0, 0); stroke-linecap: round; stroke-linejoin: round; stroke-width: 32px;"></line>
|
<line x1="256" y1="112" x2="256" y2="400" width="101" height="101" style="fill: none; stroke: rgb(0,0, 0); stroke-linecap: round; stroke-linejoin: round; stroke-width: 32px;"></line>
|
||||||
<line x1="400" y1="256" x2="112" y2="256" width="102" height="102" style="fill: none; stroke: #000; stroke-linecap: round; stroke-linejoin: round; stroke-width: 32px;"></line>
|
<line x1="400" y1="256" x2="112" y2="256" width="102" height="102" style="fill: none; stroke: #000; stroke-linecap: round; stroke-linejoin: round; stroke-width: 32px;"></line>
|
||||||
|
<polyline points="112 244 256 100 400 244" style="fill:#000;fill:#000000;fill: black;fill:rgb(0,0,0);stroke:#000;stroke:#000000;stroke:black;stroke:rgb(0, 0, 0);stroke-linecap:round;stroke-linejoin:round;stroke-width:48px"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 631 B After Width: | Height: | Size: 860 B |
Reference in New Issue
Block a user