Skip to content

Commit

Permalink
Move fontawesome icons check at compile-time
Browse files Browse the repository at this point in the history
  • Loading branch information
GuillaumeGomez committed Sep 24, 2024
1 parent d5a3784 commit 3409ada
Show file tree
Hide file tree
Showing 26 changed files with 206 additions and 136 deletions.
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::traits::*,
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 @@ -11,7 +11,9 @@ use crate::{
web::{
error::AxumResult,
extractors::{DbConnection, Path},
filters, match_version, MetaData, ReqVersion,
filters, match_version,
page::templates::traits::*,
MetaData, ReqVersion,
},
BuildQueue, Config,
};
Expand Down
2 changes: 1 addition & 1 deletion 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, traits::*},
rustdoc::RustdocHtmlParams,
MatchedRelease, ReqVersion,
},
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::traits::*,
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, traits::*};
use anyhow::{anyhow, bail, Context as _, Result};
use axum_extra::middleware::option_layer;
use rinja::Template;
Expand Down
26 changes: 21 additions & 5 deletions src/web/page/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,30 @@ pub(crate) mod web_page;

pub(crate) use templates::TemplateData;

use serde::Serialize;
use serde::ser::{Serialize, SerializeStruct, Serializer};

#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize)]
use templates::traits::*;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub(crate) struct GlobalAlert {
pub(crate) url: &'static str,
pub(crate) text: &'static str,
pub(crate) css_class: &'static str,
pub(crate) fa_icon: &'static str,
pub(crate) fa_icon: templates::filters::TriangleExclamation,
}

impl Serialize for GlobalAlert {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut s = serializer.serialize_struct("GlobalAlert", 4)?;
s.serialize_field("url", &self.url)?;
s.serialize_field("text", &self.text)?;
s.serialize_field("css_class", &self.css_class)?;
s.serialize_field("fa_icon", &self.fa_icon.as_str())?;
s.end()
}
}

#[cfg(test)]
Expand All @@ -24,14 +40,14 @@ mod tera_tests {
url: "http://www.hasthelargehadroncolliderdestroyedtheworldyet.com/",
text: "THE WORLD WILL SOON END",
css_class: "THE END IS NEAR",
fa_icon: "https://gph.is/1uOvmqR",
fa_icon: templates::filters::TriangleExclamation,
};

let correct_json = json!({
"url": "http://www.hasthelargehadroncolliderdestroyedtheworldyet.com/",
"text": "THE WORLD WILL SOON END",
"css_class": "THE END IS NEAR",
"fa_icon": "https://gph.is/1uOvmqR"
"fa_icon": "triangle-exclamation"
});

assert_eq!(correct_json, serde_json::to_value(alert).unwrap());
Expand Down
148 changes: 98 additions & 50 deletions src/web/page/templates.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::error::Result;
use crate::web::rustdoc::RustdocPage;
use anyhow::{anyhow, Context};
use anyhow::Context;
use rinja::Template;
use std::{fmt, sync::Arc};
use std::sync::Arc;
use tracing::trace;

#[derive(Template)]
Expand Down Expand Up @@ -88,7 +88,6 @@ impl TemplateData {
}

