loicpennamen / icons-bundle
Add a quick icon function to Twig templates. Compatible with font or SVG icons.
Requires
- php: >=7.4
- symfony/framework-bundle: >=6.2
This package is auto-updated.
Last update: 2024-11-10 17:06:12 UTC
README
🚀 Quickly insert webfont or SVG icons in Twig.
👍 Keep visual coherence of your icons throughout the app.
Why this bundle?
The problems
Whether you use font icons such as Font Awesome or Flaticon, or your own .svg icons... Integrating the source code of each icon in your Twig templates might be a hassle, and hard to maintain.
Furthermore, sometimes one developer chooses an icon for a context but another developer uses a different icon for the same context. For instance to represent a "Delete" action, developer 1 may choose a trash icon 🗑️, and developer 2 mays choose a cross icon ❌ thus leading to visual incoherence.
The solution
This bundle provides a Twig function called icon()
to insert your icon
with a clear view of the context.
{{ icon('delete') }}
Which generates this piece of HTML:
<i class="fi fi-rs-trash-bin"></i>
This bundle allows you to define one icon for one context.
You can define a context as the string
that defines "what is icon is used for".
For instance user
, dashboard
, warning
, etc...
Contexts are defined in a single file under config/icons.yaml
.
This way, every time you need a user icon with {{ icon('delete') }}
,
the same visual will appear throughout the app.
Parameters
key
(string
): The context or arbitrary key identifying the icon.template
(string
, optional): The template of a font icon, or the collection of the .svg icon.classes
(string
, optional): Additional classes for the font icon tag, or the .svg wrapper.
Installation
Make sure Composer is installed globally, as explained in the installation chapter of the Composer documentation. Then, open a command console, enter your project directory and execute:
composer require loicpennamen/icons-bundle
For applications that don't use Symfony Flex, enable the bundle by adding it to the list of registered bundles
in the config/bundles.php
file of your project:
// config/bundles.php
return [
// ...
LoicPennamen\IconsBundle\LoicPennamenIconsBundle::class => ['all' => true],
];
How to use with icon fonts
Include the fonts
This bundle handles the back-end logic. You are free to include your icon fonts any way you like. There are various icon fonts available across the web, some very common options are:
- Flaticons:
Website - NPMJS repository - Documentation. - Font-Awesome:
Website
With most solutions, you can either
- Use a CDN
- Download the font files and include them via CSS
- Use NPM package manager.
Read the dedicated documentation for more information. In this documentation, we will be using Flaticons for our examples. Here are the docs for Flaticons.
In the following example, we used Flaticon's NPM package and the fonts are included in a Sass file:
# Install the files
npm i @flaticon/flaticon-uicons
// app.scss
// With flaticons, each file defines a different style and shape:
@import "~@flaticon/flaticon-uicons/css/regular/straight.css"; // regular straight
@import "~@flaticon/flaticon-uicons/css/solid/rounded.css"; // solid rounded
@import "~@flaticon/flaticon-uicons/css/brands/all"; // Brand icons
Configure the contexts
Create the file config/packages/icons.yaml
that will hold your configuration.
For visual coherence, you want to use the same icon for every context.
As seen above, a context is the string
that defines "what is icon is used for".
For instance, a "delete" button should not display a trash can somewhere,
a ban-sign elsewhere and a cross somewhere else... Contexts allow to define the icon
to use via a unique string
used throughout the app.
Here is an example on how to define contexts:
# config/packages/icons.yaml
icons:
contexts:
# Use any context key you want, but dots & spaces are forbidden!
# context: "font key"
delete: "trash" # We choose Flaticon "trash" icon for deletion everywhere
cancel: "undo" # We choose Flaticon "undo" icon for cancellation everywhere
danger: "triangle-warning"
error: "triangle-warning" # Different contexts can use the same icon
menu: "burger-menu"
Context can be hierarchical for better organization
The hierarchy must use dots as separators in the icon()
function.
The hierarchy can be as deep as needed, but two levels are usually way enough.
For example with the following configuration you could write
icon('user.profile')
or icon('alert.warning')
:
# config/packages/icons.yaml
icons:
contexts:
user:
profile: "user"
dashboard: "stats"
impersonate: "refer"
alert:
info: "info-cirle"
warning: "exclamation-triangle"
error: "exclamation-triangle"
Arbitrary method
The use of contexts is not mandatory.
For instance, without configuring contexts you can still use the function
icon('xxxx')
as long as the key xxxx
exists inside the font.
This is called the arbitrary method.
For instance this snippet of code:
{{ icon('kangaroo') }}
Generates this piece of HTML regardless whether or not the font has a key called kangaroo
:
<i class="fi fi-rs-kangaroo"></i>
Configure the font template(s)
With default configuration, the function icon('user')
generates this piece of HTML:
<i class="fi fi-rs-user"></i>
This only works if you included a very specific font from Flaticon, with straight corners and regular weight. For different icon collections or designs, you want to change the HTML template used.
You can configure several templates and select one in the icon()
function.
The first template in the list is used as default.
The string [KEY]
will be replaced by the context value (or arbitrary key)
passed in the function.
The string [CLASSES]
will be replaced by the third parameter passed to the function.
# config/packages/icons.yaml
icons:
templates:
# @see https://www.npmjs.com/package/@flaticon/flaticon-uicons
default: "<i class='fi fi-rs-[KEY] [CLASSES]'></i>" # Flaticons regular straight style
solid: "<i class='fi fi-ss-[KEY] [CLASSES]'></i>" # Flaticons regular solid style
A configuration for Font Awesome could be:
# config/packages/icons.yaml
icons:
templates:
# @see https://docs.fontawesome.com/web/add-icons/how-to
duotone: "<i class='fa-duotone fa-solid fa-[KEY] [CLASSES]'></i>" # Font-awesome duotone (by default as first of the list)
solid: "<i class='fa-solid fa-[KEY] [CLASSES]'></i>" # Font-awesome solid
sharp: "<i class='fa-sharp fa-solid fa-[KEY] [CLASSES]'></i>" # Font-awesome sharp
#...
How to use SVG icons
Configuration
The icon()
function can also display SVG files.
Since they are handled back-end, you do not have to put them in the public
folder.
By default, the function looks for .svg files in the following folders:
/assets/svg/icons/<key>.svg
/public/svg/icons/<key>.svg
/public/build/svg/icons/<key>.svg
You can override this list with the svg_paths
option:
# config/packages/icons.yaml
icons:
svg_paths:
- '/assets/custom-svg-icons/'
- '/assets/brand-svg-icons/'
If a file exists in either of these directory,
it is rendered with a wrapping span with a svg-icon
class:
<span class="svg-icon"><!-- SVG file content --></span>
SVG files collections
You may also name the directories in order to create different collections. For instance you may have a collection of SVG icons divided in two versions: light and dark. If the icons in each collection (ie. folder) have the same file name, you can set the configuration as such:
# config/packages/icons.yaml
icons:
svg_paths:
light: '/assets/svg-icons/light/'
dark: '/assets/svg-icons/dark/'
With this configuration, the second parameter of the icon()
function will be the
collection (ie. folder) in which the SVG file will be searched:
{# show a light SVG user icon, in the first directory of the list by default #}
{{ icon('user') }}
{# show a light SVG user icon #}
{{ icon('user', 'light') }}
{# show a dark SVG user icon #}
{{ icon('user', 'dark') }}
Styling
You may want to add some extra CSS in your app, to ensure the correct display of your SVG icons. For instance:
.svg-icon svg{
/* Contain the icon into font dimensions */
width: 1rem;
height: 1rem;
/* Fix the icon alignment */
position: relative;
bottom: .1rem;
}
Customizing the SVG wrapper
If you want to change the HTML generated around the SVG content,
override the svg_template
option.
It is mandatory that your template contains the string [SVG]
wherever the file
content has to be inserted.
icons:
svg_template: '<span class="my-icon-class [CLASSES]">[SVG]</span>'
Methods priorities
Since the icon()
function handles several methods to display an icon,
here is their order of priority:
- Contextual: If the
key
passed as agument inicon()
exists in the contexts list, the font icon of the context is displayed. - SVG: If a file exists in any of the specified folders with
key
as filename (minus the .svg extension) it will be displayed. - Arbitrary: If the previous steps fail, the icons font template will
be displayed with the abitrary value of
key
, thus allowing to use any icon of the font collection without the use of contexts.
How to get a list of available icons?
If you work on some kind of content editor, you may need to create an icon selector.
There is no existing way to retrieve a list of every icon included in a font -
ie listing all arbitrary icon keys.
However the contextual and SVG icons can be listed via the getList()
method inside the class LoicPennamen\IconsBundle\Services\IconsService
.
It returns an array of items following this convention:
array(13) {
[0] => array(3) {
["key"] => "cancel"
["type"] => "font"
["collection"] => NULL
},
[1] => array(3) {
["key"] => "test"
["type"] => "svg"
["collection"] => "light"
}
}
The optional parameter $sortBy
allows to sort the results by any of
the items values. By default, items are sorted alphabetically by their key
value.
Here is an example on how to use it:
<?php
// src/Controller/IconController.php
namespace App\Controller;
// ...
use LoicPennamen\IconsBundle\Services\IconsService;
class IconController extends AbstractController
{
// ...
public function chooseIcon(IconsService $iconsService): Response
{
$choices = $iconsService->getList();
return $this->render('choose-icon.html.twig', [
'choices' => $choices
]);
}
}
{# /templates/choose-icon.html.twig #}
<b>Icons :</b>
<ul>
{% for choice in choices %}
<li>
{{ icon(choice.key) }}
{{ choice.key }}
</li>
{% endfor %}
</ul>
Roadmap
This bundle may be upgraded in the future, here are the upcoming changes:
- Sanitize keys: throw error or unauthorized characters
- Optimisation: Set a cache for SVG icons instead of reading every folders on each call to
icon()
. Add a console command for clearing the cache and a cache duration option. - Setup PHPUnit tests