Skip to content

Commit e47d5d6

Browse files
committed
Blend SVG for Statamic!
0 parents  commit e47d5d6

File tree

10 files changed

+361
-0
lines changed

10 files changed

+361
-0
lines changed

BladeSvg/BladeSvg.php

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
namespace Statamic\Addons\BladeSvg;
4+
5+
use Illuminate\Support\Collection;
6+
use Illuminate\Support\HtmlString;
7+
use Illuminate\Contracts\Support\Htmlable;
8+
9+
class BladeSvg implements Htmlable
10+
{
11+
private $imageName;
12+
private $renderMode;
13+
private $factory;
14+
private $attrs = [];
15+
16+
public function __construct($imageName, $renderMode, $factory, $attrs = [])
17+
{
18+
$this->imageName = $imageName;
19+
$this->renderMode = $renderMode;
20+
$this->factory = $factory;
21+
$this->attrs = $attrs;
22+
}
23+
24+
public function toHtml()
25+
{
26+
return new HtmlString(call_user_func([
27+
'inline' => [$this, 'renderInline'],
28+
'sprite' => [$this, 'renderFromSprite'],
29+
][$this->renderMode]));
30+
}
31+
32+
public function __call($method, $args)
33+
{
34+
if (count($args) === 0) {
35+
$this->attrs[] = snake_case($method, '-');
36+
} else {
37+
$this->attrs[snake_case($method, '-')] = $args[0];
38+
}
39+
40+
return $this;
41+
}
42+
43+
public function inline()
44+
{
45+
$this->renderMode = 'inline';
46+
return $this;
47+
}
48+
49+
public function sprite()
50+
{
51+
$this->renderMode = 'sprite';
52+
return $this;
53+
}
54+
55+
public function renderInline()
56+
{
57+
return str_replace(
58+
'<svg',
59+
sprintf('<svg%s', $this->renderAttributes()),
60+
$this->factory->getSvg($this->imageName)
61+
);
62+
}
63+
64+
public function renderFromSprite()
65+
{
66+
return vsprintf('<svg%s><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="%s#%s"></use></svg>', [
67+
$this->renderAttributes(),
68+
$this->factory->spritesheetUrl(),
69+
$this->factory->spriteId($this->imageName)
70+
]);
71+
}
72+
73+
private function renderAttributes()
74+
{
75+
if (count($this->attrs) == 0) {
76+
return '';
77+
}
78+
79+
return ' '.collect($this->attrs)->map(function ($value, $attr) {
80+
if (is_int($attr)) {
81+
return $value;
82+
}
83+
return sprintf('%s="%s"', $attr, $value);
84+
})->implode(' ');
85+
}
86+
}

BladeSvg/BladeSvgServiceProvider.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
namespace Statamic\Addons\BladeSvg;
4+
5+
use Statamic\API\File;
6+
use Statamic\API\Config;
7+
use Illuminate\Support\Collection;
8+
use Statamic\Extend\ServiceProvider;
9+
use Statamic\Addons\BladeSvg\SvgFactory;
10+
11+
class BladeSvgServiceProvider extends ServiceProvider
12+
{
13+
/**
14+
* Bootstrap the application services.
15+
*
16+
* @return void
17+
*/
18+
public function boot()
19+
{
20+
app(SvgFactory::class)->registerBladeTag();
21+
}
22+
23+
/**
24+
* Register the application services.
25+
*
26+
* @return void
27+
*/
28+
public function register()
29+
{
30+
$this->app->singleton(SvgFactory::class, function () {
31+
$webroot = getcwd();
32+
33+
$config = Collection::make([])->merge([
34+
'spritesheet_url' => $this->getConfig('svg_spritesheet_url'),
35+
'spritesheet_path' => $webroot.$this->getConfig('svg_spritesheet_path'),
36+
'svg_path' => $webroot.$this->getConfig('svg_path'),
37+
'inline' => $this->getConfig('svg_inline'),
38+
'class' => $this->getConfig('svg_class'),
39+
])->all();
40+
41+
return new SvgFactory($config);
42+
});
43+
44+
require_once(__DIR__.'/helpers.php');
45+
}
46+
}

