Skip to content

fix(spotlight): resolve panel stacking and hover perf issues#1654

Merged
zerob13 merged 3 commits into
devfrom
fix-style
May 21, 2026
Merged

fix(spotlight): resolve panel stacking and hover perf issues#1654
zerob13 merged 3 commits into
devfrom
fix-style

Conversation

@zhangmo8
Copy link
Copy Markdown
Collaborator

@zhangmo8 zhangmo8 commented May 21, 2026

  • Teleport spotlight overlay to body to escape sidebar compositing context
  • Drop contain:paint and will-change/translateZ from sidebar so spotlight z-index can take effect across stacking contexts
  • Add v-memo and rAF-batched mouseenter to result items; skip scrollIntoView on mouse-driven activeIndex changes
  • Raise SelectContent z-index to z-[80] so dropdowns render above the ChatStatusBar popover (z-72) and other custom overlays
  • Update Spotlight tasks.md to reflect actual completion state
  • Refresh tests for deepchat_sessions schema v28, buildHistoryTurns 5-arg signature, and ChatPage pending-lane DOM order

Summary by CodeRabbit

  • Documentation

    • Updated spotlight search task checklist and statuses.
  • Bug Fixes

    • Fixed select dropdown stacking/z-index.
    • Corrected pending chat interaction lane render order.
    • Updated session migration/version expectations.
  • Improvements

    • Enhanced spotlight navigation (mouse/keyboard) and reduced hover-driven scrolling.
    • Refined spotlight panel and overlay visuals.
    • Simplified sidebar styling to improve rendering.
  • Tests

    • Adjusted test assertions and formatting.

Review Change Stack

  - Teleport spotlight overlay to body to escape sidebar compositing context
  - Drop contain:paint and will-change/translateZ from sidebar so spotlight
    z-index can take effect across stacking contexts
  - Add v-memo and rAF-batched mouseenter to result items; skip scrollIntoView
    on mouse-driven activeIndex changes
  - Raise SelectContent z-index to z-[80] so dropdowns render above the
    ChatStatusBar popover (z-72) and other custom overlays
  - Update Spotlight tasks.md to reflect actual completion state
  - Refresh tests for deepchat_sessions schema v28, buildHistoryTurns 5-arg
    signature, and ChatPage pending-lane DOM order
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

📝 Walkthrough

Walkthrough

This PR advances the Spotlight search toward completion (Teleport rendering, keyboard/mouse active-item distinction, hover throttling), tweaks Spotlight visuals, updates DB schema tests to v28, simplifies sidebar/select CSS, and reforms a few test assertions and docs.

Changes

Spotlight Search Feature Completion & Layout Refinements

Layer / File(s) Summary
Feature Task Checklist Completion
docs/features/app-spotlight-search/tasks.md
T1–T9 checklist updated: most items checked; T6 (prefers-reduced-motion) and one T8 acceptance scenario remain unchecked.
Spotlight Keyboard/Mouse Interaction Handling
src/renderer/src/components/spotlight/SpotlightOverlay.vue
Teleport to body; result items add v-memo; activeChangeSource distinguishes keyboard vs mouse; keyboard handlers set source to keyboard; handleItemMouseEnter() coalesces hover events via requestAnimationFrame and sets source to mouse; watcher skips scroll-into-view for mouse-driven changes.
Spotlight Panel Styling
src/renderer/src/components/spotlight/SpotlightOverlay.vue
Adjusted light/dark gradients and overlay opacity/stop values for .spotlight-panel and its pseudo-elements using color-mix().
Database Schema Version 28
test/main/presenter/sqlitePresenter/deepchatSessionsTable.test.ts
Tests expect latest supported schema version 28; migration SQL mappings updated to include video_generation_options_json; unsupported-schema test simulates recorded 29 and updates error messaging.
Sidebar and Select CSS Optimizations
src/renderer/src/components/WindowSideBar.vue, src/shadcn/components/ui/select/SelectContent.vue
Sidebar scoped styles drop paint containment and remove transform/will-change; SelectContent :class z-index changed from z-50 to z-[80] (formatting adjusted).
Test Assertion Updates
test/main/presenter/agentRuntimePresenter/compactionService.test.ts, test/renderer/components/ChatPage.test.ts
Compaction service test assertions reformatted to multi-line toHaveBeenNthCalledWith blocks (no behavior change). ChatPage test DOM-order assertion reversed to expect pending input lane before the tool interaction overlay stub.

Sequence Diagram — Spotlight Interaction Flow

