镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

fix(sidenav): align indicators and preserve width across Settings - #371

Merged
wesbillman merged 12 commits into
mainfrom
cynthiac/sidenav-polish-followup
Sep 29, 2026
Merged

wesbillman merged 12 commits into
mainfrom
cynthiac/sidenav-polish-followup

Conversation

@cynfria

@cynfria cynfria commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Why

The sidenav allowed unread dots to sit outside row highlights, clipped section names, and changed width when opening Settings. Section controls and row highlights also had inconsistent spacing.

What

  • Align unread dots inside row highlights and move them 4px left.
  • Fade overflowing section names using the existing channel-row treatment, and align section actions with tighter spacing.
  • Set a 220px minimum and preserve width across Settings, Back, and reload. Retain width in memory when storage writes fail.
  • Use the existing collapsible navigation drawer at widths of 650px and below, so the sidebar does not squeeze phone-width content. Keep header controls reachable at 320px.
  • Give Settings its own sidebar while preserving personal Profile access and restoring the previous channel view on Back.

How

Reuse the existing sidebar width clamping and community/viewer storage scope. Share the existing overflow-label component between rows and section names. Keep channel labels full-width unless a DM name accessory needs space.

Risk

This touches app navigation, shared shell sizing, and sidebar geometry. At windows no wider than 650px, navigation opens as a 220px drawer over the content and starts collapsed on destination changes. If storage fails, width recovery lasts only for the current app session.

Testing

Current locally checked commit: 0c7356f0 (hosted CI pending). Previous hosted green commit: 279d6fc9. Original polish checks below were at e1060411.

  • The affected-file browser batch passed 84 Chromium/WebKit cases before rebase. Ten rebase-sensitive cases passed afterward, followed by four geometry cases after equivalent spacing-token corrections. Mandatory type, related-unit, and design hooks passed at the pushed head.
  • Added seven browser cases, removed none; three existing cases were renamed. New coverage checks Settings replacement/Back, width restoration/reload, narrow-window width, failed storage writes, section fading/recovery, scrollbar inset, and row-fill bounds. These depend on real layout, browser storage, or route integration.
  • The dot-alignment regression failed in both engines before the layout correction and passed afterward. Other new cases have passing coverage but no separately recorded fail-before run.
  • The old persistent-sidebar assertion now checks Settings replacement and restored scroll/collapse state. The existing narrow Settings test checks full-row visibility after programmatic scrolling; it no longer proves native wheel scrolling.

CI follow-up

  • Hosted CI passed at 279d6fc9: all six Chromium/WebKit journey shards, JavaScript, Rust/tool integration, and browser measurements. Hosted DCO passed; Windows native validation was skipped by the workflow.

  • Migrated Settings journeys to the replacement sidebar, its Back action, and drawer controls. The pending-modal test now exercises the channel drawer directly; its uncertain-publication, Escape, modal-inertness, and focus assertions remain.

  • Extended the width journey to check that opening the phone drawer does not shrink the content and that desktop width is restored. Existing 320px/200% text-size coverage exercises pointer access to Settings controls. No browser cases were added or removed in this follow-up.

  • Accounted for the exact native scrollbar gutter in the row-fill assertion and waited for applied resize geometry without changing tolerances. Restored the real wheel-scroll journey against the current Settings scroll container.

  • Local Chromium/WebKit batch: 165/170 passed before the final corrections. Full affected-file reruns then passed 64 cases, followed by all 10 Settings cases after updating the narrow Back assertion. These reruns cover all failures from that batch. Commands used pnpm test:browser <affected files> --project chromium --project webkit --no-deps on macOS; broad hosted CI remains authoritative for Linux.

  • After integrating main and resolving the agent-activity test overlap, all 16 agent-activity/channel-leave browser cases passed in Chromium and WebKit at bd1af890.

  • The startup-style journey now opens the phone drawer before inspecting navigation controls and closes it afterward; all styling assertions remain. The full file passed in Chromium and WebKit (2 cases, 6.4 seconds) at 279d6fc9. The preceding hosted run had only this stale-test failure in each engine; its other shards passed.

  • At the pushed head, mandatory TypeScript, 71 related unit tests, and all design guards passed. All PR commits have DCO sign-offs.

  • The original JavaScript failure was a timeout in unchanged relay replay coverage; it is tracked independently in Emergency main fix: bound live replay test runtime #372.

