-
Notifications
You must be signed in to change notification settings - Fork 1
feat: Chat scroll performance optimization with configurable placeholder sensitivity #50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…essage component - Add configurable scroll placeholder sensitivity slider in settings (0-2000, default 300) - Allow users to disable placeholders entirely by setting sensitivity to 0 - Optimize Message component with React.memo to prevent unnecessary re-renders - Convert event handlers to useCallback for stable references - Memoize userStyle, isSupportEvent, and shouldHighlightMessage calculations - Move badge calculations (kickTalkBadges, donatorBadges) to MessagesHandler for better performance - Reorganize imports and simplify conditional expressions - Add DEFAULT_SCROLL_SEEK_VELOCITY constant
WalkthroughAdds a configurable scroll-seek velocity setting and placeholder UI, wires scroll-seek configuration into Virtuoso with a placeholder component, introduces per-user badge maps passed to messages, and refactors Message to a memoized component with prop updates and optimized handlers. Adds DEFAULT_SCROLL_SEEK_VELOCITY constant used by settings and message list behavior. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Settings as Settings (General.jsx)
participant Store as SettingsData
participant Handler as MessagesHandler.jsx
participant List as Virtuoso
participant UI as ScrollSeekPlaceholder
participant Msg as MessageComponent
User->>Settings: Adjust "Scroll Placeholder Sensitivity" slider
Settings->>Store: onChange(chatrooms.scrollSeekVelocityThreshold)
Note right of Store: Defaults to DEFAULT_SCROLL_SEEK_VELOCITY if unset
Store-->>Handler: read scrollSeekVelocityThreshold
Handler->>List: set scrollSeekConfiguration (enter/exit, velocity cap)
User->>List: Fast scroll
List->>UI: Render placeholder during seek
List->>Msg: Render full message when seek ends
sequenceDiagram
autonumber
participant Handler as MessagesHandler.jsx
participant Maps as Badge Maps
participant Msg as MessageComponent
Handler->>Maps: Build kickTalkBadgeMap, donatorBadgeMap
Handler->>Msg: itemContent(..., { kickTalkBadges, donatorBadges })
Msg->>Msg: Memoized render (areEqual comparator)
Note right of Msg: Uses memoized styling, highlight checks, handlers
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
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. Comment |
There was a problem hiding this 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
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/renderer/src/components/Dialogs/Settings/Sections/General.jsx(3 hunks)src/renderer/src/components/Messages/Message.jsx(8 hunks)src/renderer/src/components/Messages/MessagesHandler.jsx(4 hunks)utils/constants.js(1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**
📄 CodeRabbit inference engine (AGENTS.md)
**: Use electron-vite + React conventions instead of raw Electron patterns
When unsure, consult electron-vite/Electron/Vite docs (Context7) to confirm patterns
Omit empty sections in release notes
Files:
utils/constants.jssrc/renderer/src/components/Dialogs/Settings/Sections/General.jsxsrc/renderer/src/components/Messages/MessagesHandler.jsxsrc/renderer/src/components/Messages/Message.jsx
!dist/**
📄 CodeRabbit inference engine (AGENTS.md)
Do not commit built installers/artifacts in dist/
Files:
utils/constants.jssrc/renderer/src/components/Dialogs/Settings/Sections/General.jsxsrc/renderer/src/components/Messages/MessagesHandler.jsxsrc/renderer/src/components/Messages/Message.jsx
src/renderer/src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
src/renderer/src/**/*.{ts,tsx,js,jsx}: Do not use direct Node APIs in the renderer
Use ipcRenderer.invoke('channel', payload) for request/response from renderer
Use import.meta.env.RENDERER_VITE_* for renderer-scoped config
Avoid bare KT_* env vars in the renderer; use RENDERER_VITE_KT_* instead
Files:
src/renderer/src/components/Dialogs/Settings/Sections/General.jsxsrc/renderer/src/components/Messages/MessagesHandler.jsxsrc/renderer/src/components/Messages/Message.jsx
src/{renderer/src,preload}/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Resolve static assets via Vite URLs (new URL('./asset', import.meta.url))
Files:
src/renderer/src/components/Dialogs/Settings/Sections/General.jsxsrc/renderer/src/components/Messages/MessagesHandler.jsxsrc/renderer/src/components/Messages/Message.jsx
src/{main,renderer/src}/**/*.{ts,tsx,js,jsx,mts,mjs,cjs}
📄 CodeRabbit inference engine (AGENTS.md)
For fire-and-forget events, use ipcRenderer.send and ipcMain.on with namespaced channels like 'app:settings:get'
Files:
src/renderer/src/components/Dialogs/Settings/Sections/General.jsxsrc/renderer/src/components/Messages/MessagesHandler.jsxsrc/renderer/src/components/Messages/Message.jsx
src/{main,preload,renderer/src}/**/*.{ts,tsx,js,jsx,mts,mjs,cjs}
📄 CodeRabbit inference engine (AGENTS.md)
Use shared non-secret variables via import.meta.env.VITE_*
Files:
src/renderer/src/components/Dialogs/Settings/Sections/General.jsxsrc/renderer/src/components/Messages/MessagesHandler.jsxsrc/renderer/src/components/Messages/Message.jsx
🧬 Code graph analysis (3)
src/renderer/src/components/Dialogs/Settings/Sections/General.jsx (3)
utils/constants.js (2)
DEFAULT_SCROLL_SEEK_VELOCITY(10-10)DEFAULT_SCROLL_SEEK_VELOCITY(10-10)src/renderer/src/components/Shared/Tooltip.jsx (3)
Tooltip(9-9)TooltipTrigger(11-11)TooltipContent(13-17)src/renderer/src/components/Shared/Slider.jsx (2)
Slider(9-69)value(10-10)
src/renderer/src/components/Messages/MessagesHandler.jsx (5)
src/renderer/src/components/Chat/index.jsx (3)
donators(21-21)subscriberBadges(30-30)allStvEmotes(31-31)src/renderer/src/providers/ChatProvider.jsx (1)
settings(4235-4235)src/preload/index.js (1)
settings(219-219)src/renderer/src/providers/SettingsProvider.jsx (1)
settings(8-8)utils/constants.js (2)
DEFAULT_SCROLL_SEEK_VELOCITY(10-10)DEFAULT_SCROLL_SEEK_VELOCITY(10-10)
src/renderer/src/components/Messages/Message.jsx (1)
utils/regex.js (1)
createMentionRegex(10-29)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: test-builds (windows-latest)
There was a problem hiding this 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.
ℹ️ 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
| const MessageComponent = ({ | ||
| message, | ||
| userChatroomInfo, | ||
| chatroomId, | ||
| subscriberBadges, | ||
| allStvEmotes, | ||
| existingKickTalkBadges, | ||
| kickTalkBadges, | ||
| donatorBadges, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update Message callers for new per-user badge props
The Message component now destructures kickTalkBadges and donatorBadges as already‑filtered badge arrays for the rendered user. MessagesHandler was updated to pass those per-user arrays, but other Message callers (e.g. the user dialog and reply thread components) still pass the entire userKickTalkBadges dataset. Since the component no longer filters internally, those dialogs will render every known KickTalk badge (with undefined type/title values) for each message. This regresses badge display in those views; they need to compute the per-user badge array before passing it, or Message should retain the filtering logic.
Useful? React with 👍 / 👎.
Summary
Changes
Settings UI
Message Component Performance
React.memoto prevent unnecessary re-rendersuseCallbackfor stable referencesuserStylelookup from cosmetics storeisSupportEventtype checkingshouldHighlightMessagelogicConstants
DEFAULT_SCROLL_SEEK_VELOCITY = 300constantTest Plan
Summary by CodeRabbit
New Features
Refactor