michal/tit
Browse tree · Show commit · Download archive
Diff
0007deff399f → ffbc13328b68
assets/style.css
Mode 100644 → 100644; object 95b436f4dc02 → 6591942e96a5
@@ -60,6 +60,43 @@
margin-block: 0.5rem;
}
+.repository-toolbar {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 0.5rem 1rem;
+ margin-block: 1.5rem;
+ padding: 0.75rem 1rem;
+ border: 1px solid GrayText;
+ border-radius: 0.25rem;
+}
+
+.repository-summary-layout {
+ display: grid;
+ grid-template-columns: minmax(0, 2fr) minmax(14rem, 1fr);
+ gap: 2rem;
+ align-items: start;
+}
+
+.repository-summary-main > section,
+.repository-sidebar > section {
+ margin-bottom: 2rem;
+}
+
+.repository-sidebar > section {
+ padding: 1rem;
+ border: 1px solid GrayText;
+ border-radius: 0.25rem;
+}
+
+.repository-sidebar h2 {
+ margin-top: 0;
+}
+
+.repository-file-list th:first-child {
+ width: 100%;
+}
+
.site-header nav,
.repository-header nav {
display: flex;
@@ -208,7 +245,8 @@
}
@media (max-width: 44rem) {
- .two-column {
+ .two-column,
+ .repository-summary-layout {
grid-template-columns: 1fr;
}
}
src/http/public.rs
Mode 100644 → 100644; object 8b99179356ac → 55bf5641ed98
@@ -436,20 +436,25 @@
.iter()
.find(|reference| reference.name == default_branch.as_bytes())
.map(|reference| reference.target);
- let (history, readme) = match head {
+ let (history, readme, entries) = match head {
Some(head) => (
service.history(head, &cancellation)?,
service.readme(head, &cancellation)?,
+ service.tree(head, &[], &cancellation)?,
),
- None => (Vec::new(), None),
+ None => (Vec::new(), None, Vec::new()),
};
Ok(RepositoryPage::summary(
record,
- description,
- clone_urls,
- head,
- history,
- readme.map(|readme| (readme.path, readme.blob.data)),
+ RepositorySummary {
+ description,
+ clone_urls,
+ default_branch,
+ head,
+ history,
+ readme: readme.map(|readme| (readme.path, readme.blob.data)),
+ entries,
+ },
))
},
)
@@ -1381,6 +1386,7 @@
encoded_path: String,
http_clone_url: String,
ssh_clone_url: String,
+ default_branch: String,
has_head: bool,
has_readme: bool,
readme_path: String,
@@ -1408,6 +1414,16 @@
next_page: usize,
}
+struct RepositorySummary {
+ description: String,
+ clone_urls: (String, String),
+ default_branch: String,
+ head: Option<ObjectId>,
+ history: Vec<CommitInfo>,
+ readme: Option<(Vec<u8>, Vec<u8>)>,
+ entries: Vec<TreeEntryInfo>,
+}
+
impl RepositoryPage {
fn base(record: RepositoryRecord, page_kind: &'static str, title: String) -> Self {
Self {
@@ -1425,6 +1441,7 @@
encoded_path: String::new(),
http_clone_url: String::new(),
ssh_clone_url: String::new(),
+ default_branch: String::new(),
has_head: false,
has_readme: false,
readme_path: String::new(),
@@ -1453,27 +1470,33 @@
}
}
- fn summary(
- record: RepositoryRecord,
- description: String,
- clone_urls: (String, String),
- head: Option<ObjectId>,
- history: Vec<CommitInfo>,
- readme: Option<(Vec<u8>, Vec<u8>)>,
- ) -> Self {
+ fn summary(record: RepositoryRecord, summary: RepositorySummary) -> Self {
let title = format!("{}/{}", record.owner, record.slug);
let mut page = Self::base(record, "summary", title);
- page.description = description;
- page.http_clone_url = clone_urls.0;
- page.ssh_clone_url = clone_urls.1;
- page.has_head = head.is_some();
- page.commit_id = head.map(|id| id.to_string()).unwrap_or_default();
- page.history = history
+ page.description = summary.description;
+ page.http_clone_url = summary.clone_urls.0;
+ page.ssh_clone_url = summary.clone_urls.1;
+ page.default_branch = summary
+ .default_branch
+ .strip_prefix("refs/heads/")
+ .unwrap_or(&summary.default_branch)
+ .to_owned();
+ page.has_head = summary.head.is_some();
+ page.commit_id = summary.head.map(|id| id.to_string()).unwrap_or_default();
+ page.history = summary
+ .history
.into_iter()
.take(MAX_SUMMARY_COMMITS)
.map(CommitView::from)
.collect();
- if let Some((path, data)) = readme {
+ if let Some(head) = summary.head {
+ page.entries = summary
+ .entries
+ .into_iter()
+ .map(|entry| TreeView::new(head, &[], entry))
+ .collect();
+ }
+ if let Some((path, data)) = summary.readme {
page.has_readme = true;
page.readme_path = display_bytes(&path);
if let Ok(content) = std::str::from_utf8(&data)
templates/repository.html
Mode 100644 → 100644; object 6e9095acc965 → 525b73c4631b
@@ -6,23 +6,37 @@
{% include "repository-nav.html" %}
</header>
-{% if has_head %}
+{% if has_head && page_kind != "summary" %}
<p><a href="/{{ owner }}/{{ repository }}/tree/{{ commit_id }}">Browse tree</a> · <a href="/{{ owner }}/{{ repository }}/commit/{{ commit_id }}">Show commit</a> · <a href="/{{ owner }}/{{ repository }}/archive/{{ commit_id }}.tar">Download archive</a></p>
{% endif %}
{% if page_kind == "summary" %}
-{% if description != "" %}
- <p class="repository-description">{{ description }}</p>
-{% endif %}
- <section aria-labelledby="clone-heading">
- <h2 id="clone-heading">Clone</h2>
- <dl>
- <dt>HTTP</dt><dd><code>{{ http_clone_url }}</code></dd>
- <dt>SSH</dt><dd><code>{{ ssh_clone_url }}</code></dd>
- <dt>Created</dt><dd><time datetime="{{ created_at }}">{{ created_at|human_time }}</time></dd>
- </dl>
- </section>
{% if has_head %}
+ <nav class="repository-toolbar" aria-label="Repository files">
+ <strong>{{ default_branch }}</strong>
+ <a href="/{{ owner }}/{{ repository }}/tree/{{ commit_id }}">Browse files</a>
+ <a href="/{{ owner }}/{{ repository }}/commit/{{ commit_id }}"><code title="{{ commit_id }}">{{ commit_id|short_id }}</code></a>
+ <a href="/{{ owner }}/{{ repository }}/archive/{{ commit_id }}.tar">Download archive</a>
+ </nav>
+{% endif %}
+ <div class="repository-summary-layout">
+ <div class="repository-summary-main">
+{% if has_head %}
+ <section aria-labelledby="files-heading">
+ <h2 id="files-heading">Files</h2>
+ <div class="table-scroll"><table class="repository-file-list">
+ <thead><tr><th scope="col">Name</th><th scope="col">Type</th><th scope="col">Object</th></tr></thead>
+ <tbody>
+{% for item in entries %}
+ <tr>
+ <th scope="row"><a href="/{{ owner }}/{{ repository }}/{{ item.href }}">{{ item.name }}</a></th>
+ <td>{{ item.kind }}</td>
+ <td><code title="{{ item.id }}">{{ item.id|short_id }}</code></td>
+ </tr>
+{% endfor %}
+ </tbody>
+ </table></div>
+ </section>
<section aria-labelledby="history-heading">
<h2 id="history-heading">Recent commits</h2>
<ol class="commit-list">
@@ -45,6 +59,26 @@
{% else %}
<p>This repository has no commits.</p>
{% endif %}
+ </div>
+ <aside class="repository-sidebar" aria-label="Repository information">
+ <section aria-labelledby="about-heading">
+ <h2 id="about-heading">About</h2>
+{% if description != "" %}
+ <p class="repository-description">{{ description }}</p>
+{% else %}
+ <p>No description is available.</p>
+{% endif %}
+ <p>Created <time datetime="{{ created_at }}">{{ created_at|human_time }}</time></p>
+ </section>
+ <section aria-labelledby="clone-heading">
+ <h2 id="clone-heading">Clone</h2>
+ <dl>
+ <dt>HTTP</dt><dd><code>{{ http_clone_url }}</code></dd>
+ <dt>SSH</dt><dd><code>{{ ssh_clone_url }}</code></dd>
+ </dl>
+ </section>
+ </aside>
+ </div>
{% endif %}
{% if page_kind == "commits" %}
tests/public_routes.rs
Mode 100644 → 100644; object 519c6052128a → 2205df793b20
@@ -115,6 +115,16 @@
assert!(summary_text.contains("https://tit.example/alice/example"));
assert!(summary_text.contains("ssh://tit.example:2222/alice/example"));
assert!(summary_text.contains(&fixture.head));
+ assert!(summary_text.contains("<div class=\"repository-summary-layout\">"));
+ assert!(summary_text.contains("<strong>main</strong>"));
+ assert!(summary_text.contains(&format!(
+ "href=\"/alice/example/blob/{}/README.md\"",
+ fixture.head
+ )));
+ assert!(summary_text.contains(&format!(
+ "href=\"/alice/example/tree/{}/nested\"",
+ fixture.head
+ )));
assert!(summary_text.contains("README.md"));
assert!(summary_text.contains("<h1>tit fixture</h1>"));
assert!(summary_text.contains("<strong>safe</strong>"));