Review follow-up

  • Restored the gated community-profile publication journey: pending busy/disabled controls, repeated Enter, rejection with retained Save focus, keyboard retry, success focus recovery, and Cancel focus recovery. Both requests are released in finally; final request counts guard duplicate publication.
  • Preserved an accessible level-one Settings heading and corrected the shell documentation for replacement Settings navigation and the all-page phone drawer.
  • After integrating main, all 22 cases in settings.spec.mjs, notification-settings.spec.mjs, and plugin-import.spec.mjs passed in Chromium and WebKit on macOS (32.0 seconds) at 9b114052. No cases added or removed.
  • Fixed the phone drawer close signal using the existing navigation attempt ID, including reselecting the current destination. Narrow navigation hands focus to main content; channel selection retains the existing composer focus. Desktop navigation remains visible and preserves its focus behavior. Removed manual Hide clicks from the shared Settings helper and channel-selection helper.
  • The narrow channel-switch regression failed before the fix in both engines (drawer remained visible). The final affected eight-file batch passed all 78 Chromium/WebKit cases on macOS in 1.7 minutes before the formatting-only commit hook (8b9ff420). Coverage includes keyboard channel switching and typing, Settings-section/reselection focus, width restoration, and existing profile publication failure/retry. No browser cases added or removed.
  • After merging current main and retaining both navigation helper imports, all 28 layout/drawer cases passed in Chromium and WebKit (58.3 seconds) at 0c7356f0.
  • Top-bar styling and animation remain in PR Polish top bar and animate contextual sidebar toggle #360; its shared shell changes must retain this navigation-attempt close signal when integrated.

Before and after

Matched WebKit fixture captures using synthetic data, light mode, a 1200×800 viewport, and 2× pixel density. Before: base 3a19fa43; after: e1060411. These illustrate browser layout; native visual acceptance remains outstanding.

Unread row — 260px sidebar

Same Alice Fixture row, hovered in both captures.

Before After
Before: unread DM row at 260px After: unread DM row at 260px

Section label and actions — 220px sidebar

Same long section label, with its actions revealed in both captures.

Before After
Before: section label and controls at 220px After: faded section label and aligned controls at 220px

Opening Settings — 360px sidebar

Both captures start with the sidebar resized to 360px before opening Settings. The updated Settings navigation occupies that same sidebar width.

Before After
Before: Settings alongside channel sidebar After: Settings replaces sidebar at the preserved width

Remaining before ready for review

  • Final native screenshots at 220px and 260px, plus a short recording and human visual acceptance, are still outstanding. Browser geometry does not establish native optical alignment.
  • The 200% Settings case uses programmatic scrolling; representative real wheel coverage passes in the layout journey.

Generated with Codex

Align row indicators and section controls, fade overflowing section names, and enforce a 220px minimum sidebar width. Keep Settings width consistent across navigation, narrow windows, and storage failures, and retain personal Profile access.

Signed-off-by: Codex <noreply@openai.com>
Signed-off-by: Codex <noreply@openai.com>
…sh-followup

