Skip to content

fix(chat): adapt compact tool wheel on mobile#1670

Merged
wehos merged 4 commits into
Project-N-E-K-O:mainfrom
rophec:mobile_toolist
Jun 6, 2026
Merged

fix(chat): adapt compact tool wheel on mobile#1670
wehos merged 4 commits into
Project-N-E-K-O:mainfrom
rophec:mobile_toolist

Conversation

@rophec
Copy link
Copy Markdown
Contributor

@rophec rophec commented Jun 6, 2026

Summary

  • detect whether the original compact tool wheel arc would overflow the mobile viewport
  • keep the original wheel layout when it fits after resizing/moving the compact chat surface
  • apply the mobile viewport-fit fallback only when the original arc would be clipped
  • add component tests for default vs viewport-fit tool wheel layout

Verification

  • npm.cmd run build
  • npm.cmd test -- App.test.tsx

Summary by CodeRabbit

  • 新功能
    • 工具轮盘在移动端新增视口自适应布局:在“默认”与“视口适配”间自动切换,确保展开时工具项可见且可交互。
  • 修复与优化
    • 在打开/关闭及窗口/视口变化时更稳健地重算并恢复布局,提升旋转/缩放与滚动场景的显示与交互稳定性。
  • 样式
    • 为视口适配场景提供保守角度、可交互样式与过渡调整,避免项溢出或不可点。
  • 测试
    • 新增移动端视口适配相关单元测试,覆盖布局决策与视觉视口使用情况。

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 6, 2026

Complex PR? Review this PR in Change Stack to move by importance, not file order.

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5afcbf3c-76f5-454c-90d3-b04cf21a6dcd

📥 Commits

Reviewing files that changed from the base of the PR and between 1d47160 and ec6009d.

📒 Files selected for processing (2)
  • frontend/react-neko-chat/src/App.test.tsx
  • frontend/react-neko-chat/src/App.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/react-neko-chat/src/App.test.tsx
  • frontend/react-neko-chat/src/App.tsx

Walkthrough

该 PR 为紧凑输入模式的工具轮盘实现视口感知的布局判定与同步:打开时测量 DOM/CSS 与 visualViewport,估算默认槽位是否溢出并在 default / viewport-fit 间切换,同时新增相应样式与测试覆盖喵。

Changes

紧凑工具轮盘响应式布局

Layer / File(s) Summary
布局类型与计算常量
src/App.tsx
引入 useLayoutEffect,新增 COMPACT_INPUT_TOOL_WHEEL_VIEWPORT_MARGIN 视口边距常量、默认与 viewport-fit 槽位配置数组,以及 CompactInputToolWheelLayout 类型喵。
状态声明与渲染属性
src/App.tsx
新增组件 state compactInputToolWheelLayout 并在轮盘容器渲染 data-compact-tool-wheel-layout 属性以暴露当前布局喵。
布局检测与同步核心
src/App.tsx
实现 resolveCompactInputToolWheelLayoutsyncCompactInputToolWheelLayout:读取轮盘 DOM、CSS 变量与 visualViewport,估算默认槽位是否溢出并决定布局喵喵。
生命周期绑定与状态复位
src/App.tsx
在轮盘打开时先置为 'default';通过 useLayoutEffectresizeneko:compact-interaction-geometry-changevisualViewportresize/scroll 下重算,关闭时复位为 'default' 喵。
移动端兜底样式
src/styles.css
新增 viewport-fit 布局下轮盘展开时五个插槽的可见性、交互、保守旋转角度与缩放,以及移除部分遮罩的规则喵。
测试用例与辅助函数
src/App.test.tsx
新增 mockMobileMatchMedia,补充默认布局断言并新增多组移动端场景用例:非裁剪保持 default、裁剪切换为 viewport-fit、使用 window.visualViewport 的裁剪判断、以及顶部裁剪仍保 default 的用例喵。

Sequence Diagram

sequenceDiagram
  participant User as 用户点击工具开关
  participant OpenFan as openCompactInputToolFan
  participant ResetLayout as 重置布局为 'default'
  participant useLayoutEffect as useLayoutEffect 副作用
  participant SyncLayout as syncCompactInputToolWheelLayout
  participant ResolveFn as resolveCompactInputToolWheelLayout
  participant DOM as 轮盘 DOM 与 CSS 变量
  participant VisualViewport as window.visualViewport
  participant State as compactInputToolWheelLayout
  participant Render as 渲染 data-compact-tool-wheel-layout
  User->>OpenFan: 点击打开轮盘
  OpenFan->>ResetLayout: 将布局设为 'default'
  OpenFan->>useLayoutEffect: 触发/绑定副作用监听
  useLayoutEffect->>SyncLayout: 调用同步函数
  SyncLayout->>DOM: 读取 getBoundingClientRect 与 CSS 变量
  SyncLayout->>VisualViewport: 读取视口尺寸/offset
  SyncLayout->>ResolveFn: 传入测量数据进行判定
  ResolveFn-->>SyncLayout: 返回 'default' 或 'viewport-fit'
  SyncLayout->>State: 更新 compactInputToolWheelLayout
  State->>Render: 渲染属性变化
  Render->>Render: 样式根据属性选择视角与可见性
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Project-N-E-K-O/N.E.K.O#1621: 也修改了 src/App.tsx 中紧凑工具轮盘相关逻辑(事件/交互处理方面),与本 PR 在相同组件上存在代码级相关性喵。

