Skip to content

Commit

Permalink
Add icon cache (closes #5)
Browse files Browse the repository at this point in the history
  • Loading branch information
Christian Wiegand committed Jun 6, 2021
1 parent 8c14dd4 commit d056457
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 25 deletions.
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,18 @@ Material Desing Icons are loaded from the default URL:
MD_ICONS_BASE_URL = 'https://cdn.jsdelivr.net/npm/@mdi/[email protected]/'
```

You can change it to your desired location by overriding this setting.
You can change it to your desired location by overriding this setting.

### Configure icon cache

To avoid rendering icons multiple times, configure the icon cache directory:

```
BS_ICONS_CACHE = os.path.join(STATIC_ROOT, 'icon_cache')
```

This will ensure that icons will be rendered only once with their individual svg properties
and stored to a local file. On each subsequent use the icon will be simply loaded from file.

## Example App

Expand Down Expand Up @@ -194,8 +205,9 @@ This project is licensed under the MIT License - see the
as long as you don't want to use MDI.
* django-bootstrap-icons 0.6.0 (Mai 2021): Update default bootstrap icons CDN to version 1.5.0
* django-bootstrap-icons 0.6.1 (June 2021): Fix path building on windows (#3)
* django-bootstrap-icons 0.6.2 (June 2021): Add icon cache to avoid multiple redering of same icon (#5)

## Migration
## Migration from 0.2

If you had installed an earlier version of this package, you have to change some things:

Expand Down
77 changes: 55 additions & 22 deletions django_bootstrap_icons/templatetags/bootstrap_icons.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from django.template import Library
from django.utils.html import format_html


register = Library()


Expand Down Expand Up @@ -54,7 +53,7 @@ def render_svg(content, size, color, extra_classes):
svg[0].setAttribute('width', size)
svg[0].setAttribute('height', size)

if not 'color' in svg[0].attributes:
if 'color' not in svg[0].attributes:
svg[0].setAttribute('fill', "currentColor")
if color:
svg[0].setAttribute('fill', color)
Expand Down Expand Up @@ -82,6 +81,44 @@ def custom_icon(icon_name, size=None, color=None, extra_classes=None):
return format_html(render_svg(content, size, color, extra_classes))


def icon(icon_path, icon_name, size=None, color=None, extra_classes=None):
"""
Manage caching of bootstrap icons
:param str icon_path: icon path given by CDN
:param str icon_name: Name of custom icon to render
:param str size: size of custom icon to render
:param str color: color of custom icon to render
:param str extra_classes: String of classes to add to icon
"""
cache_path = getattr(
settings,
'BS_ICONS_CACHE',
None
)
cache_file = None

if cache_path:
if not os.path.exists(cache_path):
os.makedirs(cache_path)
cache_name = f'{icon_name}_{size}_{color}_{extra_classes}.svg'
cache_file = os.path.join(cache_path, cache_name)
if os.path.exists(cache_file):
# icon exists in cache, use that
return open(cache_file, 'r').read()

# cached icon doesn't exist or no cache configured, create and return icon
resp = requests.get(icon_path)
if resp.status_code >= 400:
return f"Icon <{icon_path}> does not exist"

content = xml.dom.minidom.parseString(resp.text)
svg = render_svg(content, size, color, extra_classes)
# if cache configured write icon to cache
if cache_path and cache_file:
open(cache_file, 'w').write(svg)
return svg


@register.simple_tag
def bs_icon(icon_name, size=None, color=None, extra_classes=None):
"""
Expand All @@ -100,12 +137,10 @@ def bs_icon(icon_name, size=None, color=None, extra_classes=None):
'https://cdn.jsdelivr.net/npm/[email protected]/',
)
icon_path = f'{base_url}icons/{icon_name}.svg'
resp = requests.get(icon_path)
if resp.status_code >= 400:
return f"Icon <{icon_path}> does not exist"

content = xml.dom.minidom.parseString(resp.text)
return format_html(render_svg(content, size, color, extra_classes))
svg = icon(icon_path, icon_name, size, color, extra_classes)
resp = format_html(svg)
return resp


@register.simple_tag
Expand All @@ -120,25 +155,23 @@ def md_icon(icon_name, size=None, color=None, extra_classes=None):
if icon_name is None:
return ''

# set some classes, so one can style the icons globally
if extra_classes is None:
extra_classes = f'mdi mdi-{icon_name}'
else:
extra_classes = f'mdi mdi-{icon_name} {extra_classes}'

# Set same size for mdi like bi
if size is None:
size = '20'

base_url = getattr(
settings,
'MD_ICONS_BASE_URL',
'https://cdn.jsdelivr.net/npm/@mdi/[email protected]/'
)
icon_path = f'{base_url}svg/{icon_name}.svg'
resp = requests.get(icon_path)
if resp.status_code >= 400:
return f"Icon <{icon_path}> does not exist"

# Set same size for mdi like bi
if size is None:
size = '20'

# set some classes, so one can style the icons globally
if extra_classes is None:
extra_classes = f'mdi mdi-{icon_name}'
else:
extra_classes = f'mdi mdi-{icon_name} {extra_classes}'

content = xml.dom.minidom.parseString(resp.text)
return format_html(render_svg(content, size, color, extra_classes))
svg = icon(icon_path, icon_name, size, color, extra_classes)
resp = format_html(svg)
return resp
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setuptools.setup(
name='django-bootstrap-icons',
version='0.6.1',
version='0.6.2',
packages=setuptools.find_packages(),
include_package_data=True,
description='A quick way to add Bootstrap Icons with Django template tags.',
Expand Down

0 comments on commit d056457

Please sign in to comment.