Skip to content

Commit

Permalink
Use font-awesome fonts directly instead of generating our own CSS file
Browse files Browse the repository at this point in the history
  • Loading branch information
GuillaumeGomez authored and syphar committed Oct 13, 2024
1 parent dc7b89d commit b1fd58c
Show file tree
Hide file tree
Showing 47 changed files with 184 additions and 321 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ once_cell = { version = "1.4.0", features = ["parking_lot"] }
base64 = "0.22"
strum = { version = "0.26.1", features = ["derive"] }
lol_html = "1.0.0"
font-awesome-as-a-crate = { path = "crates/font-awesome-as-a-crate" }
dashmap = "6.0.0"
string_cache = "0.8.0"
zip = {version = "2.2.0", default-features = false, features = ["bzip2"]}
Expand Down Expand Up @@ -135,7 +136,6 @@ anyhow = { version = "1.0.42", features = ["backtrace"] }
grass = { version = "0.13.1", default-features = false }
once_cell = { version = "1.4.0", features = ["parking_lot"] }
syntect = { version = "5.0.0", default-features = false, features = ["parsing", "dump-create", "yaml-load", "regex-onig"] }
font-awesome-as-a-crate = { path = "crates/font-awesome-as-a-crate" }

[[bench]]
name = "compression"
Expand Down
189 changes: 1 addition & 188 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
use anyhow::{Context as _, Error, Result};
use font_awesome_as_a_crate as f_a;
use std::{
env,
path::{Path, PathBuf},
};
use std::{env, path::Path};

mod tracked {
use once_cell::sync::Lazy;
Expand Down Expand Up @@ -84,194 +80,11 @@ fn main() -> Result<()> {
write_known_targets(out_dir)?;
compile_syntax(out_dir).context("could not compile syntax files")?;

println!("cargo::rustc-check-cfg=cfg(icons_out_dir)");
println!("cargo:rustc-cfg=icons_out_dir");

let out_css = "static/icons.css";
let out_css = if std::env::var("RUN_IN_DOCKER").is_ok() {
let _ = std::fs::create_dir_all("/srv/docsrs/static");
Path::new("/srv/docsrs/").join(out_css)
} else {
let package_dir = env::var("CARGO_MANIFEST_DIR").context("missing CARGO_MANIFEST_DIR")?;
Path::new(&package_dir).join(out_css)
};
generate_css_icons(out_css, out_dir)?;

// trigger recompilation when a new migration is added
println!("cargo:rerun-if-changed=migrations");
Ok(())
}

fn capitalize(s: &str) -> String {
let mut c = s.chars();
match c.next() {
None => String::new(),
Some(f) => f.to_uppercase().chain(c).collect(),
}
}

fn render_icon(
icon_name: &str,
icon_str: &str,
type_name: String,
code_output: &mut String,
css_output: &mut String,
icon_kind: &str,
) {
let css_class = format!("f-a_{icon_name}_{icon_kind}");
css_output.push_str(&format!(
"\
.{css_class} {{
--svg_{icon_name}_{icon_kind}: url('data:image/svg+xml,{icon_str}');
-webkit-mask: var(--svg_{icon_name}_{icon_kind}) no-repeat center;
mask: var(--svg_{icon_name}_{icon_kind}) no-repeat center;
}}
",
));
let type_name = format!("{type_name}{}", capitalize(icon_kind));
code_output.push_str(&format!(
r#"#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct {type_name};
impl {type_name} {{
pub fn render(&self, fw: bool, spin: bool, extra: &str) -> rinja::filters::Safe<String> {{
render({css_class:?}, fw, spin, extra)
}}
}}
"#,
));
}

fn generate_css_icons(css_path: PathBuf, out_dir: &Path) -> Result<()> {
let mut code_output = r#"pub(crate) mod icons {
fn render(
css_class: &str,
fw: bool,
spin: bool,
extra: &str,
) -> rinja::filters::Safe<String> {
let mut classes = vec!["fa-svg"];
if fw {
classes.push("fa-svg-fw");
}
if spin {
classes.push("fa-svg-spin");
}
if !extra.is_empty() {
classes.push(extra);
}
let icon = format!(
"<span class=\"{css_class} {class}\" aria-hidden=\"true\"></span>",
class = classes.join(" "),
);
rinja::filters::Safe(icon)
}"#
.to_string();
let mut css_output = r#".svg-clipboard {
/* This icon is copied from crates.io */
--svg-clipboard: url('data:image/svg+xml,<svg width="24" height="25" viewBox="0 0 24 25" fill="currentColor" xmlns="http://www.w3.org/2000/svg" aria-label="Copy to clipboard"><path d="M18 20h2v3c0 1-1 2-2 2H2c-.998 0-2-1-2-2V5c0-.911.755-1.667 1.667-1.667h5A3.323 3.323 0 0110 0a3.323 3.323 0 013.333 3.333h5C19.245 3.333 20 4.09 20 5v8.333h-2V9H2v14h16v-3zM3 7h14c0-.911-.793-1.667-1.75-1.667H13.5c-.957 0-1.75-.755-1.75-1.666C11.75 2.755 10.957 2 10 2s-1.75.755-1.75 1.667c0 .911-.793 1.666-1.75 1.666H4.75C3.793 5.333 3 6.09 3 7z"/><path d="M4 19h6v2H4zM12 11H4v2h8zM4 17h4v-2H4zM15 15v-3l-4.5 4.5L15 21v-3l8.027-.032L23 15z"/></svg>');
-webkit-mask: var(--svg-clipboard) no-repeat center;
mask: var(--svg-clipboard) no-repeat center;
}"#.to_string();

