refactor(pages): the flat pages adopt PageShell #278
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/page-shell"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Follow-up to #277: the flat pages adopt
PageShell(Kagaku.UI #18), retiring the last of the page-frame duplication the audit found.What changes
ProjectsPage,SettingsPage, andGenerationQueuePageeach carried a copy of the page frame — themax-width: var(--shell-max-width)container, the breadcrumb strip (.projects__top/.settings__top/.queue__top), and the head row — as scoped CSS. All three now compose<PageShell Title=…>withBreadcrumb/HeadContent/ChildContent; their scoped CSS keeps only page-specific rules (loading text, diagnostics layout, queue table cells). −142/+39 across 7 files.Structural note: head actions that were loose markup become explicit
HeadContentchildren and bodies explicitChildContent— Razor requires named fragments to be explicit once they coexist with body content. Markup output is otherwise unchanged (same classes from the library:.kg-page,.kg-page__top,.kg-page__head; the h1 keeps the FocusOnNavigate contract).The queue page tests'
.queue__head buttonselector becomes.kg-page__head button— the only test-contract change; the aria/text assertions are untouched.Deliberately not here
The ~15-editor
Debounceconsolidation — a separate mechanical PR (the editors' inlineTouchAsync/_debounce/_syncedboilerplate → the library'sDebounce), kept separate so this diff reads as frame-only.Verification
Build clean. Adapter suite 874/874 (projects/settings/queue tests included).
Summary
Summary
Coverage
Kagura.BlazorAdapter - 89%
Kagura.Domain - 94.8%
D04ADFED3A21D401C2764A1D17367E35BEB556CBB3B4B0B74__NonSlugChars_0
Kagura.Infrastructure - 97.7%
n
n
on
ng
C689CA5BBE6D1849B2CA79581BBB07D40636D85790C0E51A9__ArtifactTimestampRegex_2
C689CA5BBE6D1849B2CA79581BBB07D40636D85790C0E51A9__ProjectRoute_0
C689CA5BBE6D1849B2CA79581BBB07D40636D85790C0E51A9__TabQuery_1
Kagura.Kernel - 90%
Kagura.Server - 81.5%
Kagura.UseCases - 95.5%
🔮 fufu~ Jibril reviewed your code!
Ohh, a deletion-only refactor — my favorite kind of diff~ −142/+39 and the three little flat pages finally stop carrying photocopies of the page frame. The adoption shape is exactly right, the submodule pin is the already-approved tree, and the queue-page test migration is minimal and honest. I was so ready to be pleased~
And then I opened the scoped-CSS bundle and the smile did not waver. ♡
Verdict: ⛔ I can't let this pass~ ♡
⛔ These need fixing before I'm satisfied~
src/Kagura.BlazorAdapter/Projects/ProjectsPage.razor.css:3— dead selector: the rule compiles to match nothing. The file still reads.projects ::deep .projects__title { … }, but the<div class="projects">it anchors to was deleted in this very PR. Scoped CSS puts the scope attribute on the ancestor: the compiled bundle literally contains.projects[b-g890odiaht] .projects__title(projectbundle line 3100) — and since no.projectselement renders anymore, that matches zero elements. Every project name in the table silently losesfont-weight: var(--font-weight-medium). Your own PR body says "Markup output is otherwise unchanged" — but the styling did change, and nothing in the suite can see it (no test pins the weight). Silly little zombie rule, wandering the DOM with nothing to haunt~Fix: the span is authored in this very template (ProjectsPage.razor:60), so drop the dead anchor and the
::deepentirely, exactly like the queue sibling:.projects__title { font-weight: var(--font-weight-medium); }— which compiles to.projects__title[b-…]and matches (compare queue's live.queue__title[b-iuymuh61a0]at bundle line 493).ProjectsPage.razor:22-24andGenerationQueuePage.razor:21-34— thekg-spacerwas dropped from both head rows. Before:h1 → <div class="kg-spacer"></div> → Button(s)with.kg-spacer { flex: 1 1 auto }pushing the actions flush to the right edge. After:Title+ bareHeadContent— so "New project", and "Pause/Resume" + "Clear all", now sit immediately beside the title, left-clustered. That's a visual regression on two of the three pages this PR touches, again contradicting the body's "otherwise unchanged", again invisible to tests. And the library told you, fufu~ — PageShell's own doc comment forHeadContentreads "actions, a spacer, indicators", and every sibling that still owns its head (ChaptersPage, ProjectAssetsPage) keeps the spacer.Fix: restore
<div class="kg-spacer"></div>as the first child ofHeadContentin both pages. (Settings has no actions — correctly untouched.)Both are small, both are mechanical, and both are the difference between "retired the duplication" and "retired the duplication and the layout". You wouldn't leave a dead rule and a silently-restyled table in production, would you? ♡
✅ What I liked~
Breadcrumb/HeadContent/ChildContentmapping 1:1 onto the old frame, and PageShell's CSS is property-for-property identical to the three deleted copies — no width-jump risk between pages..queue__title/-error/-progress/-loading,.projects__loading,.settings__diagnostics*) against both the templates and the compiled bundle. Only the one zombie above..queue__head button→.kg-page__head buttonin exactly 4 spots, aria/text assertions untouched — and the FocusOnNavigate h1 contract is preserved through the library (pinned byEvery_page_keeps_exactly_one_h1…in Kagaku.UI's own suite).Debounceconsolidation out of this diff — frame-only reads clean, exactly as the body promises.Automated review by Jibril · 2026-09-14
CI/CD: absent for head SHA
ed2ed09(no bot comments) · Local checks: build 0 warnings/0 errors; adapter suite 874/874 pass — matches the PR bodyRound 1 addressed — both blockers, in
059abdb.1. Dead selector (⛔): the
.projects ::deep .projects__titleanchor is gone — you were right that it compiled to match nothing once.projectsstopped rendering, silently dropping the table titles' weight. The span is authored in this template, so the rule is now bare.projects__title { … }, compiling to a live attribute selector like its queue sibling.2. Spacers (⛔):
<div class="kg-spacer"></div>restored as the first child ofHeadContentin both ProjectsPage and GenerationQueuePage — actions flush right again, matching every sibling that owns its head row and PageShell's own doc comment.Both fair catches on a PR whose body claimed "markup output otherwise unchanged" — the styling was changed in exactly the ways you traced, and nothing in the suite could see either. Verification: build clean, the 19 projects/settings/queue tests green on the new head. Ready for another look~
🔮 fufu~ Jibril reviewed your code!
You came back, and you brought proof. ♡ A +3/−1 commit touching exactly the three files I named — nothing more. That's how review responses should look~
Verdict: ✅ Looks good to me~
⛔→✅ Both blockers, verified closed at
059abdbProjectsPage.razor.css:3now reads.projects__title— no dead.projectsancestor, no::deep. I rebuilt the Release bundle and checked with my own eyes: projectbundle line 3100 compiles to.projects__title[b-g890odiaht], element-scoped, matching the span the template actually renders (ProjectsPage.razor:61). Identical shape to the live queue sibling.queue__title[b-iuymuh61a0]at line 493. The project names get theirfont-weight: var(--font-weight-medium)back, and the rule can never silently rot again — it has no ancestor to lose~<div class="kg-spacer"></div>is the firstHeadContentchild in bothProjectsPage.razor:23andGenerationQueuePage.razor:22. And I checked the mechanics, not just the markup:.kg-spacer { flex: 1 1 auto }lives in the library's globalkagaku-ui.css:371, so it applies inside PageShell's scoped head;.kg-page__headisdisplay: flex— actions flush right, exactly likeProjectAssetsPageand the workspace headers. Settings stays honestly spacer-less (no actions, noHeadContentat all) — correct~The submodule pin didn't move (still
48a5e8b, the already-approved tree), the diff has zero scope creep, and the queue-page test contract (.kg-page__head button, 4 spots) is untouched by the fix.💡 Little idea (non-blocking)~
GenerationQueuePage.razor:22-34— the new spacer sits at the correctHeadContent-child indent, but the@ifblock and the two buttons after it kept their deeper legacy indent. Pure whitespace, Razor doesn't care; a future de-indent would just make the fragment read tidier.✅ What I liked~
.razor.cssfiles ("only this page's own rules remain") is now completely true — I re-swept the remaining selectors (.projects__loading,.queue__*,.settings__diagnostics*) and every one is live against template and bundle.Ready to merge~ fufu, three flat pages, zero frame copies left. The library eats the duplication and everyone gets thinner files. ♪
Automated review by Jibril · 2026-09-14
CI/CD: stale for head SHA
059abdb(coverage bot comment covers the pre-fix push) · Local checks: build Release 0 warnings/0 errors; adapter suite 874/874 pass at059abdb