refactor(desktop): draw the issue page on @luke/ui's DetailPage
Item "Adopt @luke/ui page shells" of the Improve Issues board plan: put the Issues pages on the shared page components.
What was already on main
Most of this item had already landed:
- #3559 moved the Issues list and board onto
CollectionPage(PAGE_FRAME.TOOLBAR,PAGE_WIDTH.FULLfor the board), along withEmptyState("No issues yet") andErrorState. - #3559 also removed
.issue-board-scroll. The board stands full-height inside the shell, which allows that (flex: 1 1 0content underPAGE_WIDTH.FULL). Its sideways scroll, per-column scrolls, column +, card drag and card menu are unchanged. - #3556 moved the List view's rows onto
ListRow.
This PR covers what was left: the issue page.
What this PR changes
issue-detail.tsx:IssueDetailnow usesDetailPagewithframe={PAGE_FRAME.TOOLBAR}, named by the issue's identifier. The existing toolbar (crumbs, Experimental, ⋯) is passed in astoolbar. It no longer usesautomations-view/automations-scroll. The document inside keeps the plan's type:.desktop-document > .plan-body, 15px/1.65 and the h1 title. The archiveConfirmDialogsits beside the page; it portals either way.issues-page.tsx:DetailFrame(the issue while it is read, or why it could not be) now uses the sameDetailPage. The page's localDetailPagecomponent is renamedIssuePageso it doesn't clash with the import.issues.css: a new.issue-documentkeeps two things the plan's.plan-document-scrollused to supply:--accent, so the description editor's caret and ring keep the plan's colour.- The plan's room under the last line: the page's 40px plus 100px gives the plan's 140px. See below for why.
IssueDetailSkeleton(from #3632, which landed while this was open): it now stands inside the sameDetailPagerather than wrapping its own.plan-document-scroll, so the blocks open where the issue will land.@luke/uiDetailPage: a main column holding only anEmptyState(or a centredErrorState) now fills the column. The state sits a little above the middle, as it does onCollectionPage. Without this, "This issue is gone…" would jump to the top of the page. This is CSS only, scoped with:has(> .luke-empty-state:only-child), and it covers the narrow single-scroll layout too.
No automations-* class is left in the Issues files. Nothing in issues.css became redundant: it never styled the old frame.
Shared component change
DetailPage is shared (@charleslpan's). detail-page.css gains one scoped rule:
- Where the main column's content is only an
EmptyState(a centredErrorStateis one), the column and its content become flex columns. The state then fills the column and stands a little above the middle, asCollectionPage's notice does. - Under 720px of room, the same rule makes the single scroll a flex column.
- The selector is
:has(> .luke-detail-page-content > .luke-empty-state:only-child), so a column holding anything else lays out as before.
The web admin's callers (AdminPage in page-header.tsx: the dashboard, a day, an account, animations) are unaffected. None of them puts a lone EmptyState in a DetailPage. AdminErrorCard stands its centred ErrorState outside any DetailPage, and the refresh failure is an inline ErrorState inside a Stack beside the dimmed content.
Visible changes (agreed with the orchestrator, following #3559's contract cleanups)
On the issue page only:
- Top gap under the toolbar is 16px instead of 40px. This is the shell's section gap under a toolbar.
- No scroll fade at the document's top and bottom edges. The shell draws none (#3559 dropped it the same way).
- Bottom room is kept at 140px, not the shell's 40px. I checked this in the harness with live captions shown. The issue page has no call bar, so captions float at the window's foot (24px up, about 76px tall). With 40px of room, the description's last line ended under the caption box: line at 735–760px, caption at 700–776px in an 800px window. With 140px it clears, ending at 660px, the same as before.
Also: the content column now sits inside the column's own scrollbar-gutter. Where a scrollbar takes room, the 720px measure loses the scrollbar's width (10px in the Linux harness). With macOS overlay scrollbars it takes none.
The board and the list are pixel-identical before and after.
Tests
Every test in issues-page.test.ts passes with no assertion changed, and no assertion named a class the shell renamed. detail-page.test.ts and new-issue-dialog.test.ts pass. No new test: this changes no behaviour, and the centring and the room are CSS that jsdom can't lay out. The screenshots are the evidence.
pnpm check:affected passes: lint, knip, typecheck, tests and build. In this sandbox, discarded-effect and the test task were run one at a time because of memory limits.
Screenshots
These come from a throwaway, uncommitted jsdom test that rendered the real pages with synthetic issues. Headless Chromium then painted them at 1280×800 in .desktop-shell > main.desktop-main, with the sidebar collapsed, using the desktop stylesheet built from main (before) and from this branch (after). This is the same method as #3559.
| Before | After | |
|---|---|---|
| Board | ![]() | ![]() |
| List | ![]() | ![]() |
| Issue page | ![]() | ![]() |
| Issue page, dark | ![]() | ![]() |
| Issue page scrolled to the end, captions shown | ![]() | ![]() |
| Issue gone | ![]() | ![]() |
Not done
desktop-shell.tsx'sIssuesLoading, the empty frame shown while the Issues chunk loads, still renders an empty<section className="automations-view">. It draws nothing, and it is shared in shape withAutomationsLoading, so I left it alone.- Not checked on a Mac: real caption placement during a call, and overlay scrollbars against the column's gutter.
Made with Luke
Summary by cubic
Draws the issue page and its unread frame on @luke/ui's DetailPage under the window's toolbar, instead of borrowing the Automations page's view and scroll. The document inside keeps the plan's type and the editor's accent, and keeps the plan's bottom room so the last line scrolls clear of the floating captions. DetailPage now stands a lone empty or failed state a little above the room's middle, as CollectionPage does.
Visible changes, on the issue page only:
- The gap under the toolbar is 16px instead of 40px.
- The scroll fade at the document's top and bottom edges is gone.











