Restructure nav: wordmark, repo link, breadcrumb stack
The style guide separates the `quire` wordmark from the breadcrumb
chain and uses `/` between every crumb. Templates passed `page` as a
single string (sometimes containing `·` separators), which collapsed
distinct levels into one crumb. Replace `page: String` with
`crumbs: Vec<String>`, render the wordmark first, then `repo`, then
each crumb separated by `/`.

Assisted-by: Claude Opus 4.7 via Claude Code
change nsmlykvnxqttrlnvlppzvzvxvokxzpux
commit e54ecdb8e07f27492ecfd8e570d8928f180a4579
author Alpha Chen <alpha@kejadlen.dev>
date
parent uvlxzprp
diff --git a/src/quire/web/handlers.rs b/src/quire/web/handlers.rs
index 70b31c4..59051b3 100644
--- a/src/quire/web/handlers.rs
+++ b/src/quire/web/handlers.rs
@@ -39,7 +39,7 @@ async fn read_log(path: &std::path::Path) -> String {
 fn render_error(repo: String, status: StatusCode, title: &str, detail: String) -> Response {
     let tmpl = ErrorTemplate {
         repo,
-        page: "error".to_string(),
+        crumbs: vec!["error".to_string()],
         title: title.to_string(),
         detail: detail.clone(),
     };
@@ -87,7 +87,7 @@ pub async fn run_list(State(quire): State<Quire>, AxumPath(repo): AxumPath<Strin
 
     let tmpl = RunListTemplate {
         repo: repo_display,
-        page: "ci".to_string(),
+        crumbs: vec!["ci".to_string()],
         runs: template_runs,
     };
     render(&tmpl)
@@ -175,9 +175,10 @@ pub async fn run_detail(
         });
     }
 
+    let crumbs = vec!["ci".to_string(), detail_run.sha_short().to_string()];
     let tmpl = RunDetailTemplate {
         repo: repo_display,
-        page: format!("ci · {}", detail_run.sha_short()),
+        crumbs,
         run: detail_run,
         jobs: detail_jobs,
     };
diff --git a/src/quire/web/templates.rs b/src/quire/web/templates.rs
index b37488e..495e3ca 100644
--- a/src/quire/web/templates.rs
+++ b/src/quire/web/templates.rs
@@ -10,7 +10,7 @@ use super::format;
 #[template(path = "ci/run_list.html")]
 pub struct RunListTemplate {
     pub repo: String,
-    pub page: String,
+    pub crumbs: Vec<String>,
     pub runs: Vec<RunListRow>,
 }
 
@@ -60,7 +60,7 @@ impl RunListRow {
 #[template(path = "ci/run_detail.html")]
 pub struct RunDetailTemplate {
     pub repo: String,
-    pub page: String,
+    pub crumbs: Vec<String>,
     pub run: DetailRun,
     pub jobs: Vec<DetailJob>,
 }
@@ -194,7 +194,7 @@ impl DetailShEvent {
 #[template(path = "error.html")]
 pub struct ErrorTemplate {
     pub repo: String,
-    pub page: String,
+    pub crumbs: Vec<String>,
     pub title: String,
     pub detail: String,
 }
diff --git a/templates/_css.html b/templates/_css.html
index fa8d6c4..cb4ba99 100644
--- a/templates/_css.html
+++ b/templates/_css.html
@@ -39,9 +39,11 @@ pre { white-space: pre-wrap; word-break: break-word; }
   align-items: center;
 }
 
-.page-nav .breadcrumbs .sep { color: var(--rule2); }
-.page-nav .crumb-muted { color: var(--muted); }
-.page-nav .crumb-faint { color: var(--mutedFaint); }
+.page-nav .nav-bar { display: flex; align-items: center; gap: 6px; }
+.page-nav .nav-wordmark,
+.page-nav .nav-repo { color: var(--ink); text-decoration: none; }
+.page-nav .nav-crumb { color: var(--muted); }
+.page-nav .sep { color: var(--rule2); }
 .page-nav .shortcuts { font-size: 11px; color: var(--mutedFaint); }
 
 .page-main { padding: 22px 56px 32px; }
diff --git a/templates/_nav.html b/templates/_nav.html
index b38391b..e672171 100644
--- a/templates/_nav.html
+++ b/templates/_nav.html
@@ -1,10 +1,12 @@
 <nav class="page-nav">
-  <div class="breadcrumbs">
-    <span class="crumb-faint">quire</span>
+  <div class="nav-bar">
+    <a class="nav-wordmark" href="/">quire</a>
     <span class="sep">/</span>
-    <span>{{ repo }}</span>
+    <a class="nav-repo" href="/{{ repo }}/ci">{{ repo }}</a>
+    {% for crumb in crumbs %}
     <span class="sep">/</span>
-    <span class="crumb-muted">{{ page }}</span>
+    <span class="nav-crumb">{{ crumb }}</span>
+    {% endfor %}
   </div>
   <div class="shortcuts">press [?] for shortcuts</div>
 </nav>