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
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 | ||
| 380 | 380 | h2 class="mb-2 text-[13px] font-semibold" { "Languages" } |
| 381 | 381 | div class="box mb-5 grid items-center gap-4 p-3 sm:grid-cols-[minmax(0,400px)_1fr]" { |
| 382 | 382 | 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)) } | |
| 384 | 384 | } |
| 385 | 385 | } |
| 386 | 386 | 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 { | ||
| 127 | 127 | } |
| 128 | 128 | } |
| 129 | 129 | |
| 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 | + | |
| 130 | 163 | /// Spider chart of a language mix: one axis per language (largest first, |
| 131 | 164 | /// clockwise from the top). Shares sit on a log scale (0.05% at the centre, |
| 132 | 165 | /// the largest share at the rim): language mixes are lopsided, and on a |