BladeSvg/SvgFactory.php

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php
2+
3+
namespace Statamic\Addons\BladeSvg;
4+
5+
use Exception;
6+
use Illuminate\Support\Collection;
7+
use Illuminate\Support\HtmlString;
8+
use Illuminate\Filesystem\Filesystem;
9+
use Illuminate\Support\Facades\Blade;
10+
use Statamic\Addons\BladeSvg\BladeSvg;
11+
12+
class SvgFactory
13+
{
14+
private $files;
15+
private $svgCache;
16+
private $config = [
17+
'inline' => true,
18+
'class' => 'icon',
19+
'sprite_prefix' => '',
20+
];
21+
22+
public function __construct($config = [], $filesystem = null)
23+
{
24+
$this->config = Collection::make(array_merge($this->config, $config));
25+
$this->svgCache = Collection::make();
26+
$this->files = $filesystem ?: new Filesystem;
27+
}
28+
29+
public function registerBladeTag()
30+
{
31+
Blade::directive('icon', function ($expression) {
32+
$expression = str_replace(["(", ")"], '', $expression);
33+
return "<?php echo e(svg_image($expression)); ?>";
34+
});
35+
36+
Blade::directive('svg', function ($expression) {
37+
$expression = str_replace(["(", ")"], '', $expression);
38+
return "<?php echo e(svg_image($expression)); ?>";
39+
});
40+
}
41+
42+
private function svgPath()
43+
{
44+
return $this->config->get('svg_path', function () {
45+
throw new Exception('No svg_path set!');
46+
});
47+
}
48+
49+
private function spritesheetPath()
50+
{
51+
return $this->config->get('spritesheet_path', function () {
52+
throw new Exception('No spritesheet_path set!');
53+
});
54+
}
55+
56+
public function spritesheetUrl()
57+
{
58+
return $this->config->get('spritesheet_url', '');
59+
}
60+
61+
public function spritesheet()
62+
{
63+
return new HtmlString(
64+
sprintf(
65+
'<div style="height: 0; width: 0; position: absolute; visibility: hidden;">%s</div>',
66+
file_get_contents($this->spritesheetPath())
67+
)
68+
);
69+
}
70+
71+
public function svg($name, $class = '', $attrs = [])
72+
{
73+
if (is_array($class)) {
74+
$attrs = $class;
75+
$class = '';
76+
}
77+
78+
$attrs = array_merge([
79+
'class' => $this->buildClass($class),
80+
], $attrs);
81+
82+
return new BladeSvg($name, $this->renderMode(), $this, $attrs);
83+
}
84+
85+
public function spriteId($svgName)
86+
{
87+
return "{$this->spritePrefix()}{$svgName}";
88+
}
89+
90+
private function spritePrefix()
91+
{
92+
return $this->config->get('sprite_prefix');
93+
}
94+
95+
private function renderMode()
96+
{
97+
return $this->config['inline'] ? 'inline' : 'sprite';
98+
}
99+
100+
private function buildClass($class)
101+
{
102+
return trim(sprintf('%s %s', $this->config['class'], $class));
103+
}
104+
105+
public function getSvg($name)
106+
{
107+
return $this->svgCache->get($name, function () use ($name) {
108+
return $this->svgCache[$name] = trim($this->files->get(sprintf('%s/%s.svg', rtrim($this->svgPath()), str_replace('.', '/', $name))));
109+
});
110+
}
111+
}

BladeSvg/default.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
svg_path: "/assets/svg"
2+
svg_spritesheet_path: "/assets/svg/spritesheet.svg"
3+
svg_spritesheet_url: ''
4+
svg_inline: true
5+
svg_class: ''

