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"
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]]
name = "form_urlencoded"
version = "1.0.1"
@ -806,6 +812,7 @@ dependencies = [
"clap_complete",
"elasticlunr-rs",
"env_logger",
"font-awesome-as-a-crate",
"futures-util",
"gitignore",
"handlebars",

View File

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

View File

@ -240,41 +240,6 @@ impl HtmlHandlebars {
write_file(destination, "ayu-highlight.css", &theme.ayu_highlight_css)?;
write_file(destination, "highlight.js", &theme.highlight_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 {
write_file(destination, "fonts/fonts.css", theme::fonts::CSS)?;
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("next", Box::new(helpers::navigation::next));
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

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

View File

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

View File

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

View File

@ -34,7 +34,6 @@
{{/if}}
<!-- Fonts -->
<link rel="stylesheet" href="{{ path_to_root }}FontAwesome/css/font-awesome.css">
{{#if copy_fonts}}
<link rel="stylesheet" href="{{ path_to_root }}fonts/fonts.css">
{{/if}}
@ -116,10 +115,10 @@
<div id="menu-bar" class="menu-bar sticky bordered">
<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">
<i class="fa fa-bars"></i>
{{fa "solid" "bars"}}
</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">
<i class="fa fa-paint-brush"></i>
{{fa "solid" "paint-brush"}}
</button>
<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>
@ -130,7 +129,7 @@
</ul>
{{#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">
<i class="fa fa-search"></i>
{{fa "solid" "search"}}
</button>
{{/if}}
</div>
@ -140,12 +139,12 @@
<div class="right-buttons">
{{#if print_enable}}
<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>
{{/if}}
{{#if git_repository_url}}
<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>
{{/if}}
{{#if git_repository_edit_url}}
@ -188,13 +187,13 @@
<!-- Mobile navigation buttons -->
{{#previous}}
<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>
{{/previous}}
{{#next}}
<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>
{{/next}}
@ -206,19 +205,25 @@
<nav class="nav-wide-wrapper" aria-label="Page navigation">
{{#previous}}
<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>
{{/previous}}
{{#next}}
<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>
{{/next}}
</nav>
</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}}
<!-- Livereload script (if served using the cli tool) -->
<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 AYU_HIGHLIGHT_CSS: &[u8] = include_bytes!("ayu-highlight.css");
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 `new()` method will look if the user has a theme directory in their