Signed by hannaSSH key fingerprint: SHA256:4g9cWhkAAw8gwqhJUcVbSnGEvdGwklW+1Aa/fMUu59k
crates/web/src/repo.rs +61 −37
| @@ -806,43 +806,8 @@ async fn repo_home( | |||
| 806 | 806 | let body = match resolved { | |
| 807 | 807 | Err(_) => empty_repo_body(state, &ctx), | |
| 808 | 808 | Ok(rev) => { | |
| 809 | - | let entries = git_read(state, &ctx.repo.id, { | |
| 810 | - | let rev = rev.clone(); | |
| 811 | - | move |repo| repo.tree_entries(&rev, FsPath::new("")) | |
| 812 | - | }) | |
| 813 | - | .await?; | |
| 814 | - | let readme = load_readme(state, &ctx.repo.id, &rev, &entries).await; | |
| 815 | - | let annotations = git_read(state, &ctx.repo.id, { | |
| 816 | - | let rev = rev.clone(); | |
| 817 | - | move |repo| repo.tree_annotations(&rev, FsPath::new("")) | |
| 818 | - | }) | |
| 819 | - | .await | |
| 820 | - | .unwrap_or_default(); | |
| 821 | 809 | let branches = branch_names(state, &ctx.repo.id).await; | |
| 822 | - | // The language breakdown of the default branch (best-effort). | |
| 823 | - | let langs = git_read(state, &ctx.repo.id, { | |
| 824 | - | let rev = rev.clone(); | |
| 825 | - | move |repo| repo.blob_sizes(&rev) | |
| 826 | - | }) | |
| 827 | - | .await | |
| 828 | - | .map(|files| crate::languages::breakdown(&files)) | |
| 829 | - | .unwrap_or_default(); | |
| 830 | - | let base = format!("/{}/{}", ctx.owner.username, ctx.repo.path); | |
| 831 | - | html! { | |
| 832 | - | (repo_header(state, &ctx, Tab::Code, &rev_name, &branches)) | |
| 833 | - | form class="search-row repo-codesearch" method="get" action=(format!("{base}/-/search")) { | |
| 834 | - | input type="search" name="q" placeholder="Search this repository…" | |
| 835 | - | aria-label="Search this repository"; | |
| 836 | - | button class="btn" type="submit" { (icon(Icon::Search)) span { "Search" } } | |
| 837 | - | } | |
| 838 | - | @if !langs.is_empty() { | |
| 839 | - | (language_bar(&langs)) | |
| 840 | - | } | |
| 841 | - | (tree_table(&ctx.owner.username, &ctx.repo.path, &rev_name, "", &entries, &annotations)) | |
| 842 | - | @if let Some(rendered) = readme { | |
| 843 | - | div class="card markdown readme" { (rendered) } | |
| 844 | - | } | |
| 845 | - | } | |
| 810 | + | landing_body(state, &ctx, &rev_name, &rev, &branches).await? | |
| 846 | 811 | } | |
| 847 | 812 | }; | |
| 848 | 813 | ||
| @@ -851,6 +816,55 @@ async fn repo_home( | |||
| 851 | 816 | Ok((jar, page(&chrome, &title, body)).into_response()) | |
| 852 | 817 | } | |
| 853 | 818 | ||
| 819 | + | /// The rich repository landing for a resolved ref: search box, language bar, the | |
| 820 | + | /// root tree, and the README. Shared by the repo home (default branch) and the | |
| 821 | + | /// root tree view, so selecting a branch or tag in the ref switcher lands on the | |
| 822 | + | /// same page for that ref rather than a bare file list. | |
| 823 | + | async fn landing_body( | |
| 824 | + | state: &AppState, | |
| 825 | + | ctx: &RepoCtx, | |
| 826 | + | rev_name: &str, | |
| 827 | + | rev: &git::Resolved, | |
| 828 | + | branches: &[String], | |
| 829 | + | ) -> AppResult<Markup> { | |
| 830 | + | let entries = git_read(state, &ctx.repo.id, { | |
| 831 | + | let rev = rev.clone(); | |
| 832 | + | move |repo| repo.tree_entries(&rev, FsPath::new("")) | |
| 833 | + | }) | |
| 834 | + | .await?; | |
| 835 | + | let readme = load_readme(state, &ctx.repo.id, rev, &entries).await; | |
| 836 | + | let annotations = git_read(state, &ctx.repo.id, { | |
| 837 | + | let rev = rev.clone(); | |
| 838 | + | move |repo| repo.tree_annotations(&rev, FsPath::new("")) | |
| 839 | + | }) | |
| 840 | + | .await | |
| 841 | + | .unwrap_or_default(); | |
| 842 | + | // The language breakdown of this ref (best-effort). | |
| 843 | + | let langs = git_read(state, &ctx.repo.id, { | |
| 844 | + | let rev = rev.clone(); | |
| 845 | + | move |repo| repo.blob_sizes(&rev) | |
| 846 | + | }) | |
| 847 | + | .await | |
| 848 | + | .map(|files| crate::languages::breakdown(&files)) | |
| 849 | + | .unwrap_or_default(); | |
| 850 | + | let base = format!("/{}/{}", ctx.owner.username, ctx.repo.path); | |
| 851 | + | Ok(html! { | |
| 852 | + | (repo_header(state, ctx, Tab::Code, rev_name, branches)) | |
| 853 | + | form class="search-row repo-codesearch" method="get" action=(format!("{base}/-/search")) { | |
| 854 | + | input type="search" name="q" placeholder="Search this repository…" | |
| 855 | + | aria-label="Search this repository"; | |
| 856 | + | button class="btn" type="submit" { (icon(Icon::Search)) span { "Search" } } | |
| 857 | + | } | |
| 858 | + | @if !langs.is_empty() { | |
| 859 | + | (language_bar(&langs)) | |
| 860 | + | } | |
| 861 | + | (tree_table(&ctx.owner.username, &ctx.repo.path, rev_name, "", &entries, &annotations)) | |
| 862 | + | @if let Some(rendered) = readme { | |
| 863 | + | div class="card markdown readme" { (rendered) } | |
| 864 | + | } | |
| 865 | + | }) | |
| 866 | + | } | |
| 867 | + | ||
| 854 | 868 | /// Find and render the first matching README in the root tree. | |
| 855 | 869 | async fn load_readme( | |
| 856 | 870 | state: &AppState, | |
| @@ -909,6 +923,17 @@ async fn tree_view( | |||
| 909 | 923 | move |repo| repo.resolve_ref(&rev_name) | |
| 910 | 924 | }) | |
| 911 | 925 | .await?; | |
| 926 | + | let branches = branch_names(state, &ctx.repo.id).await; | |
| 927 | + | ||
| 928 | + | // At the repo root, render the full landing (search, language bar, README) | |
| 929 | + | // for this ref, so switching to a tag/branch mirrors the home page. | |
| 930 | + | if path.is_empty() { | |
| 931 | + | let body = landing_body(state, &ctx, &rev_name, &rev, &branches).await?; | |
| 932 | + | let (jar, chrome) = build_chrome(state, jar, viewer, uri.path().to_string()); | |
| 933 | + | let title = format!("{}/{}", ctx.owner.username, ctx.repo.path); | |
| 934 | + | return Ok((jar, page(&chrome, &title, body)).into_response()); | |
| 935 | + | } | |
| 936 | + | ||
| 912 | 937 | let entries = git_read(state, &ctx.repo.id, { | |
| 913 | 938 | let rev = rev.clone(); | |
| 914 | 939 | let path = path.clone(); | |
| @@ -923,7 +948,6 @@ async fn tree_view( | |||
| 923 | 948 | .await | |
| 924 | 949 | .unwrap_or_default(); | |
| 925 | 950 | ||
| 926 | - | let branches = branch_names(state, &ctx.repo.id).await; | |
| 927 | 951 | let body = html! { | |
| 928 | 952 | (repo_header(state, &ctx, Tab::Code, &rev_name, &branches)) | |
| 929 | 953 | (breadcrumb(&ctx.owner.username, &ctx.repo.path, &rev_name, &path)) | |