pub mod filters {
use super::IconType;
use chrono::{DateTime, Utc};
use rinja::filters::Safe;
use std::borrow::Cow;
Expand Down Expand Up @@ -201,18 +200,6 @@ pub mod filters {
Ok(unindented)
}

pub fn fas(value: &str, fw: bool, spin: bool, extra: &str) -> rinja::Result<Safe<String>> {
IconType::Strong.render(value, fw, spin, extra).map(Safe)
}

pub fn far(value: &str, fw: bool, spin: bool, extra: &str) -> rinja::Result<Safe<String>> {
IconType::Regular.render(value, fw, spin, extra).map(Safe)
}

pub fn fab(value: &str, fw: bool, spin: bool, extra: &str) -> rinja::Result<Safe<String>> {
IconType::Brand.render(value, fw, spin, extra).map(Safe)
}

pub fn highlight(code: impl std::fmt::Display, lang: &str) -> rinja::Result<Safe<String>> {
let highlighted_code = crate::web::highlight::with_lang(Some(lang), &code.to_string());
Ok(Safe(format!(
Expand All @@ -239,44 +226,107 @@ pub mod filters {
serde_json::to_string(value).expect("`encode_json` failed"),
))
}
}

enum IconType {
Strong,
Regular,
Brand,
}
macro_rules! icons {
($($name:ident => $class:literal: $($trait_:ident $(+)?)+ , )+) => {
$(
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct $name;

$(
impl super::traits::$trait_ for $name {}
)+

impl fmt::Display for IconType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let icon = match self {
Self::Strong => "solid",
Self::Regular => "regular",
Self::Brand => "brands",
impl super::traits::IconStr for $name {
fn as_str(&self) -> &'static str {
$class
}
}
)+
};
}

f.write_str(icon)
icons! {
House => "house": Solid,
CodeBranch => "code-branch": Solid,
Star => "star": Solid + Regular,
File => "file": Regular,
FileLines => "file-lines": Solid + Regular,
CircleExclamation => "circle-exclamation": Solid,
CircleInfo => "circle-info": Solid,
Cube => "cube": Solid,
Cubes => "cubes": Solid,
Gear => "gear": Solid,
Gears => "gears": Solid,
Check => "check": Solid,
TriangleExclamation => "triangle-exclamation": Solid + Regular,
X => "x": Solid,
ChevronLeft => "chevron-feft": Solid,
ChevronRight => "chevron-right": Solid,
Lock => "lock": Solid,
Table => "table": Solid,
Road => "road": Solid,
Download => "download": Solid,
Trash => "trash": Solid,
ArrowLeft => "arrow-left": Solid,
ArrowRight => "arrow-right": Solid,
Leaf => "leaf": Solid,
ChartLine => "chart-line": Solid,
List => "list": Solid,
User => "user": Solid,
SquareRSS => "square-rss": Solid,
MagnifyingGlass => "magnifying-glass": Solid,
Flag => "flag": Solid,
Book => "book": Solid,
Link => "link": Solid,
ScaleUnbalancedFlip => "scale-unbalanced-flip": Solid,
FolderOpen => "folder-open": Solid + Regular,
Spinner => "spinner": Solid,
FontIcons => "fonticons": Brands, // It's not a typo!
Rust => "rust": Brands,
Markdown => "markdown": Brands,
GitAlt => "git-alt": Brands,
}
}

impl IconType {
fn render(self, icon_name: &str, fw: bool, spin: bool, extra: &str) -> rinja::Result<String> {
let type_ = match self {
IconType::Strong => font_awesome_as_a_crate::Type::Solid,
IconType::Regular => font_awesome_as_a_crate::Type::Regular,
IconType::Brand => font_awesome_as_a_crate::Type::Brands,
};
pub mod traits {
pub trait IconStr {
fn as_str(&self) -> &'static str;
}

let icon_file_string = font_awesome_as_a_crate::svg(type_, icon_name).map_err(|err| {
rinja::Error::Custom(
anyhow!(err)
.context(format!(
"error trying to render icon with name \"{}\" and type \"{}\"",
icon_name, type_,
))
.into(),
)
})?;
macro_rules! icon_type {
($($trait_:ident => $method:ident,)+) => {
$(
pub trait $trait_: IconStr {
fn $method(&self, fw: bool, spin: bool, extra: &str) -> rinja::filters::Safe<String> {
render_icon(IconStr::as_str(self), font_awesome_as_a_crate::Type::$trait_, fw, spin, extra)
}
}
)+
}
}

icon_type!(
Solid => render_solid,
Regular => render_regular,
Brands => render_brands,
);

fn render_icon(
icon_name: &str,
type_: font_awesome_as_a_crate::Type,
fw: bool,
spin: bool,
extra: &str,
) -> rinja::filters::Safe<String> {
let Ok(icon_file_string) = font_awesome_as_a_crate::svg(type_, icon_name) else {
log::error!(
"error trying to render icon with name \"{}\" and type \"{}\"",
icon_name,
type_,
);
return rinja::filters::Safe(String::new());
};

let mut classes = vec!["fa-svg"];
if fw {
Expand All @@ -288,12 +338,10 @@ impl IconType {
if !extra.is_empty() {
classes.push(extra);
}
let icon = format!(
rinja::filters::Safe(format!(
"\
<span class=\"{class}\" aria-hidden=\"true\">{icon_file_string}</span>",
<span class=\"{class}\" aria-hidden=\"true\">{icon_file_string}</span>",
class = classes.join(" "),
);

Ok(icon)
))
}
}
2 changes: 1 addition & 1 deletion src/web/releases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
error::{AxumNope, AxumResult},
extractors::{DbConnection, Path},
match_version,
page::templates::filters,
page::templates::{filters, traits::*},
ReqVersion,
},
BuildQueue, Config, InstanceMetrics,
Expand Down
2 changes: 1 addition & 1 deletion src/web/rustdoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{
extractors::{DbConnection, Path},
file::File,
match_version,
page::templates::filters,
page::templates::{filters, traits::*},
page::TemplateData,
MetaData, ReqVersion,
},
Expand Down
2 changes: 1 addition & 1 deletion src/web/sitemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
web::{
error::{AxumNope, AxumResult},
extractors::{DbConnection, Path},
page::templates::filters,
page::templates::{filters, traits::*},
AxumErrorPage,
},
Config,
Expand Down
2 changes: 1 addition & 1 deletion src/web/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
storage::PathNotFoundError,
web::{
cache::CachePolicy, error::AxumNope, extractors::Path, file::File as DbFile, filters,
headers::CanonicalUrl, MetaData, ReqVersion,
headers::CanonicalUrl, page::templates::traits::*, MetaData, ReqVersion,
},
AsyncStorage,
};
Expand Down
12 changes: 6 additions & 6 deletions templates/about-base.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,27 @@
<h1 id="crate-title" class="no-description">Docs.rs documentation</h1>
<div class="pure-menu pure-menu-horizontal">
<ul class="pure-menu-list">
{% set text = "circle-info"|fas(false, false, "") %}
{% set text = filters::CircleInfo.render_solid(false, false, "") %}
{% set text = "{} <span class='title'>About</span>"|format(text) %}
{% call macros::active_link(expected="index", href="/about", text=text) %}

{% set text = "fonticons"|fab(false, false, "") %}
{% set text = filters::FontIcons.render_brands(false, false, "") %}
{% set text = "{} <span class='title'>Badges</span>"|format(text) %}
{% call macros::active_link(expected="badges", href="/about/badges", text=text) %}

{% set text = "gears"|fas(false, false, "") %}
{% set text = filters::Gears.render_solid(false, false, "") %}
{% set text = "{} <span class='title'>Builds</span>"|format(text) %}
{% call macros::active_link(expected="builds", href="/about/builds", text=text) %}

{% set text = "table"|fas(false, false, "") %}
{% set text = filters::Table.render_solid(false, false, "") %}
{% set text = "{} <span class='title'>Metadata</span>"|format(text) %}
{% call macros::active_link(expected="metadata", href="/about/metadata", text=text) %}

{% set text = "road"|fas(false, false, "") %}
{% set text = filters::Road.render_solid(false, false, "") %}
{% set text = "{} <span class='title'>Shorthand URLs</span>"|format(text) %}
{% call macros::active_link(expected="redirections", href="/about/redirections", text=text) %}

{% set text = "download"|fas(false, false, "") %}
{% set text = filters::Download.render_solid(false, false, "") %}
{% set text = "{} <span class='title'>Download</span>"|format(text) %}
{% call macros::active_link(expected="download", href="/about/download", text=text) %}
</ul>
Expand Down
4 changes: 2 additions & 2 deletions templates/core/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

{%- block body -%}
<div class="container landing">
<h1 class="brand">{{ "cubes"|fas(false, false, "") }} Docs.rs</h1>
<h1 class="brand">{{ filters::Cubes.render_solid(false, false, "") }} Docs.rs</h1>

<form action="/releases/search" method="GET" class="landing-search-form">
<div>
Expand All @@ -36,7 +36,7 @@ <h1 class="brand">{{ "cubes"|fas(false, false, "") }} Docs.rs</h1>
<strong>Recent Releases</strong>
</a>
<a href="/releases/feed" title="Atom feed">
{{ "square-rss"|fas(false, false, "") }}
{{ filters::SquareRSS.render_solid(false, false, "") }}
</a>
</div>

Expand Down
2 changes: 1 addition & 1 deletion templates/crate/build_details.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<li>
<a href="/crate/{{ metadata.name }}/{{ metadata.version }}/builds/{{ build_details.id }}/{{ filename }}" class="release">
<div class="pure-g">
<div class="pure-u-1 pure-u-sm-1-24 build">{{ "file-lines"|fas(false, false, "") }}</div>
<div class="pure-u-1 pure-u-sm-1-24 build">{{ filters::FileLines.render_solid(false, false, "") }}</div>
<div class="pure-u-1 pure-u-sm-10-24">
{% if current_filename.as_deref().unwrap_or_default() == filename.as_str() %}
<b>{{ filename }}</b>
Expand Down
Loading

0 comments on commit 3409ada

Please sign in to comment.