Skip to content

feat(compact): 历史堆砌区支持顶部 resize bar 调整高度上限#1664

Merged
wehos merged 5 commits into
mainfrom
claude/practical-mirzakhani-275fc2
Jun 6, 2026
Merged

feat(compact): 历史堆砌区支持顶部 resize bar 调整高度上限#1664
wehos merged 5 commits into
mainfrom
claude/practical-mirzakhani-275fc2

Conversation

@wehos
Copy link
Copy Markdown
Contributor

@wehos wehos commented Jun 6, 2026

背景

compact 紧凑态下,历史对话气泡堆叠在 CompactExportHistoryPanel,高度上限原本写死在 --compact-export-history-region-height(网页 width*1.18 / 63vh、Electron width*1.18 / workarea*0.63)。compact 态只有左右两个宽度 handle(CompactSurfaceResizeSide = ''left'' | ''right''),用户只能调宽、无法调高,想把历史区压矮节约屏幕没有任何入口。

改动

在堆砌区顶部新增一条横向 resize bar:

  • 平时透明,hover 整个历史区 / 拖动中(is-active)半透明显现;拖动中靠独立 state 保持可见
  • 上下拖拽覆盖预留变量 --compact-history-slot-height(此前无人赋值),上拖增高、下拖压矮
  • 范围 120px ~ min(width*1.46, 78% 视口/工作区),初始未拖动保持默认高度
  • React localStorage 持久化(neko.reactChatWindow.compactHistorySlotHeight
  • 复用既有宽度 resize 的指针状态机模式,但只写 CSS 变量、不走 resize-request 往返
  • 变更后 dispatch 既有的 neko:compact-interaction-geometry-refresh,让宿主重算 history 命中 rect / Electron 窗口 bounds / 鼠标穿透
  • bar 带 data-compact-hit-region + data-compact-no-drag,Electron 下可点不穿透、不触发拖窗
  • compact 单行小胶囊本身不动

验证

  • tsc --noEmit typecheck
  • ✅ vitest 173 passed(含新增 bar 渲染 / hit-region / is-active 用例)
  • ✅ pytest test_react_chat_window_static.py 30 passed(新增样式/DOM/storage key/几何事件断言 + 既有切片未破坏)
  • npm run build 完整打包

待真机验证(Electron)

Electron compact 是独立窗口、主进程在 lanlan_frd(本仓库不可见)。本 PR 靠触发几何刷新让主进程扩窗,论据是「展开历史」本身已能撑窗、属同类几何变化。需真机确认:上限拖到 78% 时是否超过主进程对 compact 窗口的高度上限而被裁;若被裁需在 lanlan_frd 侧放宽或读取该上限。

🤖 Generated with Claude Code

Summary by CodeRabbit

  • 新功能

    • 紧凑模式下历史记录面板顶部可拖拽调整高度,调整结果会持久化并在后续会话与布局变化中自动应用约束与恢复。
  • 样式

    • 新增顶部调整把手的视觉与交互:默认隐藏,悬停或激活时显示;在特定层级/布局下被置灰并禁用以防误触;活动状态有明显视觉反馈。
  • 测试

    • 新增覆盖把手可拖拽、样式呈现与持久化/刷新行为的自动化测试。

compact 紧凑态下历史对话气泡堆叠在 CompactExportHistoryPanel,其高度上限原本写死在
--compact-export-history-region-height(width*1.18 / 63vh),用户只能调宽度(左右 handle)、
无法调高度,想把历史区压矮节约屏幕没有任何入口。

在堆砌区顶部新增一条横向 resize bar(平时透明、hover 半透明显现、拖动中保持可见),
上下拖拽覆盖预留变量 --compact-history-slot-height:
- 范围 120px ~ min(width*1.46, 78% 视口/工作区),初始未拖动保持默认高度
- React localStorage 持久化(neko.reactChatWindow.compactHistorySlotHeight)
- 拖动复用宿主 neko:compact-interaction-geometry-refresh 让 Electron 窗口重算 bounds / 命中区 / 穿透
- bar 带 data-compact-hit-region + no-drag,Electron 下可点不穿透、不触发拖窗
- compact 单行小胶囊本身不动

补 vitest(bar 渲染/hit-region/is-active)与 pytest static(样式/DOM/storage key/几何事件)断言。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 6, 2026

Worried about impact? Review this PR in Change Stack to explore blast radius before you approve or request changes.

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: 4510eb09-ead7-4cca-ace1-b4818ad319de

📥 Commits

Reviewing files that changed from the base of the PR and between 189f838 and fd138cd.

📒 Files selected for processing (2)
  • frontend/react-neko-chat/src/styles.css
  • tests/unit/test_react_chat_window_static.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/react-neko-chat/src/styles.css
  • tests/unit/test_react_chat_window_static.py

Walkthrough

在紧凑模式历史面板中加入顶部可拖拽高度调整:常量与类型、localStorage 持久化、跨平台高度计算、App 内拖拽流程与 CSS 变量同步、面板 props 扩展、样式与测试覆盖喵。

Changes

紧凑历史区高度拖拽完整功能

Layer / File(s) Summary
常量与数据结构定义
frontend/react-neko-chat/src/App.tsx
新增本地存储键 COMPACT_HISTORY_HEIGHT_STORAGE_KEY,定义最小/最大/默认高度比率与 chrome 预留,并增加 CompactHistoryResizeState 类型用于追踪指针拖拽状态喵。
高度持久化与计算工具函数
frontend/react-neko-chat/src/App.tsx
实现读取/写入历史 slot 高度到 localStorage(非法/缺失返回 null、写 null 删除),并提供基于 Electron workArea 或 window.innerHeight 的基数计算及 pointer Y 归一化工具喵。
应用组件拖拽核心逻辑与流程
frontend/react-neko-chat/src/App.tsx
新增 state/ref(compactHistorySlotHeight、compactHistoryResizeActive、compactHistoryResizeStateRef),实现 pointerDown/Move/Up/Cancel 拖拽过程:计算并 clamp 高度,更新 --compact-history-slot-height,派发 neko:compact-interaction-geometry-refresh,以及拖拽结束时的持久化与清理逻辑喵。
历史面板组件UI契约与交互
frontend/react-neko-chat/src/CompactExportHistoryPanel.tsx
在组件 props 中新增 historyResizeActive 和四个指针事件回调;在渲染层于 previewOpen=false 时插入 compact-export-history-resize-bar,依据激活状态添加 .is-active,并绑定 pointer 事件与失去捕获处理;当 choiceLayerAbove 为真则移除 hit-region 属性喵。
样式表现与测试验证
frontend/react-neko-chat/src/styles.css, frontend/react-neko-chat/src/CompactExportHistoryPanel.test.tsx, tests/unit/test_react_chat_window_static.py
新增 .compact-export-history-resize-bar 及其 ::after 视觉把手样式(默认透明,hover/active 显示);把手启用 pointer-events-webkit-app-region: no-drag;增加组件单元测试覆盖条件渲染与 is-active 类切换;静态测试断言可拖拽样式(cursor: ns-resizepointer-events-webkit-app-region)、命中区 data-* 属性、localStorage key(neko.reactChatWindow.compactHistorySlotHeight)、CSS 变量与几何刷新事件存在性喵。

Sequence Diagram

sequenceDiagram
  participant User as 用户 (拖拽)
  participant Panel as CompactExportHistoryPanel
  participant App as App 组件
  participant LocalStorage as localStorage
  participant CSS as CSS 变量

  User->>Panel: pointerDown 在 resize bar
  Panel->>App: onHistoryResizePointerDown
  App->>App: 记录起始高度与 pointerId,设置 compactHistoryResizeActive=true
  User->>Panel: pointerMove
  Panel->>App: onHistoryResizePointerMove
  App->>App: 计算并 clamp 新高度
  App->>CSS: 更新 --compact-history-slot-height
  App->>App: 派发 neko:compact-interaction-geometry-refresh
  User->>Panel: pointerUp
  Panel->>App: onHistoryResizePointerUp
  App->>LocalStorage: 保存最终高度(仅当 moved)
  App->>App: 清理拖拽状态,compactHistoryResizeActive=false
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

小小把手悄然现喵,
指尖拖动高低变喵,
本地记忆暖又甜喵,
CSS 响应轻声赞喵,
测试守护不出岔喵。

🚥 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 标题准确总结了本次变更的核心功能:在 compact 历史堆砌区顶部新增 resize bar 以支持高度调整,与大量新增代码(App.tsx +219 行、样式表修改、测试覆盖)的主要改动相符喵。
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.


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: a3e08f5e05

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread frontend/react-neko-chat/src/App.tsx Outdated
Comment thread frontend/react-neko-chat/src/styles.css Outdated
Comment thread frontend/react-neko-chat/src/App.tsx Outdated
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/App.tsx`:
- Around line 2911-2915: The effect currently only writes the CSS var via
applyCompactHistorySlotHeightVar but doesn't clamp or update
compactHistorySlotHeight/state/storage when constraints change, causing a drag
deadzone; modify the useEffect that depends on applyCompactHistorySlotHeightVar,
compactHistorySlotHeight and isCompactSurface to call clampExistingHeight() on
mount and when the compact surface width changes (subscribe to/derive width
changes in the effect), and if clampExistingHeight() returns a different value,
set the new value into the state that holds compactHistorySlotHeight and persist
it to storage (same storage write used elsewhere) before calling
applyCompactHistorySlotHeightVar; apply the same change to the other similar
effect block that mirrors this logic so stored heights are clamped and saved
whenever constraints change.
🪄 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: 06682934-4aa9-467e-b99a-4507bbb5a294

📥 Commits

Reviewing files that changed from the base of the PR and between 1c9e0d6 and a3e08f5.

📒 Files selected for processing (5)
  • frontend/react-neko-chat/src/App.tsx
  • frontend/react-neko-chat/src/CompactExportHistoryPanel.test.tsx
  • frontend/react-neko-chat/src/CompactExportHistoryPanel.tsx
  • frontend/react-neko-chat/src/styles.css
  • tests/unit/test_react_chat_window_static.py

Comment thread frontend/react-neko-chat/src/App.tsx
- bar 透明从本体移到 ::after 伪元素:宿主几何收集器(app-react-chat-window.js)按 computed
  opacity<=0.01 丢弃 hit-region,bar 本体透明会让 Electron 下整条鼠标穿透、永远 hover/点不到、
  无法发起拖拽。改后本体保持不透明、只让视觉抓手伪元素平时透明。
- 起拖基准对持久高度 clamp:存量值来自更大屏 / 更宽 surface 时面板已钳到 max,用 stale 大值做
  基准会出现「先拖一段没反应」的死区。并新增监听 neko:compact-surface-resize-width-change,
  宽度变化后按新约束重写 CSS 变量(刻意不改 state / 不覆盖 storage,保留跨屏 / 跨宽度高度记忆)。
- max 扣掉 scroll 上方 bar + 下方 controls 的固定 chrome(72px),避免拖到上限时 scroll 吃满
  anchor、controls / 底部气泡溢出被 Electron 几何裁成非交互。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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: 8d309f93f2

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread frontend/react-neko-chat/src/CompactExportHistoryPanel.tsx Outdated
Comment thread frontend/react-neko-chat/src/App.tsx Outdated
- choice prompt 压在历史上方(choiceLayerAbove)时,bar 的 hit-region gate 在 !choiceLayerAbove,
  并纳入 under-choice 的 pointer-events:none / 淡化列表。原本该态历史区整体惰性,但 bar 仍保持
  pointer-events:auto + 上报命中区,会在 Electron 下留一条可拖、不穿透的活条干扰 choice UI。
- resize state 加 moved 标志,finish 只在真正拖动过才 persist:纯点击 bar 不再把响应式 CSS 默认
  高度(width*1.18 / 视口比)锁成固定像素值(否则之后视口 / compact 宽度变化不再驱动面板高度)。

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

🧹 Nitpick comments (1)
frontend/react-neko-chat/src/CompactExportHistoryPanel.test.tsx (1)

65-71: ⚡ Quick win

补齐 data-compact-hit-region-kind 的断言,避免命中区契约漏测

这段只断言了 data-compact-hit-region-iddata-compact-hit-region 被移除;建议在 Line 69-70 附近再补一条 data-compact-hit-region-kindnull 的断言,这样和组件里的同条件三属性行为完全对齐,后续回归更不容易漏掉喵。

可参考的最小改动喵
   expect(bar).not.toBeNull();
   expect(bar?.getAttribute('data-compact-hit-region-id')).toBeNull();
   expect(bar?.getAttribute('data-compact-hit-region')).toBeNull();
+  expect(bar?.getAttribute('data-compact-hit-region-kind')).toBeNull();
🤖 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 `@frontend/react-neko-chat/src/CompactExportHistoryPanel.test.tsx` around lines
65 - 71, Add an assertion to the test that the resize bar drops the third
hit-region attribute: after locating bar with
container.querySelector('.compact-export-history-resize-bar') (in
CompactExportHistoryPanel.test.tsx) assert that
bar?.getAttribute('data-compact-hit-region-kind') is null, matching the existing
checks for data-compact-hit-region-id and data-compact-hit-region so the test
covers all three attributes the component clears.
🤖 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.

Nitpick comments:
In `@frontend/react-neko-chat/src/CompactExportHistoryPanel.test.tsx`:
- Around line 65-71: Add an assertion to the test that the resize bar drops the
third hit-region attribute: after locating bar with
container.querySelector('.compact-export-history-resize-bar') (in
CompactExportHistoryPanel.test.tsx) assert that
bar?.getAttribute('data-compact-hit-region-kind') is null, matching the existing
checks for data-compact-hit-region-id and data-compact-hit-region so the test
covers all three attributes the component clears.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9e5172df-67fc-4f54-b76d-f576a5e91107

📥 Commits

Reviewing files that changed from the base of the PR and between 8d309f9 and 0963fb1.

📒 Files selected for processing (5)
  • frontend/react-neko-chat/src/App.tsx
  • frontend/react-neko-chat/src/CompactExportHistoryPanel.test.tsx
  • frontend/react-neko-chat/src/CompactExportHistoryPanel.tsx
  • frontend/react-neko-chat/src/styles.css
  • tests/unit/test_react_chat_window_static.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • frontend/react-neko-chat/src/styles.css
  • frontend/react-neko-chat/src/CompactExportHistoryPanel.tsx
  • tests/unit/test_react_chat_window_static.py
  • frontend/react-neko-chat/src/App.tsx

Hongzhi Wen and others added 2 commits June 6, 2026 12:02
回应 CodeRabbit nitpick:组件三个 hit-region 属性(region / id / kind)同条件 gate 在
!choiceLayerAbove,测试补齐 data-compact-hit-region-kind=null,与已有 id / region 两条对齐,
覆盖完整命中区契约。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
把顶部高度 bar 的浮现触发从「hover 整个历史区」收窄为:鼠标进入左右宽度 handle
(.app-shell:has(.compact-chat-resize-handle:hover),与 anchor 同在 app-shell 下,跨子树 :has)
或历史滚动条命中区(.compact-export-history-anchor:has(.compact-export-history-scrollbar-hit:hover))
时连带显现;bar 本体 hover / 拖动中(is-active)保留。这样只在「调宽 / 滚动」语境里统一提示也能
调高度,平时不再因鼠标划过历史区就亮,less intrusive。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@wehos wehos merged commit 406a9ca into main Jun 6, 2026
5 checks passed
@wehos wehos deleted the claude/practical-mirzakhani-275fc2 branch June 6, 2026 04:17
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.

1 participant