diff --git a/locales/en-US/funding.ftl b/locales/en-US/funding.ftl new file mode 100644 index 000000000..0cfd5b2e5 --- /dev/null +++ b/locales/en-US/funding.ftl @@ -0,0 +1,5 @@ +## Works in conjunction with team data from teams.ftl + +## funding.html.hbs +funding-page-title = Funding +funding-intro = Rust contributors shown on this page can be funded via GitHub Sponsors. Consider sponsoring them if you want to support the development of Rust. diff --git a/src/assets.rs b/src/assets.rs index 8836a66c0..9c327a7dd 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -56,36 +56,44 @@ fn concat_files( files: &[&str], directory: &str, extension: &str, + prefix: &str, ) -> anyhow::Result { let mut concatted = String::new(); for filestem in files { - let vendor_path = root_dir + let file_path = root_dir .join("static") .join(directory) .join(format!("{filestem}.{extension}")); - let contents = fs::read_to_string(vendor_path) - .with_context(|| anyhow::anyhow!("couldn't read vendor {extension}"))?; + let contents = fs::read_to_string(file_path) + .with_context(|| anyhow::anyhow!("couldn't read {prefix} {extension}"))?; concatted.push_str(&contents); } - let file_sha = format!("vendor_{}", hash_string(&concatted)); + let file_sha = format!("{prefix}_{}", hash_string(&concatted)); let out_file_path = out_dir .join("static") .join(directory) .join(format!("{file_sha}.{extension}")); write_file(Path::new(&out_file_path), concatted.as_bytes()) - .with_context(|| anyhow::anyhow!("couldn't write vendor {extension}"))?; + .with_context(|| anyhow::anyhow!("couldn't write {prefix} {extension}"))?; relative_url(&out_file_path, out_dir) } fn concat_vendor_css(root_dir: &Path, out_dir: &Path, files: Vec<&str>) -> anyhow::Result { - concat_files(root_dir, out_dir, &files, "styles", "css") + concat_files(root_dir, out_dir, &files, "styles", "css", "vendor") } -fn concat_app_js(root_dir: &Path, out_dir: &Path, files: Vec<&str>) -> anyhow::Result { - concat_files(root_dir, out_dir, &files, "scripts", "js") +fn build_js_file(root_dir: &Path, out_dir: &Path, file: &str) -> anyhow::Result { + concat_files( + root_dir, + out_dir, + &[file], + "scripts", + "js", + Path::new(file).file_stem().unwrap().to_str().unwrap(), + ) } #[derive(Serialize, Debug)] @@ -97,7 +105,8 @@ pub struct CSSFiles { #[derive(Serialize, Debug)] pub struct JSFiles { - app: String, + tools_install: String, + funding_shuffle: String, } #[derive(Serialize, Debug)] @@ -116,7 +125,8 @@ pub fn compile_assets( let app_css_file = compile_sass(root_dir, out_dir, "app", base_url)?; let fonts_css_file = compile_sass(root_dir, out_dir, "fonts", base_url)?; let vendor_css_file = concat_vendor_css(root_dir, out_dir, vec!["tachyons"])?; - let app_js_file = concat_app_js(root_dir, out_dir, vec!["tools-install"])?; + let tools_install_js = build_js_file(root_dir, out_dir, "tools-install")?; + let funding_shuffle_js = build_js_file(root_dir, out_dir, "funding-shuffle")?; Ok(AssetFiles { css: CSSFiles { @@ -125,7 +135,8 @@ pub fn compile_assets( vendor: format!("{base_url}/{vendor_css_file}"), }, js: JSFiles { - app: format!("{base_url}/{app_js_file}"), + tools_install: format!("{base_url}/{tools_install_js}"), + funding_shuffle: format!("{base_url}/{funding_shuffle_js}"), }, }) } diff --git a/src/main.rs b/src/main.rs index 0605c061f..060fb60f7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use crate::assets::compile_assets; use crate::i18n::{TeamHelper, create_loader}; use crate::redirect::create_redirects; -use crate::render::{RenderCtx, render_directory, render_governance, render_index}; +use crate::render::{RenderCtx, render_directory, render_funding, render_governance, render_index}; use crate::rust_version::fetch_rust_version; use crate::teams::{encode_zulip_stream, load_rust_teams}; use anyhow::Context; @@ -110,8 +110,11 @@ fn main() -> anyhow::Result<()> { ".well-known/security.txt", )?; + let all_team_members = ctx.teams.all_team_members(); + render_index(&ctx)?; - render_governance(&ctx)?; + render_governance(&ctx, &all_team_members)?; + render_funding(&ctx, &all_team_members)?; render_directory(&ctx, "community")?; render_directory(&ctx, "learn")?; render_directory(&ctx, "policies")?; diff --git a/src/render.rs b/src/render.rs index 4c6601dd2..554e9dff0 100644 --- a/src/render.rs +++ b/src/render.rs @@ -2,7 +2,7 @@ use crate::assets::AssetFiles; use crate::fs::{copy_dir_all, ensure_directory}; use crate::i18n::{EXPLICIT_LOCALE_INFO, LocaleInfo, SUPPORTED_LOCALES}; use crate::rust_version::RustVersion; -use crate::teams::{PageData, RustTeamData}; +use crate::teams::{AllTeamMembers, PageData, RustTeamData}; use crate::{BaseUrl, ENGLISH, LAYOUT}; use anyhow::Context; use handlebars::Handlebars; @@ -179,7 +179,10 @@ pub fn render_index(render_ctx: &RenderCtx) -> anyhow::Result<()> { }) } -pub fn render_governance(render_ctx: &RenderCtx) -> anyhow::Result<()> { +pub fn render_governance( + render_ctx: &RenderCtx, + all_team_members: &AllTeamMembers, +) -> anyhow::Result<()> { let data = render_ctx.teams.index_data(); // Index page @@ -226,13 +229,12 @@ pub fn render_governance(render_ctx: &RenderCtx) -> anyhow::Result<()> { })?; // Page with all team members - let all_team_members_data = render_ctx.teams.all_team_members(); for_all_langs("governance/people/index.html", |dst_path, lang| { render_ctx .page( "governance/all-team-members", "governance-all-team-members-title", - &all_team_members_data, + all_team_members, lang, ) .render(dst_path) @@ -263,6 +265,22 @@ pub fn render_governance(render_ctx: &RenderCtx) -> anyhow::Result<()> { Ok(()) } +pub fn render_funding( + render_ctx: &RenderCtx, + all_team_members: &AllTeamMembers, +) -> anyhow::Result<()> { + let data = render_ctx.teams.funding_data(all_team_members); + + // Index page + for_all_langs("funding/index.html", |dst_path, lang| { + render_ctx + .page("funding", "funding-page-title", &data, lang) + .render(dst_path) + })?; + + Ok(()) +} + /// Render all templates found in the given directory. pub fn render_directory(render_ctx: &RenderCtx, category: &str) -> anyhow::Result<()> { for dir in std::fs::read_dir(render_ctx.template_dir.join(category))? { diff --git a/src/teams.rs b/src/teams.rs index 16b66003b..00af52bc5 100644 --- a/src/teams.rs +++ b/src/teams.rs @@ -346,6 +346,27 @@ impl RustTeamData { people } + pub fn funding_data(&self, all_team_members: &AllTeamMembers) -> FundingData { + let people_with_sponsors = all_team_members + .active + .iter() + .filter_map(|member| { + let person = self.people.get(&member.github)?; + if person.github_sponsors { + Some(FundablePerson { + name: member.name.clone(), + github: member.github.to_string(), + }) + } else { + None + } + }) + .collect(); + FundingData { + people: people_with_sponsors, + } + } + fn get_toplevel_team_url<'a>(&'a self, mut team: &'a Team) -> Option { while !is_toplevel_team(team) { let Some(parent) = &team.subteam_of else { @@ -476,6 +497,17 @@ pub struct PersonData { alumni_teams: Vec, } +#[derive(Serialize)] +pub struct FundablePerson { + name: String, + github: String, +} + +#[derive(Serialize)] +pub struct FundingData { + people: Vec, +} + pub fn load_rust_teams() -> anyhow::Result { println!("Downloading Team API data"); diff --git a/static/scripts/funding-shuffle.js b/static/scripts/funding-shuffle.js new file mode 100644 index 000000000..09d9954b9 --- /dev/null +++ b/static/scripts/funding-shuffle.js @@ -0,0 +1,23 @@ +// From https://stackoverflow.com/a/2450976/1107768 +function shuffle(array) { + let currentIndex = array.length; + + // While there remain elements to shuffle... + while (currentIndex !== 0) { + // Pick a remaining element... + let randomIndex = Math.floor(Math.random() * currentIndex); + currentIndex--; + + // And swap it with the current element. + [array[currentIndex], array[randomIndex]] = [ + array[randomIndex], array[currentIndex]]; + } +} + +document.addEventListener("DOMContentLoaded", () => { + // Shuffle people to reduce ordering bias + const wrapper = document.querySelector("#people"); + const children = Array(...wrapper.children); + shuffle(children); + wrapper.replaceChildren(...children); +}); diff --git a/templates/components/tools/rustup.html.hbs b/templates/components/tools/rustup.html.hbs index d1f5660d5..fc7e909b1 100644 --- a/templates/components/tools/rustup.html.hbs +++ b/templates/components/tools/rustup.html.hbs @@ -38,4 +38,4 @@ - + diff --git a/templates/funding.html.hbs b/templates/funding.html.hbs new file mode 100644 index 000000000..62d9a9e84 --- /dev/null +++ b/templates/funding.html.hbs @@ -0,0 +1,32 @@ +{{#*inline "member"}} + +{{/inline}} + +{{#*inline "page"}} +
+
+

{{fluent "funding-intro"}}

+
+
+ +
+
+ {{#each data.people as |member|}} + {{> member member=member baseurl=../baseurl }} + {{/each}} +
+ +
+{{/inline}} + +{{~> (lookup this "parent")~}} diff --git a/templates/governance/all-team-members.html.hbs b/templates/governance/all-team-members.html.hbs index 2aec52cf8..6f4f0d4d2 100644 --- a/templates/governance/all-team-members.html.hbs +++ b/templates/governance/all-team-members.html.hbs @@ -20,6 +20,9 @@

{{#fluent "governance-all-team-members-intro"}}{{#fluentparam "count"}}{{len data.active}}{{/fluentparam}}{{/fluent}}

+