let brands: &[&dyn f_a::Brands] = &[
&f_a::icons::IconFonticons,
&f_a::icons::IconRust,
&f_a::icons::IconMarkdown,
&f_a::icons::IconGitAlt,
];
let regular: &[&dyn f_a::Regular] = &[
&f_a::icons::IconFileLines,
&f_a::icons::IconFolderOpen,
&f_a::icons::IconFile,
&f_a::icons::IconStar,
];
let solid: &[&dyn f_a::Solid] = &[
&f_a::icons::IconCircleInfo,
&f_a::icons::IconGears,
&f_a::icons::IconTable,
&f_a::icons::IconRoad,
&f_a::icons::IconDownload,
&f_a::icons::IconCubes,
&f_a::icons::IconSquareRss,
&f_a::icons::IconFileLines,
&f_a::icons::IconCheck,
&f_a::icons::IconTriangleExclamation,
&f_a::icons::IconGear,
&f_a::icons::IconX,
&f_a::icons::IconHouse,
&f_a::icons::IconCodeBranch,
&f_a::icons::IconStar,
&f_a::icons::IconCircleExclamation,
&f_a::icons::IconCube,
&f_a::icons::IconChevronLeft,
&f_a::icons::IconChevronRight,
&f_a::icons::IconFolderOpen,
&f_a::icons::IconLock,
&f_a::icons::IconFlag,
&f_a::icons::IconBook,
&f_a::icons::IconMagnifyingGlass,
&f_a::icons::IconLeaf,
&f_a::icons::IconChartLine,
&f_a::icons::IconList,
&f_a::icons::IconUser,
&f_a::icons::IconTrash,
&f_a::icons::IconArrowLeft,
&f_a::icons::IconArrowRight,
&f_a::icons::IconLink,
&f_a::icons::IconScaleUnbalancedFlip,
&f_a::icons::IconSpinner,
];

for icon in brands {
render_icon(
icon.icon_name(),
icon.icon_str(),
format!("{icon:?}"),
&mut code_output,
&mut css_output,
"brands",
);
}
for icon in regular {
render_icon(
icon.icon_name(),
icon.icon_str(),
format!("{icon:?}"),
&mut code_output,
&mut css_output,
"regular",
);
}
for icon in solid {
render_icon(
icon.icon_name(),
icon.icon_str(),
format!("{icon:?}"),
&mut code_output,
&mut css_output,
"solid",
);
}

std::fs::write(&css_path, css_output).map_err(|error| {
Error::msg(format!(
"Failed to write into `{}`: {error:?}",
css_path.display()
))
})?;

code_output.push('}');
let icons_file = out_dir.join("icons.rs");
std::fs::write(&icons_file, code_output).map_err(|error| {
Error::msg(format!(
"Failed to write `{}`: {error:?}",
icons_file.display()
))
})?;
Ok(())
}

