UI/chat polish upstream#2281
Open
Feelings0220 wants to merge 3 commits into
Open
Conversation
- Auto-growing textarea (1 row min, ~8 rows max) replaces the fixed min-h-[100px] composer; send/voice/cancel buttons are inlined so the idle composer height drops from ~220px to ~60px - Enter sends the message (Shift+Enter for newline), with an IME composition guard so CJK input confirmation doesn't trigger a send - Status/token row only renders while active instead of permanently - Messages column is centered at max-w-3xl; break-all -> break-words; reduced vertical padding - Auto-scroll only follows when the user is near the bottom, with a floating 'Latest' button to jump back down; sending always re-engages follow scrolling Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016d9SxeefoRSLZmQ1oKo17j
…er, resizable sidebars - ScrollArea switches to Radix type=scroll: the scrollbar overlays content, appears while scrolling, and fades out 600ms later; thinner thumb, no track border (applies to every ScrollArea in the app) - Token counts render in k/M units via formatTokens (exact values stay in tooltips/titles) - The composer usage row gains an approximate context-window meter: 'ctx 12.3k/200k' with a progress bar (amber >80%, red >95%), sized from the latest turn's prompt tokens against a model-prefix window table (unknown models hide the meter). ChatAgentContext gains a modelInfo value (model/provider/ModelConfig ref) provided by ChatLayoutUI so chat components can read the active model. - Chat scroll area top padding reduced (py-6 -> pt-2 pb-6) - Both sidebars are now resizable: Sidebar gains a width override prop (set on the outer wrapper so the layout gap tracks the panel, with width transitions disabled while overridden), a pointer-capture drag handle on the inner edge, 200-480px clamp, per-side localStorage persistence, and double-click to reset Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016d9SxeefoRSLZmQ1oKo17j
Contributor
There was a problem hiding this comment.
Pull request overview
This PR polishes the chat UI by introducing compact token usage formatting, adding independently resizable left/right sidebars with persistent width, and improving chat scrolling/composer ergonomics.
Changes:
- Added token formatting + model context-window estimation utilities (with tests) and surfaced them in token usage UI.
- Implemented persistent, draggable sidebar resizing for both sessions (left) and agent details (right) sidebars.
- Improved chat interface ergonomics: “jump to latest”, smarter auto-scroll behavior, and auto-growing message composer.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| ui/src/lib/tokenUtils.ts | Adds token formatting and model context-window lookup helpers. |
| ui/src/lib/tests/tokenUtils.test.ts | Adds unit tests for the new token utilities. |
| ui/src/hooks/useSidebarWidth.ts | New hook for persistent, clamped sidebar width via localStorage. |
| ui/src/components/ui/sidebar.tsx | Adds per-sidebar width override and disables width transitions while dragging. |
| ui/src/components/ui/scroll-area.tsx | Tweaks scroll behavior/appearance (overlay scrollbar behavior). |
| ui/src/components/sidebars/SidebarResizeHandle.tsx | Adds pointer-driven resize handle used by sidebars. |
| ui/src/components/sidebars/SessionsSidebar.tsx | Wires left sidebar to persistent width + resize handle. |
| ui/src/components/sidebars/AgentDetailsSidebar.tsx | Wires right sidebar to persistent width + resize handle. |
| ui/src/components/chat/TokenStatsTooltip.tsx | Displays compact token counts alongside raw counts in tooltip. |
| ui/src/components/chat/TokenStats.tsx | Shows compact token counts and adds an approximate context usage meter. |
| ui/src/components/chat/ChatMessage.tsx | Improves wrapping behavior for message content (break-words). |
| ui/src/components/chat/ChatLayoutUI.tsx | Passes model/provider/config info into chat context. |
| ui/src/components/chat/ChatInterface.tsx | Adds near-bottom tracking, “Latest” jump button, and auto-growing composer. |
| ui/src/components/chat/ChatAgentContext.tsx | Extends chat context to include model info for token/context UI. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+4
to
+9
| export function formatTokens(count: number): string { | ||
| if (!Number.isFinite(count) || count < 0) return "0"; | ||
| if (count >= 1_000_000) return `${trimDecimal(count / 1_000_000)}M`; | ||
| if (count >= 1_000) return `${trimDecimal(count / 1_000)}k`; | ||
| return String(Math.round(count)); | ||
| } |
Comment on lines
+12
to
+13
| export function useSidebarWidth(storageKey: string, defaultWidth: number) { | ||
| const [width, setWidthState] = useState<number>(defaultWidth); |
Comment on lines
+42
to
+44
| const reset = useCallback(() => { | ||
| setWidthState(defaultWidth); | ||
| try { |
Comment on lines
+24
to
+35
| const onMove = (event: PointerEvent) => { | ||
| const next = side === "left" ? event.clientX : window.innerWidth - event.clientX; | ||
| onResize(next); | ||
| }; | ||
| const onUp = (event: PointerEvent) => { | ||
| target.releasePointerCapture(event.pointerId); | ||
| target.removeEventListener("pointermove", onMove); | ||
| target.removeEventListener("pointerup", onUp); | ||
| }; | ||
| target.addEventListener("pointermove", onMove); | ||
| target.addEventListener("pointerup", onUp); | ||
| }, |
- formatTokens: 999950..999999 rounded up to '1000k'; roll to '1M' instead (with a regression test) - useSidebarWidth: a missing localStorage key made Number(null)===0 fall through the range guard by luck; read the raw value and treat missing as NaN explicitly - useSidebarWidth: clamp reset() to the min/max range in case a caller's default drifts outside it - SidebarResizeHandle: also end the drag on pointercancel (touch scroll takeover, alt-tab) and guard releasePointerCapture so an already- released capture doesn't throw Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016d9SxeefoRSLZmQ1oKo17j
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Optimized the layout with a more compact chat interface, an adjustable sidebar, and other UI improvements.
对话框紧凑,侧边栏可调节等等agent对话布局的优化