Skip to content

Commit

Permalink
Defer icons to icons stack to reduce DOM count (#191)
Browse files Browse the repository at this point in the history
* Defer icons to icons stack to reduce DOM count

* Create test for deferred icon

* Update readme with more intuitive attribute

Co-authored-by: Dries Vints <dries@vints.io>

Co-authored-by: Dries Vints <dries@vints.io>
  • Loading branch information
indykoning and driesvints authored May 11, 2022
1 parent 02fa8a5 commit 57a7c41
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 1 deletion.
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,26 @@ Or any other attributes for that matter:

> ⚠️ Note that with Blade components, using a prefix is always required, even when referencing icons from the default set.
#### Deferring icons

When you're using the same icon in lots of places on the page the DOM element count may explode upwards.
To remedy this you can add the defer attribute to the components:

```blade
<x-icon-camera defer />
```

This will push the icons to the stack "bladeicons", you should load this stack at the bottom of your page

```blade
...
<svg hidden class="hidden">
@stack('bladeicons')
</svg>
</body>
</html>
```

#### Default Component

If you don't want to use the component syntax from above you can also make use of the default `Icon` component that ships with Blade Icons. Simply pass the icon name through the `$name` attribute:
Expand Down
25 changes: 24 additions & 1 deletion src/Svg.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ final class Svg implements Htmlable
public function __construct(string $name, string $contents, array $attributes = [])
{
$this->name = $name;
$this->contents = $contents;
$this->contents = $this->deferContent($contents, $attributes['defer'] ?? false);
$this->attributes = $attributes;
}

Expand All @@ -40,4 +40,27 @@ public function toHtml(): string
$this->contents,
);
}

protected function deferContent($contents, $defer = false)
{
if (! $defer) {
return $contents;
}

$svgContent = strip_tags($contents, ['circle', 'ellipse', 'line', 'path', 'polygon', 'polyline', 'rect']);
$hash = 'icon-'.md5($svgContent);
$contents = str_replace($svgContent, strtr('<use href=":href"></use>', [':href' => '#'.$hash]), $contents);
$contents .= <<<BLADE
@once("{$hash}")
@push("bladeicons")
<g id="{$hash}">
{$svgContent}
</g>
@endpush
@endonce
BLADE;

return $contents;
}
}
11 changes: 11 additions & 0 deletions tests/SvgTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ public function it_can_compile_to_html()
$this->assertSame('<svg></svg>', $svg->toHtml());
}

/** @test */
public function it_can_compile_to_defered_html()
{
$svgPath = '<path d="M14 5l7 7m0 0l-7 7m7-7H3"></path>';
$svg = new Svg('heroicon-o-arrow-right', '<svg>'.$svgPath.'</svg>', ['defer' => true]);

$svgHtml = $svg->toHtml();
$this->assertStringContainsString('<use href="#icon-'.md5($svgPath).'"></use>', $svgHtml);
$this->assertStringContainsString($svgPath, $svgHtml);
}

/** @test */
public function it_can_compile_with_attributes()
{
Expand Down

0 comments on commit 57a7c41

Please sign in to comment.