Poem

轮盘开合测视口,喵喵量度不含糊喵,
DOM 与 CSS 来配合,visualViewport 来把关喵,
default 或 viewport-fit,一测便下判喵,
样式配齐用例全,紧凑模式更安心喵,
小轮盘转一圈,布局稳如喵星舰喵。

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR标题准确地概括了主要变更:为移动端紧凑工具轮盘添加视口适配能力,与三个文件的所有改动保持一致喵。
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f4fdd37db7

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread frontend/react-neko-chat/src/App.tsx Outdated
Comment on lines +3110 to +3111
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use the visual viewport for mobile clipping

On mobile when the soft keyboard or browser chrome shrinks the visible area, window.innerWidth/innerHeight still describe the layout viewport, so this comparison can decide that the default arc fits even though it is clipped or covered in the visual viewport. The effect already listens to visualViewport resize/scroll, but those events cannot change the result while the resolver ignores visualViewport.width/height and offsets.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Accepted and fixed in 6804728. The resolver now uses visualViewport width/height plus offsetLeft/offsetTop when available, while keeping innerWidth/innerHeight as the fallback. Added a mobile visual viewport clipping test. Verified with npm.cmd run build and npm.cmd test -- App.test.tsx.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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 `@frontend/react-neko-chat/src/styles.css`:
- Around line 4212-4220: In viewport-fit mode the edge-slot gradient masks
should be disabled so items at data-compact-tool-wheel-slot="-2" and "2" are
fully visible; add CSS overrides targeting
.compact-input-tool-fan[data-compact-tool-wheel-layout="viewport-fit"]
.compact-input-tool-item[data-compact-tool-wheel-slot="-2"], and the same
selector for slot="2", and set -webkit-mask-image: none; mask-image: none;
background: none; and also override any ::after pseudo-element and direct
img/svg children (e.g.
.compact-input-tool-item[data-compact-tool-wheel-slot="-2"]::after and img, svg)
to remove the fade-left/fade-right masks so the directional gradient is
explicitly disabled in viewport-fit layout.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5156d79d-c2ee-47ff-ad6b-bf8f6d399ace

📥 Commits

Reviewing files that changed from the base of the PR and between 03cbce3 and f4fdd37.

📒 Files selected for processing (3)
  • frontend/react-neko-chat/src/App.test.tsx
  • frontend/react-neko-chat/src/App.tsx
  • frontend/react-neko-chat/src/styles.css

Comment thread frontend/react-neko-chat/src/styles.css
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 680472890f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +4238 to +4240
.compact-input-tool-fan[data-compact-input-tool-fan-open="true"][data-compact-tool-wheel-layout="viewport-fit"] .compact-input-tool-item[data-compact-tool-wheel-slot="2"] {
transform: translate(var(--compact-tool-wheel-center-x), var(--compact-tool-wheel-center-y)) rotate(-80deg) translateX(var(--compact-tool-wheel-orbit-radius)) rotate(80deg) scale(0.86);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Handle top-edge overflows before using phone arc

When the compact surface is positioned near the top of a narrow viewport, the resolver switches to viewport-fit as soon as the default arc clips, but this fallback can make that case worse: the right preview slot moves from the default -17.35deg position to -80deg, which raises it by roughly another 55px at the current 80px radius. Since the compact shell can be fixed via --desktop-compact-surface-top, opening the wheel near the top edge still leaves the item clipped even though the layout is marked viewport-fit; the fallback needs to account for which edge overflowed or use a placement that is verified to fit.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Accepted and fixed in ec6009d. The resolver now verifies both candidate geometries: it keeps default when the default arc fits, switches to viewport-fit only when that fallback also fully fits the visual viewport, and otherwise falls back to default instead of making top-edge clipping worse. Added a top-edge regression test. Verified with npm.cmd run build and npm.cmd test -- App.test.tsx.

Copy link
Copy Markdown
Contributor

@wehos wehos left a comment

Choose a reason for hiding this comment

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

很棒哦!

@wehos wehos merged commit a4624fb into Project-N-E-K-O:main Jun 6, 2026
3 checks passed
wehos pushed a commit that referenced this pull request Jun 6, 2026
解决冲突(均来自 #1670 compact 工具轮盘移动端适配 + 本分支 compact 改动撞同区):
- App.tsx: 合并 #1670 的 compactInputToolWheel{Default,ViewportFit}VisibleSlots(移动端轮盘 slots) + 本分支 COMPACT_SURFACE_RESIZE_MIN_WIDTH=280 / COMPACT_SURFACE_DEFAULT_WIDTH=430(取 280 是本分支最短宽度功能)
- App.test.tsx: 保留 #1670 的 mockMobileMatchMedia(被 4 处 mobile 用例引用),删去本分支去气泡拖拽后已 unused 的 setupAvatarDropBounds/setupDesktopAvatarDropBounds
合并后 build + vitest 168 + python 44 全绿。

Co-Authored-By: Claude Opus 4.8 (1M context) <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.

2 participants