fabrica

hanna/fabrica

refactor(web): drop section headers that duplicate the active tab

571457d · hanna committed on 2026-07-25

Remove the Commits/Branches/Tags headings on repo views and the
listing/user-card titles on Explore — the active tab already labels the
section. repo_card now omits its heading when given an empty title, keeping
the profile and dashboard titles intact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed by hannaSSH key fingerprint: SHA256:4g9cWhkAAw8gwqhJUcVbSnGEvdGwklW+1Aa/fMUu59k
3 files changed · +2 −7UnifiedSplit
crates/web/src/pages.rs +1 −2
@@ -153,7 +153,7 @@ async fn explore_repos_body(state: &AppState, q: &str) -> AppResult<Markup> {
153 aria-label="Search repositories";153 aria-label="Search repositories";
154 button class="btn btn-primary" type="submit" { "Search" }154 button class="btn btn-primary" type="submit" { "Search" }
155 }155 }
156 (repo_card("Public repositories", "No public repositories.", &entries))156 (repo_card("", "No public repositories.", &entries))
157 })157 })
158}158}
159159
@@ -189,7 +189,6 @@ async fn explore_users_body(state: &AppState, q: &str) -> AppResult<Markup> {
189fn user_card(users: &[User]) -> Markup {189fn user_card(users: &[User]) -> Markup {
190 html! {190 html! {
191 section class="listing" {191 section class="listing" {
192 h2 { "Users" }
193 @if users.is_empty() {192 @if users.is_empty() {
194 div class="card" { p class="muted" { "No users." } }193 div class="card" { p class="muted" { "No users." } }
195 } @else {194 } @else {
crates/web/src/repo.rs +1 −4
@@ -635,7 +635,6 @@ async fn branches_view(
635 let now = crate::now_ms();635 let now = crate::now_ms();
636 let body = html! {636 let body = html! {
637 (repo_header(state, &ctx, Tab::Branches, &ctx.repo.default_branch, &branch_list))637 (repo_header(state, &ctx, Tab::Branches, &ctx.repo.default_branch, &branch_list))
638 h2 { "Branches" }
639 ul class="entry-list card" {638 ul class="entry-list card" {
640 @for b in &branches {639 @for b in &branches {
641 li class="entry-row" {640 li class="entry-row" {
@@ -681,7 +680,6 @@ async fn tags_view(
681 let base = format!("/{}/{}", ctx.owner.username, ctx.repo.path);680 let base = format!("/{}/{}", ctx.owner.username, ctx.repo.path);
682 let body = html! {681 let body = html! {
683 (repo_header(state, &ctx, Tab::Tags, &ctx.repo.default_branch, &branches))682 (repo_header(state, &ctx, Tab::Tags, &ctx.repo.default_branch, &branches))
684 h2 { "Tags" }
685 @if tags.is_empty() {683 @if tags.is_empty() {
686 div class="card" { p class="muted" { "No tags." } }684 div class="card" { p class="muted" { "No tags." } }
687 } @else {685 } @else {
@@ -762,7 +760,6 @@ async fn commits_view(
762 let branches = branch_names(state, &ctx.repo.id).await;760 let branches = branch_names(state, &ctx.repo.id).await;
763 let body = html! {761 let body = html! {
764 (repo_header(state, &ctx, Tab::Commits, &rev_name, &branches))762 (repo_header(state, &ctx, Tab::Commits, &rev_name, &branches))
765 h2 { "Commits" }
766 ul class="entry-list card" {763 ul class="entry-list card" {
767 @for (commit, sig) in commits.iter().zip(states.iter()) {764 @for (commit, sig) in commits.iter().zip(states.iter()) {
768 @let commit_url = format!("{base}/-/commit/{}", commit.oid);765 @let commit_url = format!("{base}/-/commit/{}", commit.oid);
@@ -1195,7 +1192,7 @@ fn visibility_badge(visibility: model::Visibility) -> Markup {
1195pub(crate) fn repo_card(title: &str, empty: &str, entries: &[RepoEntry]) -> Markup {1192pub(crate) fn repo_card(title: &str, empty: &str, entries: &[RepoEntry]) -> Markup {
1196 html! {1193 html! {
1197 section class="listing" {1194 section class="listing" {
1198 h2 { (title) }1195 @if !title.is_empty() { h2 { (title) } }
1199 @if entries.is_empty() {1196 @if entries.is_empty() {
1200 div class="card" { p class="muted" { (empty) } }1197 div class="card" { p class="muted" { (empty) } }
1201 } @else {1198 } @else {
crates/web/src/tests.rs +0 −1
@@ -314,7 +314,6 @@ async fn explore_lists_public_repos_for_anonymous() {
314 let res = app.oneshot(get("/explore")).await.unwrap();314 let res = app.oneshot(get("/explore")).await.unwrap();
315 assert_eq!(res.status(), StatusCode::OK);315 assert_eq!(res.status(), StatusCode::OK);
316 let html = body_string(res).await;316 let html = body_string(res).await;
317 assert!(html.contains("Public repositories"), "explore heading");
318 assert!(html.contains("ada/open"), "public repo listed");317 assert!(html.contains("ada/open"), "public repo listed");
319 // The Explore sub-nav offers the repositories and users tabs.318 // The Explore sub-nav offers the repositories and users tabs.
320 assert!(html.contains("/explore/users"), "users tab present");319 assert!(html.contains("/explore/users"), "users tab present");