sequenceDiagram
  participant User
  participant SpotlightOverlay
  participant KeyboardHandler
  participant HoverHandler
  participant SpotlightStore
  participant DOM
  User->>SpotlightOverlay: Keyboard event (ArrowUp/Down/Home/End)
  SpotlightOverlay->>KeyboardHandler: handleKeyNavigation
  KeyboardHandler->>SpotlightStore: set activeChangeSource = 'keyboard'
  KeyboardHandler->>SpotlightStore: update active index
  SpotlightStore->>SpotlightOverlay: reactive update triggers watcher
  SpotlightOverlay->>DOM: scroll active item into view
  User->>SpotlightOverlay: Mouse enter on result item
  SpotlightOverlay->>HoverHandler: handleItemMouseEnter(item)
  HoverHandler->>HoverHandler: requestAnimationFrame coalescing
  HoverHandler->>SpotlightStore: set activeChangeSource = 'mouse' and update active index
  SpotlightStore->>SpotlightOverlay: reactive update triggers watcher
  SpotlightOverlay->>DOM: watcher early-returns (skip scroll for mouse)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

A rabbit nudges spotlight's glow, 🐇
Keys and hovers tell it where to go,
Schema grows to twenty-eight tonight,
CSS trimmed so panels sit just right,
Quick search hops forward under moonlight. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly addresses the main objectives: fixing spotlight panel stacking issues and hover performance problems through teleporting, z-index adjustments, and RAF-batched interactions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-style

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/renderer/src/components/spotlight/SpotlightOverlay.vue (1)

18-19: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Reset activeChangeSource before query-driven updates.

After one hover, this watcher treats later active-index changes as mouse-driven until Arrow/Home/End runs again. Typing a new query after hovering can therefore skip scrollIntoView and leave the new active result offscreen.

Suggested fix
-          `@input`="spotlightStore.setQuery(($event.target as HTMLInputElement).value)"
+          `@input`="handleInput"
const handleInput = (event: Event) => {
  activeChangeSource = 'keyboard'
  spotlightStore.setQuery((event.target as HTMLInputElement).value)
}

Also applies to: 124-126, 287-289

🤖 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 `@src/renderer/src/components/spotlight/SpotlightOverlay.vue` around lines 18 -
19, The input handler should reset activeChangeSource to 'keyboard' before
calling spotlightStore.setQuery so subsequent active-index changes are treated
as keyboard-driven (ensuring scrollIntoView runs); update the inline `@input`
handler (or the handleInput function if present) to set activeChangeSource =
'keyboard' immediately before calling spotlightStore.setQuery, and apply the
same change to the other input/update code paths referenced (the blocks around
the other occurrences of spotlightStore.setQuery at the locations noted).
🤖 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 `@src/renderer/src/components/spotlight/SpotlightOverlay.vue`:
- Line 5: Spotlight's teleported root is currently using z-[70] and gets painted
under newer overlays at z-72 and z-[80]; update the container's class in
SpotlightOverlay.vue (the element with class "window-no-drag-region fixed
inset-0 z-[70] ...") to use a higher z-index (e.g., z-[90] or above) so the
spotlight renders above the other overlays, and ensure any other teleported
roots or portal wrappers for this component are updated to the same z value.
- Around line 125-126: The current rAF flow stores a stale numeric index
(pendingMouseEnterIndex) causing setActiveItem to pick the wrong or out-of-range
row; change to capture the hovered item's unique id instead: introduce
pendingMouseEnterId (string|number), set it when mouse enters, cancel/reset
mouseEnterRaf as before, and in the rAF callback look up the current item in
spotlightStore.results by id and call setActiveItem(foundItem) only if found;
mirror the same replacement for the second occurrence that uses
pendingMouseEnterIndex (lines ~227-244) and ensure you clear pendingMouseEnterId
when leaving or when the raf is cancelled.
- Line 28: The v-memo in SpotlightOverlay.vue is too narrow (v-memo="[item.id,
index === spotlightStore.activeIndex, spotlightStore.query]") so rows can remain
stale when item fields change; update the memo dependency to either remove
v-memo entirely or include all rendered item properties (e.g., item, item.icon,
item.kind, item.title/item.titleKey via resolveItemTitle(item), item.subtitle,
item.snippet) and the activeIndex/query flags so the cached subtree updates when
useSpotlightStore rebuilds results; locate the v-memo usage in the
SpotlightOverlay component and replace the dependency array with a broader
dependency (or memoize on the entire item object identity) referencing
resolveItemTitle, spotlightStore.activeIndex, and spotlightStore.query as
needed.

---

Outside diff comments:
In `@src/renderer/src/components/spotlight/SpotlightOverlay.vue`:
- Around line 18-19: The input handler should reset activeChangeSource to
'keyboard' before calling spotlightStore.setQuery so subsequent active-index
changes are treated as keyboard-driven (ensuring scrollIntoView runs); update
the inline `@input` handler (or the handleInput function if present) to set
activeChangeSource = 'keyboard' immediately before calling
spotlightStore.setQuery, and apply the same change to the other input/update
code paths referenced (the blocks around the other occurrences of
spotlightStore.setQuery at the locations noted).
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 46abd22a-1d04-4f0f-aa3d-275d80f5588a

📥 Commits

Reviewing files that changed from the base of the PR and between e7085fb and 2893de9.

📒 Files selected for processing (7)
  • docs/features/app-spotlight-search/tasks.md
  • src/renderer/src/components/WindowSideBar.vue
  • src/renderer/src/components/spotlight/SpotlightOverlay.vue
  • src/shadcn/components/ui/select/SelectContent.vue
  • test/main/presenter/agentRuntimePresenter/compactionService.test.ts
  • test/main/presenter/sqlitePresenter/deepchatSessionsTable.test.ts
  • test/renderer/components/ChatPage.test.ts

Comment thread src/renderer/src/components/spotlight/SpotlightOverlay.vue Outdated
Comment thread src/renderer/src/components/spotlight/SpotlightOverlay.vue Outdated
Comment thread src/renderer/src/components/spotlight/SpotlightOverlay.vue Outdated
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 1 file(s) based on 3 unresolved review comments.

Files modified:

  • src/renderer/src/components/spotlight/SpotlightOverlay.vue

Commit: d80b8ce410d9da09362ea6be4a3c7b845f7d8655

The changes have been pushed to the fix-style branch.

Time taken: 4m 11s

Fixed 1 file(s) based on 3 unresolved review comments.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
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)
src/renderer/src/components/spotlight/SpotlightOverlay.vue (1)