BladeSvg/helpers.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
use Statamic\Addons\BladeSvg\SvgFactory;
4+
5+
if (! function_exists('svg_spritesheet')) {
6+
function svg_spritesheet()
7+
{
8+
return app(SvgFactory::class)->spritesheet();
9+
}
10+
}
11+
12+
if (! function_exists('svg_image')) {
13+
function svg_image($icon, $class = '', $attrs = [])
14+
{
15+
return app(SvgFactory::class)->svg($icon, $class, $attrs);
16+
}
17+
}
18+
19+
if (! function_exists('svg_icon')) {
20+
/**
21+
* @deprecated Use `svg_image`
22+
*/
23+
function svg_icon($icon, $class = '', $attrs = [])
24+
{
25+
return app(SvgFactory::class)->svg($icon, $class, $attrs);
26+
}
27+
}

BladeSvg/meta.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
name: 'Blade SVG'
2+
version: '1.0'
3+
description: Easily inline SVG images in your Blade templates with Statamic.
4+
url: https://github.com/zawilliams/statamic-blade-svg
5+
developer: Zach Williams
6+
developer_url: zachwilliams.me
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
return [
4+
'svg_path_instruct' => "This value is the path to the directory of individual SVG files. This path is then resolved internally. Please ensure that this value is set relative to the root directory and not the public directory.",
5+
'svg_spritesheet_path_instruct' => "If you would rather have one spritesheet than a lot of individual SVG files, you may specify a path to a spritesheet. The SVG images are extracted from this spritesheet to be rendered out individually.",
6+
'svg_spritesheet_url_instruct' => "If you don't want to embed the spritesheet directly in your markup and would rather reference an external URL, you can specify the path to the external spritesheet to use with this configuration option.",
7+
'svg_inline_instruct' => "This value will determine whether or not the SVG should be rendered inline or if it should reference a spritesheet through a <use> element.",
8+
'svg_class_instruct' => "If you would like to have CSS classes applied to your SVGs, you must specify them here. Much like how you would define multiple classes in an HTML attribute, you may separate each class using a space.",
9+
];

BladeSvg/settings.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
fields:
2+
general:
3+
type: section
4+
svg_path:
5+
display: SVG Path
6+
type: text
7+
validate: required
8+
width: 100
9+
svg_spritesheet_path:
10+
display: Spritesheet Path
11+
type: text
12+
width: 100
13+
svg_spritesheet_url:
14+
display: Spritesheet URL
15+
type: text
16+
width: 100
17+
svg_inline:
18+
display: Inline
19+
type: toggle
20+
svg_class:
21+
display: Class
22+
type: text
23+
width: 100

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2019 Zach Williams
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Blave SVG for Statamic ![Statamic 2.11](https://img.shields.io/badge/statamic-2.11-blue.svg?style=flat-square)
2+
3+
Use [Blade SVG](https://github.com/adamwathan/blade-svg) with Statamic in Blade templates.
4+
5+
## Installation
6+
7+
Simply copy the `BladeSvg` folder into `site/addons/`. That's it!
8+
9+
## Configuration
10+
11+
You can set all of the settings under the addon's settings page. You can get to it from the Addons page and click those 3 dots -> Settings.
12+
13+
The default path for SVGs is `/assets/svg` and the default SVG sprite path is `/assets/svg/spritesheet.svg`.
14+
15+
## Usage
16+
17+
Just use it like you would normally use [Blade SVG](https://github.com/adamwathan/blade-svg) with Laravel Blade templates:
18+
19+
```html
20+
<a href="/settings">
21+
@svg('cog', 'icon-lg', ['id' => 'settings-icon']) Settings
22+
</a>
23+
```
24+
25+
## Acknowledgements
26+
27+
- Thanks to [Adam Wathan](https://github.com/adamwathan) for his [Blade SVG](https://github.com/adamwathan/blade-svg) package

0 commit comments

Comments
 (0)