fix(3.1.10): responsive chat header pills (wrap instead of overlap on narrow chat) - #267
Conversation
π¦ ClawReviewPoked my eyestalks out for this one. Quick tour: CSS-only fix for chat header pills overlapping on narrow panels: switches At a glance
Good to know
β ClawReview π¦, your resident reef crab. Just orientation β CodeRabbit does the line-by-line, humans do the merge. Conventions: docs. |
3acb623 to
b31f181
Compare
|
Warning Review limit reachedYouβve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 53 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review detailsβοΈ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: π Files selected for processing (1)
π WalkthroughWalkthroughChatPopup now enforces a 340px minimum width during resizing and panel layout, updates its opening animation, and freezes mascot positioning while open. Chat header pills constrain overflow, and the service worker cache version advances to v4. ChangesChat popup layout and interaction
Service worker cache version
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested reviewers: π₯ Pre-merge checks | β 3 | β 2β Failed checks (2 warnings)
β Passed checks (3 passed)
β¨ Finishing Touchesπ§ͺ Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
π€ Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/ChatPopup.tsx`:
- Around line 1397-1400: Normalize persisted panel widths to MIN_CHAT_WIDTH when
initializing or synchronizing panel state, including any initialPanelWidth value
below the new floor, so panelWidth and parent state reflect the rendered width.
Update the persisted parent value when clamping is required, while preserving
existing mobile and sizing behavior.
πͺ Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
βΉοΈ Review info
βοΈ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 22c10d73-e509-4954-9a9b-4fae29ea77a3
π Files selected for processing (2)
src/app/globals.csssrc/components/ChatPopup.tsx
| ? { width: panelWidth, minWidth: MIN_CHAT_WIDTH, height: 'auto', maxHeight: 'none', borderRadius: 0 } | ||
| : mobile | ||
| ? { width: 'auto', height: 'auto', maxHeight: 'none', borderRadius: 0 } | ||
| : { width: size.w, height: size.h, maxHeight: 'calc(100vh - 60px)', borderRadius: 16 }), | ||
| : { width: size.w, minWidth: MIN_CHAT_WIDTH, height: size.h, maxHeight: 'calc(100vh - 60px)', borderRadius: 16 }), |
There was a problem hiding this comment.
ποΈ Data Integrity & Integration | π‘ Minor | β‘ Quick win
Normalize persisted panel widths to the new floor.
minWidth changes only the rendered CSS width. An existing persisted initialPanelWidth between 280px and 339px can still remain in panelWidth and the parent state, producing a 340px panel with a smaller recorded width. Clamp the value when initializing/syncing panel state, and update the persisted value if the parent stores it.
π€ Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/ChatPopup.tsx` around lines 1397 - 1400, Normalize persisted
panel widths to MIN_CHAT_WIDTH when initializing or synchronizing panel state,
including any initialPanelWidth value below the new floor, so panelWidth and
parent state reflect the rendered width. Update the persisted parent value when
clamping is required, while preserving existing mobile and sizing behavior.
On a narrow chat the provider / model / thinking selector pills overlapped into an unreadable strip. Two parts: 1. .header-dropdown-trigger gets width:100% so the button fills its flex-shrinking .header-dropdown parent. Previously the button kept its content width and spilled past the shrunk parent, so overflow:hidden on .chat-header-pills clipped / overlapped the pills instead of the labels truncating. Now every pill gives ground evenly and its label ellipsizes (the chevron stays β it's reserved in the 24px right padding). 2. Single row (no wrap) + overflow:hidden, and the chat window clamps to MIN_CHAT_WIDTH (340px) on both resize paths + the rendered width, so the window stops shrinking once the pills reach a readable minimum instead of smashing them. The open menu is portaled to <body> (HeaderDropdown), so clipping the row can't hide it. Verified at 320-420px: even truncation, carets visible, zero overlap. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
b31f181 to
e5c6e23
Compare
- Stop streaming the frozen mascot's position into mascotX while the chat is open (page.tsx). That nudged mascotX for a frame right after opening, so the popup flashed to the wrong corner before settling. mascotX is now captured once from the tap. - Grow the popup OUT of the mascot: transform-origin pinned to the popup's bottom edge, aligned horizontally with the mascot, and scale 0.82 -> 1 on an easeOutExpo curve (cubic-bezier(0.16,1,0.3,1)) over 0.36s. Smooth, premium, emanates from where you tapped instead of scaling from the popup centre. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
e239971 to
419106a
Compare
β¦he 3.1.10 chat-UI changes Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
π€ Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/app/globals.css`:
- Around line 143-150: Update the header selector-pills container around the
existing overflow rules to allow wrapping with flex-wrap: wrap, and ensure the
header/layout grows to accommodate additional rows instead of clipping them.
Apply the same behavior to the related selectors at the referenced nearby rule
blocks, preserving the existing pill styling and overflow behavior where it does
not prevent wrapping.
In `@src/components/ChatPopup.tsx`:
- Around line 1391-1395: Align the fallback mascot percentage used by popup
positioning and animation origin in ChatPopup: update the defaultLeft
calculation and mascotCenterPx calculation to reuse the same fallback value when
mascotX is omitted, preserving the existing explicit mascotX behavior.
πͺ Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
βΉοΈ Review info
βοΈ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 4e2e07a7-4740-443b-859c-6d2c422f0d94
π Files selected for processing (4)
public/sw.jssrc/app/globals.csssrc/app/page.tsxsrc/components/ChatPopup.tsx
| /* Keep the pills on a SINGLE row: as the chat panel narrows they squeeze | ||
| * and their labels truncate with "..." (each trigger reserves 24px on the | ||
| * right so the chevron never disappears) β they never wrap to a second row | ||
| * or overlap. overflow:hidden clips any final overshoot cleanly; the chat | ||
| * window enforces a min-width (see ChatPopup) so the pills can't be | ||
| * squeezed past a readable size. The open menu is portaled to <body> | ||
| * (see HeaderDropdown), so clipping the row here can't hide the popover. */ | ||
| overflow: hidden; |
There was a problem hiding this comment.
π― Functional Correctness | π Major | β‘ Quick win
Allow selector pills to wrap onto a second row.
These rules explicitly enforce a single row and never add flex-wrap, so narrow headers can only shrink/truncate or clip the pills. The stated PR objective of moving pills to a second row is therefore not implemented. Add flex-wrap: wrap and let the header grow with the wrapped content.
Also applies to: 153-156, 180-186
π€ Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/app/globals.css` around lines 143 - 150, Update the header selector-pills
container around the existing overflow rules to allow wrapping with flex-wrap:
wrap, and ensure the header/layout grows to accommodate additional rows instead
of clipping them. Apply the same behavior to the related selectors at the
referenced nearby rule blocks, preserving the existing pill styling and overflow
behavior where it does not prevent wrapping.
| const winW = typeof window !== 'undefined' ? window.innerWidth : 1000 | ||
| const mascotCenterPx = ((mascotX ?? 85) / 100) * winW | ||
| const anchorLeft = pos ? pos.x : (trayMode ? winW - size.w - 8 : defaultLeft) | ||
| const originX = Math.max(20, Math.min(mascotCenterPx - anchorLeft, size.w - 20)) | ||
| const transformOrigin = panelMode ? 'right center' : mobile ? 'center bottom' : `${originX}px bottom` |
There was a problem hiding this comment.
π― Functional Correctness | π‘ Minor | β‘ Quick win
Use one fallback for both popup positioning and animation origin.
defaultLeft falls back to mascotX ?? 15, while mascotCenterPx falls back to mascotX ?? 85. If mascotX is omitted, the popup is positioned near 15% of the viewport but animates from 85%.
π€ Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/ChatPopup.tsx` around lines 1391 - 1395, Align the fallback
mascot percentage used by popup positioning and animation origin in ChatPopup:
update the defaultLeft calculation and mascotCenterPx calculation to reuse the
same fallback value when mascotX is omitted, preserving the existing explicit
mascotX behavior.
The un-dragged popup anchors from the bottom (bottom:170 above the mascot, bottom:65 in tray mode) but its maxHeight budget was a flat 100vh-60px, so on viewports shorter than ~680px (small windows, browser zoom) a 500px-tall popup shoved its whole header β pills, status dot, close button β off the TOP of the screen (rect.y = -76 measured on a 594px viewport). Subtract the bottom anchor from the height budget per mode (+12px top margin) so the header is always visible and the popup just gets shorter instead. Found by driving the real desktop over CDP and sampling the popup rect during open; the same probe confirmed the mascot-open animation runs and there is no left-corner flash. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* Harden gateway recovery after updates (#263) * fix: migrate legacy openai/<gpt> model+fallbacks to codex on startup (#266) ChatGPT-subscription boxes (Codex OAuth, no OpenAI API key) that stored their active model or a fallback as `openai/gpt-5.5` (etc.) before the setup UI routed ChatGPT picks through Codex hit `401 Missing bearer or basic authentication in header` on api.openai.com/v1/responses β often only as a FailoverError days into use, once the OAuth token first refreshes and the failover chain reaches the keyless `openai/*` fallback. The chat-model pick route already rewrites openai/<gpt> -> codex/<gpt>, but only when the user re-picks the model; existing configs never re-pick, so an updated box stays broken until manually re-selected. Migrate primary + fallbacks in gateway-pre-start.sh on gateway start, guarded on "codex OAuth present AND no OpenAI API key" so keyed / dual-auth boxes (where openai/* is a valid route) are left untouched. Mirrors CODEX_SUPPORTED_MODEL_RE / hasOpenAiApiKeyProfile / hasCodexOauthProfile in src/app/setup-api/chat/model/route.ts. Verified against 6 fixtures: openai->codex primary+fallback migrate; keyed box untouched; non-supported (gpt-4o) primary left as-is; already-codex no-op; no-codex-auth untouched; composes with the retired-Sonnet migration. bash -n and py_compile pass. Co-authored-by: Mike (IDRobots) <mike@idrobots.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix(3.1.10): responsive chat header pills (wrap instead of overlap on narrow chat) (#267) * fix: chat header pills squeeze + truncate cleanly on narrow panels On a narrow chat the provider / model / thinking selector pills overlapped into an unreadable strip. Two parts: 1. .header-dropdown-trigger gets width:100% so the button fills its flex-shrinking .header-dropdown parent. Previously the button kept its content width and spilled past the shrunk parent, so overflow:hidden on .chat-header-pills clipped / overlapped the pills instead of the labels truncating. Now every pill gives ground evenly and its label ellipsizes (the chevron stays β it's reserved in the 24px right padding). 2. Single row (no wrap) + overflow:hidden, and the chat window clamps to MIN_CHAT_WIDTH (340px) on both resize paths + the rendered width, so the window stops shrinking once the pills reach a readable minimum instead of smashing them. The open menu is portaled to <body> (HeaderDropdown), so clipping the row can't hide it. Verified at 320-420px: even truncation, carets visible, zero overlap. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: open chat from mascot with a macOS-style animation, no corner flash - Stop streaming the frozen mascot's position into mascotX while the chat is open (page.tsx). That nudged mascotX for a frame right after opening, so the popup flashed to the wrong corner before settling. mascotX is now captured once from the tap. - Grow the popup OUT of the mascot: transform-origin pinned to the popup's bottom edge, aligned horizontally with the mascot, and scale 0.82 -> 1 on an easeOutExpo curve (cubic-bezier(0.16,1,0.3,1)) over 0.36s. Smooth, premium, emanates from where you tapped instead of scaling from the popup centre. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore: bump SW cache clawbox-v3 -> v4 to invalidate stale assets on the 3.1.10 chat-UI changes Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: keep chat popup header on-screen on short/zoomed viewports The un-dragged popup anchors from the bottom (bottom:170 above the mascot, bottom:65 in tray mode) but its maxHeight budget was a flat 100vh-60px, so on viewports shorter than ~680px (small windows, browser zoom) a 500px-tall popup shoved its whole header β pills, status dot, close button β off the TOP of the screen (rect.y = -76 measured on a 594px viewport). Subtract the bottom anchor from the height budget per mode (+12px top margin) so the header is always visible and the popup just gets shorter instead. Found by driving the real desktop over CDP and sampling the popup rect during open; the same probe confirmed the mascot-open animation runs and there is no left-corner flash. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Mike (IDRobots) <mike@idrobots.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Mike (IDRobots) <mike@idrobots.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The provider/model/Thinking selector pills overlapped into an unreadable strip on narrow chat panels (see report).
.chat-header-pillshad noflex-wrap+overflow:visible, so pills spilled past their min width. Addflex-wrap:wrap(drop to a 2nd row) +max-width:100%per pill (lone wrapped pill truncates). Popover is portaled to body, so overflow:visible was no longer needed for it. CSS-only,src/app/globals.css. Last fix for 3.1.10 before betaβmain; pending Karchev visual sign-off on box 192.168.50.40.π€ Generated with Claude Code
Summary by CodeRabbit