Skip to content

Commit

Permalink
Use embedded Font Awesome SVG icons
Browse files Browse the repository at this point in the history
Co-authored-by: Michael Howell <[email protected]>
  • Loading branch information
uncenter and notriddle committed Nov 15, 2024
1 parent 9096012 commit 9004849
Show file tree
Hide file tree
Showing 17 changed files with 171 additions and 2,752 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ clap = { version = "4.3.12", features = ["cargo", "wrap_help"] }
clap_complete = "4.3.2"
once_cell = "1.17.1"
env_logger = "0.11.1"
font-awesome-as-a-crate = "0.3.0"
handlebars = "6.0"
log = "0.4.17"
memchr = "2.5.0"
Expand Down
98 changes: 62 additions & 36 deletions src/renderer/html_handlebars/hbs_renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ impl HtmlHandlebars {
let rendered = fix_code_blocks(&rendered);
let rendered = add_playground_pre(&rendered, playground_config, edition);
let rendered = hide_lines(&rendered, code_config);
let rendered = convert_fontawesome(&rendered);

rendered
}
Expand Down Expand Up @@ -258,41 +259,7 @@ 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,
)?;

// Don't copy the stock fonts if the user has specified their own fonts to use.
if html_config.copy_fonts && theme.fonts_css.is_none() {
write_file(destination, "fonts/fonts.css", theme::fonts::CSS)?;
Expand Down Expand Up @@ -379,6 +346,7 @@ impl HtmlHandlebars {
handlebars.register_helper("next", Box::new(helpers::navigation::next));
// TODO: remove theme_option in 0.5, it is not needed.
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
Expand Down Expand Up @@ -754,9 +722,19 @@ fn make_data(

let git_repository_icon = match html_config.git_repository_icon {
Some(ref git_repository_icon) => git_repository_icon,
None => "fa-github",
None => "fab-github",
};
let git_repository_icon_class = match git_repository_icon.split('-').next() {
Some("fa") => "regular",
Some("fas") => "solid",
Some("fab") => "brands",
_ => "regular",
};
data.insert("git_repository_icon".to_owned(), json!(git_repository_icon));
data.insert(
"git_repository_icon_class".to_owned(),
json!(git_repository_icon_class),
);

let mut chapters = vec![];

Expand Down Expand Up @@ -855,6 +833,54 @@ fn insert_link_into_header(
)
}

// Convert fontawesome `<i>` tags to inline SVG
fn convert_fontawesome(html: &str) -> String {
use font_awesome_as_a_crate as fa;

let regex = Regex::new(r##"<i([^>]+)class="([^"]+)"([^>]*)></i>"##).unwrap();
regex
.replace_all(html, |caps: &Captures<'_>| {
let text = &caps[0];
let before = &caps[1];
let classes = &caps[2];
let after = &caps[3];

let mut icon = String::new();
let mut type_ = fa::Type::Regular;
let mut other_classes = String::new();

for class in classes.split(" ") {
if let Some(class) = class.strip_prefix("fa-") {
icon = class.to_owned();
} else if class == "fa" {
type_ = fa::Type::Regular;
} else if class == "fas" {
type_ = fa::Type::Solid;
} else if class == "fab" {
type_ = fa::Type::Brands;
} else {
other_classes += " ";
other_classes += class;
}
}

if icon.is_empty() {
text.to_owned()
} else if let Ok(svg) = fa::svg(type_, &icon) {
format!(
r#"<span{before}class="fa-svg{other_classes}"{after}>{svg}</span>"#,
before = before,
other_classes = other_classes,
after = after,
svg = svg
)
} else {
text.to_owned()
}
})
.into_owned()
}

// The rust book uses annotations for rustdoc to test code snippets,
// like the following:
// ```rust,should_panic
Expand Down
53 changes: 53 additions & 0 deletions src/renderer/html_handlebars/helpers/fontawesome.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use font_awesome_as_a_crate as fa;
use handlebars::{
Context, Handlebars, Helper, Output, RenderContext, RenderError, RenderErrorReason,
};
use log::trace;
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(|| {
RenderErrorReason::Other(
"Param 0 with String type is required for fontawesome helper.".to_owned(),
)
})?;

let name = h.param(1).and_then(|v| v.value().as_str()).ok_or_else(|| {
RenderErrorReason::Other(
"Param 1 with String type is required for fontawesome helper.".to_owned(),
)
})?;

trace!("fa_helper: {} {}", type_, name);

let name = name
.strip_prefix("fa-")
.or_else(|| name.strip_prefix("fab-"))
.or_else(|| name.strip_prefix("fas-"))
.unwrap_or(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(|_| RenderErrorReason::Other(format!("Missing font {}", name)))?,
)?;
out.write("</span>")?;

Ok(())
}
1 change: 1 addition & 0 deletions src/renderer/html_handlebars/helpers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod fontawesome;
pub mod navigation;
pub mod theme;
pub mod toc;
4 changes: 0 additions & 4 deletions src/theme/FontAwesome/css/font-awesome.min.css

This file was deleted.

Binary file removed src/theme/FontAwesome/fonts/FontAwesome.otf
Binary file not shown.
Binary file removed src/theme/FontAwesome/fonts/fontawesome-webfont.eot
Binary file not shown.
Loading

0 comments on commit 9004849

Please sign in to comment.