Skip to content

feat(plan-sidebar): add drag-to-resize with localStorage persistence#1439

Open
mia-riezebos wants to merge 3 commits intopingdotgg:mainfrom
mia-riezebos:plan-sidebar-resize-history-fix
Open

feat(plan-sidebar): add drag-to-resize with localStorage persistence#1439
mia-riezebos wants to merge 3 commits intopingdotgg:mainfrom
mia-riezebos:plan-sidebar-resize-history-fix

Conversation

@mia-riezebos
Copy link
Copy Markdown

@mia-riezebos mia-riezebos commented Mar 26, 2026

What Changed

Adds drag-to-resize to the Plan sidebar and follows up with cleanup for drag styles if the sidebar unmounts mid-resize.

  • Replaced the fixed w-[340px] layout with a dynamic width driven by React state
  • Added a left-edge resize handle for PlanSidebar
  • Clamp width between 240px and 560px and persist it to localStorage
  • Clean up document.body cursor and user-select overrides if the sidebar unmounts during a drag

Why

The Plan sidebar was fixed at 340px with no way to adjust it for different screen sizes or content widths.

This implementation keeps the resize handle fully inside the Plan sidebar bounds so it does not steal pointer interactions from the chat area. That is the same class of interaction problem described in #958, but this PR does not close #958 because that issue is specifically about the diff sidebar / SidebarRail.

Supersedes #1438 to correct the commit history and remove the incorrect Closes #958 reference from the original branch.

UI Changes

This is a drag-interaction change. The resize handle is invisible by default and shows a 2px border indicator on hover, consistent with the existing resize affordances.

Before:

Screen.Recording.2026-03-26.at.14.37.34_compressed.mp4

After:

Screen.Recording.2026-03-26.at.14.39.16_compressed.mp4

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Low Risk
Low risk UI-only change that adds pointer-based resizing and localStorage persistence; main risk is minor UX regressions (drag/scroll interactions or leaked cursor styles) mitigated by pointer capture and unmount cleanup.

Overview
Adds drag-to-resize support to PlanSidebar by replacing the fixed w-[340px] width with a state-driven inline width and a left-edge pointer resize handle.

Sidebar width is clamped (240–560px), restored from localStorage on mount, and persisted back to localStorage on drag end; body cursor/user-select overrides are applied during drag and cleaned up on release or unmount.

Written by Cursor Bugbot for commit 27f82f7. This will update automatically on new commits. Configure here.

Note

Add drag-to-resize with localStorage persistence to PlanSidebar

  • Adds a draggable left-edge handle to PlanSidebar.tsx that lets users resize the sidebar between 240px and 560px.
  • Width is persisted to localStorage under plan-sidebar-width and restored on subsequent renders via a new readStoredWidth helper.
  • During drag, document.body cursor is set to col-resize and text selection is disabled; both are cleaned up on drag end or unmount.

Macroscope summarized 27f82f7.

mia-riezebos and others added 2 commits March 26, 2026 14:58
The Plan sidebar was hardcoded at 340px with no way to resize it.
Now it has a proper resize handle on its left edge - drag to widen
or narrow between 240-560px. Width persists across close/reopen
and page refresh via localStorage.

Follows the same pointer-capture pattern as ThreadTerminalDrawer:
pointerDown captures, pointerMove updates width in real-time,
pointerEnd persists to storage. The resize hit-area lives fully
inside the sidebar bounds so it never overlaps the chat scroll
viewport.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PlanSidebar is conditionally rendered — if the component unmounts
mid-drag (user closes the sidebar while resizing), the body cursor
and user-select overrides would leak permanently. Added a useEffect
cleanup that unconditionally removes them, matching SidebarRail's
existing cleanup pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 26, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: da887f2c-00b9-4eaf-83e1-f113ec24eec5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with 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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Mar 26, 2026
Turns out localStorage remembers everything, including bad data. If
`plan-sidebar-width` gets corrupted, `Schema.decodeSync` would throw
inside the lazy state initializer and the sidebar would faceplant before
it mounted.

This catches decode failures, logs the error, and falls back to the
default width so one busted persisted value doesn't take the whole panel
down.

Co-Authored-By: GPT-5.4 <noreply@openai.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Diff sidebar resize rail steals chat scroll/drag interactions at the chat boundary

1 participant