Files
multica/packages/ui/styles
Naiyuan Qing d8ae2005f1 MUL-5713: fix mobile issue detail spacing (#6415)
* fix(issues): give the phone back the space issue detail was spending on chrome

Issue detail reads as cramped on a phone because three separate things each
take a slice of a 393px screen and none of them was decided for that width.

Content gutters. `px-8 py-8` is a comfortable reading margin on a desktop
column; on a phone it spends 64px — 16% of the width — on nothing. Below `md`
they drop to 16px.

A pinned composer. `sticky` is a stored preference, answered by a user sitting
at a wide screen. Applied to a phone it costs ~15% of the viewport at every
scroll position on a surface people mostly read, and it parks the composer
under the chat launcher — covering its own send button. It now yields below
`md` without rewriting the preference, so widening the window restores it.

The launcher's corner. `tokens.css` already declares that corner off-limits to
page content and ships `--chat-launcher-clearance` to yield by; exactly one
site honoured it. Two sibling utilities cover the other two ways of reaching
the corner (scroll content ending in it, a centred overlay growing into it),
and the six floating toolbars plus the issue-detail column now use them.

Also fixes two mobile bugs found on the way:

Inbox wrapped `IssueDetail` in its own `overflow-y-auto`, which collapsed the
detail's inner scroller to content height. That took its header — and the
done/pin/more/sidebar actions in it — out of the pinned position, made
`position: sticky` inside it a no-op, and pointed both scroll restoration and
the timeline virtualizer at an element that never scrolls. Removing the wrapper
would have left two stacked 48px bars, so the inbox's back control moves into
the detail's own header through a `leading` slot on `PageHeader`. The detail
owns the whole phone screen in four states, so the slot is threaded through all
four — loaded, loading, not-found and crashed — since missing one strands the
reader with no way back.

The sidebar is a Sheet on a phone and never closed itself, so tapping a nav
item navigated underneath it and read as a dead tap. It now dismisses on
`pathname`, which covers the nav groups, the pinned items and the workspace
switcher's programmatic push in one place.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(inbox): keep the way back for a mobile notification with no issue

`InboxItem.issue_id` is nullable, and `detailContent`'s ternary has three
branches, not two: a null-issue row falls to a plain notification block, not
to `null`. So the mobile `{detailContent ?? mobileBackBar}` guard was dead
code — `detailContent` is truthy whenever a row is selected — and that block
has no header, which is where the back control now lives.

The result was a dead end: opening a quick_create_failed or
quick_create_unconfirmed item on a phone left the reader with the notification
body, an archive button, and no route back to the list.

The two kinds of selection get their chrome from different places, so the
mobile branch now splits on `issue_id`. An issue hands the whole screen to
`IssueDetail`, which owns its scroller and takes the back control through
`leadingAction`. A notification keeps a bar and a scroll body of its own,
since a plain block has neither.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 13:58:18 +08:00
..