Skip to content

fix(3.1.10): responsive chat header pills (wrap instead of overlap on narrow chat) - #267

Merged
yalexx merged 4 commits into
betafrom
fix/v3.1.10-chat-header-pills-responsive
Jul 22, 2026
Merged

fix(3.1.10): responsive chat header pills (wrap instead of overlap on narrow chat)#267
yalexx merged 4 commits into
betafrom
fix/v3.1.10-chat-header-pills-responsive

Conversation

@yalexx

@yalexx yalexx commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

The provider/model/Thinking selector pills overlapped into an unreadable strip on narrow chat panels (see report). .chat-header-pills had no flex-wrap + overflow:visible, so pills spilled past their min width. Add flex-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

  • Bug Fixes
    • Improved narrow chat layouts so header pill controls stay on a single row without overlapping.
    • Enforced a new minimum chat panel width during both dragging and edge-resizing to keep content and controls readable.
    • Updated the desktop mascot chat toggle so mascot positioning no longer continuously updates while the chat is open.
  • Maintenance
    • Refreshed the service worker cache version to ensure updated offline caching behavior.

@yalexx
yalexx requested a review from a team as a code owner July 21, 2026 12:25
@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown

πŸ¦€ ClawReview

Poked my eyestalks out for this one. Quick tour:

CSS-only fix for chat header pills overlapping on narrow panels: switches .chat-header-pills from overflow:visible to overflow:hidden and adds flex:0 1 auto + width:100% to each pill so labels truncate with ellipsis instead of spilling past their container. Also raises the chat window's minimum width floor from 280β†’340 px across all resize handles, adds a macOS-style scale animation that grows the popup outward from the mascot tap point, fixes a one-frame position flash when the chat opens, and bumps the service worker cache to v4.

At a glance

  • πŸ”§ Fix Β· touches chat popup UI (ChatPopup + globals.css) + desktop mascot interaction + service worker cache
  • Base branch: beta Β· +67 source / +0 tests across 4 files
  • βœ… base beta matches the beta-first convention
  • βœ… conventional PR title
  • 🟑 src/ changes without test changes β€” add or update tests if behavior changed

Good to know

  • 🟑 Service worker cache bumped v3β†’v4 β€” existing customer installs will clear their offline cache on next visit and re-fetch all precached assets.
  • ℹ️ Minimum chat window width raised from 280 to 340 px (new MIN_CHAT_WIDTH constant). Any saved panel widths below that will be clamped on the next user resize.
  • ℹ️ No test changes included alongside the ChatPopup/page.tsx behaviour changes; the policy check flagged this as well.
  • 🟑 PR body notes it's pending visual sign-off on device 192.168.50.40 before the planned betaβ†’main promote for 3.1.10.

β€” ClawReview πŸ¦€, your resident reef crab. Just orientation β€” CodeRabbit does the line-by-line, humans do the merge. Conventions: docs.

@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown

CI Summary

βœ… Tests

  • Result: passed
  • View run
  • Coverage: statements 69.77%, branches 59.68%, functions 65.16%, lines 71.79%

βœ… E2E

βœ… E2E Install

@yalexx
yalexx force-pushed the fix/v3.1.10-chat-header-pills-responsive branch from 3acb623 to b31f181 Compare July 21, 2026 12:42
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 53 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3e75b3e6-eb12-43ab-83e1-931b202e99f5

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between d7ab658 and 3b584b6.

πŸ“’ Files selected for processing (1)
  • src/components/ChatPopup.tsx
πŸ“ Walkthrough

Walkthrough

ChatPopup 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.

Changes

Chat popup layout and interaction

Layer / File(s) Summary
Chat width and popup animation
src/components/ChatPopup.tsx
Resizing and panel rendering clamp the chat to MIN_CHAT_WIDTH (340px), while popup transform-origin and transition behavior are updated.
Mascot position freeze
src/app/page.tsx
Desktop mascot position updates occur on tap rather than continuously while the chat popup is open.
Header overflow layout
src/app/globals.css
Header pills clip overflow, and dropdown controls shrink within the flex layout using updated width constraints.

Service worker cache version

Layer / File(s) Summary
Cache version update
public/sw.js
The service worker cache identifier changes from clawbox-v3 to clawbox-v4.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: krasimirkralev

πŸš₯ Pre-merge checks | βœ… 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers the summary but omits the required type of change, testing, checklist, and screenshots/logs sections. Add the missing template sections, including change type, tests run, checklist items, and any UI screenshots or logs.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
βœ… Passed checks (3 passed)
Check name Status Explanation
Title check βœ… Passed The title clearly matches the main change: fixing responsive chat header pills on narrow chat panels.
Linked Issues check βœ… Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check βœ… Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/v3.1.10-chat-header-pills-responsive

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the area: ui Auto-triage area label Jul 21, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 120fcd3 and b31f181.

πŸ“’ Files selected for processing (2)
  • src/app/globals.css
  • src/components/ChatPopup.tsx

Comment thread src/components/ChatPopup.tsx Outdated
Comment on lines +1397 to +1400
? { 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 }),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

πŸ—„οΈ 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>
@yalexx
yalexx force-pushed the fix/v3.1.10-chat-header-pills-responsive branch from b31f181 to e5c6e23 Compare July 21, 2026 13:16
- 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>
@yalexx
yalexx force-pushed the fix/v3.1.10-chat-header-pills-responsive branch from e239971 to 419106a Compare July 21, 2026 13:35
…he 3.1.10 chat-UI changes

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between b31f181 and d7ab658.

πŸ“’ Files selected for processing (4)
  • public/sw.js
  • src/app/globals.css
  • src/app/page.tsx
  • src/components/ChatPopup.tsx

Comment thread src/app/globals.css
Comment on lines +143 to +150
/* 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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 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.

Comment on lines +1391 to +1395
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`

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 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>
@yalexx
yalexx merged commit c7beb31 into beta Jul 22, 2026
7 checks passed
yalexx added a commit that referenced this pull request Jul 22, 2026
* 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: ui Auto-triage area

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant