diff --git a/README.md b/README.md index 8336121d62..98a9533924 100644 --- a/README.md +++ b/README.md @@ -140,7 +140,13 @@ For our styles we use [SASS](http://sass-lang.com/) and [Bootstrap 3](https://ge We compile Bootstrap ourselves from the SASS source in the `style/bootstrap/` directory. We do that to be able to easily customize it by changing values in `style/variables.scss`. Modifying the files in `style/bootstrap/` is probably -not a good idea. +a bad idea. + +### Icons + +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 `` element of the icon being added must be turned into a `` 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. ### Testing diff --git a/liberapay/elsewhere/_base.py b/liberapay/elsewhere/_base.py index 2b89cdd113..37090d2698 100644 --- a/liberapay/elsewhere/_base.py +++ b/liberapay/elsewhere/_base.py @@ -77,7 +77,6 @@ def parse_as_xml(response): class Platform: - fontawesome_name = None has_teams = False optional_user_name = False single_domain = True diff --git a/liberapay/elsewhere/bitbucket.py b/liberapay/elsewhere/bitbucket.py index 7c1ae86f79..2196478c6b 100644 --- a/liberapay/elsewhere/bitbucket.py +++ b/liberapay/elsewhere/bitbucket.py @@ -9,7 +9,6 @@ class Bitbucket(PlatformOAuth1): # Platform attributes name = 'bitbucket' display_name = 'Bitbucket' - fontawesome_name = name account_url = 'https://bitbucket.org/{user_name}' # Auth attributes diff --git a/liberapay/elsewhere/github.py b/liberapay/elsewhere/github.py index 37b5b862cf..775bed154d 100644 --- a/liberapay/elsewhere/github.py +++ b/liberapay/elsewhere/github.py @@ -8,7 +8,6 @@ class GitHub(PlatformOAuth2): # Platform attributes name = 'github' display_name = 'GitHub' - fontawesome_name = name account_url = 'https://github.com/{user_name}' repo_url = 'https://github.com/{slug}' has_teams = True diff --git a/liberapay/elsewhere/gitlab.py b/liberapay/elsewhere/gitlab.py index ba90c1dbd8..7f090e654f 100644 --- a/liberapay/elsewhere/gitlab.py +++ b/liberapay/elsewhere/gitlab.py @@ -8,7 +8,6 @@ class GitLab(PlatformOAuth2): # Platform attributes name = 'gitlab' display_name = 'GitLab.com' - fontawesome_name = name account_url = 'https://gitlab.com/{user_name}' repo_url = 'https://gitlab.com/{slug}' has_teams = True diff --git a/liberapay/elsewhere/mastodon.py b/liberapay/elsewhere/mastodon.py index 3f615494cb..6f27876d38 100644 --- a/liberapay/elsewhere/mastodon.py +++ b/liberapay/elsewhere/mastodon.py @@ -14,7 +14,6 @@ class Mastodon(PlatformOAuth2): # Platform attributes name = 'mastodon' display_name = 'Mastodon' - fontawesome_name = name account_url = 'https://{domain}/@{user_name}' single_domain = False diff --git a/liberapay/elsewhere/pleroma.py b/liberapay/elsewhere/pleroma.py index dbad08eb09..1f049754d0 100644 --- a/liberapay/elsewhere/pleroma.py +++ b/liberapay/elsewhere/pleroma.py @@ -7,7 +7,6 @@ class Pleroma(Mastodon): # Platform attributes name = 'pleroma' display_name = 'Pleroma' - fontawesome_name = name account_url = 'https://{domain}/{user_name}' single_domain = False diff --git a/liberapay/elsewhere/twitch.py b/liberapay/elsewhere/twitch.py index cb9fe59d86..406c151d50 100644 --- a/liberapay/elsewhere/twitch.py +++ b/liberapay/elsewhere/twitch.py @@ -8,7 +8,6 @@ class Twitch(PlatformOAuth2): # Platform attributes name = 'twitch' display_name = 'Twitch' - fontawesome_name = name account_url = 'https://twitch.tv/{user_name}' user_type = 'channel' diff --git a/liberapay/elsewhere/twitter.py b/liberapay/elsewhere/twitter.py index 045575294e..2f2bb56cf1 100644 --- a/liberapay/elsewhere/twitter.py +++ b/liberapay/elsewhere/twitter.py @@ -8,7 +8,6 @@ class Twitter(PlatformOAuth1): # Platform attributes name = 'twitter' display_name = 'Twitter' - fontawesome_name = name account_url = 'https://twitter.com/{user_name}' # Auth attributes diff --git a/liberapay/elsewhere/youtube.py b/liberapay/elsewhere/youtube.py index 9217de9483..4027d90919 100644 --- a/liberapay/elsewhere/youtube.py +++ b/liberapay/elsewhere/youtube.py @@ -9,7 +9,6 @@ class Youtube(PlatformOAuth2): based_on = 'google' name = 'youtube' display_name = 'YouTube' - fontawesome_name = 'youtube-play' account_url = 'https://youtube.com/channel/{user_id}' optional_user_name = True user_type = 'channel' diff --git a/liberapay/main.py b/liberapay/main.py index 3dfd109848..b1c37d1278 100644 --- a/liberapay/main.py +++ b/liberapay/main.py @@ -103,17 +103,26 @@ def _assert(x): assert x, repr(x) return x +def soft_assert(x, msg): + if not x: + try: + raise AssertionError(msg) + except AssertionError as e: + website.tell_sentry(e) + return x + website.renderer_factories['jinja2'].Renderer.global_context.update(builtins.__dict__) website.renderer_factories['jinja2'].Renderer.global_context.update({ # This is shared via class inheritance with jinja2_* renderers. 'assert': _assert, + 'b64decode_s': b64decode_s, + 'b64encode_s': b64encode_s, 'Bold': Bold, 'Community': Community, 'Country': Country, 'Currency': Currency, - 'b64decode_s': b64decode_s, - 'b64encode_s': b64encode_s, 'generate_session_token': Participant.generate_session_token, + 'soft_assert': soft_assert, 'to_age': to_age, 'to_javascript': utils.to_javascript, 'urlquote': urlquote, diff --git a/liberapay/website.py b/liberapay/website.py index 6eeebc4f07..a97a699bc1 100644 --- a/liberapay/website.py +++ b/liberapay/website.py @@ -37,6 +37,18 @@ def compute_previous_and_next_payday_dates(self): def link(self, path, text): return self._html_link % (path, text) + def read_asset(self, path): + try: + assert '..' not in path + resource = website.request_processor.resources.get( + f'{website.www_root}/assets/{path}' + ) + bs = resource.render().body if resource.raw is None else resource.raw + return bs.decode('utf8') + except Exception as e: + self.tell_sentry(e) + return '' + def respond(self, *args, **kw): # Run in a new (sub)context return copy_context().run(super().respond, *args, **kw) diff --git a/liberapay/wireup.py b/liberapay/wireup.py index 14eba6b274..89f3f5f82c 100644 --- a/liberapay/wireup.py +++ b/liberapay/wireup.py @@ -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 @@ -605,15 +606,15 @@ def accounts_elsewhere(app_conf, asset, canonical_url, db): platforms = PlatformRegistry(platforms) for platform in platforms: - if platform.fontawesome_name: - continue - platform.icon = asset( - 'platforms/%s.svg' % platform.name, + platform.icon_16 = asset( + 'platforms/%s.16.webp' % platform.name, 'platforms/%s.16.png' % platform.name, + 'platforms/%s.svg' % platform.name, ) - platform.logo = asset( + platform.icon_32 = asset( + 'platforms/%s.32.webp' % platform.name, + 'platforms/%s.32.png' % platform.name, 'platforms/%s.svg' % platform.name, - 'platforms/%s.png' % platform.name, ) return {'platforms': platforms} @@ -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 = '' @@ -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( + 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 without an id") + if icon_id in icon_identifiers: + raise AssertionError( + 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. """ @@ -865,6 +889,7 @@ def currency_exchange_rates(db): username_restrictions, load_i18n, asset_url_generator, + icon_names, accounts_elsewhere, load_scss_variables, s3, diff --git a/simplates/refresh.spt b/simplates/refresh.spt index d63e6b75e5..1e874e13f9 100644 --- a/simplates/refresh.spt +++ b/simplates/refresh.spt @@ -9,6 +9,7 @@ else: response.headers[b'Refresh'] = refresh_header [---] text/html +% from "templates/macros/icons.html" import icon with context @@ -18,14 +19,13 @@ response.headers[b'Refresh'] = refresh_header - diff --git a/style/base/alerts.scss b/style/base/alerts.scss index 10583dcf88..6223faf76d 100644 --- a/style/base/alerts.scss +++ b/style/base/alerts.scss @@ -20,7 +20,7 @@ .actions { position: absolute; right: 10px; - top: 8px; + top: 7px; & > button { -moz-appearance: none; -webkit-appearance: none; diff --git a/style/base/base.scss b/style/base/base.scss index 6326b2dcac..5f4d364822 100644 --- a/style/base/base.scss +++ b/style/base/base.scss @@ -119,43 +119,30 @@ 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; + } + } } -img.platform-icon { - height: 16px; -} -i.platform-icon { - display: inline-block; - font-size: 16px; - width: 16px; - text-align: center; - vertical-align: middle; -} -img.account-type { - height: 32px; -} -i.account-type { - display: inline-block; - font-size: 32px; - width: 32px; - text-align: center; - vertical-align: middle; -} a.account-link[href="#not-available"] { color: inherit; cursor: default; @@ -240,9 +227,6 @@ p.summary { max-width: 320px; text-align: center; width: 320px; - .platform-icon { - margin-top: -3px; - } h4 { margin-top: 5px; line-height: 23px; @@ -302,9 +286,13 @@ p.summary { margin: 0 1ex 0.6em 0; } } - .glyphicon-star { + small { + display: inline-block; + font-size: $font-size-base; + line-height: $line-height-computed; + } + .stars > .icon { color: $gray-light; - font-size: 80%; } .description { margin: 0.2em 0 1em; @@ -744,10 +732,6 @@ p.event { margin-bottom: 0.5em; } -.glyphicon + span { - margin-left: 2px; -} - span.help-title { border-bottom: 1px dotted; cursor: help; @@ -768,28 +752,41 @@ span.help-title { .payment-methods { margin-right: -10px; - & > div { + & > .panel { display: inline-block; margin-right: 10px; - min-height: 145px; text-align: center; vertical-align: top; width: 350px; max-width: 100%; - } - .payment-icon { - font-size: 2em; + & > .panel-body { + min-height: 165px; + } } .muted { color: #888; - .payment-icon { + svg { color: #ccc; } } - small.text-warning, small.text-danger { + h4 { + margin-bottom: 0; + } + small { + display: block; font-size: $font-size-medium; font-weight: bold; line-height: $font-size-medium * $line-height-base; + margin-top: 11px; + } +} + +.card-brands { + display: block; + margin: 0 -2ex -.3em 0; + & > svg { + margin: 0 2ex .3em 0; + vertical-align: top; } } @@ -818,9 +815,9 @@ span.help-title { } .payment-icons { - font-size: $font-size-large; - text-wrap: nowrap; + display: inline-block; vertical-align: middle; + white-space: nowrap; } .s-logo { diff --git a/style/base/forms.scss b/style/base/forms.scss index 6c25d54d62..591fffa04e 100644 --- a/style/base/forms.scss +++ b/style/base/forms.scss @@ -78,10 +78,10 @@ button.corner-icon { font-size: 18px; line-height: 24px; margin-left: 5px; - opacity: 0.2; + opacity: 0.5; padding: 0 5px; &:hover { - opacity: 0.5; + opacity: 0.8; } } diff --git a/style/base/icons.scss b/style/base/icons.scss index c00a257346..53a2028244 100644 --- a/style/base/icons.scss +++ b/style/base/icons.scss @@ -1,11 +1,17 @@ -.fa-brand-color { - // https://logo-colors.com/ - &.fa-bitbucket { color: #0052cc; } - &.fa-github { color: #24292e; } - &.fa-gitlab { color: #fca326; } - &.fa-mastodon { color: #6364ff; } - &.fa-pleroma { color: #fba457; } - &.fa-twitch { color: #6441a5; } - &.fa-twitter { color: #1da1f2; } - &.fa-youtube-play { color: #ff0000; } +.icon { + display: inline-block; + fill: currentColor; +} +.icon + span { + margin-left: 2px; +} +.icon-16 { + height: 16px; + margin-top: calc((1lh - 16px) / 2); + vertical-align: top; + width: 16px; +} +.icon-32 { + height: 32px; + width: 32px; } diff --git a/style/base/navbar.scss b/style/base/navbar.scss index 7cdcf47123..ae5d6efccb 100644 --- a/style/base/navbar.scss +++ b/style/base/navbar.scss @@ -78,18 +78,10 @@ margin-left: 0; } .navbar-brand { - & > img { - border-radius: 4px; - color: #000; - height: $font-size-base * 2; - line-height: $font-size-base * 2; - margin-top: -$font-size-base / 3; - } - & > .fa-liberapay { - font-size: $font-size-base * 2; - line-height: $font-size-base * 2; - margin-top: -$font-size-base / 3; - } + height: 50px; + line-height: 32px; + padding: 9px; + width: 50px; } } diff --git a/style/bootstrap/_carousel.scss b/style/bootstrap/_carousel.scss index 753d881f45..82e573caa4 100644 --- a/style/bootstrap/_carousel.scss +++ b/style/bootstrap/_carousel.scss @@ -126,22 +126,18 @@ // Toggles .icon-prev, - .icon-next, - .glyphicon-chevron-left, - .glyphicon-chevron-right { + .icon-next { position: absolute; top: 50%; margin-top: -10px; z-index: 5; display: inline-block; } - .icon-prev, - .glyphicon-chevron-left { + .icon-prev { left: 50%; margin-left: -10px; } - .icon-next, - .glyphicon-chevron-right { + .icon-next { right: 50%; margin-right: -10px; } @@ -237,8 +233,6 @@ // Scale up the controls a smidge .carousel-control { - .glyphicon-chevron-left, - .glyphicon-chevron-right, .icon-prev, .icon-next { width: ($carousel-control-font-size * 1.5); @@ -246,11 +240,9 @@ margin-top: ($carousel-control-font-size / -2); font-size: ($carousel-control-font-size * 1.5); } - .glyphicon-chevron-left, .icon-prev { margin-left: ($carousel-control-font-size / -2); } - .glyphicon-chevron-right, .icon-next { margin-right: ($carousel-control-font-size / -2); } diff --git a/style/bootstrap/_glyphicons.scss b/style/bootstrap/_glyphicons.scss deleted file mode 100644 index 07a0fc91fe..0000000000 --- a/style/bootstrap/_glyphicons.scss +++ /dev/null @@ -1,307 +0,0 @@ -// -// Glyphicons for Bootstrap -// -// Since icons are fonts, they can be placed anywhere text is placed and are -// thus automatically sized to match the surrounding child. To use, create an -// inline element with the appropriate classes, like so: -// -// Star - -@at-root { - // Import the fonts - @font-face { - font-family: 'Glyphicons Halflings'; - src: url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.eot'), '#{$icon-font-path}#{$icon-font-name}.eot')); - src: url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.eot?#iefix'), '#{$icon-font-path}#{$icon-font-name}.eot?#iefix')) format('embedded-opentype'), - url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.woff2'), '#{$icon-font-path}#{$icon-font-name}.woff2')) format('woff2'), - url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.woff'), '#{$icon-font-path}#{$icon-font-name}.woff')) format('woff'), - url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.ttf'), '#{$icon-font-path}#{$icon-font-name}.ttf')) format('truetype'), - url(if($bootstrap-sass-asset-helper, twbs-font-path('#{$icon-font-path}#{$icon-font-name}.svg##{$icon-font-svg-id}'), '#{$icon-font-path}#{$icon-font-name}.svg##{$icon-font-svg-id}')) format('svg'); - } -} - -// Catchall baseclass -.glyphicon { - position: relative; - top: 1px; - display: inline-block; - font-family: 'Glyphicons Halflings'; - font-style: normal; - font-weight: normal; - line-height: 1; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -// Individual icons -.glyphicon-asterisk { &:before { content: "\002a"; } } -.glyphicon-plus { &:before { content: "\002b"; } } -.glyphicon-euro, -.glyphicon-eur { &:before { content: "\20ac"; } } -.glyphicon-minus { &:before { content: "\2212"; } } -.glyphicon-cloud { &:before { content: "\2601"; } } -.glyphicon-envelope { &:before { content: "\2709"; } } -.glyphicon-pencil { &:before { content: "\270f"; } } -.glyphicon-glass { &:before { content: "\e001"; } } -.glyphicon-music { &:before { content: "\e002"; } } -.glyphicon-search { &:before { content: "\e003"; } } -.glyphicon-heart { &:before { content: "\e005"; } } -.glyphicon-star { &:before { content: "\e006"; } } -.glyphicon-star-empty { &:before { content: "\e007"; } } -.glyphicon-user { &:before { content: "\e008"; } } -.glyphicon-film { &:before { content: "\e009"; } } -.glyphicon-th-large { &:before { content: "\e010"; } } -.glyphicon-th { &:before { content: "\e011"; } } -.glyphicon-th-list { &:before { content: "\e012"; } } -.glyphicon-ok { &:before { content: "\e013"; } } -.glyphicon-remove { &:before { content: "\e014"; } } -.glyphicon-zoom-in { &:before { content: "\e015"; } } -.glyphicon-zoom-out { &:before { content: "\e016"; } } -.glyphicon-off { &:before { content: "\e017"; } } -.glyphicon-signal { &:before { content: "\e018"; } } -.glyphicon-cog { &:before { content: "\e019"; } } -.glyphicon-trash { &:before { content: "\e020"; } } -.glyphicon-home { &:before { content: "\e021"; } } -.glyphicon-file { &:before { content: "\e022"; } } -.glyphicon-time { &:before { content: "\e023"; } } -.glyphicon-road { &:before { content: "\e024"; } } -.glyphicon-download-alt { &:before { content: "\e025"; } } -.glyphicon-download { &:before { content: "\e026"; } } -.glyphicon-upload { &:before { content: "\e027"; } } -.glyphicon-inbox { &:before { content: "\e028"; } } -.glyphicon-play-circle { &:before { content: "\e029"; } } -.glyphicon-repeat { &:before { content: "\e030"; } } -.glyphicon-refresh { &:before { content: "\e031"; } } -.glyphicon-list-alt { &:before { content: "\e032"; } } -.glyphicon-lock { &:before { content: "\e033"; } } -.glyphicon-flag { &:before { content: "\e034"; } } -.glyphicon-headphones { &:before { content: "\e035"; } } -.glyphicon-volume-off { &:before { content: "\e036"; } } -.glyphicon-volume-down { &:before { content: "\e037"; } } -.glyphicon-volume-up { &:before { content: "\e038"; } } -.glyphicon-qrcode { &:before { content: "\e039"; } } -.glyphicon-barcode { &:before { content: "\e040"; } } -.glyphicon-tag { &:before { content: "\e041"; } } -.glyphicon-tags { &:before { content: "\e042"; } } -.glyphicon-book { &:before { content: "\e043"; } } -.glyphicon-bookmark { &:before { content: "\e044"; } } -.glyphicon-print { &:before { content: "\e045"; } } -.glyphicon-camera { &:before { content: "\e046"; } } -.glyphicon-font { &:before { content: "\e047"; } } -.glyphicon-bold { &:before { content: "\e048"; } } -.glyphicon-italic { &:before { content: "\e049"; } } -.glyphicon-text-height { &:before { content: "\e050"; } } -.glyphicon-text-width { &:before { content: "\e051"; } } -.glyphicon-align-left { &:before { content: "\e052"; } } -.glyphicon-align-center { &:before { content: "\e053"; } } -.glyphicon-align-right { &:before { content: "\e054"; } } -.glyphicon-align-justify { &:before { content: "\e055"; } } -.glyphicon-list { &:before { content: "\e056"; } } -.glyphicon-indent-left { &:before { content: "\e057"; } } -.glyphicon-indent-right { &:before { content: "\e058"; } } -.glyphicon-facetime-video { &:before { content: "\e059"; } } -.glyphicon-picture { &:before { content: "\e060"; } } -.glyphicon-map-marker { &:before { content: "\e062"; } } -.glyphicon-adjust { &:before { content: "\e063"; } } -.glyphicon-tint { &:before { content: "\e064"; } } -.glyphicon-edit { &:before { content: "\e065"; } } -.glyphicon-share { &:before { content: "\e066"; } } -.glyphicon-check { &:before { content: "\e067"; } } -.glyphicon-move { &:before { content: "\e068"; } } -.glyphicon-step-backward { &:before { content: "\e069"; } } -.glyphicon-fast-backward { &:before { content: "\e070"; } } -.glyphicon-backward { &:before { content: "\e071"; } } -.glyphicon-play { &:before { content: "\e072"; } } -.glyphicon-pause { &:before { content: "\e073"; } } -.glyphicon-stop { &:before { content: "\e074"; } } -.glyphicon-forward { &:before { content: "\e075"; } } -.glyphicon-fast-forward { &:before { content: "\e076"; } } -.glyphicon-step-forward { &:before { content: "\e077"; } } -.glyphicon-eject { &:before { content: "\e078"; } } -.glyphicon-chevron-left { &:before { content: "\e079"; } } -.glyphicon-chevron-right { &:before { content: "\e080"; } } -.glyphicon-plus-sign { &:before { content: "\e081"; } } -.glyphicon-minus-sign { &:before { content: "\e082"; } } -.glyphicon-remove-sign { &:before { content: "\e083"; } } -.glyphicon-ok-sign { &:before { content: "\e084"; } } -.glyphicon-question-sign { &:before { content: "\e085"; } } -.glyphicon-info-sign { &:before { content: "\e086"; } } -.glyphicon-screenshot { &:before { content: "\e087"; } } -.glyphicon-remove-circle { &:before { content: "\e088"; } } -.glyphicon-ok-circle { &:before { content: "\e089"; } } -.glyphicon-ban-circle { &:before { content: "\e090"; } } -.glyphicon-arrow-left { &:before { content: "\e091"; } } -.glyphicon-arrow-right { &:before { content: "\e092"; } } -.glyphicon-arrow-up { &:before { content: "\e093"; } } -.glyphicon-arrow-down { &:before { content: "\e094"; } } -.glyphicon-share-alt { &:before { content: "\e095"; } } -.glyphicon-resize-full { &:before { content: "\e096"; } } -.glyphicon-resize-small { &:before { content: "\e097"; } } -.glyphicon-exclamation-sign { &:before { content: "\e101"; } } -.glyphicon-gift { &:before { content: "\e102"; } } -.glyphicon-leaf { &:before { content: "\e103"; } } -.glyphicon-fire { &:before { content: "\e104"; } } -.glyphicon-eye-open { &:before { content: "\e105"; } } -.glyphicon-eye-close { &:before { content: "\e106"; } } -.glyphicon-warning-sign { &:before { content: "\e107"; } } -.glyphicon-plane { &:before { content: "\e108"; } } -.glyphicon-calendar { &:before { content: "\e109"; } } -.glyphicon-random { &:before { content: "\e110"; } } -.glyphicon-comment { &:before { content: "\e111"; } } -.glyphicon-magnet { &:before { content: "\e112"; } } -.glyphicon-chevron-up { &:before { content: "\e113"; } } -.glyphicon-chevron-down { &:before { content: "\e114"; } } -.glyphicon-retweet { &:before { content: "\e115"; } } -.glyphicon-shopping-cart { &:before { content: "\e116"; } } -.glyphicon-folder-close { &:before { content: "\e117"; } } -.glyphicon-folder-open { &:before { content: "\e118"; } } -.glyphicon-resize-vertical { &:before { content: "\e119"; } } -.glyphicon-resize-horizontal { &:before { content: "\e120"; } } -.glyphicon-hdd { &:before { content: "\e121"; } } -.glyphicon-bullhorn { &:before { content: "\e122"; } } -.glyphicon-bell { &:before { content: "\e123"; } } -.glyphicon-certificate { &:before { content: "\e124"; } } -.glyphicon-thumbs-up { &:before { content: "\e125"; } } -.glyphicon-thumbs-down { &:before { content: "\e126"; } } -.glyphicon-hand-right { &:before { content: "\e127"; } } -.glyphicon-hand-left { &:before { content: "\e128"; } } -.glyphicon-hand-up { &:before { content: "\e129"; } } -.glyphicon-hand-down { &:before { content: "\e130"; } } -.glyphicon-circle-arrow-right { &:before { content: "\e131"; } } -.glyphicon-circle-arrow-left { &:before { content: "\e132"; } } -.glyphicon-circle-arrow-up { &:before { content: "\e133"; } } -.glyphicon-circle-arrow-down { &:before { content: "\e134"; } } -.glyphicon-globe { &:before { content: "\e135"; } } -.glyphicon-wrench { &:before { content: "\e136"; } } -.glyphicon-tasks { &:before { content: "\e137"; } } -.glyphicon-filter { &:before { content: "\e138"; } } -.glyphicon-briefcase { &:before { content: "\e139"; } } -.glyphicon-fullscreen { &:before { content: "\e140"; } } -.glyphicon-dashboard { &:before { content: "\e141"; } } -.glyphicon-paperclip { &:before { content: "\e142"; } } -.glyphicon-heart-empty { &:before { content: "\e143"; } } -.glyphicon-link { &:before { content: "\e144"; } } -.glyphicon-phone { &:before { content: "\e145"; } } -.glyphicon-pushpin { &:before { content: "\e146"; } } -.glyphicon-usd { &:before { content: "\e148"; } } -.glyphicon-gbp { &:before { content: "\e149"; } } -.glyphicon-sort { &:before { content: "\e150"; } } -.glyphicon-sort-by-alphabet { &:before { content: "\e151"; } } -.glyphicon-sort-by-alphabet-alt { &:before { content: "\e152"; } } -.glyphicon-sort-by-order { &:before { content: "\e153"; } } -.glyphicon-sort-by-order-alt { &:before { content: "\e154"; } } -.glyphicon-sort-by-attributes { &:before { content: "\e155"; } } -.glyphicon-sort-by-attributes-alt { &:before { content: "\e156"; } } -.glyphicon-unchecked { &:before { content: "\e157"; } } -.glyphicon-expand { &:before { content: "\e158"; } } -.glyphicon-collapse-down { &:before { content: "\e159"; } } -.glyphicon-collapse-up { &:before { content: "\e160"; } } -.glyphicon-log-in { &:before { content: "\e161"; } } -.glyphicon-flash { &:before { content: "\e162"; } } -.glyphicon-log-out { &:before { content: "\e163"; } } -.glyphicon-new-window { &:before { content: "\e164"; } } -.glyphicon-record { &:before { content: "\e165"; } } -.glyphicon-save { &:before { content: "\e166"; } } -.glyphicon-open { &:before { content: "\e167"; } } -.glyphicon-saved { &:before { content: "\e168"; } } -.glyphicon-import { &:before { content: "\e169"; } } -.glyphicon-export { &:before { content: "\e170"; } } -.glyphicon-send { &:before { content: "\e171"; } } -.glyphicon-floppy-disk { &:before { content: "\e172"; } } -.glyphicon-floppy-saved { &:before { content: "\e173"; } } -.glyphicon-floppy-remove { &:before { content: "\e174"; } } -.glyphicon-floppy-save { &:before { content: "\e175"; } } -.glyphicon-floppy-open { &:before { content: "\e176"; } } -.glyphicon-credit-card { &:before { content: "\e177"; } } -.glyphicon-transfer { &:before { content: "\e178"; } } -.glyphicon-cutlery { &:before { content: "\e179"; } } -.glyphicon-header { &:before { content: "\e180"; } } -.glyphicon-compressed { &:before { content: "\e181"; } } -.glyphicon-earphone { &:before { content: "\e182"; } } -.glyphicon-phone-alt { &:before { content: "\e183"; } } -.glyphicon-tower { &:before { content: "\e184"; } } -.glyphicon-stats { &:before { content: "\e185"; } } -.glyphicon-sd-video { &:before { content: "\e186"; } } -.glyphicon-hd-video { &:before { content: "\e187"; } } -.glyphicon-subtitles { &:before { content: "\e188"; } } -.glyphicon-sound-stereo { &:before { content: "\e189"; } } -.glyphicon-sound-dolby { &:before { content: "\e190"; } } -.glyphicon-sound-5-1 { &:before { content: "\e191"; } } -.glyphicon-sound-6-1 { &:before { content: "\e192"; } } -.glyphicon-sound-7-1 { &:before { content: "\e193"; } } -.glyphicon-copyright-mark { &:before { content: "\e194"; } } -.glyphicon-registration-mark { &:before { content: "\e195"; } } -.glyphicon-cloud-download { &:before { content: "\e197"; } } -.glyphicon-cloud-upload { &:before { content: "\e198"; } } -.glyphicon-tree-conifer { &:before { content: "\e199"; } } -.glyphicon-tree-deciduous { &:before { content: "\e200"; } } -.glyphicon-cd { &:before { content: "\e201"; } } -.glyphicon-save-file { &:before { content: "\e202"; } } -.glyphicon-open-file { &:before { content: "\e203"; } } -.glyphicon-level-up { &:before { content: "\e204"; } } -.glyphicon-copy { &:before { content: "\e205"; } } -.glyphicon-paste { &:before { content: "\e206"; } } -// The following 2 Glyphicons are omitted for the time being because -// they currently use Unicode codepoints that are outside the -// Basic Multilingual Plane (BMP). Older buggy versions of WebKit can't handle -// non-BMP codepoints in CSS string escapes, and thus can't display these two icons. -// Notably, the bug affects some older versions of the Android Browser. -// More info: https://github.com/twbs/bootstrap/issues/10106 -// .glyphicon-door { &:before { content: "\1f6aa"; } } -// .glyphicon-key { &:before { content: "\1f511"; } } -.glyphicon-alert { &:before { content: "\e209"; } } -.glyphicon-equalizer { &:before { content: "\e210"; } } -.glyphicon-king { &:before { content: "\e211"; } } -.glyphicon-queen { &:before { content: "\e212"; } } -.glyphicon-pawn { &:before { content: "\e213"; } } -.glyphicon-bishop { &:before { content: "\e214"; } } -.glyphicon-knight { &:before { content: "\e215"; } } -.glyphicon-baby-formula { &:before { content: "\e216"; } } -.glyphicon-tent { &:before { content: "\26fa"; } } -.glyphicon-blackboard { &:before { content: "\e218"; } } -.glyphicon-bed { &:before { content: "\e219"; } } -.glyphicon-apple { &:before { content: "\f8ff"; } } -.glyphicon-erase { &:before { content: "\e221"; } } -.glyphicon-hourglass { &:before { content: "\231b"; } } -.glyphicon-lamp { &:before { content: "\e223"; } } -.glyphicon-duplicate { &:before { content: "\e224"; } } -.glyphicon-piggy-bank { &:before { content: "\e225"; } } -.glyphicon-scissors { &:before { content: "\e226"; } } -.glyphicon-bitcoin { &:before { content: "\e227"; } } -.glyphicon-btc { &:before { content: "\e227"; } } -.glyphicon-xbt { &:before { content: "\e227"; } } -.glyphicon-yen { &:before { content: "\00a5"; } } -.glyphicon-jpy { &:before { content: "\00a5"; } } -.glyphicon-ruble { &:before { content: "\20bd"; } } -.glyphicon-rub { &:before { content: "\20bd"; } } -.glyphicon-scale { &:before { content: "\e230"; } } -.glyphicon-ice-lolly { &:before { content: "\e231"; } } -.glyphicon-ice-lolly-tasted { &:before { content: "\e232"; } } -.glyphicon-education { &:before { content: "\e233"; } } -.glyphicon-option-horizontal { &:before { content: "\e234"; } } -.glyphicon-option-vertical { &:before { content: "\e235"; } } -.glyphicon-menu-hamburger { &:before { content: "\e236"; } } -.glyphicon-modal-window { &:before { content: "\e237"; } } -.glyphicon-oil { &:before { content: "\e238"; } } -.glyphicon-grain { &:before { content: "\e239"; } } -.glyphicon-sunglasses { &:before { content: "\e240"; } } -.glyphicon-text-size { &:before { content: "\e241"; } } -.glyphicon-text-color { &:before { content: "\e242"; } } -.glyphicon-text-background { &:before { content: "\e243"; } } -.glyphicon-object-align-top { &:before { content: "\e244"; } } -.glyphicon-object-align-bottom { &:before { content: "\e245"; } } -.glyphicon-object-align-horizontal{ &:before { content: "\e246"; } } -.glyphicon-object-align-left { &:before { content: "\e247"; } } -.glyphicon-object-align-vertical { &:before { content: "\e248"; } } -.glyphicon-object-align-right { &:before { content: "\e249"; } } -.glyphicon-triangle-right { &:before { content: "\e250"; } } -.glyphicon-triangle-left { &:before { content: "\e251"; } } -.glyphicon-triangle-bottom { &:before { content: "\e252"; } } -.glyphicon-triangle-top { &:before { content: "\e253"; } } -.glyphicon-console { &:before { content: "\e254"; } } -.glyphicon-superscript { &:before { content: "\e255"; } } -.glyphicon-subscript { &:before { content: "\e256"; } } -.glyphicon-menu-left { &:before { content: "\e257"; } } -.glyphicon-menu-right { &:before { content: "\e258"; } } -.glyphicon-menu-down { &:before { content: "\e259"; } } -.glyphicon-menu-up { &:before { content: "\e260"; } } diff --git a/style/paper/paper.scss b/style/paper/paper.scss index c524a6f7f7..e506b57e23 100644 --- a/style/paper/paper.scss +++ b/style/paper/paper.scss @@ -1,4 +1,4 @@ -html, body { +html { color: #000; width: 100%; height: 100%; @@ -123,9 +123,9 @@ h2 { body { margin: 0; padding: 0; - } - body > header { - display: none; + & > header, & > footer { + display: none; + } } .page { page-break-after: always; diff --git a/style/variables.scss b/style/variables.scss index 5b70b85285..b7e08717e5 100644 --- a/style/variables.scss +++ b/style/variables.scss @@ -73,20 +73,6 @@ $headings-line-height: 1.1 !default; $headings-color: inherit !default; -//== Iconography -// -//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower. - -//** Load fonts from this directory. - -$icon-font-path: "../fonts/" !default; - -//** File name for all font files. -$icon-font-name: "glyphicons-halflings-regular" !default; -//** Element ID within SVG icon file. -$icon-font-svg-id: "glyphicons_halflingsregular" !default; - - //== Components // //## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start). diff --git a/templates/layouts/base.html b/templates/layouts/base.html index 4a8d74e5e5..7859e5ae97 100644 --- a/templates/layouts/base.html +++ b/templates/layouts/base.html @@ -14,7 +14,6 @@ - % block head_alternates % if request.method in constants.SAFE_METHODS and response.code == 200 @@ -29,7 +28,7 @@ % endif {% block head %}{% endblock %} -% from "templates/macros/icons.html" import fontawesome, glyphicon +% from "templates/macros/icons.html" import icon with context % from 'templates/macros/nav.html' import nav, nav_about, nav_explore with context % from 'templates/macros/search.html' import search_form with context @@ -55,7 +54,7 @@ data-target="#navbar-liberapay-collapse" data-parent="#navbar" aria-expanded="false"> {{ _("Toggle navigation") }} - {{ glyphicon('menu-hamburger') }} + {{ icon('list') }} % block navbar_alternates @@ -65,30 +64,30 @@ % include "templates/layouts/components/navbar-logged-in.html" % elif response.no_navbar_sign_in|default(True) % from "templates/macros/sign-in-link.html" import sign_in_link with context -
  • {{ sign_in_link('glyphicon glyphicon-log-in', 'navbar-btn') }}
  • +
  • {{ sign_in_link(icon('enter'), 'navbar-btn') }}
  • % endif diff --git a/templates/macros/admin.html b/templates/macros/admin.html index 14d7c2bc3f..cb99a33ac1 100644 --- a/templates/macros/admin.html +++ b/templates/macros/admin.html @@ -1,3 +1,5 @@ +% from "templates/macros/icons.html" import icon with context + % macro admin_form(p, reload=False, style='columns-sm-2 block-labels')
    @@ -20,7 +22,7 @@ unsettling % if p.is_unsettling.__and__(1)   - + {{ icon('ok-sign', "This account has been marked as unsettling by its owner.") }} % endif