Use embedded SVG instead of fonts for icons

The [downsides of icon fonts] are well-documented, and also, why ship all of
the icons when it only uses 14?

[downsides of icon fonts]: https://speakerdeck.com/ninjanails/death-to-icon-fonts
This commit is contained in:
Michael Howell 2020-09-15 16:20:01 -07:00
parent c8db0c8ec6
commit 7560a2b9b6
17 changed files with 106 additions and 2753 deletions

7
Cargo.lock generated
View File

@ -327,6 +327,12 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "font-awesome-as-a-crate"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86afa981f309a5d0ddbcb682820e5d6066157f903d06b9fb2959707b958f6618"
[[package]] [[package]]
name = "form_urlencoded" name = "form_urlencoded"
version = "1.0.1" version = "1.0.1"
@ -806,6 +812,7 @@ dependencies = [
"clap_complete", "clap_complete",
"elasticlunr-rs", "elasticlunr-rs",
"env_logger", "env_logger",
"font-awesome-as-a-crate",
"futures-util", "futures-util",
"gitignore", "gitignore",
"handlebars", "handlebars",

View File

@ -21,6 +21,7 @@ chrono = "0.4"
clap = { version = "3.0", features = ["cargo"] } clap = { version = "3.0", features = ["cargo"] }
clap_complete = "3.0" clap_complete = "3.0"
env_logger = "0.9.0" env_logger = "0.9.0"
font-awesome-as-a-crate = "0.2.0"
handlebars = "4.0" handlebars = "4.0"
lazy_static = "1.0" lazy_static = "1.0"
log = "0.4" log = "0.4"

View File

@ -240,41 +240,6 @@ impl HtmlHandlebars {
write_file(destination, "ayu-highlight.css", &theme.ayu_highlight_css)?; write_file(destination, "ayu-highlight.css", &theme.ayu_highlight_css)?;
write_file(destination, "highlight.js", &theme.highlight_js)?; write_file(destination, "highlight.js", &theme.highlight_js)?;
write_file(destination, "clipboard.min.js", &theme.clipboard_js)?; write_file(destination, "clipboard.min.js", &theme.clipboard_js)?;
write_file(
destination,
"FontAwesome/css/font-awesome.css",
theme::FONT_AWESOME,
)?;
write_file(
destination,
"FontAwesome/fonts/fontawesome-webfont.eot",
theme::FONT_AWESOME_EOT,
)?;
write_file(
destination,
"FontAwesome/fonts/fontawesome-webfont.svg",
theme::FONT_AWESOME_SVG,
)?;
write_file(
destination,
"FontAwesome/fonts/fontawesome-webfont.ttf",
theme::FONT_AWESOME_TTF,
)?;
write_file(
destination,
"FontAwesome/fonts/fontawesome-webfont.woff",
theme::FONT_AWESOME_WOFF,
)?;
write_file(
destination,
"FontAwesome/fonts/fontawesome-webfont.woff2",
theme::FONT_AWESOME_WOFF2,
)?;
write_file(
destination,
"FontAwesome/fonts/FontAwesome.ttf",
theme::FONT_AWESOME_TTF,
)?;
if html_config.copy_fonts { if html_config.copy_fonts {
write_file(destination, "fonts/fonts.css", theme::fonts::CSS)?; write_file(destination, "fonts/fonts.css", theme::fonts::CSS)?;
for (file_name, contents) in theme::fonts::LICENSES.iter() { for (file_name, contents) in theme::fonts::LICENSES.iter() {
@ -341,6 +306,7 @@ impl HtmlHandlebars {
handlebars.register_helper("previous", Box::new(helpers::navigation::previous)); handlebars.register_helper("previous", Box::new(helpers::navigation::previous));
handlebars.register_helper("next", Box::new(helpers::navigation::next)); handlebars.register_helper("next", Box::new(helpers::navigation::next));
handlebars.register_helper("theme_option", Box::new(helpers::theme::theme_option)); handlebars.register_helper("theme_option", Box::new(helpers::theme::theme_option));
handlebars.register_helper("fa", Box::new(helpers::fontawesome::fa_helper));
} }
/// Copy across any additional CSS and JavaScript files which the book /// Copy across any additional CSS and JavaScript files which the book

View File

@ -0,0 +1,45 @@
use font_awesome_as_a_crate as fa;
use handlebars::{Context, Handlebars, Helper, Output, RenderContext, RenderError};
use std::str::FromStr;
pub fn fa_helper(
h: &Helper<'_, '_>,
_r: &Handlebars<'_>,
_ctx: &Context,
_rc: &mut RenderContext<'_, '_>,
out: &mut dyn Output,
) -> Result<(), RenderError> {
trace!("fa_helper (handlebars helper)");
let type_ = h
.param(0)
.and_then(|v| v.value().as_str())
.and_then(|v| fa::Type::from_str(v).ok())
.ok_or_else(|| {
RenderError::new("Param 0 with String type is required for fontawesome helper.")
})?;
let name = h.param(1).and_then(|v| v.value().as_str()).ok_or_else(|| {
RenderError::new("Param 1 with String type is required for fontawesome helper.")
})?;
trace!("fa_helper: {} {}", type_, name);
let name = if name.starts_with("fa-") {
&name[3..]
} else {
&name[..]
};
if let Some(id) = h.param(2).and_then(|v| v.value().as_str()) {
out.write(&format!("<span class=fa-svg id=\"{}\">", id))?;
} else {
out.write("<span class=fa-svg>")?;
}
out.write(
fa::svg(type_, name).map_err(|_| RenderError::new(format!("Missing font {}", name)))?,
)?;
out.write("</span>")?;
Ok(())
}

View File

@ -1,3 +1,4 @@
pub mod fontawesome;
pub mod navigation; pub mod navigation;
pub mod theme; pub mod theme;
pub mod toc; pub mod toc;

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 434 KiB

View File

@ -92,6 +92,7 @@ function playground_text(playground) {
if (all_available) { if (all_available) {
play_button.classList.remove("hidden"); play_button.classList.remove("hidden");
play_button.hidden = false;
} else { } else {
play_button.classList.add("hidden"); play_button.classList.add("hidden");
} }
@ -187,25 +188,24 @@ function playground_text(playground) {
var buttons = document.createElement('div'); var buttons = document.createElement('div');
buttons.className = 'buttons'; buttons.className = 'buttons';
buttons.innerHTML = "<button class=\"fa fa-eye\" title=\"Show hidden lines\" aria-label=\"Show hidden lines\"></button>"; buttons.innerHTML = "<button title=\"Show hidden lines\" aria-label=\"Show hidden lines\"></button>";
buttons.firstChild.innerHTML = document.getElementById('fa-eye').innerHTML;
// add expand button // add expand button
var pre_block = block.parentNode; var pre_block = block.parentNode;
pre_block.insertBefore(buttons, pre_block.firstChild); pre_block.insertBefore(buttons, pre_block.firstChild);
pre_block.querySelector('.buttons').addEventListener('click', function (e) { buttons.firstChild.addEventListener('click', function (e) {
if (e.target.classList.contains('fa-eye')) { if (this.title === "Show hidden lines") {
e.target.classList.remove('fa-eye'); this.innerHTML = document.getElementById('fa-eye-slash').innerHTML;
e.target.classList.add('fa-eye-slash'); this.title = 'Hide lines';
e.target.title = 'Hide lines'; this.setAttribute('aria-label', e.target.title);
e.target.setAttribute('aria-label', e.target.title);
block.classList.remove('hide-boring'); block.classList.remove('hide-boring');
} else if (e.target.classList.contains('fa-eye-slash')) { } else if (this.title === "Hide lines") {
e.target.classList.remove('fa-eye-slash'); this.innerHTML = document.getElementById('fa-eye').innerHTML;
e.target.classList.add('fa-eye'); this.title = 'Show hidden lines';
e.target.title = 'Show hidden lines'; this.setAttribute('aria-label', e.target.title);
e.target.setAttribute('aria-label', e.target.title);
block.classList.add('hide-boring'); block.classList.add('hide-boring');
} }
@ -224,10 +224,11 @@ function playground_text(playground) {
} }
var clipButton = document.createElement('button'); var clipButton = document.createElement('button');
clipButton.className = 'fa fa-copy clip-button'; clipButton.className = 'clip-button';
clipButton.title = 'Copy to clipboard'; clipButton.title = 'Copy to clipboard';
clipButton.setAttribute('aria-label', clipButton.title); clipButton.setAttribute('aria-label', clipButton.title);
clipButton.innerHTML = '<i class=\"tooltiptext\"></i>'; clipButton.innerHTML = '<i class=\"tooltiptext\"></i>';
clipButton.innerHTML += document.getElementById('fa-copy').innerHTML;
buttons.insertBefore(clipButton, buttons.firstChild); buttons.insertBefore(clipButton, buttons.firstChild);
} }
@ -245,10 +246,11 @@ function playground_text(playground) {
} }
var runCodeButton = document.createElement('button'); var runCodeButton = document.createElement('button');
runCodeButton.className = 'fa fa-play play-button'; runCodeButton.className = 'play-button';
runCodeButton.hidden = true; runCodeButton.hidden = true;
runCodeButton.title = 'Run this code'; runCodeButton.title = 'Run this code';
runCodeButton.setAttribute('aria-label', runCodeButton.title); runCodeButton.setAttribute('aria-label', runCodeButton.title);
runCodeButton.innerHTML = document.getElementById('fa-play').innerHTML;
buttons.insertBefore(runCodeButton, buttons.firstChild); buttons.insertBefore(runCodeButton, buttons.firstChild);
runCodeButton.addEventListener('click', function (e) { runCodeButton.addEventListener('click', function (e) {
@ -257,8 +259,9 @@ function playground_text(playground) {
if (window.playground_copyable) { if (window.playground_copyable) {
var copyCodeClipboardButton = document.createElement('button'); var copyCodeClipboardButton = document.createElement('button');
copyCodeClipboardButton.className = 'fa fa-copy clip-button'; copyCodeClipboardButton.className = 'clip-button';
copyCodeClipboardButton.innerHTML = '<i class="tooltiptext"></i>'; copyCodeClipboardButton.innerHTML = '<i class="tooltiptext"></i>';
copyCodeClipboardButton.innerHTML += document.getElementById('fa-copy').innerHTML;
copyCodeClipboardButton.title = 'Copy to clipboard'; copyCodeClipboardButton.title = 'Copy to clipboard';
copyCodeClipboardButton.setAttribute('aria-label', copyCodeClipboardButton.title); copyCodeClipboardButton.setAttribute('aria-label', copyCodeClipboardButton.title);
@ -268,9 +271,10 @@ function playground_text(playground) {
let code_block = pre_block.querySelector("code"); let code_block = pre_block.querySelector("code");
if (window.ace && code_block.classList.contains("editable")) { if (window.ace && code_block.classList.contains("editable")) {
var undoChangesButton = document.createElement('button'); var undoChangesButton = document.createElement('button');
undoChangesButton.className = 'fa fa-history reset-button'; undoChangesButton.className = 'reset-button';
undoChangesButton.title = 'Undo changes'; undoChangesButton.title = 'Undo changes';
undoChangesButton.setAttribute('aria-label', undoChangesButton.title); undoChangesButton.setAttribute('aria-label', undoChangesButton.title);
undoChangesButton.innerHTML += document.getElementById('fa-history').innerHTML;
buttons.insertBefore(undoChangesButton, buttons.firstChild); buttons.insertBefore(undoChangesButton, buttons.firstChild);
@ -580,12 +584,12 @@ function playground_text(playground) {
function hideTooltip(elem) { function hideTooltip(elem) {
elem.firstChild.innerText = ""; elem.firstChild.innerText = "";
elem.className = 'fa fa-copy clip-button'; elem.className = 'clip-button';
} }
function showTooltip(elem, msg) { function showTooltip(elem, msg) {
elem.firstChild.innerText = msg; elem.firstChild.innerText = msg;
elem.className = 'fa fa-copy tooltipped'; elem.className = 'tooltipped';
} }
var clipboardSnippets = new ClipboardJS('.clip-button', { var clipboardSnippets = new ClipboardJS('.clip-button', {

View File

@ -51,7 +51,7 @@ a > .hljs {
#menu-bar.bordered { #menu-bar.bordered {
border-bottom-color: var(--table-border-color); border-bottom-color: var(--table-border-color);
} }
#menu-bar i, #menu-bar .icon-button { #menu-bar .fa-svg, #menu-bar .icon-button {
position: relative; position: relative;
padding: 0 8px; padding: 0 8px;
z-index: 10; z-index: 10;
@ -60,7 +60,7 @@ a > .hljs {
transition: color 0.5s; transition: color 0.5s;
} }
@media only screen and (max-width: 420px) { @media only screen and (max-width: 420px) {
#menu-bar i, #menu-bar .icon-button { #menu-bar .fa-svg, #menu-bar .icon-button {
padding: 0 5px; padding: 0 5px;
} }
} }
@ -71,7 +71,7 @@ a > .hljs {
padding: 0; padding: 0;
color: inherit; color: inherit;
} }
.icon-button i { .icon-button .fa-svg {
margin: 0; margin: 0;
} }
@ -113,14 +113,14 @@ a > .hljs {
.mobile-nav-chapters, .mobile-nav-chapters,
.mobile-nav-chapters:visited, .mobile-nav-chapters:visited,
.menu-bar .icon-button, .menu-bar .icon-button,
.menu-bar a i { .menu-bar a .fa-svg {
color: var(--icons); color: var(--icons);
} }
.menu-bar i:hover, .menu-bar .fa-svg:hover,
.menu-bar .icon-button:hover, .menu-bar .icon-button:hover,
.nav-chapters:hover, .nav-chapters:hover,
.mobile-nav-chapters i:hover { .mobile-nav-chapters .fa-svg:hover {
color: var(--icons-hover); color: var(--icons-hover);
} }
@ -228,7 +228,7 @@ pre > .buttons :hover {
border-color: var(--icons-hover); border-color: var(--icons-hover);
background-color: var(--theme-hover); background-color: var(--theme-hover);
} }
pre > .buttons i { pre > .buttons .fa-svg {
margin-left: 8px; margin-left: 8px;
} }
pre > .buttons button { pre > .buttons button {

View File

@ -189,3 +189,10 @@ blockquote {
.result-no-output { .result-no-output {
font-style: italic; font-style: italic;
} }
.fa-svg svg {
width: 1em;
height: 1em;
fill: currentColor;
margin-bottom: -0.1em;
}

View File

@ -34,7 +34,6 @@
{{/if}} {{/if}}
<!-- Fonts --> <!-- Fonts -->
<link rel="stylesheet" href="{{ path_to_root }}FontAwesome/css/font-awesome.css">
{{#if copy_fonts}} {{#if copy_fonts}}
<link rel="stylesheet" href="{{ path_to_root }}fonts/fonts.css"> <link rel="stylesheet" href="{{ path_to_root }}fonts/fonts.css">
{{/if}} {{/if}}
@ -116,10 +115,10 @@
<div id="menu-bar" class="menu-bar sticky bordered"> <div id="menu-bar" class="menu-bar sticky bordered">
<div class="left-buttons"> <div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar"> <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i> {{fa "solid" "bars"}}
</button> </button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list"> <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i> {{fa "solid" "paint-brush"}}
</button> </button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu"> <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">{{ theme_option "Light" }}</button></li> <li role="none"><button role="menuitem" class="theme" id="light">{{ theme_option "Light" }}</button></li>
@ -130,7 +129,7 @@
</ul> </ul>
{{#if search_enabled}} {{#if search_enabled}}
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar"> <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i> {{fa "solid" "search"}}
</button> </button>
{{/if}} {{/if}}
</div> </div>
@ -140,12 +139,12 @@
<div class="right-buttons"> <div class="right-buttons">
{{#if print_enable}} {{#if print_enable}}
<a href="{{ path_to_root }}print.html" title="Print this book" aria-label="Print this book"> <a href="{{ path_to_root }}print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i> {{fa "solid" "print" "print-button"}}
</a> </a>
{{/if}} {{/if}}
{{#if git_repository_url}} {{#if git_repository_url}}
<a href="{{git_repository_url}}" title="Git repository" aria-label="Git repository"> <a href="{{git_repository_url}}" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa {{git_repository_icon}}"></i> {{fa "solid" git_repository_icon}}
</a> </a>
{{/if}} {{/if}}
{{#if git_repository_edit_url}} {{#if git_repository_edit_url}}
@ -188,13 +187,13 @@
<!-- Mobile navigation buttons --> <!-- Mobile navigation buttons -->
{{#previous}} {{#previous}}
<a rel="prev" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left"> <a rel="prev" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i> {{fa "solid" "angle-left"}}
</a> </a>
{{/previous}} {{/previous}}
{{#next}} {{#next}}
<a rel="next" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right"> <a rel="next" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i> {{fa "solid" "angle-right"}}
</a> </a>
{{/next}} {{/next}}
@ -206,19 +205,25 @@
<nav class="nav-wide-wrapper" aria-label="Page navigation"> <nav class="nav-wide-wrapper" aria-label="Page navigation">
{{#previous}} {{#previous}}
<a rel="prev" href="{{ path_to_root }}{{link}}" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left"> <a rel="prev" href="{{ path_to_root }}{{link}}" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i> {{fa "solid" "angle-left"}}
</a> </a>
{{/previous}} {{/previous}}
{{#next}} {{#next}}
<a rel="next" href="{{ path_to_root }}{{link}}" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right"> <a rel="next" href="{{ path_to_root }}{{link}}" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i> {{fa "solid" "angle-right"}}
</a> </a>
{{/next}} {{/next}}
</nav> </nav>
</div> </div>
<template id=fa-eye>{{fa "solid" "eye"}}</template>
<template id=fa-eye-slash>{{fa "solid" "eye-slash"}}</template>
<template id=fa-copy>{{fa "regular" "copy"}}</template>
<template id=fa-play>{{fa "solid" "play"}}</template>
<template id=fa-history>{{fa "solid" "history"}}</template>
{{#if live_reload_endpoint}} {{#if live_reload_endpoint}}
<!-- Livereload script (if served using the cli tool) --> <!-- Livereload script (if served using the cli tool) -->
<script> <script>

View File

@ -29,14 +29,6 @@ pub static TOMORROW_NIGHT_CSS: &[u8] = include_bytes!("tomorrow-night.css");
pub static HIGHLIGHT_CSS: &[u8] = include_bytes!("highlight.css"); pub static HIGHLIGHT_CSS: &[u8] = include_bytes!("highlight.css");
pub static AYU_HIGHLIGHT_CSS: &[u8] = include_bytes!("ayu-highlight.css"); pub static AYU_HIGHLIGHT_CSS: &[u8] = include_bytes!("ayu-highlight.css");
pub static CLIPBOARD_JS: &[u8] = include_bytes!("clipboard.min.js"); pub static CLIPBOARD_JS: &[u8] = include_bytes!("clipboard.min.js");
pub static FONT_AWESOME: &[u8] = include_bytes!("FontAwesome/css/font-awesome.min.css");
pub static FONT_AWESOME_EOT: &[u8] = include_bytes!("FontAwesome/fonts/fontawesome-webfont.eot");
pub static FONT_AWESOME_SVG: &[u8] = include_bytes!("FontAwesome/fonts/fontawesome-webfont.svg");
pub static FONT_AWESOME_TTF: &[u8] = include_bytes!("FontAwesome/fonts/fontawesome-webfont.ttf");
pub static FONT_AWESOME_WOFF: &[u8] = include_bytes!("FontAwesome/fonts/fontawesome-webfont.woff");
pub static FONT_AWESOME_WOFF2: &[u8] =
include_bytes!("FontAwesome/fonts/fontawesome-webfont.woff2");
pub static FONT_AWESOME_OTF: &[u8] = include_bytes!("FontAwesome/fonts/FontAwesome.otf");
/// The `Theme` struct should be used instead of the static variables because /// The `Theme` struct should be used instead of the static variables because
/// the `new()` method will look if the user has a theme directory in their /// the `new()` method will look if the user has a theme directory in their