Skip to main content

max / makenotwork

Put /git on the residual seam Fifteen of MNW's seventeen described screens serve from a template generated at build time. This one was blocked on its pager: a `Rest` handed over whole is a hole the residual cannot hold. Described instead (quasicoherent cbb63155) it is a `Rest` settled by its own body, back and forward each under their own guard, and the two addresses are the only request-varying bytes -- measured, because `Rest::page` with no total leaves the readout saying "Show more". The region splits out of the screen so it can be staged, and the empty-listing dispatch becomes two guards, which is what a staged shape asks of every screen that joins. /git was the last public document mounted through the adapter, so `public_document_mount` and the handler it called are gone. Every public document answers no `Screen` now. feeds sets `Jump::here` per jump rather than leaving three renderers to work out which page is current. /feed itself stays off the seam: its numbered strip marks that page by substituting a span for a control, which needs `Op::Arms`. Filled byte for byte across the first page, a middle one, the last, and the single page that draws no pager, crossed against an empty listing and a signed-out reader. mnw-server 14d42beb.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session
https://claude.ai/code/session_01P8ostB2UmZJGj5WjSHRSot
Author: Max Johnson <me@maxj.phd> · 2026-09-08 14:26 UTC
Signed with PGP, not checked
Commit: 43adcbd9873b2529c5541c1e24e192b987be0284
Parent: d2288e8
6 files changed, +242 insertions, -154 deletions
@@ -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.105" }
166 + quasi-router = { git = "https://makenot.work/git/max/quasi.git", version = "0.106" }
167 167 # The declared form. A screen written as `declare!` is compiled to the same
168 168 # `quasi_router` constructors the hand-written shape called, at build time, so
169 169 # nothing new reaches the binary and the macro is not in the request path.
@@ -183,13 +183,13 @@
183 183 # For the request head the per-viewer state factory reads. axum re-exports it,
184 184 # but the factory's signature is quasi-axum's and names `http::request::Parts`.
185 185 http = "1.3.1"
186 - quasi-axum = { git = "https://makenot.work/git/max/quasi.git", version = "0.105" }
187 - quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.105" }
186 + quasi-axum = { git = "https://makenot.work/git/max/quasi.git", version = "0.106" }
187 + quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.106" }
188 188 # The first-party widget set. The carousel was proved here against three pages
189 189 # and then moved there; what is left in `quasi/widgets/carousel.rs` is the
190 190 # Askama glue. Not `makeover-basics`: a widget is an assembly of `Node`s, so it
191 191 # sits above quasi-router rather than inside the description suite.
192 - quasi-basics = { git = "https://makenot.work/git/max/quasi.git", version = "0.105" }
192 + quasi-basics = { git = "https://makenot.work/git/max/quasi.git", version = "0.106" }
193 193
194 194 # Git source browser
195 195 gix = { version = "0.86", default-features = false, features = ["blame", "mailmap", "revision", "sha1", "max-performance-safe"] }
@@ -288,7 +288,7 @@
288 288 # Written from the crate rather than copied into the repo for the reason the
289 289 # constants exist: a stale copy in a static directory is a silently dead bulk
290 290 # bar, and the version has to be the one the emitter agrees with.
291 - quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.105" }
291 + quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.106" }
292 292
293 293 [dev-dependencies]
294 294 tower = { version = "0.5.3", features = ["util"] }
@@ -432,8 +432,18 @@
432 432 if page.current_page < page.total_pages {
433 433 rest = rest.forward(surface.address(page.current_page + 1));
434 434 }
435 + // Which page the reader is on is carried per jump rather than compared
436 + // against the paging inside each renderer. `Jump::here`'s reason is
437 + // `Choice::chosen`'s: a strip is a loop, and a residual holds one compiled
438 + // body per loop.
435 439 for jump in page.pagination_range {
436 - rest = rest.jumping(*jump as usize, surface.address(*jump));
440 + let at = *jump as usize;
441 + let jumping = quasi_router::screen::Jump::new(at, surface.address(*jump));
442 + rest = rest.jumping(if at == page.current_page as usize {
443 + jumping.here()
444 + } else {
445 + jumping
446 + });
437 447 }
438 448
439 449 rest
@@ -568,17 +578,23 @@
568 578 }
569 579
570 580 /// A first page offers no way back and a last page no way forward, and the
571 - /// renderer draws each as disabled rather than absent.
581 + /// renderer draws neither rather than drawing one it has to disable.
582 + ///
583 + /// Ruled by Max 2026-09-08, against the disabled control that stood here: a
584 + /// Prev that cannot go back is a control that answers nothing. See
585 + /// `quasi-webview`'s `rest_html`.
572 586 #[test]
573 587 fn the_ends_of_the_set_say_so() {
574 588 let first = library(1, 4);
575 - assert!(first.contains("<button type=\"button\""), "{first}");
576 - assert!(first.contains("disabled>Prev"), "{first}");
577 - assert!(!first.contains("disabled>Next"), "{first}");
589 + assert!(!first.contains("rest-previous"), "{first}");
590 + assert!(first.contains("rest-next"), "{first}");
578 591
579 592 let last = library(4, 4);
580 - assert!(last.contains("disabled>Next"), "{last}");
581 - assert!(!last.contains("disabled>Prev"), "{last}");
593 + assert!(last.contains("rest-previous"), "{last}");
594 + assert!(!last.contains("rest-next"), "{last}");
595 +
596 + assert!(!first.contains("disabled>"), "{first}");
597 + assert!(!last.contains("disabled>"), "{last}");
582 598 }
583 599
584 600 /// One page is no rest at all, which is what `{% if total_pages > 1 %}`
@@ -30,7 +30,7 @@
30 30 use makeover_layout as layout;
31 31 use quasi_declare::declare;
32 32 use quasi_router::screen::Rest;
33 - use quasi_router::{Action, Document, Request, Response, RouteError};
33 + use quasi_router::{Action, Document, RouteError};
34 34 use quasi_webview::Webview;
35 35
36 36 use crate::{constants, db};
@@ -44,7 +44,7 @@
44 44 const MEASURE: layout::Measure = layout::Measure::Wide;
45 45
46 46 /// Everything the screen draws, resolved before it is drawn.
47 - struct Loaded {
47 + pub(crate) struct Loaded {
48 48 repos: Vec<Repo>,
49 49 page: usize,
50 50 has_more: bool,
@@ -52,6 +52,26 @@
52 52 signed_in: bool,
53 53 }
54 54
55 + impl Loaded {
56 + /// Where this page starts, which is what a `Rest` counts from.
57 + ///
58 + /// A supplier because the declared form has no arithmetic, and it is the
59 + /// same sum [`load`] makes to ask the database.
60 + fn offset(&self) -> usize {
61 + (self.page - 1).saturating_mul(constants::GIT_REPOS_PER_PAGE)
62 + }
63 +
64 + /// The page back, and the page on. Suppliers for [`offset`](Self::offset)'s
65 + /// reason.
66 + fn previous(&self) -> usize {
67 + self.page.saturating_sub(1)
68 + }
69 +
70 + fn next(&self) -> usize {
71 + self.page + 1
72 + }
73 + }
74 +
55 75 /// One repository in the listing.
56 76 struct Repo {
57 77 owner: String,
@@ -59,21 +79,21 @@
59 79 description: String,
60 80 }
61 81
62 - /// The page.
63 - pub fn screen(viewer: &super::Viewer, request: Request) -> Result<Response, RouteError> {
64 - // Moved out of the request rather than borrowed: the signature is quasi's.
65 - let carried = request.carried;
66 - // Clamped exactly as the shipped handler clamped it: a page number out of a
67 - // query string is reader input, and the offset it becomes is multiplied.
82 + /// The one read this page makes, for the mount that serves it from a residual.
83 + ///
84 + /// The clamp is the shipped handler's, unchanged: a page number out of a query
85 + /// string is reader input, and the offset it becomes is multiplied.
86 + pub(crate) fn reading(
87 + viewer: &super::Viewer,
88 + carried: &super::Carried,
89 + ) -> Result<Loaded, RouteError> {
68 90 let page = carried
69 - .get("page")
91 + .asked("page")
70 92 .and_then(|value| value.trim().parse::<usize>().ok())
71 93 .unwrap_or(1)
72 94 .clamp(1, 10_000);
73 95
74 - let loaded = load(viewer, page)?;
75 -
76 - Ok(page_screen(&loaded).into())
96 + load(viewer, page)
77 97 }
78 98
79 99 /// Read one page of public repositories, plus one row to learn whether there is
@@ -110,38 +130,44 @@
110 130
111 131 declare! {
112 132 /// The whole document: the title, the measure, the body.
113 - shape page_screen(loaded: &Loaded) -> Screen;
133 + pub(crate) shape page_screen(loaded: &Loaded) -> Screen;
114 134
115 135 screen single "Repositories - Git - Makenotwork" {
116 136 measured MEASURE;
117 137 documented Document::default().classed(crate::shell::body_class(MEASURE, &[]));
118 138 summarised "Public repositories on Makenotwork, with git notes rendered on every commit.";
119 139
120 - region PAGE_REGION as Pane {
121 - page "Repositories";
140 + include page_region(loaded);
141 + }
142 + }
122 143
123 - // Notes are the one thing this browser does that no other forge
124 - // does, and nothing on a repository page says so to somebody who
125 - // has never seen one. The landing page is where that sentence
126 - // reaches everybody.
127 - include super::own_prose(
128 - "Every repository here renders [git notes](/docs/git-notes): annotation attached \
129 - to a commit without rewriting it, stored in the repository and carried by a clone."
130 - );
144 + declare! {
145 + /// The page's one region, split out so it can be staged.
146 + #[staged]
147 + pub(crate) shape page_region(loaded: &Loaded) -> Slot;
131 148
132 - // The only route to an annotation whose target repository is gone:
133 - // nothing else links to it once there is no commit page to link
134 - // from.
135 - include super::own_prose(
136 - "[Your annotations](/git/my-annotations), private to you, across every repository \
137 - you have read here."
138 - ) when loaded.signed_in;
149 + region PAGE_REGION as Pane {
150 + page "Repositories";
139 151
140 - given loaded.repos.is_empty() {
141 - true -> empty "No public repositories yet.";
142 - otherwise -> include listing(loaded);
143 - }
144 - }
152 + // Notes are the one thing this browser does that no other forge
153 + // does, and nothing on a repository page says so to somebody who
154 + // has never seen one. The landing page is where that sentence
155 + // reaches everybody.
156 + include super::own_prose(
157 + "Every repository here renders [git notes](/docs/git-notes): annotation attached \
158 + to a commit without rewriting it, stored in the repository and carried by a clone."
159 + );
160 +
161 + // The only route to an annotation whose target repository is gone:
162 + // nothing else links to it once there is no commit page to link
163 + // from.
164 + include super::own_prose(
165 + "[Your annotations](/git/my-annotations), private to you, across every repository \
166 + you have read here."
167 + ) when loaded.signed_in;
168 +
169 + empty "No public repositories yet." when loaded.repos.is_empty();
170 + include listing(loaded) unless loaded.repos.is_empty();
145 171 }
146 172 }
147 173
@@ -151,6 +177,7 @@
151 177 /// Two columns, two cells, all four written here, so the row stays
152 178 /// positional: naming would buy nothing a reader cannot already check by
153 179 /// looking up four lines.
180 + #[staged]
154 181 shape listing(loaded: &Loaded) -> Node;
155 182
156 183 table {
@@ -171,35 +198,43 @@
171 198 }
172 199
173 200 // One page of one is the whole listing, and the pager is what says so.
174 - // The condition is `rest`'s own, said here rather than answered with an
175 - // `Option`: a table either shows what it has not shown or does not, and
176 - // that is what a guard is for.
177 - more rest(loaded) when loaded.page over 1 or loaded.has_more;
201 + // A table either shows what it has not shown or does not, and that is
202 + // what a guard is for.
203 + //
204 + // Described rather than supplied. A `Rest` has no sentinel and a
205 + // supplier of one takes a struct, so a pager handed over whole was a
206 + // hole the residual could not hold; everything it carries is a number
207 + // or an address, which are the two things a residual already has.
208 + // The directions are written back-then-forward because that is the
209 + // order they draw in, which `quasi-declare` holds this to.
210 + // quasicoherent `cbb63155`.
211 + more Rest::page(loaded.offset(), constants::GIT_REPOS_PER_PAGE) {
212 + back Action::get("{PATH}?page={loaded.previous()}").navigating()
213 + when loaded.page over 1;
214 + forward Action::get("{PATH}?page={loaded.next()}").navigating()
215 + when loaded.has_more;
216 + } when loaded.page over 1 or loaded.has_more;
178 217 }
179 218 }
180 219
181 - /// What the reader has not been shown.
220 + /// One page of repositories as the tests draw it.
182 221 ///
183 - /// Prev/next only. The template drew `Newer` and `Older` and no numbers, and
184 - /// `Rest` draws numbers only for a screen that calls `jumping`, so this is a
185 - /// parity conversion rather than a reduction.
186 - ///
187 - /// Whether there is anything to show is [`listing`]'s guard rather than an
188 - /// `Option` here: built for a page that offers neither direction this is a
189 - /// `Rest` with no controls, and nothing asks for it.
190 - fn rest(loaded: &Loaded) -> Rest {
191 - let per = constants::GIT_REPOS_PER_PAGE;
192 - let from = (loaded.page - 1) * per;
193 -
194 - let mut rest = Rest::page(from, per);
195 - if loaded.page > 1 {
196 - rest = rest.back(Action::get(format!("{PATH}?page={}", loaded.page - 1)).navigating());
222 + /// Module-level rather than inside `mod tests` because `quasi::residuals` needs
223 + /// one too, and `Loaded` is this module's own type. Test-only.
224 + #[cfg(test)]
225 + pub(crate) fn loaded(count: usize, page: usize, has_more: bool, signed_in: bool) -> Loaded {
226 + Loaded {
227 + repos: (0..count)
228 + .map(|n| Repo {
229 + owner: "ada".into(),
230 + name: format!("repo{n}"),
231 + description: format!("Number {n}"),
232 + })
233 + .collect(),
234 + page,
235 + has_more,
236 + signed_in,
197 237 }
198 - if loaded.has_more {
199 - rest = rest.forward(Action::get(format!("{PATH}?page={}", loaded.page + 1)).navigating());
200 - }
201 -
202 - rest
203 238 }
204 239
205 240 /// The document this screen is drawn in.
@@ -216,21 +251,6 @@
216 251 mod tests {
217 252 use super::*;
218 253
219 - fn loaded(count: usize, page: usize, has_more: bool, signed_in: bool) -> Loaded {
220 - Loaded {
221 - repos: (0..count)
222 - .map(|n| Repo {
223 - owner: "ada".into(),
224 - name: format!("repo{n}"),
225 - description: format!("Number {n}"),
226 - })
227 - .collect(),
228 - page,
229 - has_more,
230 - signed_in,
231 - }
232 - }
233 -
234 254 fn html(loaded: &Loaded) -> String {
235 255 use quasi_axum::Serves as _;
236 256
@@ -835,11 +835,18 @@
835 835 // tests did not run either, because an undeclared module is not compiled.
836 836 (
837 837 git_explore::PATH,
838 - public_document_mount(
838 + served_document_mount(
839 839 app,
840 840 git_explore::PATH,
841 - git_explore::screen,
842 841 git_explore::renderer,
842 + |viewer, carried| {
843 + let loaded = git_explore::reading(viewer, carried)?;
844 + Ok(Served {
845 + screen: git_explore::page_screen(&loaded),
846 + markup: git_explore::page_region_serve(&residuals::GIT_EXPLORE, &loaded)
847 + .into(),
848 + })
849 + },
843 850 )
844 851 .layer(tower_governor::GovernorLayer::new(
845 852 crate::helpers::rate_limiter_ms(
@@ -952,54 +959,14 @@
952 959 )
953 960 }
954 961
955 - /// A described document a reader NAVIGATES to with or without a session.
956 - ///
957 - /// [`document_mount`] with the two things that make it gated removed: the
958 - /// factory is built on [`Audience::Anyone`], so a signed-out request builds a
959 - /// viewer rather than being refused, and there is no [`signed_in`] layer in
960 - /// front of it, so nothing turns that into a 401. What is left is identical,
961 - /// including the exact-address registration -- see [`document_mount`] for why a
962 - /// document is not mounted as a nest.
963 - ///
964 - /// The screens here are the sessionless pages: the ones whose whole purpose is
965 - /// to be reachable by somebody who cannot sign in. A page that merely *reads*
966 - /// better when signed in is still gated; the test is whether refusing a visitor
967 - /// is the right answer.
968 - ///
969 - /// # Layers go on the returned router, at the call site
970 - ///
971 - /// This returns an `axum::Router`, so a mount that needs middleware takes it
972 - /// with `.layer(..)` where it is registered rather than through a parameter
973 - /// here. That matters because the middleware is per-address rather than per
974 - /// mount kind: the git browse addresses carry a per-IP cap and the marketing
975 - /// pages carry none, and threading an `Option<Layer>` through every call would
976 - /// make the mount know about a policy that belongs to the route.
977 - ///
978 - /// **Check what the address carried before moving it.** A route lifted out of a
979 - /// router with a `route_layer` silently loses that layer, and for the git tree
980 - /// that would be a rate limit removed from a route that walks repositories on
981 - /// disk. See `git_repos`.
982 - fn public_document_mount(
983 - app: &AppState,
984 - path: &'static str,
985 - screen: Screen,
986 - renderer: fn(&Viewer) -> quasi_webview::Webview,
987 - ) -> axum::Router {
988 - let router = quasi_router::Router::<Viewer>::new().get(path, screen);
989 - quasi_axum::Adapter::per_viewer(
990 - router,
991 - viewer_factory(app.clone(), Audience::Anyone),
992 - move |viewer, _, _| renderer(viewer),
993 - )
994 - .into_router()
995 - }
996 -
997 962 /// A public document whose regions are already written, mounted.
998 963 ///
999 - /// The seam's mount, shared by every screen on it. It is not
1000 - /// [`public_document_mount`] and cannot be: that one builds a
1001 - /// `quasi_axum::Adapter`, whose whole job is to call a handler that answers a
1002 - /// `Screen` and render it, and there is no `Screen` here to answer with. The
964 + /// The seam's mount, shared by every screen on it. It replaced an adapter mount
965 + /// that built a `quasi_axum::Adapter`, whose whole job is to call a handler that
966 + /// answers a `Screen` and render it, and there is no `Screen` here to answer
967 + /// with -- so the two could never have been one, and once `/git` moved across on
968 + /// 2026-09-08 there was no public document left on the adapter and that mount
969 + /// was deleted, and so was the handler it called. The
1003 970 /// markup was derived on a build machine, so answering is writing the document
1004 971 /// around it (quasicoherent `793d99dd`).
1005 972 ///
@@ -1047,13 +1014,12 @@
1047 1014
1048 1015 /// A gated document whose regions are already written, mounted.
1049 1016 ///
1050 - /// [`served_document_mount`] with the two things [`public_document_mount`]
1051 - /// removes put back: the factory is built on [`Audience::Reader`], so a
1052 - /// signed-out request is refused rather than answered, and [`signed_in`] runs in
1053 - /// front so that refusal is the branded 401 with its way back in rather than a
1054 - /// bare 403. The relationship is exactly [`document_mount`]'s to
1055 - /// [`public_document_mount`], and it is written twice for the same reason those
1056 - /// are: what a mount refuses is what a test can press it for.
1017 + /// [`served_document_mount`] with the two things a public mount leaves out put
1018 + /// back: the factory is built on [`Audience::Reader`], so a signed-out request
1019 + /// is refused rather than answered, and [`signed_in`] runs in front so that
1020 + /// refusal is the branded 401 with its way back in rather than a bare 403. The
1021 + /// two are written out separately rather than parameterised, because what a
1022 + /// mount refuses is what a test can press it for.
1057 1023 fn served_gated_mount(
1058 1024 app: &AppState,
1059 1025 path: &'static str,
@@ -1545,13 +1511,13 @@
1545 1511 .split_once("\n}")
1546 1512 .expect("public_document_mounts ends")
1547 1513 .0;
1548 - // Two mount styles, and both are public documents. Most screens go
1549 - // through the adapter, which calls a handler that answers a `Screen`
1550 - // and renders it. A screen on the residual seam has no `Screen` to
1551 - // answer with, so it takes [`served_document_mount`] instead
1552 - // (quasicoherent `793d99dd`). Counting only the first style would let a
1553 - // screen leave `PUBLIC_DOCUMENT_PATHS` unnoticed by moving onto the
1554 - // seam, which is the drift this test exists to catch.
1514 + // Both mount styles, though only one of them has a caller left. Every
1515 + // public document is on the residual seam as of 2026-09-08 and takes
1516 + // `served_document_mount`, which answers no `Screen`; the adapter mount
1517 + // that answered one is gone. The first count stays because what this
1518 + // test exists to catch is a screen leaving `PUBLIC_DOCUMENT_PATHS`
1519 + // unnoticed by changing how it is mounted, and a count that only knows
1520 + // today's style would not catch it changing back.
1555 1521 let adapted = mounted.matches("public_document_mount(").count();
1556 1522 let served = mounted.matches("served_document_mount(").count();
1557 1523 assert_eq!(
@@ -102,6 +102,9 @@
102 102 Node::Region(super::creators::page_region_staged(plan))
103 103 }),
104 104 ("SSH_KEYS", |plan| super::ssh_keys::pane_staged(plan)),
105 + ("GIT_EXPLORE", |plan| {
106 + Node::Region(super::git_explore::page_region_staged(plan))
107 + }),
105 108 ]
106 109 }
107 110
@@ -771,6 +774,38 @@
771 774 }
772 775 }
773 776
777 + /// The git listing fills to what the renderer builds, at every page shape.
778 + ///
779 + /// The first residual holding a **described pager** (quasicoherent
780 + /// `cbb63155`). A pager used to be a `Rest` the screen supplied whole,
781 + /// which has no sentinel, so a paged screen could not reach the seam at
782 + /// all. Said as a description it is a `Rest` settled by its own body, one
783 + /// guard per direction, and everything it carries is a number or an
784 + /// address.
785 + ///
786 + /// Four page shapes, because a pager has four and each drops a different
787 + /// branch: the first page, a middle one, the last, and the single page that
788 + /// draws no pager. Crossed against an empty listing and a signed-out
789 + /// reader, which are the region's other two guards.
790 + #[test]
791 + fn the_git_listing_residual_fills_to_what_the_renderer_builds() {
792 + use crate::quasi::git_explore::{loaded, page_region, page_region_serve};
793 + use quasi_axum::Serves as _;
794 +
795 + for (page, has_more) in [(1, true), (2, true), (3, false), (1, false)] {
796 + for count in [0, 3] {
797 + for signed_in in [true, false] {
798 + let held = loaded(count, page, has_more, signed_in);
799 + assert_eq!(
800 + page_region_serve(&GIT_EXPLORE, &held),
801 + Webview::new().fragment(&Node::Region(page_region(&held))),
802 + "page {page}, has_more {has_more}, {count} repos, signed in {signed_in}",
803 + );
804 + }
805 + }
806 + }
807 + }
808 +
774 809 /// The payout card fills to what the renderer builds.
775 810 ///
776 811 /// The first residual holding a **figure strip**, which is the other half
@@ -872,12 +907,12 @@
872 907 /// is to describe the chart rather than to compile around it, so this
873 908 /// screen stays here until a chart is in the vocabulary.
874 909 /// quasicoherent `7d6ad166`.
875 - /// - `/git` and `/feed`: both page, and a pager is a supplied `Rest`
876 - /// with no sentinel. The answer is to describe `more` rather than
877 - /// supply it. quasicoherent `cbb63155`.
910 + /// - `/feed`: pages with a numbered strip, which prints each page
911 + /// number and marks the one being read by comparing it against the
912 + /// paging -- "exactly one row differs" inside a loop, which takes the
913 + /// Select's answer. quasicoherent `cbb63155`.
878 914 const OFF_THE_SEAM: &[&str] = &[
879 915 crate::quasi::user_analytics::PATH,
880 - crate::quasi::git_explore::PATH,
881 916 crate::quasi::feeds::PATH,
882 917 ];
883 918
@@ -920,8 +955,8 @@
920 955 /// Screens with their own filling test: `/use-cases`, `/fan-plus`,
921 956 /// `/c/{username}/{slug}`, `/dashboard/export`, `/git/{owner}`, and the
922 957 /// two forum panes, the two contact panes, the payout card,
923 - /// `/creators` and `/dashboard/tabs/ssh-keys`.
924 - const HOLED: usize = 12;
958 + /// `/creators`, `/dashboard/tabs/ssh-keys` and `/git`.
959 + const HOLED: usize = 13;
925 960
926 961 assert_eq!(
927 962 roster().len(),
@@ -542,4 +542,55 @@
542 542 ])),
543 543 ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("<form class=\"form\" hx-post=\"/api/users/me/git-tokens\" hx-swap=\"outerMorph\" hx-disable=\"find button[type='submit']\" data-awaiting=\"indeterminate\"><div class=\"form-group\"><label class=\"form-label\" for=\"name\">Name</label><input type=\"text\" class=\"field\" id=\"name\" name=\"name\" required value=\"\"></div><div class=\"form-group\"><label class=\"form-label\" for=\"expires_on\">Expires (optional)</label><input type=\"date\" class=\"field\" id=\"expires_on\" name=\"expires_on\" aria-describedby=\"expires_on-hint\" value=\"\"><div class=\"form-hint\" id=\"expires_on-hint\">Leave blank for a token that does not expire.</div></div><div class=\"form-group\"><label class=\"form-checkbox-label\"><input type=\"checkbox\" id=\"can_push\" name=\"can_push\"><span>Allow push (write access)</span></label></div><button type=\"submit\" class=\"button act-submit\">Create Token</button></form><div class=\"anchored\" id=\"settings-ssh-keys-anchored\" data-menu=\"anchored\" hidden></div></div>")),
544 544 ]);
545 +
546 + pub static GIT_EXPLORE: ::quasi_router::stage::Residual =
547 + ::quasi_router::stage::Residual::compiled(&[
548 + ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("<div id=\"git-explore\" class=\"region pane\"><h1 class=\"heading\">Repositories</h1><div class=\"rich\" data-disable-scripting><p>Every repository here renders <a href=\"/docs/git-notes\" rel=\"noopener noreferrer\">git notes</a>: annotation attached to a commit without rewriting it, stored in the repository and carried by a clone.</p>\n</div>")),
549 + ::quasi_router::stage::Op::Branch(::std::borrow::Cow::Borrowed(&[
550 + ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("<div class=\"rich\" data-disable-scripting><p><a href=\"/git/my-annotations\" rel=\"noopener noreferrer\">Your annotations</a>, private to you, across every repository you have read here.</p>\n</div>")),
551 +
552 + ])),
553 + ::quasi_router::stage::Op::Branch(::std::borrow::Cow::Borrowed(&[
554 + ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("<div class=\"placeholder\" data-state=\"empty\" role=\"status\" aria-live=\"polite\"><p class=\"placeholder-text\">No public repositories yet.</p></div>")),
555 +
556 + ])),
557 + ::quasi_router::stage::Op::Branch(::std::borrow::Cow::Borrowed(&[
558 + ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("<div role=\"table\" class=\"table\"><div role=\"row\" class=\"table-head\"><span role=\"columnheader\" class=\"table-heading col-Repository cell-content cell-keeps\">Repository</span><span role=\"columnheader\" class=\"table-heading col-Description cell-fill cell-drops-next\">Description</span></div>")),
559 + ::quasi_router::stage::Op::Loop(::std::borrow::Cow::Borrowed(&[
560 + ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("<div role=\"row\" class=\"table-row\" data-row href=\"/git/")),
561 + ::quasi_router::stage::Op::Hole { scope: 1, id: 3 },
562 + ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("/")),
563 + ::quasi_router::stage::Op::Hole { scope: 1, id: 4 },
564 + ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("\"><div class=\"cell col-Repository cell-content cell-keeps cell-value\">")),
565 + ::quasi_router::stage::Op::Hole { scope: 1, id: 0 },
566 + ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("/")),
567 + ::quasi_router::stage::Op::Hole { scope: 1, id: 1 },
568 + ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("</div><div class=\"cell col-Description cell-fill cell-drops-next cell-value\">")),
569 + ::quasi_router::stage::Op::Hole { scope: 1, id: 2 },
570 + ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("</div></div>")),
571 +
572 + ])),
573 + ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("</div>")),
574 + ::quasi_router::stage::Op::Branch(::std::borrow::Cow::Borrowed(&[
575 + ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("<div class=\"rest\">")),
576 + ::quasi_router::stage::Op::Branch(::std::borrow::Cow::Borrowed(&[
577 + ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("<a class=\"button rest-previous\" href=\"/git?page=")),
578 + ::quasi_router::stage::Op::Hole { scope: 1, id: 6 },
579 + ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("\">Prev</a>")),
580 +
581 + ])),
582 + ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("<span class=\"rest-position\">Show more</span>")),
583 + ::quasi_router::stage::Op::Branch(::std::borrow::Cow::Borrowed(&[
584 + ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("<a class=\"button rest-next\" href=\"/git?page=")),
585 + ::quasi_router::stage::Op::Hole { scope: 1, id: 7 },
586 + ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("\">Next</a>")),
587 +
588 + ])),
589 + ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("</div>")),
590 +
591 + ])),
592 +
593 + ])),
594 + ::quasi_router::stage::Op::Lit(::std::borrow::Cow::Borrowed("<div class=\"anchored\" id=\"git-explore-anchored\" data-menu=\"anchored\" hidden></div></div>")),
595 + ]);
545 596