refactor(desktop): draw the issue page on @luke/ui's DetailPage

Merged
DA
7d ago
+105-53

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.FULL for the board), along with EmptyState ("No issues yet") and ErrorState.
  • #3559 also removed .issue-board-scroll. The board stands full-height inside the shell, which allows that (flex: 1 1 0 content under PAGE_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: IssueDetail now uses DetailPage with frame={PAGE_FRAME.TOOLBAR}, named by the issue's identifier. The existing toolbar (crumbs, Experimental, ⋯) is passed in as toolbar. It no longer uses automations-view/automations-scroll. The document inside keeps the plan's type: .desktop-document > .plan-body, 15px/1.65 and the h1 title. The archive ConfirmDialog sits 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 same DetailPage. The page's local DetailPage component is renamed IssuePage so it doesn't clash with the import.
  • issues.css: a new .issue-document keeps two things the plan's .plan-document-scroll used 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 same DetailPage rather than wrapping its own .plan-document-scroll, so the blocks open where the issue will land.
  • @luke/ui DetailPage: a main column holding only an EmptyState (or a centred ErrorState) now fills the column. The state sits a little above the middle, as it does on CollectionPage. 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 centred ErrorState is one), the column and its content become flex columns. The state then fills the column and stands a little above the middle, as CollectionPage'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:

  1. Top gap under the toolbar is 16px instead of 40px. This is the shell's section gap under a toolbar.
  2. No scroll fade at the document's top and bottom edges. The shell draws none (#3559 dropped it the same way).
  3. 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.

BeforeAfter
Board
List
Issue page
Issue page, dark
Issue page scrolled to the end, captions shown
Issue gone

Not done

  • desktop-shell.tsx's IssuesLoading, 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 with AutomationsLoading, 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


Devin Review


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.