diff --git a/src/utils/html.rs b/src/utils/html.rs index 961b5eea3..738a2dbf3 100644 --- a/src/utils/html.rs +++ b/src/utils/html.rs @@ -2,7 +2,7 @@ use crate::web::page::TemplateData; use lol_html::errors::RewritingError; use tera::Context; -/// Rewrite a rustdoc page to have the docs.rs header +/// Rewrite a rustdoc page to have the docs.rs topbar /// /// Given a rustdoc HTML page and a context to serialize it with, /// render the `rustdoc/` templates with the `html`. @@ -21,7 +21,7 @@ pub(crate) fn rewrite_lol( let tera_head = templates.render("rustdoc/head.html", &ctx).unwrap(); let tera_vendored_css = templates.render("rustdoc/vendored.html", &ctx).unwrap(); let tera_body = templates.render("rustdoc/body.html", &ctx).unwrap(); - let tera_rustdoc_header = templates.render("rustdoc/header.html", &ctx).unwrap(); + let tera_rustdoc_topbar = templates.render("rustdoc/topbar.html", &ctx).unwrap(); // Append `style.css` stylesheet after all head elements. let head_handler = |head: &mut Element| { @@ -54,10 +54,10 @@ pub(crate) fn rewrite_lol( rustdoc_body_class.set_tag_name("div")?; // Prepend the tera content rustdoc_body_class.prepend(&tera_body, ContentType::Html); - // Wrap the tranformed body and rustdoc header into a element + // Wrap the tranformed body and topbar into a element rustdoc_body_class.before("", ContentType::Html); - // Insert the header outside of the rustdoc div - rustdoc_body_class.before(&tera_rustdoc_header, ContentType::Html); + // Insert the topbar outside of the rustdoc div + rustdoc_body_class.before(&tera_rustdoc_topbar, ContentType::Html); // Finalize body with rustdoc_body_class.after("", ContentType::Html); diff --git a/src/web/crate_details.rs b/src/web/crate_details.rs index 4b2cd0d1b..15cc60ba8 100644 --- a/src/web/crate_details.rs +++ b/src/web/crate_details.rs @@ -39,8 +39,6 @@ pub struct CrateDetails { github_issues: Option, pub(crate) metadata: MetaData, is_library: bool, - yanked: bool, - pub(crate) doc_targets: Vec, license: Option, documentation_url: Option, total_items: Option, @@ -144,18 +142,8 @@ impl CrateDetails { rustdoc_status: krate.get("rustdoc_status"), target_name: krate.get("target_name"), default_target: krate.get("default_target"), - }; - - let doc_targets = { - let data: Value = krate.get("doc_targets"); - data.as_array() - .map(|array| { - array - .iter() - .filter_map(|item| item.as_str().map(|s| s.to_owned())) - .collect() - }) - .unwrap_or_else(Vec::new) + doc_targets: MetaData::parse_doc_targets(krate.get("doc_targets")), + yanked: krate.get("yanked"), }; let documented_items: Option = krate.get("documented_items"); @@ -189,8 +177,6 @@ impl CrateDetails { github_issues: krate.get("github_issues"), metadata, is_library: krate.get("is_library"), - yanked: krate.get("yanked"), - doc_targets, license: krate.get("license"), documentation_url: krate.get("documentation_url"), documented_items: documented_items.map(|v| v as f32), diff --git a/src/web/mod.rs b/src/web/mod.rs index 64136a08f..642251f79 100644 --- a/src/web/mod.rs +++ b/src/web/mod.rs @@ -3,6 +3,7 @@ pub(crate) mod page; use log::{debug, info}; +use serde_json::Value; /// ctry! (cratesfyitry) is extremely similar to try! and itry! /// except it returns an error page response instead of plain Err. @@ -542,6 +543,8 @@ pub(crate) struct MetaData { pub(crate) target_name: Option, pub(crate) rustdoc_status: bool, pub(crate) default_target: String, + pub(crate) doc_targets: Vec, + pub(crate) yanked: bool, } impl MetaData { @@ -553,7 +556,9 @@ impl MetaData { releases.description, releases.target_name, releases.rustdoc_status, - releases.default_target + releases.default_target, + releases.doc_targets, + releases.yanked FROM releases INNER JOIN crates ON crates.id = releases.crate_id WHERE crates.name = $1 AND releases.version = $2", @@ -570,8 +575,22 @@ impl MetaData { target_name: row.get(3), rustdoc_status: row.get(4), default_target: row.get(5), + doc_targets: MetaData::parse_doc_targets(row.get(6)), + yanked: row.get(7), }) } + + fn parse_doc_targets(targets: Value) -> Vec { + targets + .as_array() + .map(|array| { + array + .iter() + .filter_map(|item| item.as_str().map(|s| s.to_owned())) + .collect() + }) + .unwrap_or_else(Vec::new) + } } #[derive(Debug, Clone, PartialEq, Serialize)] @@ -840,6 +859,11 @@ mod test { target_name: None, rustdoc_status: true, default_target: "x86_64-unknown-linux-gnu".to_string(), + doc_targets: vec![ + "x86_64-unknown-linux-gnu".to_string(), + "arm64-unknown-linux-gnu".to_string(), + ], + yanked: false, }; let correct_json = json!({ @@ -848,19 +872,29 @@ mod test { "description": "serde does stuff", "target_name": null, "rustdoc_status": true, - "default_target": "x86_64-unknown-linux-gnu" + "default_target": "x86_64-unknown-linux-gnu", + "doc_targets": [ + "x86_64-unknown-linux-gnu", + "arm64-unknown-linux-gnu", + ], + "yanked": false, }); assert_eq!(correct_json, serde_json::to_value(&metadata).unwrap()); - metadata.target_name = Some("x86_64-apple-darwin".to_string()); + metadata.target_name = Some("serde_lib_name".to_string()); let correct_json = json!({ "name": "serde", "version": "1.0.0", "description": "serde does stuff", - "target_name": "x86_64-apple-darwin", + "target_name": "serde_lib_name", "rustdoc_status": true, - "default_target": "x86_64-unknown-linux-gnu" + "default_target": "x86_64-unknown-linux-gnu", + "doc_targets": [ + "x86_64-unknown-linux-gnu", + "arm64-unknown-linux-gnu", + ], + "yanked": false, }); assert_eq!(correct_json, serde_json::to_value(&metadata).unwrap()); @@ -870,9 +904,14 @@ mod test { "name": "serde", "version": "1.0.0", "description": null, - "target_name": "x86_64-apple-darwin", + "target_name": "serde_lib_name", "rustdoc_status": true, - "default_target": "x86_64-unknown-linux-gnu" + "default_target": "x86_64-unknown-linux-gnu", + "doc_targets": [ + "x86_64-unknown-linux-gnu", + "arm64-unknown-linux-gnu", + ], + "yanked": false, }); assert_eq!(correct_json, serde_json::to_value(&metadata).unwrap()); diff --git a/src/web/rustdoc.rs b/src/web/rustdoc.rs index 063e11df3..99a32b829 100644 --- a/src/web/rustdoc.rs +++ b/src/web/rustdoc.rs @@ -5,7 +5,7 @@ use crate::{ utils, web::{ crate_details::CrateDetails, error::Nope, file::File, match_version, - metrics::RenderingTimesRecorder, redirect_base, MatchSemver, + metrics::RenderingTimesRecorder, redirect_base, MatchSemver, MetaData, }, Config, Metrics, Storage, }; @@ -186,6 +186,7 @@ struct RustdocPage { is_latest_version: bool, is_prerelease: bool, krate: CrateDetails, + metadata: MetaData, } impl RustdocPage { @@ -390,7 +391,7 @@ pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult { "/{}/{}/{}", name, latest_version, - path_for_version(&latest_path, &krate.doc_targets, &storage, &config) + path_for_version(&latest_path, &krate.metadata.doc_targets, &storage, &config) ) } else { format!("/crate/{}/{}", name, latest_version) @@ -407,7 +408,12 @@ pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult { // Drop the `rustdoc/:crate/:version[/:platform]` prefix inner_path.drain(..3).for_each(drop); - let target = if inner_path.len() > 1 && krate.doc_targets.iter().any(|s| s == inner_path[0]) + let target = if inner_path.len() > 1 + && krate + .metadata + .doc_targets + .iter() + .any(|s| s == inner_path[0]) { let mut target = inner_path.remove(0).to_string(); target.push('/'); @@ -427,6 +433,7 @@ pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult { inner_path, is_latest_version, is_prerelease, + metadata: krate.metadata.clone(), krate, } .into_response(&file.0.content, config.max_parse_memory, req, &path) @@ -513,7 +520,12 @@ pub fn target_redirect_handler(req: &mut Request) -> IronResult { file_path }; - let path = path_for_version(&file_path, &crate_details.doc_targets, &storage, &config); + let path = path_for_version( + &file_path, + &crate_details.metadata.doc_targets, + &storage, + &config, + ); let url = format!( "{base}/{name}/{version}/{path}", base = base, diff --git a/src/web/source.rs b/src/web/source.rs index 587092fe1..30bb48fa7 100644 --- a/src/web/source.rs +++ b/src/web/source.rs @@ -56,7 +56,9 @@ impl FileList { releases.target_name, releases.rustdoc_status, releases.files, - releases.default_target + releases.default_target, + releases.doc_targets, + releases.yanked FROM releases LEFT OUTER JOIN crates ON crates.id = releases.crate_id WHERE crates.name = $1 AND releases.version = $2", @@ -133,6 +135,8 @@ impl FileList { target_name: rows[0].get(3), rustdoc_status: rows[0].get(4), default_target: rows[0].get(6), + doc_targets: MetaData::parse_doc_targets(rows[0].get(7)), + yanked: rows[0].get(8), }, files: file_list, }) diff --git a/templates/base.html b/templates/base.html index a8a61d433..498035470 100644 --- a/templates/base.html +++ b/templates/base.html @@ -24,7 +24,9 @@ - {%- include "header/topbar.html" -%} + {%- block topbar -%} + {%- include "header/topbar.html" -%} + {%- endblock topbar -%} {%- block header %}{% endblock header -%} diff --git a/templates/crate/builds.html b/templates/crate/builds.html index 47d5520fd..e3b011df2 100644 --- a/templates/crate/builds.html +++ b/templates/crate/builds.html @@ -5,6 +5,16 @@ {{ macros::doc_title(name=metadata.name, version=metadata.version) }} {%- endblock title -%} +{%- block topbar -%} + {%- set latest_version = "" -%} + {%- set latest_path = "" -%} + {%- set target = "" -%} + {%- set inner_path = metadata.target_name ~ "/index.html" -%} + {%- set is_latest_version = true -%} + {%- set is_prerelease = false -%} + {%- include "rustdoc/topbar.html" -%} +{%- endblock topbar -%} + {%- block header -%} {{ navigation::package_navigation(metadata=metadata, active_tab="builds") }} {%- endblock header -%} diff --git a/templates/crate/details.html b/templates/crate/details.html index b3a3639ad..b1d8a0f83 100644 --- a/templates/crate/details.html +++ b/templates/crate/details.html @@ -5,6 +5,17 @@ {{ macros::doc_title(name=details.name, version=details.version) }} {%- endblock title -%} +{%- block topbar -%} + {%- set metadata = details.metadata -%} + {%- set latest_version = "" -%} + {%- set latest_path = "" -%} + {%- set target = "" -%} + {%- set inner_path = details.metadata.target_name ~ "/index.html" -%} + {%- set is_latest_version = true -%} + {%- set is_prerelease = false -%} + {%- include "rustdoc/topbar.html" -%} +{%- endblock topbar -%} + {%- block header -%} {# Set the active tab to the `crate` tab #} {{ navigation::package_navigation(metadata=details.metadata, active_tab="crate") }} diff --git a/templates/crate/source.html b/templates/crate/source.html index cf5c32bb0..4312e924d 100644 --- a/templates/crate/source.html +++ b/templates/crate/source.html @@ -5,6 +5,17 @@ {{ macros::doc_title(name=file_list.metadata.name, version=file_list.metadata.version) }} {%- endblock title -%} +{%- block topbar -%} + {%- set metadata = file_list.metadata -%} + {%- set latest_version = "" -%} + {%- set latest_path = "" -%} + {%- set target = "" -%} + {%- set inner_path = metadata.target_name ~ "/index.html" -%} + {%- set is_latest_version = true -%} + {%- set is_prerelease = false -%} + {%- include "rustdoc/topbar.html" -%} +{%- endblock topbar -%} + {%- block header -%} {# Set the active tab to the `source` tab #} {{ navigation::package_navigation(metadata=file_list.metadata, active_tab="source") }} diff --git a/templates/header/topbar.html b/templates/header/topbar.html index 4092f5962..5b1d42f83 100644 --- a/templates/header/topbar.html +++ b/templates/header/topbar.html @@ -1,104 +1,2 @@ -{# - This is the unchanging top bar that is on every single page. - The only piece of context it can take is `search_query`, which should - be a string and will populate the search field if it exists -#} - +{%- include "header/topbar_begin.html" -%} +{%- include "header/topbar_end.html" -%} diff --git a/templates/header/topbar_begin.html b/templates/header/topbar_begin.html new file mode 100644 index 000000000..b6b67303b --- /dev/null +++ b/templates/header/topbar_begin.html @@ -0,0 +1,106 @@ +{# + This is the unchanging top bar that is on every single page. + The only piece of context it can take is `search_query`, which should + be a string and will populate the search field if it exists +#} + +{%- import "macros.html" as macros -%} + + diff --git a/templates/rustdoc/header.html b/templates/rustdoc/header.html deleted file mode 100644 index bcbc49975..000000000 --- a/templates/rustdoc/header.html +++ /dev/null @@ -1,242 +0,0 @@ -{%- import "macros.html" as macros -%} - -{# The url of the current release, `/crate/:name/:version` #} -{%- set crate_url = "/crate/" ~ krate.name ~ "/" ~ krate.version -%} - - diff --git a/templates/rustdoc/topbar.html b/templates/rustdoc/topbar.html new file mode 100644 index 000000000..f7c44dea1 --- /dev/null +++ b/templates/rustdoc/topbar.html @@ -0,0 +1,232 @@ +{%- import "macros.html" as macros -%} + +{# The url of the current release, `/crate/:name/:version` #} +{%- set crate_url = "/crate/" ~ metadata.name ~ "/" ~ metadata.version -%} + +{%- include "header/topbar_begin.html" -%} + + + +{%- include "header/topbar_end.html" -%} diff --git a/templates/style/_navbar.scss b/templates/style/_navbar.scss index f103237b4..4aac81344 100644 --- a/templates/style/_navbar.scss +++ b/templates/style/_navbar.scss @@ -30,6 +30,10 @@ div.nav-container { } } + .pure-menu-right { + float: right; + } + form.landing-search-form-nav { max-width: 1200px; @@ -98,50 +102,74 @@ div.nav-container { } } - div.rustdoc-navigation { - span.title { - display: none; + // use a .title span inside a menu to hide it on small screens + span.title { + display: none; + @media #{$media-sm} { + display: inline; + } + } + + // Make menu item optional and disappear on small screens + .pure-menu-opt { + display: none; + @media #{$media-sm} { + display: inline-block; + } + } + // Make children of menu optional and disappear on small screens + .pure-menu-opt-children { + > .pure-menu-link::after { + display: none; @media #{$media-sm} { display: inline; } } - div.package-details-menu { - width: 350px; + &.pure-menu-allow-hover:hover > .pure-menu-children, + &.pure-menu-active > .pure-menu-children { + display: none; + @media #{$media-sm} { + display: block; + } + } + } - p.description { - font-family: $font-family-sans; - font-size: 0.8em; - color: #777; // color from pure - padding: 0.5em 1em; - margin: 0; - } + div.package-details-menu { + width: 350px; - ul.pure-menu-list { - width: 100%; - } + p.description { + font-family: $font-family-sans; + font-size: 0.8em; + color: #777; // color from pure + padding: 0.5em 1em; + margin: 0; + } - div.right-border { - border-right: 1px solid $color-border; - } + ul.pure-menu-list { + width: 100%; + } - a.pure-menu-link { - word-wrap: normal; - white-space: normal; - } + div.right-border { + border-right: 1px solid $color-border; + } + + a.pure-menu-link { + word-wrap: normal; + white-space: normal; + } - div.sub-menu { - max-height: 150px; - overflow-y: auto; + div.sub-menu { + max-height: 150px; + overflow-y: auto; - ul.pure-menu-list { - border-top: none; - } + ul.pure-menu-list { + border-top: none; + } - li.pure-menu-item:last-child { - border-bottom: none; - } + li.pure-menu-item:last-child { + border-bottom: none; } } }