-
Notifications
You must be signed in to change notification settings - Fork 516
feat: improve scroll-to-bottom button loading animation with glow effect #794
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
Conversation
WalkthroughRefactors the scroll-to-bottom control in MessageList.vue by introducing a wrapper container that manages a new rotating gradient glow animation and conditional rendering. Renames CSS classes and animations, adjusts stacking and layout, and moves visual effects from the Button to the wrapper without altering exported interfaces. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant MessageList
participant Wrapper as Loading Container
participant Button
participant CSS as CSS Animations
User->>MessageList: Scrolls / reaches threshold
MessageList->>Wrapper: Render when (aboveThreshold || showCancelButton)
Wrapper->>CSS: Apply rotate-glow animation (gradient)
Wrapper->>Button: Render button (z-index above glow)
User->>Button: Click "Scroll to bottom"
Button->>MessageList: onClick handler invoked
MessageList->>MessageList: Scroll to bottom logic (unchanged)
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Suggested reviewers
Poem
✨ 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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
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
🧹 Nitpick comments (5)
src/renderer/src/components/message/MessageList.vue (5)
426-439
: Support reduced motion and minor perf nits
- Use a unique keyframe name to avoid global collisions.
- Hint the compositor with will-change.
- Add a reduced-motion fallback (see separate block below).
Apply this diff:
.scroll-to-bottom-loading-container::before { content: ''; position: absolute; top: -3px; left: -3px; right: -3px; bottom: -3px; border-radius: 0.5rem; background: linear-gradient(135deg, #9b59b6, #84cdfa, #5ad1cd); - animation: rotate-glow 1.2s linear infinite; + animation: dc-rotate-glow 1.2s linear infinite; + will-change: transform; pointer-events: none; z-index: 1; filter: blur(8px); }Additional (outside selected range) CSS for reduced motion is provided below.
441-455
: Mirror the perf and naming tweaks for ::afterKeep naming consistent and add will-change here as well.
Apply this diff:
.scroll-to-bottom-loading-container::after { content: ''; position: absolute; top: -5px; left: -5px; right: -5px; bottom: -5px; border-radius: 0.5rem; background: linear-gradient(135deg, #9b59b6, #84cdfa, #5ad1cd); - animation: rotate-glow 1.2s linear infinite; + animation: dc-rotate-glow 1.2s linear infinite; + will-change: transform; pointer-events: none; z-index: 0; filter: blur(20px); opacity: 0.6; }
457-463
: Make keyframe name uniqueKeyframes in scoped CSS are global; use a namespaced name to avoid clashes.
Apply this diff:
-@keyframes rotate-glow { +@keyframes dc-rotate-glow { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
426-455
: Nit: potential visual overlap with neighborsThe pseudo-elements extend 3–5px beyond the button; with
gap-2
(8px) this can encroach visually on adjacent buttons. If you notice overlap in dense layouts, consider increasing the gap slightly whenshowCancelButton
is true or reducing the negative offsets by 1–2px.
457-463
: Add reduced-motion fallback (outside selected range)Provide a non-animated fallback for users who prefer reduced motion.
You can append the following CSS after the keyframes block:
@media (prefers-reduced-motion: reduce) { .scroll-to-bottom-loading-container::before, .scroll-to-bottom-loading-container::after { animation: none !important; filter: blur(8px); opacity: 0.5; } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
src/renderer/src/components/message/MessageList.vue
(2 hunks)
🧰 Additional context used
📓 Path-based instructions (10)
src/renderer/src/**/*
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
src/renderer/src/**/*
: All user-facing strings must use i18n keys (avoid hardcoded user-visible text in code)
Use the 'vue-i18n' framework for all internationalization in the renderer
Ensure all user-visible text in the renderer uses the translation system
Files:
src/renderer/src/components/message/MessageList.vue
src/renderer/**/*.{vue,ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
渲染进程代码放在
src/renderer
Files:
src/renderer/src/components/message/MessageList.vue
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}
: Use the Composition API for better code organization and reusability
Implement proper state management with Pinia
Utilize Vue Router for navigation and route management
Leverage Vue's built-in reactivity system for efficient data handling
Files:
src/renderer/src/components/message/MessageList.vue
src/renderer/src/**/*.vue
📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)
Use scoped styles to prevent CSS conflicts between components
src/renderer/src/**/*.vue
: Follow existing component patterns when creating new UI components
Ensure responsive design with Tailwind CSS for new UI components
Add proper error handling and loading states to UI components
Files:
src/renderer/src/components/message/MessageList.vue
src/renderer/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
src/renderer/**/*.{ts,tsx,vue}
: Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
Use TypeScript for all code; prefer types over interfaces.
Avoid enums; use const objects instead.
Use arrow functions for methods and computed properties.
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.
Files:
src/renderer/src/components/message/MessageList.vue
src/renderer/**/*.{vue,ts}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
Implement lazy loading for routes and components.
Files:
src/renderer/src/components/message/MessageList.vue
src/renderer/**/*.{ts,vue}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
src/renderer/**/*.{ts,vue}
: Use useFetch and useAsyncData for data fetching.
Implement SEO best practices using Nuxt's useHead and useSeoMeta.
src/renderer/**/*.{ts,vue}
: Use Pinia for frontend state management
From renderer to main, call presenters via the usePresenter.ts composable
Files:
src/renderer/src/components/message/MessageList.vue
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use English for all logs and comments
Files:
src/renderer/src/components/message/MessageList.vue
src/renderer/**/*.vue
📄 CodeRabbit inference engine (CLAUDE.md)
src/renderer/**/*.vue
: Use Vue 3 Composition API for all components
Use Tailwind CSS with scoped styles for component styling
Files:
src/renderer/src/components/message/MessageList.vue
src/renderer/src/**
📄 CodeRabbit inference engine (CLAUDE.md)
Organize UI components by feature under src/renderer/src/
Files:
src/renderer/src/components/message/MessageList.vue
⏰ 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: build-check (x64)
🔇 Additional comments (2)
src/renderer/src/components/message/MessageList.vue (2)
71-74
: Wrapper-based glow composition: LGTMThe conditional wrapper and class binding cleanly decouple the visual glow from the Button component.
421-425
: Good call using isolation to contain stacking
isolation: isolate
ensures the glow layers don’t interfere with sibling stacking contexts.
<Button | ||
variant="outline" | ||
size="icon" | ||
class="w-8 h-8 shrink-0 rounded-lg relative z-10" | ||
@click="scrollToBottom" | ||
> | ||
<Icon icon="lucide:arrow-down" class="w-5 h-5 text-muted-foreground" /> | ||
</Button> | ||
</div> |
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.
🛠️ Refactor suggestion
Add accessible label (i18n) to icon-only button
Screen readers won’t have a name for this control. Provide an aria-label/title and hide the decorative icon from AT.
Apply this diff:
- <Button
- variant="outline"
- size="icon"
- class="w-8 h-8 shrink-0 rounded-lg relative z-10"
- @click="scrollToBottom"
- >
- <Icon icon="lucide:arrow-down" class="w-5 h-5 text-muted-foreground" />
- </Button>
+ <Button
+ variant="outline"
+ size="icon"
+ class="w-8 h-8 shrink-0 rounded-lg relative z-10"
+ :aria-label="t('common.scrollToBottom')"
+ :title="t('common.scrollToBottom')"
+ @click="scrollToBottom"
+ >
+ <Icon
+ icon="lucide:arrow-down"
+ class="w-5 h-5 text-muted-foreground"
+ aria-hidden="true"
+ />
+ </Button>
If the i18n key doesn’t exist, please add common.scrollToBottom
.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
<Button | |
variant="outline" | |
size="icon" | |
class="w-8 h-8 shrink-0 rounded-lg relative z-10" | |
@click="scrollToBottom" | |
> | |
<Icon icon="lucide:arrow-down" class="w-5 h-5 text-muted-foreground" /> | |
</Button> | |
</div> | |
<Button | |
variant="outline" | |
size="icon" | |
class="w-8 h-8 shrink-0 rounded-lg relative z-10" | |
:aria-label="t('common.scrollToBottom')" | |
:title="t('common.scrollToBottom')" | |
@click="scrollToBottom" | |
> | |
<Icon | |
icon="lucide:arrow-down" | |
class="w-5 h-5 text-muted-foreground" | |
aria-hidden="true" | |
/> | |
</Button> |
🤖 Prompt for AI Agents
In src/renderer/src/components/message/MessageList.vue around lines 75 to 83,
the icon-only Button lacks an accessible name; add an aria-label and title that
use the i18n key common.scrollToBottom (e.g.,
:aria-label="t('common.scrollToBottom')" and
:title="t('common.scrollToBottom')") and mark the decorative Icon as
aria-hidden="true" so assistive tech ignores it; also ensure the translations
file(s) include a common.scrollToBottom entry (add it if missing).
improve scroll-to-bottom button loading animation with glow effect

Summary by CodeRabbit