* origin/main:
  Open pages from search by keyboard once the palette is final (#365)
  feat(agents): one-click Pi install and provider setup (slice 5/5) (#330)

Signed-off-by: Codex <noreply@openai.com>
…sh-followup

* origin/main:
  fix(workflows): keep deletion on the grid with toast recovery (#328)
  feat(channels): leave channels from the management pane (#363)

Signed-off-by: Codex <noreply@openai.com>

# Conflicts:
#	tests/browser/agent-activity.spec.mjs
@cynfria
cynfria marked this pull request as ready for review September 28, 2026 22:26
@cynfria
cynfria requested review from a team, comp615 and wesbillman as code owners September 28, 2026 22:26
Signed-off-by: Codex <noreply@openai.com>

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Star Lord automated source review (via Wes’s account)

Reviewed head 279d6fc900823ea6bb6a16e39113d4da2b099481 against base 5ce7836b197fc4f19b9bd4c23d3f8cd56495df3b. This is a COMMENT, not approval or merge authorization.

Findings

Two actionable findings are attached inline: the narrow overlay does not close for channel/Settings-section navigation, and the Settings test migration removes the held-publication keyboard/failure/retry regression journey without equivalent browser coverage. The latter is a coverage-contract regression, not a claim that profile publication is currently broken.

Assessment: minimalness 9/10, elegance 9/10, correctness 8/10 pending the drawer repair and preservation of the affected recovery contract. Width clamping/session fallback and extraction of the existing fading-label behavior reuse existing owners appropriately. Groot’s independent navigation/accessibility source review was reconciled against the same snapshot.

Optional improvements

  • Preserve a screen-reader-accessible level-one Settings heading. Settings.module.css:104–106 hides the old sidebar including the h1 in Settings.tsx:182; the replacement sidebar has group h2s and the detail headers default to h2. The region still has its Settings name, so this is heading-navigation polish, not an unnamed-region defect. An sr-only heading in the detail pane would preserve that landmark in heading traversal.
  • Update docs/shell-design.md to describe the Settings replacement sidebar and all-page narrow drawer; its persistent-channel-sidebar/Settings-only disclosure descriptions now contradict the implementation.

Evidence and limits

  • Read the full 37-file diff, relevant owners/callers, repository instructions and design/vision documents. Reviewed success/cancel separately from error/retry/focus paths. The retained real-wheel Settings journey at tests/browser/layout.spec.mjs:640–680 addresses representative wheel input; the 200% case is explicitly programmatic, as the description discloses.
  • Reviewed the public description, all six attached images and all six commit messages. No additional public-material disclosure finding in those inputs or the changed source/configuration/fixtures. The synthetic browser images compare 3a19fa43 to e1060411, not this head.
  • Isolated exact-head source archive: 1,649 Git blobs verified, then SHA-256 contents rechecked unchanged; no dirty source inputs or live-checkout changes.
  • Source-only: no PR code, tests, builds, installs or app launches executed. One hosted CI snapshot for run 36493396900 reports JavaScript, Rust/tool integration, all six Chromium/WebKit journey shards, browser measurements and CI required passing at this head; Windows native validation was skipped. Author-reported local checks were not independently rerun. Green CI does not establish the missing behavior.
  • Current-head native geometry, browser focus/recovery behavior and human acceptance remain unverified. The description itself leaves final native captures/recording and human visual acceptance outstanding; this review does not attest the readiness checklist or buzz-review-completed.

Comment thread src/app/shell/AppShell.tsx Resolved
Comment thread tests/browser/settings.spec.mjs Resolved
Signed-off-by: Codex <noreply@openai.com>
Signed-off-by: Codex <noreply@openai.com>
Signed-off-by: Codex <noreply@openai.com>
…sh-followup

* origin/main:
  Add message-level read and unread controls (#352)
  feat: add per-category notification alert sounds with app-owned playback (#356)
  test(relay): stabilize per-channel replay boundary coverage (#378)
  fix(design-system): keep button labels single-line and corners capsule-shaped (#357)

Signed-off-by: Codex <noreply@openai.com>
Signed-off-by: Codex <noreply@openai.com>
@cynfria
cynfria marked this pull request as draft September 29, 2026 00:04
…sh-followup

* origin/main:
  Keep image attachments compact with scrolling thumbnail strips (#313)
  Retire the notification presentation wait when its service closes (#379)

Signed-off-by: Codex <noreply@openai.com>

# Conflicts:
#	tests/browser/layout.spec.mjs
@cynfria
cynfria marked this pull request as ready for review September 29, 2026 00:08

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Carl, an automated reviewer, commenting via Wes’s GitHub account.

No blocking findings at 0c7356f0d5591e541f60591a4dd2249c9a1e8a98. This is a follow-up COMMENT, not approval or merge authorization. Minimalness, elegance and correctness: 9/10 each.

  • Both prior P2 findings are resolved: navigation attempts close the phone drawer and hand off focus, including Settings-section reselection; the gated profile publication failure/keyboard-retry journey is restored. The accessible Settings heading and shell documentation are also corrected. Independent navigation and profile/persistence source-review lanes agree.
  • Independently ran the complete settings.spec.mjs and settings-sidebar-width.spec.mjs files in Chromium and WebKit on macOS at this clean head: 16/16 passed (20.6s). This covers drawer focus, width persistence/reload/storage failure and profile rejection/retry. One optional P3 remains inline: restore the distinct-local-default reload guard. It is a coverage weakness, not a demonstrated runtime defect.
  • Current-head hosted CI is still in progress; native visual acceptance and the final native captures/recording remain outstanding as disclosed in the description. Browser checks do not certify those. Reviewed the full base-to-head diff, description, attached media and commit text for publication hygiene; no internal-information or accidental committed review-artifact finding in those materials.

Code review is non-blocking. Finish hosted checks and the disclosed human/native acceptance before claiming the readiness checklist complete.

await page.getByRole("menuitem", { name: "Settings", exact: true }).click();
await expect(
page.getByRole("menu", { name: "Updated community profile" }),
page.getByRole("menu", { name: "Updated local profile" }),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3, optional] Restore the distinct local-default reload guard

The migrated test no longer changes the saved local profile before reload. A successful community save also updates that local default (src/app/ProfileSettings.tsx:270–277), so both now contain “Updated community profile”: the reload assertions can pass even if Settings/the header incorrectly use the local seed instead of confirmed community state. The base deliberately set saved.profile.name = "Local default only" before reloading to distinguish them.

Please restore that injection and check the actual menu name here (Updated community profile). Updated local profile is not supplied anywhere else in the current src/tests inputs, so this hidden assertion currently passes without proving dismissal. This is lost regression coverage, not evidence that runtime profile loading is broken.

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Star Lord automated source review (via Wes’s account)

Reviewed head 0c7356f0d5591e541f60591a4dd2249c9a1e8a98 against base 423f7215e124aa68b828c85f9040703a3fe9913d. This is a COMMENT, not approval or merge authorization.

Follow-up result

Both prior P2 findings are addressed in source; no new actionable finding in the repairs. This follow-up preserves the previous review’s exit criteria rather than reopening unrelated portions of the change.

  • Narrow drawer navigation: App.tsx:157 supplies the existing navigation-attempt ID to AppShell.tsx:56–62. The controller starts a fresh attempt for channel/Settings-section selection, reselection and ordinary retry, while in-place target normalization retains the ID. The drawer therefore closes on navigation, not on unrelated resolution updates. Focus is handed to the main region only when the narrow toggle is visible; desktop section focus is not changed by this effect. Reviewed the supported navigation callers, failure/retry presentation and composer mount-focus ownership. settings-sidebar-width.spec.mjs:76–116 now asserts channel closure and typing, Settings-section closure and main focus, and same-section reselection. The shared helpers no longer hide the drawer on the implementation’s behalf.
  • Profile publication coverage: settings.spec.mjs:408–573 restores an explicit request gate, pending busy/disabled assertions, repeated Enter, rejection with retained Save focus, keyboard retry, success/Cancel focus recovery and exactly two publication requests. Both held requests are released in finally. These assertions match the existing form, publication receipt and focus-cleanup owners; this resolves the earlier coverage-contract finding, not a claim of newly repaired publication code.
  • The previously optional accessible Settings heading and shell-documentation corrections are also present.

Source assessment: minimalness 9/10, elegance 9/10, correctness 9/10. The repair reuses the navigation owner rather than adding another route tracker. Groot’s bounded independent navigation/accessibility lane is complete and reconciled against this snapshot.

Evidence and limits

  • Reviewed the follow-up changes and affected owners/callers against repository instructions, contribution/test-layer rules, shell design and the relevant Buzz vision documents. Success/cancel and error/retry focus paths were considered separately.
  • Inspected the public description, all six attached images, all twelve PR commit messages and the changed publication surface. No additional disclosure finding in those reviewed inputs. The synthetic images compare 3a19fa43 to e1060411, not this head.
  • Isolated exact-head archive: 1,679 Git blobs verified, then SHA-256 contents rechecked unchanged; no dirty source inputs or live-checkout changes.
  • Source-only: no PR code, tests, builds, installs or app launches executed. The single hosted CI snapshot for run 36501498676 showed browser measurements, DCO, Semgrep and zizmor passing; JavaScript, Rust/tool integration and all six browser-journey shards were still in progress. Windows native validation was skipped. This is a snapshot, not a current CI-green claim; author-reported local runs were not independently rerun.
  • Current-head browser focus/recovery behavior, native geometry and human acceptance remain independently unverified. The description still leaves final native captures/recording and human visual acceptance outstanding. This review does not attest the readiness checklist or buzz-review-completed.

@wesbillman
wesbillman merged commit 7e065bd into main Sep 29, 2026
14 checks passed
@wesbillman
wesbillman deleted the cynthiac/sidenav-polish-followup branch September 29, 2026 00:38
matt2e added a commit that referenced this pull request Nov 7, 2026
## Problem

The **Drafts & sent** row in the sidebar didn't line up with the channel
rows beneath it:

- The count (`1`) sat **2px** from the right edge of the row's highlight
instead of the 6px every other sidebar row uses, so it looked glued to
the edge.
- The row's highlight and count ran **10px past** the channel rows' end
column wherever scrollbars take space, because the page rows reserved no
scrollbar gutter while `.channelList` reserves one.
- The paper-plane icon started **1px** and the label **2px** left of the
`#` and channel names, because page rows used an 18px icon box while
channel rows use 20px.

Only the Drafts & sent row changes. The channel rows and the header
controls (All | Solo | Team, `+`) are pixel-identical to `main`.

| Before | After |
|---|---|
| ![Before: the 1 hugs the highlight edge, the row runs past the Alpha
pill, and the icon/label start left of the channel
rows](https://github.com/user-attachments/assets/7a862359-c08e-48c1-8b19-31261d2031ca)
| ![After: the 1 ends in the channel rows' trailing column; the icon and
label share the channel rows' columns; the header controls are
unchanged](https://github.com/user-attachments/assets/54d25ab1-67e9-4219-b7cb-dfdc48f4b560)
|

Same shots with **Drafts & sent** hovered so its highlight is visible,
and guide lines drawn at the channel row's icon-left (magenta),
label-left (blue) and trailing-right (orange):

| Before | After |
|---|---|
| ![Before, annotated: the Drafts highlight overshoots the Alpha pill by
10px; the 1 is well right of the orange line; the icon tip crosses the
magenta line and the D crosses the blue
line](https://github.com/user-attachments/assets/9afb91b1-d72a-4437-a252-f25403691721)
| ![After, annotated: both highlights share edges; the 1 ends on the
orange line 6px inside; the icon and label sit on the magenta and blue
lines like # and
Alpha](https://github.com/user-attachments/assets/75b44b55-c672-4072-bd7f-caa624b1ee16)
|

Zoom on the icon and label columns (4× on a 2× capture):

![Zoom: before, the paper plane and D sit 1–2px left of the guides while
# and A sit on them; after, both rows sit on the
guides](https://github.com/user-attachments/assets/1cfd838e-427e-4d8f-83bd-8b82a7b2147c)

### What did *not* change

Header controls, `main` vs this branch, same crop — **0 of 45,760 pixels
differ**:

![Header controls before, after, and diff: the segmented control and +
button are
identical](https://github.com/user-attachments/assets/f793fcb3-ed54-4234-a491-92e3fba4333c)

Whole-sidebar pixel diff (`main` vs branch): every changed pixel is
inside the Drafts & sent row.

![Whole-sidebar diff with changed pixels in red: only the Drafts & sent
icon, label and count change; header, section headings and channel rows
are
untouched](https://github.com/user-attachments/assets/0b789a24-ae5e-46c1-83b1-8ecdc8f1236d)

## Measurements

CSS px from the viewport's left edge, Chromium, light theme, 1440px,
default font size. The channel row and header values are identical on
`main` and this branch.

| | Channel row | Drafts & sent, before | Drafts & sent, after |
|---|---|---|---|
| Pill left | 69 | 69 | 69 |
| Pill right | 295 | **305 (+10)** | 295 |
| Icon box width | 20 | **18** | 20 |
| Icon glyph left | 75 | **74 (−1)** | 75 |
| Label left | 99 | **97 (−2)** | 99 |
| Trailing / count right edge | 289 | **303 (+14)** | 289 |
| Count's inset from pill edge | 6 | **2** | 6 |

| Header | main | branch |
|---|---|---|
| Segmented control (tablist) | x 73–261, 188×24 | x 73–261, 188×24 |
| `+` New button | x 273–305, 32×32 | x 273–305, 32×32 |
| One-line wrap breakpoint (sidebar width) | 224 | 224 |

## Changes

Three commits, each passing on its own:

1. **`fix(sidebar): align drafts & sent count`** —
`Channels.module.css`: the shared rule for rows that paint their own
highlight (page rows, plugin contribution rows, Solo chat rows) was
subtracting the highlight's 4px left offset from the *right* padding
too, leaving 2px. It is now always 6px, matching `ChannelSidebarRow` and
`DESIGN.md`.
2. **`fix(sidebar): align page rows with channel rows`** —
`.shell-page-icon` goes 18px → 20px to match `.iconSpace`.
`PrimarySidebar.module.css`: the existing `.destinations` container that
holds the header's page rows adopts `.channelList`'s scrollbar-gutter
recipe (`scrollbar-gutter: stable`, thin transparent scrollbar,
`overflow: hidden`), so the page rows and the channel list reserve the
same width on every platform. It swaps 4px of block margin for 4px of
block padding so the rows' focus rings aren't clipped and the rows don't
move. The header controls are not touched.
3. **`test(sidebar): lock in page row geometry`** — new cases in
`tests/browser/sidebar-geometry.spec.mjs` that create a draft and assert
the count inset (quarter-px rounded; light/dark, 1440/900, larger text),
that the Drafts row's pill edges, icon center, label and trailing column
match a channel row, that the segmented control and `+` still span the
header's full content width, and that the first/last page rows' focus
rings fit inside the clipped container. A `@classic-scrollbars` case
covers the gutter so it can't silently pass. Each assertion fails with
the corresponding CSS reverted.

Because the fixes are in shared rules, the Reminders "due" count and
plugin row counts get the same inset.

## Things to be aware of

- Channel unread *dots* still sit 4px further in than counts
(deliberate, from #371); untouched.
- `.destinations` now clips at its padding box. Measured: first and last
page rows keep the 4px a focus ring needs on all sides. Menus, tooltips
and popovers are portaled, so unaffected.

## Verification

- `sidebar-geometry` spec: 7/7 in Chromium, WebKit and
`chromium-classic-scrollbars` at head; fix commit alone passes
`sidebar-geometry` + `new-menu-layout`.
- Broader sidebar, layout, solo, new-menu-layout,
settings-sidebar-width, sidenav-polish, navigation-sidebar and
page-placement specs: 243/243 across all three projects.
- Biome (`--error-on-warnings`) and `design:check` pass.
- Not checked directly: macOS WKWebView with always-visible scrollbars,
Windows WebView2 (both areas now share one rule, so they should agree
whatever the scrollbar width).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: mtoohey <mtoohey@squareup.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants