irongit

Git hosting and a container registry in one Rust binary (axum + Astro)

Profile: list every language in the breakdown instead of folding small ones into Other

huncholanehuncholaneauthored
parent 2364aeecommit 4dc24a25c6a3c50234245bb6e794b19e1fe96a87Browse files

2 files changed, +34 -1

+1-1backend/src/web/profile.rs
@@ -380,7 +380,7 @@ async fn user_page(ctx: &Ctx, account: &Account, query: &ProfileQuery) -> AppRes
380380 h2 class="mb-2 text-[13px] font-semibold" { "Languages" }
381381 div class="box mb-5 grid items-center gap-4 p-3 sm:grid-cols-[minmax(0,400px)_1fr]" {
382382 div class="flex justify-center" { (ui::language_radar(&languages)) }
383- div class="min-w-0" { (ui::language_breakdown(&languages)) }
383+ div class="min-w-0" { (ui::language_breakdown_full(&languages)) }
384384 }
385385 }
386386 h2 class="mb-2 text-[13px] font-semibold" { "Activity" }
+33-0backend/src/web/ui.rs
@@ -127,6 +127,39 @@ pub fn language_breakdown(stats: &[crate::languages::LanguageBytes]) -> Markup {
127127 }
128128 }
129129
130+/// Every language of an account with its share, for the profile: the bar
131+/// and a dense legend grid, nothing folded into "Other". Tiny shares keep
132+/// two decimals so they do not all read 0.0%.
133+pub fn language_breakdown_full(stats: &[crate::languages::LanguageBytes]) -> Markup {
134+ let total: u64 = stats.iter().map(|l| l.bytes).sum();
135+ if total == 0 {
136+ return html! {};
137+ }
138+ let rows: Vec<(&str, f64, u64)> = stats.iter().map(|l| (l.name.as_str(), l.bytes as f64 * 100.0 / total as f64, l.bytes)).collect();
139+ let share = |pct: f64| match pct {
140+ p if p >= 0.1 => format!("{p:.1}%"),
141+ p if p >= 0.01 => format!("{p:.2}%"),
142+ _ => "<0.01%".to_string(),
143+ };
144+ html! {
145+ div class="flex h-2 overflow-hidden rounded-[3px] bg-surface-hover" role="img"
146+ aria-label={ @for (i, (name, pct, _)) in rows.iter().enumerate() { @if i > 0 { ", " } (name) " " (share(*pct)) } } {
147+ @for (name, pct, _) in &rows {
148+ span class="h-full" style={ "width:" (format!("{pct:.3}")) "%;background:" (crate::languages::color(name)) } data-tip={ (name) " " (share(*pct)) } {}
149+ }
150+ }
151+ ul class="mt-2 grid grid-cols-2 gap-x-4 gap-y-0.5 text-xs lg:grid-cols-3" {
152+ @for (name, pct, bytes) in &rows {
153+ li class="flex min-w-0 items-center gap-1" data-tip={ (name) ": " (self::bytes(*bytes)) " of code" } {
154+ span class="inline-block h-2.5 w-2.5 shrink-0 rounded-[2px]" style={ "background:" (crate::languages::color(name)) } {}
155+ span class="truncate font-semibold text-ink" { (name) }
156+ span class="ml-auto shrink-0 pl-1 tabular-nums text-ink-dim" { (share(*pct)) }
157+ }
158+ }
159+ }
160+ }
161+}
162+
130163 /// Spider chart of a language mix: one axis per language (largest first,
131164 /// clockwise from the top). Shares sit on a log scale (0.05% at the centre,
132165 /// the largest share at the rim): language mixes are lopsided, and on a