Skip to content

feat: collapsible sidebar#2305

Open
basmilius wants to merge 3 commits intopingdotgg:mainfrom
basmilius:feat/collapsible-sidebar
Open

feat: collapsible sidebar#2305
basmilius wants to merge 3 commits intopingdotgg:mainfrom
basmilius:feat/collapsible-sidebar

Conversation

@basmilius
Copy link
Copy Markdown
Contributor

@basmilius basmilius commented Apr 23, 2026

What Changed

  • Added a sidebar.toggle keybinding command bound to mod+b by default, gated on when: "!terminalFocus" so it stays out of the way inside the terminal drawer.
  • Added a matching Toggle sidebar action to the command palette that surfaces the active shortcut hint.
  • Lifted SidebarProvider to the root layout so both the palette and the global chat shortcut handler can call useSidebar().toggleSidebar().
  • Exposed sidebar open/collapsed state via data-state on the sidebar wrapper so chrome can react with group-data-* classes instead of reading the context everywhere.
  • Electron drag-region headers (ChatView, NoActiveThreadState, settings) reserve pl-[90px] when the sidebar is collapsed so the macOS traffic lights don't overlap the active title. Windows/Linux fall through to the existing wco: overrides. The padding transitions at the same duration-200 ease-linear as the sidebar width, so it slides in sync.
  • Ran the sidebar toggle on the capture phase because Lexical's core onKeyDown claims mod+b for the bold command and calls preventDefault, which would trip the event.defaultPrevented guard in the shared handler.
  • Updated apps/web/src/keybindings.test.ts, apps/server/src/keybindings.test.ts defaults, and KEYBINDINGS.md.

Why

Closes #2282. The thread sidebar was always visible, which made it hard to fully focus on the active chat. A toggle is the smallest useful change that enables focus mode while keeping thread switching (mod+1..9, mod+shift+[/]) available even when the sidebar is collapsed — those listeners live on window in Sidebar.tsx and the sidebar DOM stays mounted under collapsible="offcanvas", so nothing extra was needed to satisfy that requirement from the issue.

Reusing the existing SidebarProvider / useSidebar() / cookie persistence already shipped in ui/sidebar.tsx kept the diff small and means sidebar state still survives reloads.

UI Changes

Video attached showing open → collapsed → open with mod+b, thread switching while collapsed, and the animated header padding on macOS so the traffic lights aren't covered.

Schermopname.2026-04-23.om.12.20.58.mov

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

Medium Risk
Moderate risk because it changes global keyboard handling (including capture-phase listeners) and lifts sidebar state to the app root, which could affect shortcut precedence and layout behavior across routes.

Overview
Introduces a new sidebar.toggle keybinding command, registered in contracts/server defaults (bound to mod+b when !terminalFocus) and documented in KEYBINDINGS.md, with corresponding test coverage updates.

Updates the web app to allow toggling the thread sidebar from both the command palette (new “Toggle sidebar” action showing the shortcut) and a global capture-phase keydown handler to avoid editor interception. Sidebar state management is lifted by moving SidebarProvider to the root route, and the sidebar wrapper now exposes data-state so Electron drag-region headers (ChatView, NoActiveThreadState, settings) can adjust left padding/transition when collapsed.

Reviewed by Cursor Bugbot for commit 5b49b1e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add collapsible sidebar with mod+b keybinding and command palette action

  • Adds a sidebar.toggle command registered in keybinding contracts, server defaults, and the command palette, mapped to mod+b when not in terminal focus.
  • Moves SidebarProvider from AppSidebarLayout to the app root in __root.tsx so sidebar state is accessible across routes.
  • Adds a capture-phase keydown listener in _chat.tsx to intercept mod+b before editor handlers (e.g. bold) can consume it.
  • Chat header and empty-state header animate left padding in Electron when the sidebar collapses, driven by group-data selectors on the SidebarProvider wrapper.

Macroscope summarized 5b49b1e.

Adds a `sidebar.toggle` keybinding command so users can collapse and
re-expand the thread sidebar to focus on the active chat, addressing
pingdotgg#2282. The default shortcut is `mod+b` and is gated on
`!terminalFocus` so it doesn't interfere with shell shortcuts.

- Contract: register `sidebar.toggle` as a static keybinding command.
- Server: add the default rule so it gets backfilled into the user's
  keybindings.json on startup.
- Web: lift `SidebarProvider` to the root so both the command palette
  and the global keydown handler in `_chat.tsx` can call
  `useSidebar().toggleSidebar()`. Expose sidebar state via
  `data-state` on the wrapper so header chrome can react without
  calling `useSidebar()`.
- Palette: add a "Toggle sidebar" action with the bound shortcut hint.
- Chrome: reserve 90px padding-left on the Electron drag-region
  headers when the sidebar is collapsed, so the macOS traffic lights
  don't overlap the active title; animate the padding to match the
  sidebar's width transition.
- Tests + docs updated.
Lexical's core keydown handler claims mod+b for the bold formatting
command and calls preventDefault, even under PlainTextPlugin. The
existing `event.defaultPrevented` guard in the global chat shortcut
handler then dropped the sidebar toggle before we could act.

Move sidebar.toggle into its own effect bound on the capture phase so
we see the event before Lexical does, and stopPropagation to keep it
from reaching the editor. Other shortcuts (chat.new, chat.newLocal)
stay on the bubble-phase listener since Lexical doesn't intercept
their keys.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 23, 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: cdffecad-a985-4e37-9873-f3319c47b7a5

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:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Apr 23, 2026
@basmilius basmilius changed the title Feat/collapsible sidebar feat: collapsible sidebar Apr 23, 2026
Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 92c64f5. Configure here.

Comment thread apps/web/src/routes/_chat.tsx
@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp Bot commented Apr 23, 2026

Approvability

Verdict: Needs human review

This PR introduces a new user-facing feature (collapsible sidebar with keyboard shortcut) that adds new behavior across multiple components and routes. New features with user-facing behavior changes warrant human review.

You can customize Macroscope's approvability policy. Learn more.

The bubble-phase handler in ChatRouteGlobalShortcuts already bails out
when useCommandPaletteStore.getState().open is true. The new
capture-phase listener for sidebar.toggle was missing that guard, so
mod+b would collapse the sidebar behind the open dialog.

Flagged by Cursor Bugbot on PR pingdotgg#2305.
@basmilius
Copy link
Copy Markdown
Contributor Author

@juliusmarminge Do I need to authenticate with Vercel or is it something that needs approval?

@Almighty-Shogun
Copy link
Copy Markdown

For someone who doesn't use T3 on fullscreen, this is very usefull!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 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.

[Feature]: Collapsible sidebar

2 participants