Skip to main content

max / makenotwork

Move the git screens onto Run, and take quasi 0.100 Slot::beside is gone: a row is a Run now, built with Run::new(fallback) and handed to Slot::across whole. The six git screens are the ones that build rows, so they carry the whole of this repo's share of the change.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session
https://claude.ai/code/session_01MptwXZ8k65v19rFmdGAyki
Author: Max Johnson <me@maxj.phd> · 2026-09-03 02:15 UTC
Signed with PGP, not checked
Commit: 027fd1950f52ebac23266e2c87e868b74b741332
Parent: 8cc7e63
7 files changed, +210 insertions, -197 deletions
M server/Cargo.lock +20 -20
@@ -2875,7 +2875,7 @@
2875 2875 checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
2876 2876 dependencies = [
2877 2877 "libc",
2878 - "windows-sys 0.52.0",
2878 + "windows-sys 0.59.0",
2879 2879 ]
2880 2880
2881 2881 [[package]]
@@ -6636,7 +6636,7 @@
6636 6636
6637 6637 [[package]]
6638 6638 name = "quasi-axum"
6639 - version = "0.99.1"
6639 + version = "0.100.0"
6640 6640 dependencies = [
6641 6641 "axum",
6642 6642 "http 1.4.2",
@@ -6647,7 +6647,7 @@
6647 6647
6648 6648 [[package]]
6649 6649 name = "quasi-basics"
6650 - version = "0.99.1"
6650 + version = "0.100.0"
6651 6651 dependencies = [
6652 6652 "makeover-layout",
6653 6653 "quasi-router",
@@ -6655,7 +6655,7 @@
6655 6655
6656 6656 [[package]]
6657 6657 name = "quasi-http"
6658 - version = "0.99.1"
6658 + version = "0.100.0"
6659 6659 dependencies = [
6660 6660 "form_urlencoded",
6661 6661 "http 1.4.2",
@@ -6664,7 +6664,7 @@
6664 6664
6665 6665 [[package]]
6666 6666 name = "quasi-router"
6667 - version = "0.99.1"
6667 + version = "0.100.0"
6668 6668 dependencies = [
6669 6669 "makeover-layout",
6670 6670 ]
@@ -6687,7 +6687,7 @@
6687 6687
6688 6688 [[package]]
6689 6689 name = "quasi-webview"
6690 - version = "0.99.1"
6690 + version = "0.100.0"
6691 6691 dependencies = [
6692 6692 "docengine",
6693 6693 "makeover-layout",
@@ -7339,7 +7339,7 @@
7339 7339 "errno",
7340 7340 "libc",
7341 7341 "linux-raw-sys 0.12.1",
7342 - "windows-sys 0.52.0",
7342 + "windows-sys 0.59.0",
7343 7343 ]
7344 7344
7345 7345 [[package]]
@@ -7419,7 +7419,7 @@
7419 7419 "security-framework 3.7.0",
7420 7420 "security-framework-sys",
7421 7421 "webpki-root-certs",
7422 - "windows-sys 0.52.0",
7422 + "windows-sys 0.59.0",
7423 7423 ]
7424 7424
7425 7425 [[package]]
@@ -8545,7 +8545,7 @@
8545 8545 "getrandom 0.4.3",
8546 8546 "once_cell",
8547 8547 "rustix 1.1.4",
8548 - "windows-sys 0.52.0",
8548 + "windows-sys 0.59.0",
8549 8549 ]
8550 8550
8551 8551 [[package]]
@@ -10761,11 +10761,11 @@
10761 10761
10762 10762 [[patch.unused]]
10763 10763 name = "quasi-immediate"
10764 - version = "0.99.1"
10764 + version = "0.100.0"
10765 10765
10766 10766 [[patch.unused]]
10767 10767 name = "quasi-notifs"
10768 - version = "0.99.1"
10768 + version = "0.100.0"
10769 10769
10770 10770 [[patch.unused]]
10771 10771 name = "quasi-store"
@@ -10773,7 +10773,15 @@
10773 10773
10774 10774 [[patch.unused]]
10775 10775 name = "quasi-tauri"
10776 - version = "0.99.1"
10776 + version = "0.100.0"
10777 +
10778 + [[patch.unused]]
10779 + name = "synckit-client"
10780 + version = "0.10.0"
10781 +
10782 + [[patch.unused]]
10783 + name = "synckit-config"
10784 + version = "0.2.0"
10777 10785
10778 10786 [[patch.unused]]
10779 10787 name = "kberg"
@@ -10786,11 +10794,3 @@
10786 10794 [[patch.unused]]
10787 10795 name = "painhours"
10788 10796 version = "0.1.0"
10789 -
10790 - [[patch.unused]]
10791 - name = "synckit-client"
10792 - version = "0.10.0"
10793 -
10794 - [[patch.unused]]
10795 - name = "synckit-config"
10796 - version = "0.2.0"
@@ -163,7 +163,7 @@
163 163 # through quasi beside its Askama equivalent, so the cost of describing a screen
164 164 # here is measured rather than argued. Not load-bearing for any shipped route.
165 165 # See wiki look-wave-2, tier G.
166 - quasi-router = { git = "https://makenot.work/git/max/quasi.git", version = "0.99" }
166 + quasi-router = { git = "https://makenot.work/git/max/quasi.git", version = "0.100" }
167 167 # The description vocabulary quasi's screen types are built from. Pinned here
168 168 # rather than reached through quasi-router's re-export because a described
169 169 # screen names FieldKind and Tone directly; it has to track what quasi-router
@@ -179,13 +179,13 @@
179 179 # For the request head the per-viewer state factory reads. axum re-exports it,
180 180 # but the factory's signature is quasi-axum's and names `http::request::Parts`.
181 181 http = "1.3.1"
182 - quasi-axum = { git = "https://makenot.work/git/max/quasi.git", version = "0.99" }
183 - quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.99" }
182 + quasi-axum = { git = "https://makenot.work/git/max/quasi.git", version = "0.100" }
183 + quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.100" }
184 184 # The first-party widget set. The carousel was proved here against three pages
185 185 # and then moved there; what is left in `quasi/widgets/carousel.rs` is the
186 186 # Askama glue. Not `makeover-basics`: a widget is an assembly of `Node`s, so it
187 187 # sits above quasi-router rather than inside the description suite.
188 - quasi-basics = { git = "https://makenot.work/git/max/quasi.git", version = "0.99" }
188 + quasi-basics = { git = "https://makenot.work/git/max/quasi.git", version = "0.100" }
189 189
190 190 # Git source browser
191 191 gix = { version = "0.86", default-features = false, features = ["blame", "mailmap", "revision", "sha1", "max-performance-safe"] }
@@ -277,7 +277,7 @@
277 277 # Written from the crate rather than copied into the repo for the reason the
278 278 # constants exist: a stale copy in a static directory is a silently dead bulk
279 279 # bar, and the version has to be the one the emitter agrees with.
280 - quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.99" }
280 + quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.100" }
281 281
282 282 [dev-dependencies]
283 283 tower = { version = "0.5.3", features = ["util"] }
@@ -31,7 +31,7 @@
31 31
32 32 use makeover_layout as layout;
33 33 use quasi_router::screen::{Cell, Cells, Column, Lexeme};
34 - use quasi_router::{Action, Document, Node, RegionKind, Screen, Slot};
34 + use quasi_router::{Action, Document, Node, RegionKind, Run, Screen, Slot};
35 35 use quasi_webview::Webview;
36 36
37 37 use crate::git::{BlameLine, Breadcrumb, RefInfo};
@@ -107,31 +107,32 @@
107 107 };
108 108
109 109 Node::Region(
110 - Slot::new("git-file-header", RegionKind::Group)
111 - .across(layout::Fallback::Wrap)
112 - .beside(Node::text(lines), layout::Priority::Secondary)
113 - .beside(
114 - Node::Link {
115 - text: "Source".to_owned(),
116 - action: Action::get(format!(
117 - "{base}/tree/{}/{}",
118 - view.current_ref, view.file_path
119 - ))
120 - .navigating(),
121 - },
122 - layout::Priority::Essential,
123 - )
124 - .beside(
125 - Node::Link {
126 - text: "Raw".to_owned(),
127 - action: Action::get(format!(
128 - "{base}/raw/{}/{}",
129 - view.current_ref, view.file_path
130 - ))
131 - .navigating(),
132 - },
133 - layout::Priority::Essential,
134 - ),
110 + Slot::new("git-file-header", RegionKind::Group).across(
111 + Run::new(layout::Fallback::Wrap)
112 + .beside(Node::text(lines), layout::Priority::Secondary)
113 + .beside(
114 + Node::Link {
115 + text: "Source".to_owned(),
116 + action: Action::get(format!(
117 + "{base}/tree/{}/{}",
118 + view.current_ref, view.file_path
119 + ))
120 + .navigating(),
121 + },
122 + layout::Priority::Essential,
123 + )
124 + .beside(
125 + Node::Link {
126 + text: "Raw".to_owned(),
127 + action: Action::get(format!(
128 + "{base}/raw/{}/{}",
129 + view.current_ref, view.file_path
130 + ))
131 + .navigating(),
132 + },
133 + layout::Priority::Essential,
134 + ),
135 + ),
135 136 )
136 137 }
137 138
@@ -20,7 +20,7 @@
20 20
21 21 use makeover_layout as layout;
22 22 use quasi_router::screen::{Cell, Cells, Column, Lexeme};
23 - use quasi_router::{Action, Document, Node, RegionKind, Screen, Slot};
23 + use quasi_router::{Action, Document, Node, RegionKind, Run, Screen, Slot};
24 24 use quasi_webview::Webview;
25 25
26 26 use crate::git::{Breadcrumb, RefInfo, TreeItem, TreeItemKind};
@@ -213,9 +213,8 @@
213 213 format!("{} - {count} lines", file.file_size)
214 214 };
215 215
216 - let mut strip = Slot::new("git-file-header", RegionKind::Group)
217 - .across(layout::Fallback::Wrap)
218 - .beside(Node::text(meta), layout::Priority::Secondary);
216 + let mut strip =
217 + Run::new(layout::Fallback::Wrap).beside(Node::text(meta), layout::Priority::Secondary);
219 218
220 219 for (label, route) in [
221 220 (
@@ -240,31 +239,32 @@
240 239 );
241 240 }
242 241
243 - Node::Region(strip)
242 + Node::Region(Slot::new("git-file-header", RegionKind::Group).across(strip))
244 243 }
245 244
246 245 /// A file nothing can usefully draw, and the way to get it anyway.
247 246 fn binary(frame: &Frame<'_>, file: &File<'_>) -> Node {
248 247 Node::Region(
249 - Slot::new("git-binary-notice", RegionKind::Group)
250 - .across(layout::Fallback::Wrap)
251 - .beside(
252 - Node::text(format!("Binary file ({}).", file.file_size)),
253 - layout::Priority::Essential,
254 - )
255 - .beside(
256 - Node::Link {
257 - text: "Download".to_owned(),
258 - action: Action::get(format!(
259 - "{}/raw/{}/{}",
260 - frame.base(),
261 - frame.current_ref,
262 - file.file_path
263 - ))
264 - .navigating(),
265 - },
266 - layout::Priority::Essential,
267 - ),
248 + Slot::new("git-binary-notice", RegionKind::Group).across(
249 + Run::new(layout::Fallback::Wrap)
250 + .beside(
251 + Node::text(format!("Binary file ({}).", file.file_size)),
252 + layout::Priority::Essential,
253 + )
254 + .beside(
255 + Node::Link {
256 + text: "Download".to_owned(),
257 + action: Action::get(format!(
258 + "{}/raw/{}/{}",
259 + frame.base(),
260 + frame.current_ref,
261 + file.file_path
262 + ))
263 + .navigating(),
264 + },
265 + layout::Priority::Essential,
266 + ),
267 + ),
268 268 )
269 269 }
270 270
@@ -35,7 +35,7 @@
35 35
36 36 use makeover_layout as layout;
37 37 use quasi_router::screen::{Cell, Cells, Column, Field, Lexeme, Row};
38 - use quasi_router::{Act, Action, Document, Node, RegionKind, Screen, Slot};
38 + use quasi_router::{Act, Action, Document, Node, RegionKind, Run, Screen, Slot};
39 39 use quasi_webview::Webview;
40 40
41 41 use crate::git::signing::SignatureStatus;
@@ -179,23 +179,22 @@
179 179 // The full id, which is machine text: it is copied into a command far more
180 180 // often than it is read.
181 181 meta = meta.with(Node::Region(
182 - Slot::new("git-commit-oid", RegionKind::Group)
183 - .across(layout::Fallback::Wrap)
184 - .beside(Node::text("Commit:"), layout::Priority::Secondary)
185 - .beside(literal(&detail.oid), layout::Priority::Essential),
182 + Slot::new("git-commit-oid", RegionKind::Group).across(
183 + Run::new(layout::Fallback::Wrap)
184 + .beside(Node::text("Commit:"), layout::Priority::Secondary)
185 + .beside(literal(&detail.oid), layout::Priority::Essential),
186 + ),
186 187 ));
187 188
188 189 if !detail.parents.is_empty() {
189 - let mut parents = Slot::new("git-commit-parents", RegionKind::Group)
190 - .across(layout::Fallback::Wrap)
191 - .beside(
192 - Node::text(if detail.parents.len() == 1 {
193 - "Parent:"
194 - } else {
195 - "Parents:"
196 - }),
197 - layout::Priority::Secondary,
198 - );
190 + let mut parents = Run::new(layout::Fallback::Wrap).beside(
191 + Node::text(if detail.parents.len() == 1 {
192 + "Parent:"
193 + } else {
194 + "Parents:"
195 + }),
196 + layout::Priority::Secondary,
197 + );
199 198 for parent in &detail.parents {
200 199 parents = parents.beside(
201 200 Node::Link {
@@ -206,7 +205,9 @@
206 205 layout::Priority::Essential,
207 206 );
208 207 }
209 - meta = meta.with(Node::Region(parents));
208 + meta = meta.with(Node::Region(
209 + Slot::new("git-commit-parents", RegionKind::Group).across(parents),
210 + ));
210 211 }
211 212
212 213 Node::Region(block.with(Node::Region(meta)))
@@ -238,14 +239,16 @@
238 239 } => Some(Node::Region(
239 240 Slot::new("git-signature", RegionKind::Group)
240 241 .named(format!("Signed by {username}, key {fingerprint}"))
241 - .across(layout::Fallback::Wrap)
242 - .beside(Node::text("Signed by"), layout::Priority::Essential)
243 - .beside(
244 - Node::Link {
245 - text: username.clone(),
246 - action: Action::get(format!("/u/{username}")).navigating(),
247 - },
248 - layout::Priority::Essential,
242 + .across(
243 + Run::new(layout::Fallback::Wrap)
244 + .beside(Node::text("Signed by"), layout::Priority::Essential)
245 + .beside(
246 + Node::Link {
247 + text: username.clone(),
248 + action: Action::get(format!("/u/{username}")).navigating(),
249 + },
250 + layout::Priority::Essential,
251 + ),
249 252 ),
250 253 )),
251 254 SignatureStatus::ValidUnknownKey { .. } => {
@@ -353,14 +356,10 @@
353 356 ));
354 357
355 358 for annotation in view.personal_annotations {
356 - let mut header = Slot::new(
357 - format!("annotation-header-{}", annotation.short_target),
358 - RegionKind::Group,
359 - )
360 - .across(layout::Fallback::Wrap);
359 + let mut row = Run::new(layout::Fallback::Wrap);
361 360
362 361 if let Some(origin) = &annotation.origin {
363 - header = header.beside(
362 + row = row.beside(
364 363 match &annotation.link {
365 364 Some(link) => Node::Link {
366 365 text: origin.clone(),
@@ -371,18 +370,18 @@
371 370 layout::Priority::Secondary,
372 371 );
373 372 }
374 - header = header.beside(
373 + row = row.beside(
375 374 literal(&annotation.short_target),
376 375 layout::Priority::Essential,
377 376 );
378 377 if !annotation.updated.is_empty() {
379 - header = header.beside(
378 + row = row.beside(
380 379 Node::text(annotation.updated.clone()),
381 380 layout::Priority::Optional,
382 381 );
383 382 }
384 383 if annotation.orphan {
385 - header = header.beside(
384 + row = row.beside(
386 385 Node::Text {
387 386 text: "Annotates a commit makenot.work no longer serves.".to_owned(),
388 387 tone: layout::Tone::Warning,
@@ -391,6 +390,12 @@
391 390 );
392 391 }
393 392
393 + let header = Slot::new(
394 + format!("annotation-header-{}", annotation.short_target),
395 + RegionKind::Group,
396 + )
397 + .across(row);
398 +
394 399 block = block.with(Node::Region(
395 400 Slot::new(
396 401 format!("annotation-{}", annotation.short_target),
@@ -484,26 +489,27 @@
484 489 };
485 490
486 491 Node::Region(
487 - Slot::new("git-diff-stats", RegionKind::Group)
488 - .across(layout::Fallback::Wrap)
489 - .beside(
490 - Node::text(format!("{} changed,", plural(view.total_files, "file"))),
491 - layout::Priority::Essential,
492 - )
493 - .beside(
494 - Node::Text {
495 - text: format!("+{},", plural(view.total_additions, "insertion")),
496 - tone: layout::Tone::Success,
497 - },
498 - layout::Priority::Essential,
499 - )
500 - .beside(
501 - Node::Text {
502 - text: format!("-{}", plural(view.total_deletions, "deletion")),
503 - tone: layout::Tone::Danger,
504 - },
505 - layout::Priority::Essential,
506 - ),
492 + Slot::new("git-diff-stats", RegionKind::Group).across(
493 + Run::new(layout::Fallback::Wrap)
494 + .beside(
495 + Node::text(format!("{} changed,", plural(view.total_files, "file"))),
496 + layout::Priority::Essential,
497 + )
498 + .beside(
499 + Node::Text {
500 + text: format!("+{},", plural(view.total_additions, "insertion")),
501 + tone: layout::Tone::Success,
502 + },
503 + layout::Priority::Essential,
504 + )
505 + .beside(
506 + Node::Text {
507 + text: format!("-{}", plural(view.total_deletions, "deletion")),
508 + tone: layout::Tone::Danger,
509 + },
510 + layout::Priority::Essential,
511 + ),
512 + ),
507 513 )
508 514 }
509 515
@@ -515,37 +521,33 @@
515 521 None => file.path.clone(),
516 522 };
517 523
518 - let mut header = Slot::new(
519 - format!("diff-header-{}", slug(&file.path)),
520 - RegionKind::Group,
521 - )
522 - .across(layout::Fallback::Wrap)
523 - // The one-letter status, as the tag it always was.
524 - .beside(
525 - {
526 - let mut badge = quasi_router::screen::Tag::badge(file.status.label());
527 - // The four colours the shipped `.diff-status-*` rules picked,
528 - // said as tones rather than as a class per status.
529 - badge.tone = match file.status {
530 - crate::git::DiffStatus::Added => layout::Tone::Success,
531 - crate::git::DiffStatus::Deleted => layout::Tone::Danger,
532 - crate::git::DiffStatus::Modified => layout::Tone::Warning,
533 - crate::git::DiffStatus::Renamed => layout::Tone::Info,
534 - };
535 - Node::Token(badge.hinted(file.status.name()))
536 - },
537 - layout::Priority::Essential,
538 - )
539 - .beside(
540 - Node::Link {
541 - text: label,
542 - action: Action::get(path_url).navigating(),
543 - },
544 - layout::Priority::Essential,
545 - );
524 + let mut row = Run::new(layout::Fallback::Wrap)
525 + // The one-letter status, as the tag it always was.
526 + .beside(
527 + {
528 + let mut badge = quasi_router::screen::Tag::badge(file.status.label());
529 + // The four colours the shipped `.diff-status-*` rules picked,
530 + // said as tones rather than as a class per status.
531 + badge.tone = match file.status {
532 + crate::git::DiffStatus::Added => layout::Tone::Success,
533 + crate::git::DiffStatus::Deleted => layout::Tone::Danger,
534 + crate::git::DiffStatus::Modified => layout::Tone::Warning,
535 + crate::git::DiffStatus::Renamed => layout::Tone::Info,
536 + };
537 + Node::Token(badge.hinted(file.status.name()))
538 + },
539 + layout::Priority::Essential,
540 + )
541 + .beside(
542 + Node::Link {
543 + text: label,
544 + action: Action::get(path_url).navigating(),
545 + },
546 + layout::Priority::Essential,
547 + );
546 548
547 549 if file.additions > 0 {
548 - header = header.beside(
550 + row = row.beside(
549 551 Node::Text {
550 552 text: format!("+{}", file.additions),
551 553 tone: layout::Tone::Success,
@@ -554,7 +556,7 @@
554 556 );
555 557 }
556 558 if file.deletions > 0 {
557 - header = header.beside(
559 + row = row.beside(
558 560 Node::Text {
559 561 text: format!("-{}", file.deletions),
560 562 tone: layout::Tone::Danger,
@@ -563,6 +565,12 @@
563 565 );
564 566 }
565 567
568 + let header = Slot::new(
569 + format!("diff-header-{}", slug(&file.path)),
570 + RegionKind::Group,
571 + )
572 + .across(row);
573 +
566 574 let mut block = Slot::new(format!("diff-{}", slug(&file.path)), RegionKind::Group)
567 575 .with(Node::Region(header));
568 576
@@ -43,7 +43,7 @@
43 43
44 44 use makeover_layout as layout;
45 45 use quasi_router::screen::{Field, Row};
46 - use quasi_router::{Action, Node, RegionKind, Slot};
46 + use quasi_router::{Action, Node, RegionKind, Run, Slot};
47 47
48 48 use crate::git::{Breadcrumb, RefInfo};
49 49
@@ -91,16 +91,16 @@
91 91 /// that changes nothing on the page. They pass no refs and get the strip.
92 92 #[must_use]
93 93 pub fn region(nav: &Nav<'_>) -> Node {
94 - let mut bar = Slot::new(REGION, RegionKind::Group)
95 - // The bar is one row that wraps below the breakpoint. Nothing in it may
96 - // drop: the chooser and the strip are the only ways off this page.
97 - .across(layout::Fallback::Wrap);
94 + // The bar is one row that wraps below the breakpoint. Nothing in it may
95 + // drop: the chooser and the strip are the only ways off this page.
96 + let mut bar = Run::new(layout::Fallback::Wrap);
98 97
99 98 if !nav.refs.is_empty() {
100 99 bar = bar.beside(Node::field(chooser(nav)), layout::Priority::Essential);
101 100 }
102 101
103 - Node::Region(bar.beside(strip(nav), layout::Priority::Essential))
102 + let bar = bar.beside(strip(nav), layout::Priority::Essential);
103 + Node::Region(Slot::new(REGION, RegionKind::Group).across(bar))
104 104 }
105 105
106 106 /// The markup, for an Askama template to drop in.
@@ -206,20 +206,22 @@
206 206 Node::Region(
207 207 Slot::new("git-repo-name", RegionKind::Group)
208 208 .named(format!("{owner} / {repo}"))
209 - .across(layout::Fallback::Wrap)
210 - .beside(
211 - Node::Link {
212 - text: owner.to_owned(),
213 - action: Action::get(format!("/git/{owner}")).navigating(),
214 - },
215 - layout::Priority::Essential,
216 - )
217 - .beside(
218 - Node::Link {
219 - text: repo.to_owned(),
220 - action: Action::get(format!("/git/{owner}/{repo}")).navigating(),
221 - },
222 - layout::Priority::Essential,
209 + .across(
210 + Run::new(layout::Fallback::Wrap)
211 + .beside(
212 + Node::Link {
213 + text: owner.to_owned(),
214 + action: Action::get(format!("/git/{owner}")).navigating(),
215 + },
216 + layout::Priority::Essential,
217 + )
218 + .beside(
219 + Node::Link {
220 + text: repo.to_owned(),
221 + action: Action::get(format!("/git/{owner}/{repo}")).navigating(),
222 + },
223 + layout::Priority::Essential,
224 + ),
223 225 ),
224 226 )
225 227 }
@@ -233,16 +235,13 @@
233 235 pub fn breadcrumb(owner: &str, repo: &str, current_ref: &str, crumbs: &[Breadcrumb]) -> Node {
234 236 let tree = format!("/git/{owner}/{repo}/tree/{current_ref}");
235 237
236 - let mut trail = Slot::new("git-breadcrumb", RegionKind::Group)
237 - .named("Path")
238 - .across(layout::Fallback::Wrap)
239 - .beside(
240 - Node::Link {
241 - text: repo.to_owned(),
242 - action: Action::get(tree.clone()).navigating(),
243 - },
244 - layout::Priority::Essential,
245 - );
238 + let mut trail = Run::new(layout::Fallback::Wrap).beside(
239 + Node::Link {
240 + text: repo.to_owned(),
241 + action: Action::get(tree.clone()).navigating(),
242 + },
243 + layout::Priority::Essential,
244 + );
246 245
247 246 for crumb in crumbs {
248 247 let node = if crumb.is_link {
@@ -256,7 +255,11 @@
256 255 trail = trail.beside(node, layout::Priority::Essential);
257 256 }
258 257
259 - Node::Region(trail)
258 + Node::Region(
259 + Slot::new("git-breadcrumb", RegionKind::Group)
260 + .named("Path")
261 + .across(trail),
262 + )
260 263 }
261 264
262 265 #[cfg(test)]
@@ -30,7 +30,7 @@
30 30
31 31 use makeover_layout as layout;
32 32 use quasi_router::screen::Lexeme;
33 - use quasi_router::{Node, RegionKind, Slot};
33 + use quasi_router::{Node, RegionKind, Run, Slot};
34 34 use quasi_webview::Webview;
35 35
36 36 use crate::routes::git::notes_view::CommitNote;
@@ -122,15 +122,10 @@
122 122
123 123 /// One note: what it is, where it came from, and what it says.
124 124 fn one(note: &CommitNote) -> Slot {
125 - let mut header = Slot::new(
126 - format!("note-header-{}", slug(&note.namespace)),
127 - RegionKind::Group,
128 - )
129 125 // The header is one line: a name on the left and a provenance on the
130 126 // right. Wrapping keeps both when there is no room for one line, which
131 127 // is what the shipped rule's `flex-wrap` did.
132 - .across(layout::Fallback::Wrap)
133 - .beside(
128 + let mut header = Run::new(layout::Fallback::Wrap).beside(
134 129 Node::Code {
135 130 runs: vec![Lexeme::plain(&note.namespace)],
136 131 language: None,
@@ -173,7 +168,13 @@
173 168 }
174 169
175 170 Slot::new(format!("note-{}", slug(&note.namespace)), RegionKind::Group)
176 - .with(Node::Region(header))
171 + .with(Node::Region(
172 + Slot::new(
173 + format!("note-header-{}", slug(&note.namespace)),
174 + RegionKind::Group,
175 + )
176 + .across(header),
177 + ))
177 178 .with(Node::Region(Slot::handover(
178 179 body_region(&note.namespace),
179 180 "a rendered note",