fn write_git_version(out_dir: &Path) -> Result<()> {
let maybe_hash = get_git_hash()?;
let git_hash = maybe_hash.as_deref().unwrap_or("???????");
Expand Down
2 changes: 1 addition & 1 deletion crates/font-awesome-as-a-crate/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ fn write_fontawesome_sprite() {
pub struct {type_name};
impl IconStr for {type_name} {{
fn icon_name(&self) -> &'static str {{ r#\"{icon}\"# }}
fn icon_str(&self) -> &'static str {{ r#\"{data}\"# }}
fn icon_svg(&self) -> &'static str {{ r#\"{data}\"# }}
}}
{kinds}"
)
Expand Down
8 changes: 4 additions & 4 deletions crates/font-awesome-as-a-crate/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,21 +91,21 @@ pub trait IconStr {
/// Name of the icon, like "triangle-exclamation".
fn icon_name(&self) -> &'static str;
/// The SVG content of the icon.
fn icon_str(&self) -> &'static str;
fn icon_svg(&self) -> &'static str;
}

pub trait Brands: IconStr + Debug {
fn get_type(&self) -> Type {
fn get_type() -> Type {
Type::Brands
}
}
pub trait Regular: IconStr + Debug {
fn get_type(&self) -> Type {
fn get_type() -> Type {
Type::Regular
}
}
pub trait Solid: IconStr + Debug {
fn get_type(&self) -> Type {
fn get_type() -> Type {
Type::Solid
}
}
Expand Down
1 change: 0 additions & 1 deletion dockerfiles/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ COPY assets assets/
COPY .sqlx .sqlx/
COPY migrations migrations/

ENV RUN_IN_DOCKER="1"
RUN cargo build --profile=$PROFILE

######################
Expand Down
5 changes: 1 addition & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ pub use self::registry_api::RegistryApi;
pub use self::storage::{AsyncStorage, Storage};
pub use self::web::{start_background_metrics_webserver, start_web_server};

#[cfg(icons_out_dir)]
include!(concat!(env!("OUT_DIR"), "/icons.rs"));
#[cfg(not(icons_out_dir))]
include!("icons.rs");
pub use font_awesome_as_a_crate::icons;

mod build_queue;
pub mod cdn;
Expand Down
4 changes: 3 additions & 1 deletion src/web/build_details.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use crate::{
error::{AxumNope, AxumResult},
extractors::{DbConnection, Path},
file::File,
filters, MetaData,
filters,
page::templates::{RenderRegular, RenderSolid},
MetaData,
},
AsyncStorage, Config,
};
Expand Down
4 changes: 3 additions & 1 deletion src/web/builds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ use crate::{
web::{
error::AxumResult,
extractors::{DbConnection, Path},
filters, match_version, MetaData, ReqVersion,
filters, match_version,
page::templates::{RenderRegular, RenderSolid},
MetaData, ReqVersion,
},
AsyncBuildQueue, Config,
};
Expand Down
4 changes: 2 additions & 2 deletions src/web/crate_details.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
encode_url_path,
error::{AxumNope, AxumResult},
extractors::{DbConnection, Path},
page::templates::filters,
page::templates::{filters, RenderRegular, RenderSolid},
rustdoc::RustdocHtmlParams,
MatchedRelease, ReqVersion,
},
Expand Down Expand Up @@ -1614,7 +1614,7 @@ mod tests {
.borrow()
.get("class")
.unwrap(),
"f-a_code-branch_solid fa-svg"
"fa fa-solid fa-code-branch "
);

Ok(())
Expand Down
8 changes: 4 additions & 4 deletions src/web/csp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl Csp {
// the MIME type to allow loading favicons.
//
// Images from other HTTPS origins are also temporary allowed until issue #66 is fixed.
result.push_str("; img-src 'self' https: data:");
result.push_str("; img-src 'self' https:");

match content_type {
ContentType::Html => self.render_html(&mut result),
Expand Down Expand Up @@ -169,7 +169,7 @@ mod tests {
fn test_csp_other() {
let csp = Csp::new();
assert_eq!(
Some("default-src 'none'; base-uri 'none'; img-src 'self' https: data:".into()),
Some("default-src 'none'; base-uri 'none'; img-src 'self' https:".into()),
csp.render(ContentType::Other)
);
}
Expand All @@ -179,7 +179,7 @@ mod tests {
let csp = Csp::new();
assert_eq!(
Some(
"default-src 'none'; base-uri 'none'; img-src 'self' https: data:; \
"default-src 'none'; base-uri 'none'; img-src 'self' https:; \
style-src 'self' 'unsafe-inline'"
.into()
),
Expand All @@ -192,7 +192,7 @@ mod tests {
let csp = Csp::new();
assert_eq!(
Some(format!(
"default-src 'none'; base-uri 'none'; img-src 'self' https: data:; \
"default-src 'none'; base-uri 'none'; img-src 'self' https:; \
style-src 'self'; font-src 'self'; connect-src 'self'; script-src 'nonce-{}'",
csp.nonce()
)),
Expand Down
4 changes: 3 additions & 1 deletion src/web/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use crate::{
extractors::{DbConnection, Path},
filters,
headers::CanonicalUrl,
match_version, MetaData, ReqVersion,
match_version,
page::templates::{RenderRegular, RenderSolid},
MetaData, ReqVersion,
},
};
use anyhow::anyhow;
Expand Down
2 changes: 1 addition & 1 deletion src/web/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub mod page;
use crate::db::types::BuildStatus;
use crate::utils::get_correct_docsrs_style_file;
use crate::utils::report_error;
use crate::web::page::templates::filters;
use crate::web::page::templates::{filters, RenderSolid};
use anyhow::{anyhow, bail, Context as _, Result};
use axum_extra::middleware::option_layer;
use rinja::Template;
Expand Down
2 changes: 1 addition & 1 deletion src/web/page/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ pub(crate) struct GlobalAlert {
pub(crate) url: &'static str,
pub(crate) text: &'static str,
pub(crate) css_class: &'static str,
pub(crate) fa_icon: crate::icons::IconTriangleExclamationSolid,
pub(crate) fa_icon: crate::icons::IconTriangleExclamation,
}
Loading

0 comments on commit b1fd58c

Please sign in to comment.