Repository navigation
Commit a49d633
fix(app-shell): the inbox popover fits a phone, and its controls and the notification switches are 44 px tap targets (#29165)
<!-- claude-projects-attribution: {"github_login":"zhuangjianguo"} -->
_Requested by **Steedos** · [project
thread](https://claude.ai/code/project/chan_018ETKaNwMZCNRYD7D8Q9Ubb?thread=cmsg_018ETKaNwMZCNRYD7D8Q9UbbVnsesRDUVqMHYYYFpsmioi)_
Fixes #29076
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么**:手机宽度(`md` 以下)下,收件箱弹层的宽度不再超出屏幕,左右各留 0.5 rem;弹层里的按钮都至少 44 px
高,包括「全部已读」、三个标签页、未读/全部筛选,以及三个「查看全部」类入口。三个标签页在手机上不显示图标,因此能排进一行。账号菜单里的两个通知开关,现在整行都可以点,行高
44 px。桌面尺寸不变。
- **为什么改**:移动端 App 直接嵌入 Console。375 px 的手机上弹层宽 384 px,右侧 9 px
被裁掉,「Activity feed」标签和「Mark read」列看不全。弹层内的按钮只有 16–36 px 高,开关只有 44 × 24。
- **风险与回滚**:低。只改两个组件的 `className`:开关行从 `div` 改成 `label`,弹层加了
`collisionPadding`。不加键、不加 prop、不加文案。回滚即回退本 PR。
- **先看**:`ui/packages/app-shell/src/layout/InboxPopover.tsx` 里的
`PopoverContent`(`max-w-[calc(100vw-1rem)]` 与 `collisionPadding`),以及
`PHONE_TAP` /
`TAB_TRIGGER_CLASS`;`ui/packages/app-shell/src/layout/NotificationPreferencesMenu.tsx`
里的 `ROW_CLASS`:开关行改成 `label` 后,点整行就是点开关,被浏览器屏蔽的桌面通知开关仍然点不动。
- **两分钟验证**:`pnpm --dir ui exec vitest run
packages/app-shell/src/layout/__tests__/InboxPopover.phoneWidth-29076.test.tsx
packages/app-shell/src/layout/__tests__/NotificationPreferencesMenu.phoneWidth-29076.test.tsx`,预期
9 个用例全部通过。
- **需要你做的**:无,席位落地。
Part of #29040. Claim: issuecomment-6571189550, surface amended in
issuecomment-6572115270.
## What changes
The mobile app hosts the Console in a WebView, so below `md` the Console
is the phone UI. This PR covers the Notifications flow: the inbox
popover, marking notifications read, opening the target record, and the
account menu's notification switches.
- **`InboxPopover`**: the popover keeps `w-96` and gains
`max-w-[calc(100vw-1rem)]` with `collisionPadding={8}`. At 375 px it is
now 359 px wide at x = 8; it was 384 px at x = 0, with its right 9 px
cut off. Below `md` (`max-md:` utilities, so desktop is unchanged),
every control the popover draws besides the rows gets `min-h-11`. These
are "Mark all read", the three tabs, the Unread and All filters, "View
all notifications", "View approvals", "Open Approvals Inbox" and "View
all activity". "All" also gets `min-w-11`. Below `md` the tabs drop
their icons and size by content (`flex-auto`, `px-1.5`), so all three
fit the narrower strip. The bell trigger's class is not touched; #29075
owns it.
- **`NotificationPreferencesMenu`**: each switch row is now a `label`
that wraps its switch. A tap anywhere on the row toggles the switch, and
below `md` the row is 44 px tall. The `Switch` primitive (44 × 24) is
not touched. A disabled desktop switch stays off whatever is tapped, and
turning it on still asks for permission from that tap, the one gesture
that may ask.
No key, prop, locale string or spec surface is added.
## Tests
- `InboxPopover.phoneWidth-29076.test.tsx` (new, real Radix popover,
tabs and English pack): the dialog carries the viewport cap and keeps
`w-96`. Every listed control carries the phone floor in each tab and
state, including both Approvals states. "All" carries its min width.
Each tab's icon is hidden below `md`.
- `NotificationPreferencesMenu.phoneWidth-29076.test.tsx` (new): each
switch sits in a 44 px label row. Tapping the "In-app alerts" text
toggles it. Tapping the "Desktop notifications" text asks for permission
once. A blocked desktop row is neither asked nor turned on.
- Against `origin/main`'s two source files, the new files went 8 failed
and 1 passed. The one that passed is the blocked-row guard, which main
also satisfies.
## Acceptance notes
The card's run record, measured in a real browser. The Console is a
production build of `ui/apps/console`, served by `vite preview` and
proxied to `objectstack dev --seed-admin --fresh`. The examples are
showcase (`com.example.showcase`) and CRM (`com.example.crm`). Chromium
ran with `isMobile` and `hasTouch` at 375×812 and 390×844. Showcase's
inbox rows come from its shipped `showcase_task_assigned_notify` flow,
fired by reassigning seeded tasks. CRM ships no notify flow, so its rows
were inserted as `sys_inbox_message` rows that link to `crm_lead`
records. Pages: the app's landing page, the open inbox and its three
tabs, the target record, the full inbox (`sys_inbox_message?view=mine`)
and the account menu.
| Check | 375 showcase | 375 CRM | 390 showcase | 390 CRM |
| --- | --- | --- | --- | --- |
| No horizontal page scroll | pass / pass | pass / pass | pass / pass |
pass / pass |
| Touch targets ≥ 44 px | **fail** / pass | **fail** / pass | **fail** /
pass | **fail** / pass |
| Dialogs and drawers fit the viewport | **fail** / pass | **fail** /
pass | pass (0 px spare) / pass | pass (0 px spare) / pass |
| Virtual keyboard does not cover the focused field | n/a | n/a | n/a |
n/a |
| Long lists responsive at 4× CPU | pass / pass | pass / pass | pass /
pass | pass / pass |
| Mark read, open the target record | pass / pass | pass / pass | pass /
pass | pass / pass |
Each cell reads before / after.
- **Touch targets, before → after (375 / 390):**
| Control | Before | After |
| --- | --- | --- |
| Mark all read | 71 × 16 | 87 × 44 |
| Tabs | 28 tall | 44 tall |
| Unread | 24 tall | 44 tall |
| All | 30 × 24 | 44 × 44 |
| View all notifications | 16 tall | full width × 44 |
| View approvals | 36 tall | 124 × 44 |
| Open Approvals Inbox | 16 tall | 146 × 44 |
| View all activity | 16 tall | full width × 44 |
| In-app alerts / Desktop notifications switches | 44 × 24 | rows 246 ×
44 |
Rows (293–318 × 75) and the group "Mark read" (64 × 75) already passed.
- **Keyboard: not applicable.** No step of this flow focuses a text
field. The popover has none, and at phone width the full inbox page
shows no search input; its toolbar is the view switcher, Filter and
Display.
- **4× CPU** (CDP `Emulation.setCPUThrottlingRate`, production build):
tap to open the popover, five opens at 375 px. On main this took 298–554
ms (showcase) and 316–662 ms (CRM). On this branch it took 460–627 ms
and 288–498 ms. Scrolling the popover's list (up to 20 rows) had a worst
frame of 27–85 ms.
- **Still failing, carried by other cards:** the bell trigger is 32 ×
32. Its class belongs to the top-bar sweep, #29075, and this PR leaves
it alone. The full inbox page is the generic list view. Its toolbar has
the view switcher at 125 × 24 and Filter and Display at 28 × 28, and in
some runs the first scroll frame took 284–495 ms at 4×. That belongs to
the Lists card, #29074.
- Before and after screenshots of each step at both widths are in the
project folder, as the card asks. The seat links them.
## Verification
Readings on head `e2c6f5d4` (base `6b3ba82c`).
<details><summary>Tests</summary>
- Every ui test file that names `InboxPopover` or
`NotificationPreferencesMenu` (`git grep -l`, 47 files, including the
two new ones and the `AppHeader` and Home suites), under the verify lock
with `--maxWorkers=2`: 47 files and 454 tests passed. This is a
narrowing; CI's Test UI runs the rest of app-shell.
- Ablation (one time, not kept): with `origin/main`'s `InboxPopover.tsx`
and `NotificationPreferencesMenu.tsx` copied in, the two new files went
8 failed and 1 passed. The restore was proven by `cmp` against the fix.
</details>
<details><summary>Type-check and lint</summary>
- `pnpm --filter @object-ui/app-shell run type-check` (both `tsc` legs,
src and tests): exit 0.
- eslint (`--no-inline-config`, from `ui/`) on the four changed source
and test files: exit 0.
- `pnpm check:new-line-citations` under `ui/`: 0 new citations.
</details>
<details><summary>Derived gates</summary>
`node scripts/pm/dispatch-gates.mjs --ran`: 34 derived families
accounted for, 34 run, 0 NOT MEASURED, every one exit 0. That includes
`node scripts/check-sdui-manifest.mjs` and its `--self-test`, `pnpm
--dir ui exec vitest run scripts/` (169 files passed, 2 skipped; 4900
tests passed) and `pnpm check:type-check-debt` under the verify lock.
The PR-body gates (`check-changeset-no-major`,
`check-closing-keyword-parity`, `check-adr-0087-registration`,
`check-empty-changeset`) ran on this body.
</details>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01QsR2jS2XRtTSjBZnMRZ9UG
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 6dda0ce commit a49d633
5 files changed
Lines changed: 268 additions & 19 deletions
File tree
- .changeset
- ui/packages/app-shell/src/layout
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
105 | 105 | | |
106 | 106 | | |
107 | 107 | | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
108 | 120 | | |
109 | 121 | | |
110 | 122 | | |
| |||
384 | 396 | | |
385 | 397 | | |
386 | 398 | | |
387 | | - | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
388 | 407 | | |
389 | 408 | | |
390 | 409 | | |
| |||
393 | 412 | | |
394 | 413 | | |
395 | 414 | | |
396 | | - | |
| 415 | + | |
397 | 416 | | |
398 | 417 | | |
399 | 418 | | |
| |||
438 | 457 | | |
439 | 458 | | |
440 | 459 | | |
441 | | - | |
442 | | - | |
443 | | - | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
444 | 463 | | |
445 | 464 | | |
446 | 465 | | |
| |||
451 | 470 | | |
452 | 471 | | |
453 | 472 | | |
454 | | - | |
455 | | - | |
| 473 | + | |
| 474 | + | |
456 | 475 | | |
457 | 476 | | |
458 | 477 | | |
| |||
464 | 483 | | |
465 | 484 | | |
466 | 485 | | |
467 | | - | |
468 | | - | |
| 486 | + | |
| 487 | + | |
469 | 488 | | |
470 | 489 | | |
471 | 490 | | |
| |||
479 | 498 | | |
480 | 499 | | |
481 | 500 | | |
482 | | - | |
| 501 | + | |
483 | 502 | | |
484 | 503 | | |
485 | 504 | | |
| |||
493 | 512 | | |
494 | 513 | | |
495 | 514 | | |
496 | | - | |
| 515 | + | |
497 | 516 | | |
498 | 517 | | |
499 | 518 | | |
| |||
624 | 643 | | |
625 | 644 | | |
626 | 645 | | |
627 | | - | |
| 646 | + | |
628 | 647 | | |
629 | 648 | | |
630 | 649 | | |
| |||
642 | 661 | | |
643 | 662 | | |
644 | 663 | | |
645 | | - | |
| 664 | + | |
646 | 665 | | |
647 | 666 | | |
648 | 667 | | |
| |||
656 | 675 | | |
657 | 676 | | |
658 | 677 | | |
659 | | - | |
| 678 | + | |
660 | 679 | | |
661 | 680 | | |
662 | 681 | | |
| |||
731 | 750 | | |
732 | 751 | | |
733 | 752 | | |
734 | | - | |
| 753 | + | |
735 | 754 | | |
736 | 755 | | |
737 | 756 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
42 | 49 | | |
43 | 50 | | |
44 | 51 | | |
| |||
65 | 72 | | |
66 | 73 | | |
67 | 74 | | |
68 | | - | |
| 75 | + | |
69 | 76 | | |
70 | 77 | | |
71 | 78 | | |
| |||
75 | 82 | | |
76 | 83 | | |
77 | 84 | | |
78 | | - | |
79 | | - | |
| 85 | + | |
| 86 | + | |
80 | 87 | | |
81 | 88 | | |
82 | 89 | | |
| |||
91 | 98 | | |
92 | 99 | | |
93 | 100 | | |
94 | | - | |
| 101 | + | |
95 | 102 | | |
96 | 103 | | |
97 | 104 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
0 commit comments