Skip to content

Commit

Permalink
use a single SVG file for icons
Browse files Browse the repository at this point in the history
This should improve performance by reducing network traffic.

The SVG file is always loaded from the same domain as the page it's linked from, because cross-domain requests would allegedly be blocked by Chrome and possibly by other browsers.
  • Loading branch information
Changaco committed Mar 19, 2024
1 parent 5f3a11a commit 1572411
Show file tree
Hide file tree
Showing 64 changed files with 326 additions and 299 deletions.
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,7 @@ a bad idea.

### Icons

An icon can be included in a page by calling the `icon` macro from `templates/macros/icons.html`. That file contains a mapping of icon names to file paths.

For user interface icons we use [Bootstrap Icons](https://icons.getbootstrap.com/). A new icon can be added to Liberapay by simply copying its SVG file from Bootstrap Icons into the `www/assets/bootstrap-icons/` directory (and not forgetting to `git add` it, of course).
For user interface icons we use [Bootstrap Icons](https://icons.getbootstrap.com/). An icon can be included in a page by calling the `icon` macro from `templates/macros/icons.html`, e.g. `{{ icon('liberapay') }}`. The icons are stored in the `www/assets/icons.svg` file. To add a new icon in that file, the root `<svg>` element of the icon being added must be turned into a `<symbol>` element, preserving only its `viewBox` attribute and adding an `id` attribute.

If you don't find any icon in Bootstrap Icons that fits your use case, you can try to search online catalogs like [Flaticon](https://www.flaticon.com/search?type=uicon), [Icons8](https://icons8.com/icons), [Pictogrammers](https://pictogrammers.com/), [SVG Repo](https://www.svgrepo.com/) and [The Noun Project](https://thenounproject.com/). For brand icons, [Simple Icons](https://simpleicons.org/) is a good resource.

Expand Down
29 changes: 27 additions & 2 deletions liberapay/wireup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import socket
from sys import intern
import traceback
import xml.etree.ElementTree as ET

import babel
from babel.messages.pofile import read_po
Expand Down Expand Up @@ -795,7 +796,7 @@ def compute_percentage(it, total):


def asset_url_generator(env, asset_url, tell_sentry, www_root):
def asset(*paths):
def asset(*paths, domain=True):
for path in paths:
fspath = www_root+'/assets/'+path
etag = ''
Expand All @@ -812,10 +813,33 @@ def asset(*paths):
continue
except Exception as e:
tell_sentry(e)
return asset_url+path+(etag and '?etag='+etag)
if domain:
return asset_url+path+(etag and '?etag='+etag)
else:
return '/assets/'+path+(etag and '?etag='+etag)
return {'asset': asset}


def icon_names(www_root):
icons_file_path = f'{www_root}/assets/icons.svg'
svg = ET.parse(icons_file_path).getroot()
icon_identifiers = set()
for el in svg:
if el.tag != '{http://www.w3.org/2000/svg}symbol':
raise AssertionError(

Check warning on line 829 in liberapay/wireup.py

View check run for this annotation

Codecov / codecov/patch

liberapay/wireup.py#L829

Added line #L829 was not covered by tests
f"{icons_file_path} contains unknown element <{el.tag.split('}')[1]}>"
)
icon_id = el.get('id')
if not icon_id:
raise AssertionError(f"{icons_file_path} contains a <symbol> without an id")

Check warning on line 834 in liberapay/wireup.py

View check run for this annotation

Codecov / codecov/patch

liberapay/wireup.py#L834

Added line #L834 was not covered by tests
if icon_id in icon_identifiers:
raise AssertionError(

Check warning on line 836 in liberapay/wireup.py

View check run for this annotation

Codecov / codecov/patch

liberapay/wireup.py#L836

Added line #L836 was not covered by tests
f'{icons_file_path} contains multiple symbols with id="{icon_id}"'
)
icon_identifiers.add(icon_id)
return {'icon_names': icon_identifiers}


def load_scss_variables(project_root):
"""Build a dict representing the `style/variables.scss` file.
"""
Expand Down Expand Up @@ -865,6 +889,7 @@ def currency_exchange_rates(db):
username_restrictions,
load_i18n,
asset_url_generator,
icon_names,
accounts_elsewhere,
load_scss_variables,
s3,
Expand Down
38 changes: 21 additions & 17 deletions style/base/base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -119,21 +119,28 @@ input.amount {
}

div.account {
.auth-button {
display: inline-block;
}
& > .account-link {
display: inline-block;
margin-bottom: 0.3em;
padding: 0.1em 0;
text-decoration: none;
}
& > form {
margin-bottom: 0.9em;
line-height: 32px;
}
@media (max-width: $screen-xs-min - 1) {
div.account {
margin: .5em 0 2em 0;
& > * {
display: block;
text-align: center;
}
& > a.account-link {
margin: 0 0 .5em;
}
}
}
.account-username {
margin-left: 0.5ex;
@media (min-width: $screen-xs-min) {
div.account {
margin: .5em 0 .5em 0;
& > a.account-link {
display: inline-block;
margin: 0 2ex 0 .5ex;
}
}
}

a.account-link[href="#not-available"] {
Expand Down Expand Up @@ -724,10 +731,6 @@ p.event {
margin-bottom: 0.5em;
}

.icon + span {
margin-left: 2px;
}

span.help-title {
border-bottom: 1px dotted;
cursor: help;
Expand Down Expand Up @@ -779,6 +782,7 @@ span.help-title {

.card-brands > svg {
margin: 0 2ex .3em 0;
vertical-align: top;
}

@media (max-width: $screen-sm-min - 1) {
Expand Down
25 changes: 10 additions & 15 deletions style/base/icons.scss
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
svg {
.icon {
display: inline-block;
fill: currentColor;
vertical-align: top;
}
.icon + span {
margin-left: 2px;
}
span.icon-16 {
display: inline-block;
line-height: 16px;
& > svg {
height: 16px;
width: 16px;
}
.icon-16 {
height: 16px;
margin-top: calc((1lh - 16px) / 2);
width: 16px;
}
span.icon-32 {
display: inline-block;
line-height: 32px;
& > svg {
height: 32px;
width: 32px;
}
.icon-32 {
height: 32px;
width: 32px;
}
7 changes: 3 additions & 4 deletions templates/macros/elsewhere.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
% macro account_elsewhere(account, edit=False)
% set platform = account.platform_data
<div class="account">
<span aria-hidden="true">{{ platform_icon_large(platform) }}</span>
<a class="account-link" rel="me" href="{{ account.html_url }}">
{{ platform_icon_large(platform) }}
<span class="sr-only">{{ platform.display_name }}:</span>
<span class="account-username">{{ account.friendly_name_long }}</span>
</a>
% if edit
&nbsp;&nbsp;&nbsp;
<form action="/{{ account.participant.username }}/elsewhere/delete"
method="POST" class="inline-block js-submit">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
Expand Down Expand Up @@ -43,11 +42,11 @@
% endmacro

% macro platform_icon_small(platform)
<img class="icon" height=16 width=16 src="{{ platform.icon_16 }}" alt="{{ platform.display_name }}" />
<img class="icon icon-16" src="{{ platform.icon_16 }}" alt="{{ platform.display_name }}" />
% endmacro

% macro platform_icon_large(platform)
<img class="icon" height=32 width=32 src="{{ platform.icon_32 }}" alt="{{ platform.display_name }}" />
<img class="icon icon-32" src="{{ platform.icon_32 }}" alt="{{ platform.display_name }}" />
% endmacro

% macro user_lookup_form()
Expand Down
103 changes: 50 additions & 53 deletions templates/macros/icons.html
Original file line number Diff line number Diff line change
@@ -1,60 +1,57 @@
% set icons = {
'advertise': 'bootstrap-icons/broadcast.svg',
'bank-account': 'bootstrap-icons/bank2.svg',
'change-image': 'bootstrap-icons/images.svg',
'create-profile': 'bootstrap-icons/file-person.svg',
'direct-debit': 'bootstrap-icons/bank2.svg',
'disconnect': 'bootstrap-icons/x-lg.svg',
'discontinue': 'bootstrap-icons/stop-fill.svg',
'donations': 'bootstrap-icons/gift.svg',
'enter': 'bootstrap-icons/box-arrow-in-right.svg',
'external-link': 'bootstrap-icons/box-arrow-up-right.svg',
'exclamation-sign': 'bootstrap-icons/exclamation-circle-fill.svg',
'exit': 'bootstrap-icons/box-arrow-right.svg',
'explore': 'bootstrap-icons/globe2.svg',
'feed': 'bootstrap-icons/rss.svg',
'homepage': 'bootstrap-icons/house.svg',
'index': 'bootstrap-icons/list.svg',
'info-sign': 'bootstrap-icons/info-circle.svg',
'integrate': 'bootstrap-icons/gear.svg',
'liberapay': 'liberapay/icon-v2_black.svg',
'locale': 'bootstrap-icons/translate.svg',
'manual': 'bootstrap-icons/hand-index.svg',
'mark-as-read': 'bootstrap-icons/eye-fill.svg',
'markdown': 'bootstrap-icons/markdown-fill.svg',
'mastodon': 'bootstrap-icons/mastodon.svg',
'ok': 'bootstrap-icons/check-circle.svg',
'payment-card': 'bootstrap-icons/credit-card.svg',
'pledge': 'bootstrap-icons/balloon-heart.svg',
'private': 'bootstrap-icons/eye-slash.svg',
'public': 'bootstrap-icons/globe2.svg',
'ok-sign': 'bootstrap-icons/check-circle.svg',
'pay': 'bootstrap-icons/cash.svg',
'print': 'bootstrap-icons/printer.svg',
'question-sign': 'bootstrap-icons/question-circle.svg',
'refresh': 'bootstrap-icons/arrow-clockwise.svg',
'remove': 'bootstrap-icons/x-lg.svg',
'secret': 'bootstrap-icons/incognito.svg',
'secure': 'bootstrap-icons/shield-check.svg',
'set-up': 'bootstrap-icons/sliders.svg',
'smile': 'bootstrap-icons/emoji-smile.svg',
'stats': 'bootstrap-icons/bar-chart.svg',
'team': 'bootstrap-icons/people.svg',
'text-prompt': 'bootstrap-icons/input-cursor-text.svg',
'twitter': 'bootstrap-icons/twitter-x.svg',
'users': 'bootstrap-icons/person-add.svg',
'warning-sign': 'bootstrap-icons/exclamation-triangle-fill.svg',
% set icon_aliases = {
'advertise': 'broadcast',
'bank-account': 'bank2',
'change-image': 'images',
'create-profile': 'file-person',
'direct-debit': 'bank2',
'disconnect': 'x-lg',
'discontinue': 'stop-fill',
'donations': 'gift',
'enter': 'box-arrow-in-right',
'external-link': 'box-arrow-up-right',
'exclamation-sign': 'exclamation-circle-fill',
'exit': 'box-arrow-right',
'explore': 'globe2',
'feed': 'rss',
'homepage': 'house',
'index': 'list',
'info-sign': 'info-circle',
'integrate': 'gear',
'locale': 'translate',
'manual': 'hand-index',
'mark-as-read': 'eye-fill',
'markdown': 'markdown-fill',
'mastodon': 'mastodon',
'ok': 'check-circle',
'payment-card': 'credit-card',
'pledge': 'balloon-heart',
'private': 'eye-slash',
'public': 'globe2',
'ok-sign': 'check-circle',
'pay': 'cash',
'print': 'printer',
'question-sign': 'question-circle',
'refresh': 'arrow-clockwise',
'remove': 'x-lg',
'secret': 'incognito',
'secure': 'shield-check',
'set-up': 'sliders',
'smile': 'emoji-smile',
'stats': 'bar-chart',
'team': 'people',
'text-prompt': 'input-cursor-text',
'twitter': 'twitter-x',
'users': 'person-add',
'warning-sign': 'exclamation-triangle-fill',
}

% macro icon(name, sr='', size=16)
% set svg_path = icons.get(name) or 'bootstrap-icons/' + name + '.svg'
% set svg = website.read_asset(svg_path)|safe
% if svg
<span aria-hidden="true" class="icon icon-{{ size }}" {% if sr %} title="{{ sr }}" {% endif %}>{{
svg
}}</span>
% set name = icon_aliases.get(name, name)
% if name in website.icon_names
<svg aria-hidden="true" class="icon icon-{{ size }}" {% if sr %} title="{{ sr }}"{% endif %}{#
#}><use xlink:href="{{ website.asset('icons.svg', domain=False) }}#{{ name }}"/></svg>
% else
<img aria-hidden="true" class="icon" {% if sr %} title="{{ sr }}" {% endif %} src="/assets/nonexistent" height={{size}} width={{size}} />
<img aria-hidden="true" class="icon icon-{{ size }}" {% if sr %} title="{{ sr }}"{% endif %} src="/assets/nonexistent" />
% endif
% if sr
<span class="sr-only">{{ sr }}</span>
Expand Down
23 changes: 12 additions & 11 deletions www/admin/users.spt
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ title = "Users Admin"
[---] text/html
% from 'templates/macros/admin.html' import admin_form with context
% from 'templates/macros/avatar-url.html' import avatar_img with context
% from 'templates/macros/elsewhere.html' import platform_icon_small with context
% from 'templates/macros/icons.html' import icon with context
% from 'templates/macros/nav.html' import querystring_nav with context
% from "templates/macros/payment-methods.html" import payment_method_icon with context
Expand Down Expand Up @@ -275,19 +276,19 @@ title = "Users Admin"
% if p.status == 'stub'
% for account in elsewhere
<div class="account">
<span aria-hidden="true">{{ platform_icon_small(account.platform_data) }}</span>
<a class="account-link" href="{{ account.html_url }}">
{{ icon(account.platform) }}
<span class="sr-only">{{ account.platform_data.display_name }}:</span>
<span class="account-username">{{ account.friendly_name_long }}</span>
</a>
<br>
% if account.description
<section class="profile-statement embedded raw">{{
account.get_excerpt(500)
}}</section>
% else
(no description)
% endif
</div>
% if account.description
<section class="profile-statement embedded raw">{{
account.get_excerpt(500)
}}</section>
% else
(no description)
% endif
% else
(ghost stub account)
% endfor
Expand Down Expand Up @@ -322,8 +323,8 @@ title = "Users Admin"
% if elsewhere
<br>
% for account in elsewhere
<a class="account-link" href="{{ account.html_url }}">
<span class="symbol-3ex">{{ icon(account.platform) }}</span>
<a href="{{ account.html_url }}">
<span class="symbol-3ex">{{ platform_icon_small(account.platform_data) }}</span>
<span>{{ account.friendly_name_long }}</span>
</a>
<br>
Expand Down
4 changes: 0 additions & 4 deletions www/assets/bootstrap-icons/arrow-clockwise.svg

This file was deleted.

3 changes: 0 additions & 3 deletions www/assets/bootstrap-icons/arrow-left-right.svg

This file was deleted.

3 changes: 0 additions & 3 deletions www/assets/bootstrap-icons/balloon-heart.svg

This file was deleted.

3 changes: 0 additions & 3 deletions www/assets/bootstrap-icons/bank2.svg

This file was deleted.

3 changes: 0 additions & 3 deletions www/assets/bootstrap-icons/bar-chart.svg

This file was deleted.

4 changes: 0 additions & 4 deletions www/assets/bootstrap-icons/box-arrow-in-right.svg

This file was deleted.

4 changes: 0 additions & 4 deletions www/assets/bootstrap-icons/box-arrow-right.svg

This file was deleted.

4 changes: 0 additions & 4 deletions www/assets/bootstrap-icons/box-arrow-up-right.svg

This file was deleted.

Loading

0 comments on commit 1572411

Please sign in to comment.