227-254: 💤 Low value

Optional: collapse the duplicate findIndex/find lookups.

The rAF body iterates spotlightStore.results three times (the upfront findIndex on Line 228, then find on Line 243, then findIndex again on Line 247). For typical result counts this is negligible, but it can be reduced to one pass without changing semantics. The early bail-out on Line 229 can also be made O(1) by comparing against results[activeIndex]?.id instead of scanning the array on every hover.

♻️ Suggested simplification
 const handleItemMouseEnter = (item: SpotlightItem) => {
-  const currentIndex = spotlightStore.results.findIndex((r) => r.id === item.id)
-  if (currentIndex === -1 || spotlightStore.activeIndex === currentIndex) {
+  if (spotlightStore.results[spotlightStore.activeIndex]?.id === item.id) {
     return
   }
   pendingMouseEnterId = item.id
   if (mouseEnterRaf !== 0) {
     return
   }
   mouseEnterRaf = window.requestAnimationFrame(() => {
     mouseEnterRaf = 0
     const targetId = pendingMouseEnterId
     pendingMouseEnterId = null
     if (targetId === null) {
       return
     }
-    const foundItem = spotlightStore.results.find((r) => r.id === targetId)
-    if (!foundItem) {
-      return
-    }
     const targetIndex = spotlightStore.results.findIndex((r) => r.id === targetId)
     if (targetIndex < 0 || spotlightStore.activeIndex === targetIndex) {
       return
     }
     activeChangeSource = 'mouse'
     spotlightStore.setActiveItem(targetIndex)
   })
 }
🤖 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 `@src/renderer/src/components/spotlight/SpotlightOverlay.vue` around lines 227
- 254, handleItemMouseEnter performs multiple scans of spotlightStore.results;
simplify by caching const results = spotlightStore.results and use
results[spotlightStore.activeIndex]?.id for the early bail-out instead of
findIndex, then inside the RAF use the cached results to locate the target item
and index in a single pass (or use results.findIndex once and derive the item
from results[index])—update references to pendingMouseEnterId, mouseEnterRaf,
activeChangeSource and call spotlightStore.setActiveItem(targetIndex) as before
but without repeated array iterations.
🤖 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 `@src/renderer/src/components/spotlight/SpotlightOverlay.vue`:
- Around line 227-254: handleItemMouseEnter performs multiple scans of
spotlightStore.results; simplify by caching const results =
spotlightStore.results and use results[spotlightStore.activeIndex]?.id for the
early bail-out instead of findIndex, then inside the RAF use the cached results
to locate the target item and index in a single pass (or use results.findIndex
once and derive the item from results[index])—update references to
pendingMouseEnterId, mouseEnterRaf, activeChangeSource and call
spotlightStore.setActiveItem(targetIndex) as before but without repeated array
iterations.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 86410631-4e3d-431c-9d6a-60c1209d5189

📥 Commits

Reviewing files that changed from the base of the PR and between 1380253 and d80b8ce.

📒 Files selected for processing (1)
  • src/renderer/src/components/spotlight/SpotlightOverlay.vue

@zerob13 zerob13 merged commit d99e435 into dev May 21, 2026
3 checks passed
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